added retry for setCurrentUser race condition

This commit is contained in:
Brian Long 2022-07-11 18:52:16 -04:00
parent 782e785b6d
commit 970f1348e9
2 changed files with 27 additions and 1 deletions

View File

@ -15,13 +15,17 @@
*/ */
package de.acosix.alfresco.keycloak.repo.authentication; package de.acosix.alfresco.keycloak.repo.authentication;
import java.nio.file.AccessDeniedException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.alfresco.repo.management.subsystems.ActivateableBean; import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent; import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.util.PropertyCheck; import org.alfresco.util.PropertyCheck;
import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
@ -36,6 +40,7 @@ import de.acosix.alfresco.keycloak.repo.token.AccessTokenClient;
import de.acosix.alfresco.keycloak.repo.token.AccessTokenException; import de.acosix.alfresco.keycloak.repo.token.AccessTokenException;
import de.acosix.alfresco.keycloak.repo.token.AccessTokenRefreshException; import de.acosix.alfresco.keycloak.repo.token.AccessTokenRefreshException;
import de.acosix.alfresco.keycloak.repo.util.RefreshableAccessTokenHolder; import de.acosix.alfresco.keycloak.repo.util.RefreshableAccessTokenHolder;
import net.sf.acegisecurity.Authentication;
/** /**
* This component provides Keycloak-integrated user/password authentication support to an Alfresco instance. * This component provides Keycloak-integrated user/password authentication support to an Alfresco instance.
@ -68,6 +73,8 @@ public class KeycloakAuthenticationComponent extends AbstractAuthenticationCompo
protected List<TokenProcessor> tokenProcessors; protected List<TokenProcessor> tokenProcessors;
private RetryingTransactionHelper rthelper;
/** /**
* *
* {@inheritDoc} * {@inheritDoc}
@ -83,6 +90,15 @@ public class KeycloakAuthenticationComponent extends AbstractAuthenticationCompo
List<TokenProcessor> tokenProcessors = new ArrayList<>(this.applicationContext.getBeansOfType(TokenProcessor.class, false, true).values()); List<TokenProcessor> tokenProcessors = new ArrayList<>(this.applicationContext.getBeansOfType(TokenProcessor.class, false, true).values());
Collections.sort(tokenProcessors); Collections.sort(tokenProcessors);
this.tokenProcessors = Collections.unmodifiableList(tokenProcessors); this.tokenProcessors = Collections.unmodifiableList(tokenProcessors);
this.rthelper = new RetryingTransactionHelper();
this.rthelper.setMaxRetries(3);
this.rthelper.setMinRetryWaitMs(2000);
this.rthelper.setTransactionService(this.getTransactionService());
this.rthelper.setExtraExceptions(Arrays.asList(
AccessDeniedException.class // likely caused by a race condition, where multiple threads are authenticating at the same time
// this is due to modern web apps and threading
));
} }
/** /**
@ -296,4 +312,14 @@ public class KeycloakAuthenticationComponent extends AbstractAuthenticationCompo
{ {
return this.allowGuestLogin; return this.allowGuestLogin;
} }
public Authentication setCurrentUser(final String realUserName) throws AuthenticationException {
RetryingTransactionCallback<Authentication> rtcallback = new RetryingTransactionCallback<Authentication>() {
@Override
public Authentication execute() throws RuntimeException {
return KeycloakAuthenticationComponent.super.setCurrentUser(realUserName);
}
};
return this.rthelper.doInTransaction(rtcallback, this.getTransactionService().isReadOnly(), true);
}
} }

View File

@ -986,7 +986,7 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
if (sessionUser == null) if (sessionUser == null)
{ {
LOGGER.debug("Propagating through the user identity: {}", AlfrescoCompatibilityUtil.maskUsername(userId)); LOGGER.debug("Propagating through the user identity: {}", AlfrescoCompatibilityUtil.maskUsername(userId));
this.authenticationComponent.setCurrentUser(userId); this.keycloakAuthenticationComponent.setCurrentUser(userId);
session = httpServletRequest.getSession(); session = httpServletRequest.getSession();
try try