mirror of
https://github.com/bmlong137/alfresco-keycloak.git
synced 2025-09-10 14:11:09 +00:00
abstraction of KeycloakAuthenticationComponent.handleUserTokens()
This commit is contained in:
@@ -49,8 +49,6 @@
|
|||||||
<property name="allowUserNamePasswordLogin" value="${keycloak.authentication.allowUserNamePasswordLogin}" />
|
<property name="allowUserNamePasswordLogin" value="${keycloak.authentication.allowUserNamePasswordLogin}" />
|
||||||
<property name="allowGuestLogin" value="${keycloak.authentication.allowGuestLogin}" />
|
<property name="allowGuestLogin" value="${keycloak.authentication.allowGuestLogin}" />
|
||||||
<property name="failExpiredTicketTokens" value="${keycloak.authentication.failExpiredTicketTokens}" />
|
<property name="failExpiredTicketTokens" value="${keycloak.authentication.failExpiredTicketTokens}" />
|
||||||
<property name="mapAuthorities" value="${keycloak.authentication.mapAuthorities}" />
|
|
||||||
<property name="mapPersonPropertiesOnLogin" value="${keycloak.authentication.mapPersonPropertiesOnLogin}" />
|
|
||||||
<property name="deployment" ref="keycloakDeployment" />
|
<property name="deployment" ref="keycloakDeployment" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
@@ -189,6 +187,11 @@
|
|||||||
<property name="processResourceRoles" value="${keycloak.roles.mapResourceRoles}" />
|
<property name="processResourceRoles" value="${keycloak.roles.mapResourceRoles}" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="authorityMapper" class="${project.artifactId}.authentication.KeycloakTokenAuthorityMapper">
|
||||||
|
<property name="enabled" value="${keycloak.authentication.mapAuthorities}" />
|
||||||
|
<property name="mapPersonPropertiesOnLogin" value="${keycloak.authentication.mapPersonPropertiesOnLogin}" />
|
||||||
|
</bean>
|
||||||
|
|
||||||
<bean id="userAuthority.default" class="${project.artifactId}.authentication.DefaultAuthorityExtractor">
|
<bean id="userAuthority.default" class="${project.artifactId}.authentication.DefaultAuthorityExtractor">
|
||||||
<property name="adapterConfig" ref="keycloakAdapterConfig" />
|
<property name="adapterConfig" ref="keycloakAdapterConfig" />
|
||||||
<property name="enabled" value="${keycloak.roles.mapRoles}" />
|
<property name="enabled" value="${keycloak.roles.mapRoles}" />
|
||||||
|
@@ -15,26 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package de.acosix.alfresco.keycloak.repo.authentication;
|
package de.acosix.alfresco.keycloak.repo.authentication;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
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.AlfrescoTransactionSupport;
|
|
||||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
|
||||||
import org.alfresco.service.cmr.repository.NodeService;
|
|
||||||
import org.alfresco.service.namespace.QName;
|
|
||||||
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;
|
||||||
@@ -48,12 +35,7 @@ import org.springframework.context.ApplicationContextAware;
|
|||||||
import de.acosix.alfresco.keycloak.repo.token.AccessTokenClient;
|
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.AlfrescoCompatibilityUtil;
|
|
||||||
import de.acosix.alfresco.keycloak.repo.util.RefreshableAccessTokenHolder;
|
import de.acosix.alfresco.keycloak.repo.util.RefreshableAccessTokenHolder;
|
||||||
import net.sf.acegisecurity.Authentication;
|
|
||||||
import net.sf.acegisecurity.GrantedAuthority;
|
|
||||||
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
|
||||||
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
@@ -80,17 +62,11 @@ public class KeycloakAuthenticationComponent extends AbstractAuthenticationCompo
|
|||||||
|
|
||||||
protected boolean allowGuestLogin;
|
protected boolean allowGuestLogin;
|
||||||
|
|
||||||
protected boolean mapAuthorities;
|
|
||||||
|
|
||||||
protected boolean mapPersonPropertiesOnLogin;
|
|
||||||
|
|
||||||
protected KeycloakDeployment deployment;
|
protected KeycloakDeployment deployment;
|
||||||
|
|
||||||
protected AccessTokenClient accessTokenClient;
|
protected AccessTokenClient accessTokenClient;
|
||||||
|
|
||||||
protected Collection<AuthorityExtractor> authorityExtractors;
|
protected List<TokenProcessor> tokenProcessors;
|
||||||
|
|
||||||
protected Collection<UserProcessor> userProcessors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -103,10 +79,10 @@ public class KeycloakAuthenticationComponent extends AbstractAuthenticationCompo
|
|||||||
PropertyCheck.mandatory(this, "keycloakDeployment", this.deployment);
|
PropertyCheck.mandatory(this, "keycloakDeployment", this.deployment);
|
||||||
|
|
||||||
this.accessTokenClient = new AccessTokenClient(this.deployment);
|
this.accessTokenClient = new AccessTokenClient(this.deployment);
|
||||||
this.authorityExtractors = Collections
|
|
||||||
.unmodifiableList(new ArrayList<>(this.applicationContext.getBeansOfType(AuthorityExtractor.class, false, true).values()));
|
List<TokenProcessor> tokenProcessors = new ArrayList<>(this.applicationContext.getBeansOfType(TokenProcessor.class, false, true).values());
|
||||||
this.userProcessors = Collections
|
Collections.sort(tokenProcessors);
|
||||||
.unmodifiableList(new ArrayList<>(this.applicationContext.getBeansOfType(UserProcessor.class, false, true).values()));
|
this.tokenProcessors = Collections.unmodifiableList(tokenProcessors);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,24 +150,6 @@ public class KeycloakAuthenticationComponent extends AbstractAuthenticationCompo
|
|||||||
this.setAllowGuestLogin(Boolean.TRUE.equals(allowGuestLogin));
|
this.setAllowGuestLogin(Boolean.TRUE.equals(allowGuestLogin));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mapAuthorities
|
|
||||||
* the mapAuthorities to set
|
|
||||||
*/
|
|
||||||
public void setMapAuthorities(final boolean mapAuthorities)
|
|
||||||
{
|
|
||||||
this.mapAuthorities = mapAuthorities;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mapPersonPropertiesOnLogin
|
|
||||||
* the mapPersonPropertiesOnLogin to set
|
|
||||||
*/
|
|
||||||
public void setMapPersonPropertiesOnLogin(final boolean mapPersonPropertiesOnLogin)
|
|
||||||
{
|
|
||||||
this.mapPersonPropertiesOnLogin = mapPersonPropertiesOnLogin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param deployment
|
* @param deployment
|
||||||
* the deployment to set
|
* the deployment to set
|
||||||
@@ -323,89 +281,11 @@ public class KeycloakAuthenticationComponent extends AbstractAuthenticationCompo
|
|||||||
*/
|
*/
|
||||||
public void handleUserTokens(final AccessToken accessToken, final IDToken idToken, final boolean freshLogin)
|
public void handleUserTokens(final AccessToken accessToken, final IDToken idToken, final boolean freshLogin)
|
||||||
{
|
{
|
||||||
if (this.mapAuthorities)
|
for (TokenProcessor processor : this.tokenProcessors)
|
||||||
{
|
{
|
||||||
LOGGER.debug("Mapping Keycloak access token to user authorities");
|
LOGGER.debug("Processing token with {}", processor.getName());
|
||||||
|
processor.handleUserTokens(this, accessToken, idToken, freshLogin);
|
||||||
final Set<String> mappedAuthorities = new HashSet<>();
|
}
|
||||||
this.authorityExtractors.stream().map(extractor -> extractor.extractAuthorities(accessToken))
|
|
||||||
.forEach(mappedAuthorities::addAll);
|
|
||||||
|
|
||||||
LOGGER.debug("Mapped user authorities from access token: {}", mappedAuthorities);
|
|
||||||
|
|
||||||
if (!mappedAuthorities.isEmpty())
|
|
||||||
{
|
|
||||||
final Authentication currentAuthentication = this.getCurrentAuthentication();
|
|
||||||
if (currentAuthentication instanceof UsernamePasswordAuthenticationToken)
|
|
||||||
{
|
|
||||||
GrantedAuthority[] grantedAuthorities = currentAuthentication.getAuthorities();
|
|
||||||
|
|
||||||
final List<GrantedAuthority> grantedAuthoritiesL = mappedAuthorities.stream().map(GrantedAuthorityImpl::new)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
grantedAuthoritiesL.addAll(Arrays.asList(grantedAuthorities));
|
|
||||||
|
|
||||||
grantedAuthorities = grantedAuthoritiesL.toArray(new GrantedAuthority[0]);
|
|
||||||
((UsernamePasswordAuthenticationToken) currentAuthentication).setAuthorities(grantedAuthorities);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOGGER.warn(
|
|
||||||
"Authentication for user is not of the expected type {} - Keycloak access token cannot be mapped to granted authorities",
|
|
||||||
UsernamePasswordAuthenticationToken.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (freshLogin && this.mapPersonPropertiesOnLogin)
|
|
||||||
{
|
|
||||||
final boolean requiresNew = AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY;
|
|
||||||
this.getTransactionService().getRetryingTransactionHelper().doInTransaction(() -> {
|
|
||||||
this.updatePerson(accessToken, idToken);
|
|
||||||
return null;
|
|
||||||
}, false, requiresNew);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the person for the current user with data mapped from the Keycloak tokens.
|
|
||||||
*
|
|
||||||
* @param accessToken
|
|
||||||
* the access token
|
|
||||||
* @param idToken
|
|
||||||
* the ID token
|
|
||||||
*/
|
|
||||||
protected void updatePerson(final AccessToken accessToken, final IDToken idToken)
|
|
||||||
{
|
|
||||||
final String userName = this.getCurrentUserName();
|
|
||||||
|
|
||||||
LOGGER.debug("Mapping person property updates for user {}", AlfrescoCompatibilityUtil.maskUsername(userName));
|
|
||||||
|
|
||||||
final NodeRef person = this.getPersonService().getPerson(userName);
|
|
||||||
|
|
||||||
final Map<QName, Serializable> updates = new HashMap<>();
|
|
||||||
this.userProcessors.forEach(processor -> processor.mapUser(accessToken, idToken != null ? idToken : accessToken, updates));
|
|
||||||
|
|
||||||
LOGGER.debug("Determined property updates for person node of user {}", AlfrescoCompatibilityUtil.maskUsername(userName));
|
|
||||||
|
|
||||||
final Set<QName> propertiesToRemove = updates.keySet().stream().filter(k -> updates.get(k) == null).collect(Collectors.toSet());
|
|
||||||
updates.keySet().removeAll(propertiesToRemove);
|
|
||||||
|
|
||||||
final NodeService nodeService = this.getNodeService();
|
|
||||||
final Map<QName, Serializable> currentProperties = nodeService.getProperties(person);
|
|
||||||
|
|
||||||
propertiesToRemove.retainAll(currentProperties.keySet());
|
|
||||||
if (!propertiesToRemove.isEmpty())
|
|
||||||
{
|
|
||||||
// there is no bulk-remove, so we need to use setProperties to achieve a single update event
|
|
||||||
final Map<QName, Serializable> newProperties = new HashMap<>(currentProperties);
|
|
||||||
newProperties.putAll(updates);
|
|
||||||
newProperties.keySet().removeAll(propertiesToRemove);
|
|
||||||
nodeService.setProperties(person, newProperties);
|
|
||||||
}
|
|
||||||
else if (!updates.isEmpty())
|
|
||||||
{
|
|
||||||
nodeService.addProperties(person, updates);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -0,0 +1,171 @@
|
|||||||
|
package de.acosix.alfresco.keycloak.repo.authentication;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent;
|
||||||
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||||
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.NodeService;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.IDToken;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
|
||||||
|
import de.acosix.alfresco.keycloak.repo.util.AlfrescoCompatibilityUtil;
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.GrantedAuthority;
|
||||||
|
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||||
|
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
|
||||||
|
public class KeycloakTokenAuthorityMapper implements TokenProcessor, InitializingBean, ApplicationContextAware {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(KeycloakTokenAuthorityMapper.class);
|
||||||
|
|
||||||
|
private static final String NAME = "AuthorityMapper";
|
||||||
|
|
||||||
|
protected ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
protected boolean enabled;
|
||||||
|
|
||||||
|
protected boolean mapPersonPropertiesOnLogin;
|
||||||
|
|
||||||
|
protected Collection<AuthorityExtractor> authorityExtractors;
|
||||||
|
|
||||||
|
protected Collection<UserProcessor> userProcessors;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mapPersonPropertiesOnLogin
|
||||||
|
* the mapPersonPropertiesOnLogin to set
|
||||||
|
*/
|
||||||
|
public void setMapPersonPropertiesOnLogin(final boolean mapPersonPropertiesOnLogin) {
|
||||||
|
this.mapPersonPropertiesOnLogin = mapPersonPropertiesOnLogin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws BeansException {
|
||||||
|
this.authorityExtractors = Collections
|
||||||
|
.unmodifiableList(new ArrayList<>(this.applicationContext.getBeansOfType(AuthorityExtractor.class, false, true).values()));
|
||||||
|
this.userProcessors = Collections
|
||||||
|
.unmodifiableList(new ArrayList<>(this.applicationContext.getBeansOfType(UserProcessor.class, false, true).values()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleUserTokens(AbstractAuthenticationComponent authComponent, AccessToken accessToken,
|
||||||
|
IDToken idToken, boolean freshLogin) {
|
||||||
|
if (!this.enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOGGER.debug("Mapping Keycloak access token to user authorities");
|
||||||
|
|
||||||
|
final Set<String> mappedAuthorities = new HashSet<>();
|
||||||
|
this.authorityExtractors.stream().map(extractor -> extractor.extractAuthorities(accessToken))
|
||||||
|
.forEach(mappedAuthorities::addAll);
|
||||||
|
|
||||||
|
LOGGER.debug("Mapped user authorities from access token: {}", mappedAuthorities);
|
||||||
|
|
||||||
|
if (!mappedAuthorities.isEmpty())
|
||||||
|
{
|
||||||
|
final Authentication currentAuthentication = authComponent.getCurrentAuthentication();
|
||||||
|
if (currentAuthentication instanceof UsernamePasswordAuthenticationToken)
|
||||||
|
{
|
||||||
|
GrantedAuthority[] grantedAuthorities = currentAuthentication.getAuthorities();
|
||||||
|
|
||||||
|
final List<GrantedAuthority> grantedAuthoritiesL = mappedAuthorities.stream().map(GrantedAuthorityImpl::new)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
grantedAuthoritiesL.addAll(Arrays.asList(grantedAuthorities));
|
||||||
|
|
||||||
|
grantedAuthorities = grantedAuthoritiesL.toArray(new GrantedAuthority[0]);
|
||||||
|
((UsernamePasswordAuthenticationToken) currentAuthentication).setAuthorities(grantedAuthorities);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGGER.warn(
|
||||||
|
"Authentication for user is not of the expected type {} - Keycloak access token cannot be mapped to granted authorities",
|
||||||
|
UsernamePasswordAuthenticationToken.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (freshLogin && this.mapPersonPropertiesOnLogin)
|
||||||
|
{
|
||||||
|
final boolean requiresNew = AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY;
|
||||||
|
authComponent.getTransactionService().getRetryingTransactionHelper().doInTransaction(() -> {
|
||||||
|
this.updatePerson(authComponent, accessToken, idToken);
|
||||||
|
return null;
|
||||||
|
}, false, requiresNew);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the person for the current user with data mapped from the Keycloak tokens.
|
||||||
|
*
|
||||||
|
* @param accessToken
|
||||||
|
* the access token
|
||||||
|
* @param idToken
|
||||||
|
* the ID token
|
||||||
|
*/
|
||||||
|
protected void updatePerson(AbstractAuthenticationComponent authComponent,
|
||||||
|
final AccessToken accessToken, final IDToken idToken)
|
||||||
|
{
|
||||||
|
final String userName = authComponent.getCurrentUserName();
|
||||||
|
|
||||||
|
LOGGER.debug("Mapping person property updates for user {}", AlfrescoCompatibilityUtil.maskUsername(userName));
|
||||||
|
|
||||||
|
final NodeRef person = authComponent.getPersonService().getPerson(userName);
|
||||||
|
|
||||||
|
final Map<QName, Serializable> updates = new HashMap<>();
|
||||||
|
this.userProcessors.forEach(processor -> processor.mapUser(accessToken, idToken != null ? idToken : accessToken, updates));
|
||||||
|
|
||||||
|
LOGGER.debug("Determined property updates for person node of user {}", AlfrescoCompatibilityUtil.maskUsername(userName));
|
||||||
|
|
||||||
|
final Set<QName> propertiesToRemove = updates.keySet().stream().filter(k -> updates.get(k) == null).collect(Collectors.toSet());
|
||||||
|
updates.keySet().removeAll(propertiesToRemove);
|
||||||
|
|
||||||
|
final NodeService nodeService = authComponent.getNodeService();
|
||||||
|
final Map<QName, Serializable> currentProperties = nodeService.getProperties(person);
|
||||||
|
|
||||||
|
propertiesToRemove.retainAll(currentProperties.keySet());
|
||||||
|
if (!propertiesToRemove.isEmpty())
|
||||||
|
{
|
||||||
|
// there is no bulk-remove, so we need to use setProperties to achieve a single update event
|
||||||
|
final Map<QName, Serializable> newProperties = new HashMap<>(currentProperties);
|
||||||
|
newProperties.putAll(updates);
|
||||||
|
newProperties.keySet().removeAll(propertiesToRemove);
|
||||||
|
nodeService.setProperties(person, newProperties);
|
||||||
|
}
|
||||||
|
else if (!updates.isEmpty())
|
||||||
|
{
|
||||||
|
nodeService.addProperties(person, updates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,51 @@
|
|||||||
|
package de.acosix.alfresco.keycloak.repo.authentication;
|
||||||
|
|
||||||
|
import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent;
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.IDToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this interface are used to process access tokens from Keycloak authenticated users. All instances of this
|
||||||
|
* interface in the Keycloak authentication subsystem will be consulted in the order of the priority field, followed by the
|
||||||
|
* order the beans are defined in the Spring application context.
|
||||||
|
*
|
||||||
|
* @author Brian Long
|
||||||
|
*/
|
||||||
|
public interface TokenProcessor extends Comparable<TokenProcessor> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A name of the processor for logging and reference purposes.
|
||||||
|
* @return A processor name.
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A priority for sorting beans for execution order.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
default int getPriority() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles access tokens from Keycloak.
|
||||||
|
*
|
||||||
|
* @param accessToken
|
||||||
|
* the Keycloak access token for the authenticated user
|
||||||
|
* @param idToken
|
||||||
|
* the Keycloak ID token for the authenticated user - may be {@code null} if not contained in the authentication response
|
||||||
|
* @param freshLogin
|
||||||
|
* {@code true} if the tokens are fresh, that is have just been obtained from an initial login, {@code false} otherwise
|
||||||
|
*/
|
||||||
|
void handleUserTokens(
|
||||||
|
final AbstractAuthenticationComponent authComponent,
|
||||||
|
final AccessToken accessToken,
|
||||||
|
final IDToken idToken,
|
||||||
|
final boolean freshLogin);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default int compareTo(TokenProcessor o) {
|
||||||
|
return Integer.compare(this.getPriority(), o.getPriority());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user