Clear external group cache on explicit logout or user deletion (#1819)

Clears the external group cache whenever a user gets logged out by the logout rest method or the user gets deleted.

Co-authored-by: Eduard Heimbuch <eduard.heimbuch@cloudogu.com>
This commit is contained in:
Sebastian Sdorra
2021-10-06 14:34:10 +02:00
committed by GitHub
parent 1318f40e6d
commit d1de7bf214
8 changed files with 160 additions and 25 deletions

View File

@@ -40,15 +40,18 @@ import io.swagger.v3.oas.annotations.security.SecuritySchemes;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.event.ScmEventBus;
import sonia.scm.metrics.AuthenticationMetrics;
import sonia.scm.security.AccessToken;
import sonia.scm.security.AccessTokenBuilder;
import sonia.scm.security.AccessTokenBuilderFactory;
import sonia.scm.security.AccessTokenCookieIssuer;
import sonia.scm.security.AllowAnonymousAccess;
import sonia.scm.security.LogoutEvent;
import sonia.scm.security.Scope;
import sonia.scm.security.Tokens;
import sonia.scm.web.VndMediaType;
@@ -86,7 +89,6 @@ import java.util.Optional;
@Tag(name = "Authentication", description = "Authentication related endpoints")
})
@Path(AuthenticationResource.PATH)
@AllowAnonymousAccess
public class AuthenticationResource {
private static final Logger LOG = LoggerFactory.getLogger(AuthenticationResource.class);
@@ -99,17 +101,19 @@ public class AuthenticationResource {
private final Counter loginAttemptsCounter;
private final Counter loginFailedCounter;
private final Counter logoutCounter;
private final ScmEventBus eventBus;
@Inject(optional = true)
private LogoutRedirection logoutRedirection;
@Inject
public AuthenticationResource(AccessTokenBuilderFactory tokenBuilderFactory, AccessTokenCookieIssuer cookieIssuer, MeterRegistry meterRegistry) {
public AuthenticationResource(AccessTokenBuilderFactory tokenBuilderFactory, AccessTokenCookieIssuer cookieIssuer, MeterRegistry meterRegistry, ScmEventBus eventBus) {
this.tokenBuilderFactory = tokenBuilderFactory;
this.cookieIssuer = cookieIssuer;
this.loginAttemptsCounter = AuthenticationMetrics.loginAttempts(meterRegistry, AUTH_METRIC_TYPE);
this.loginFailedCounter = AuthenticationMetrics.loginFailed(meterRegistry, AUTH_METRIC_TYPE);
this.logoutCounter = AuthenticationMetrics.logout(meterRegistry, AUTH_METRIC_TYPE);
this.eventBus = eventBus;
}
@POST
@@ -134,6 +138,7 @@ public class AuthenticationResource {
schema = @Schema(implementation = ErrorDto.class)
)
)
@AllowAnonymousAccess
public Response authenticateViaForm(
@Context HttpServletRequest request,
@Context HttpServletResponse response,
@@ -174,6 +179,7 @@ public class AuthenticationResource {
schema = @Schema(implementation = ErrorDto.class)
)
)
@AllowAnonymousAccess
public Response authenticateViaJSONBody(
@Context HttpServletRequest request,
@Context HttpServletResponse response,
@@ -238,7 +244,12 @@ public class AuthenticationResource {
public Response logout(@Context HttpServletRequest request, @Context HttpServletResponse response) {
logoutCounter.increment();
SecurityUtils.getSubject().logout();
Subject subject = SecurityUtils.getSubject();
String primaryPrincipal = subject.getPrincipals().getPrimaryPrincipal().toString();
subject.logout();
eventBus.post(new LogoutEvent(primaryPrincipal));
// remove authentication cookie
cookieIssuer.invalidate(request, response);

View File

@@ -25,12 +25,16 @@
package sonia.scm.group;
import com.cronutils.utils.VisibleForTesting;
import com.github.legman.Subscribe;
import com.google.common.collect.ImmutableSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.HandlerEventType;
import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager;
import sonia.scm.security.Authentications;
import sonia.scm.security.LogoutEvent;
import sonia.scm.user.UserEvent;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -78,6 +82,19 @@ public class DefaultGroupCollector implements GroupCollector {
return groups;
}
@Subscribe(async = false)
public void clearCacheOnLogOut(LogoutEvent event) {
String principal = event.getPrimaryPrincipal();
cache.remove(principal);
}
@Subscribe(async = false)
public void clearCacheOnUserDeletion(UserEvent event) {
if (event.getEventType().equals(HandlerEventType.DELETE)) {
cache.remove(event.getItem().getName());
}
}
private void appendInternalGroups(String principal, ImmutableSet.Builder<String> builder) {
for (Group group : groupDAO.getAll()) {
if (group.isMember(principal)) {

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.security;
import javax.servlet.http.HttpServletRequest;
@@ -41,7 +41,11 @@ public final class SecurityRequests {
public static boolean isAuthenticationRequest(HttpServletRequest request) {
String uri = request.getRequestURI().substring(request.getContextPath().length());
return isAuthenticationRequest(uri);
return isAuthenticationRequest(uri) && !isLogoutMethod(request);
}
private static boolean isLogoutMethod(HttpServletRequest request) {
return "DELETE".equals(request.getMethod());
}
public static boolean isAuthenticationRequest(String uri) {