mirror of
https://github.com/bmlong137/alfresco-keycloak.git
synced 2025-09-10 14:11:09 +00:00
Add inverse mapping / check
This commit is contained in:
@@ -130,7 +130,22 @@ public interface IDMClient
|
||||
* the processor handling the loaded roles
|
||||
* @return the number of processed roles
|
||||
*/
|
||||
int processRoles(int offset, int roleBatchSize, Consumer<RoleRepresentation> roleProcessor);
|
||||
int processRealmRoles(int offset, int roleBatchSize, Consumer<RoleRepresentation> roleProcessor);
|
||||
|
||||
/**
|
||||
* Loads and processes a batch of realm roles from Keycloak using an externally specified processor.
|
||||
*
|
||||
* @param search
|
||||
* a search term to filter roles
|
||||
* @param offset
|
||||
* the index of the first role to retrieve
|
||||
* @param roleBatchSize
|
||||
* the number of roles to load in one batch
|
||||
* @param roleProcessor
|
||||
* the processor handling the loaded roles
|
||||
* @return the number of processed roles
|
||||
*/
|
||||
int processRealmRoles(String search, int offset, int roleBatchSize, Consumer<RoleRepresentation> roleProcessor);
|
||||
|
||||
/**
|
||||
* Loads and processes a batch of client roles from Keycloak using an externally specified processor.
|
||||
@@ -145,5 +160,22 @@ public interface IDMClient
|
||||
* the processor handling the loaded roles
|
||||
* @return the number of processed roles
|
||||
*/
|
||||
int processRoles(String clientId, int offset, int roleBatchSize, Consumer<RoleRepresentation> roleProcessor);
|
||||
int processClientRoles(String clientId, int offset, int roleBatchSize, Consumer<RoleRepresentation> roleProcessor);
|
||||
|
||||
/**
|
||||
* Loads and processes a batch of client roles from Keycloak using an externally specified processor.
|
||||
*
|
||||
* @param clientId
|
||||
* the {@link ClientRepresentation#getId() (technical) ID} of a client from which to process defined roles
|
||||
* @param search
|
||||
* a search term to filter roles
|
||||
* @param offset
|
||||
* the index of the first role to retrieve
|
||||
* @param roleBatchSize
|
||||
* the number of roles to load in one batch
|
||||
* @param roleProcessor
|
||||
* the processor handling the loaded roles
|
||||
* @return the number of processed roles
|
||||
*/
|
||||
int processClientRoles(String clientId, String search, int offset, int roleBatchSize, Consumer<RoleRepresentation> roleProcessor);
|
||||
}
|
||||
|
@@ -310,7 +310,7 @@ public class IDMClientImpl implements InitializingBean, IDMClient
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int processRoles(final int offset, final int userBatchSize, final Consumer<RoleRepresentation> roleProcessor)
|
||||
public int processRealmRoles(final int offset, final int userBatchSize, final Consumer<RoleRepresentation> roleProcessor)
|
||||
{
|
||||
ParameterCheck.mandatory("roleProcessor", roleProcessor);
|
||||
|
||||
@@ -335,7 +335,35 @@ public class IDMClientImpl implements InitializingBean, IDMClient
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int processRoles(final String clientId, final int offset, final int userBatchSize,
|
||||
public int processRealmRoles(final String search, final int offset, final int userBatchSize,
|
||||
final Consumer<RoleRepresentation> roleProcessor)
|
||||
{
|
||||
ParameterCheck.mandatory("roleProcessor", roleProcessor);
|
||||
ParameterCheck.mandatoryString("search", search);
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("offset must be a non-negative integer");
|
||||
}
|
||||
if (userBatchSize <= 0)
|
||||
{
|
||||
throw new IllegalArgumentException("userBatchSize must be a positive integer");
|
||||
}
|
||||
|
||||
final URI uri = KeycloakUriBuilder.fromUri(this.deployment.getAuthServerBaseUrl()).path("/admin/realms/{realm}/roles")
|
||||
.queryParam("first", offset).queryParam("max", userBatchSize).queryParam("search", search)
|
||||
.build(this.deployment.getRealm());
|
||||
|
||||
final int processedRoles = this.processEntityBatch(uri, roleProcessor, RoleRepresentation.class);
|
||||
return processedRoles;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int processClientRoles(final String clientId, final int offset, final int userBatchSize,
|
||||
final Consumer<RoleRepresentation> roleProcessor)
|
||||
{
|
||||
ParameterCheck.mandatoryString("clientId", clientId);
|
||||
@@ -358,6 +386,35 @@ public class IDMClientImpl implements InitializingBean, IDMClient
|
||||
return processedRoles;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int processClientRoles(final String clientId, final String search, final int offset, final int userBatchSize,
|
||||
final Consumer<RoleRepresentation> roleProcessor)
|
||||
{
|
||||
ParameterCheck.mandatoryString("clientId", clientId);
|
||||
ParameterCheck.mandatoryString("search", search);
|
||||
ParameterCheck.mandatory("roleProcessor", roleProcessor);
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("offset must be a non-negative integer");
|
||||
}
|
||||
if (userBatchSize <= 0)
|
||||
{
|
||||
throw new IllegalArgumentException("userBatchSize must be a positive integer");
|
||||
}
|
||||
|
||||
final URI uri = KeycloakUriBuilder.fromUri(this.deployment.getAuthServerBaseUrl())
|
||||
.path("/admin/realms/{realm}/clients/{clientId}/roles").queryParam("first", offset).queryParam("max", userBatchSize)
|
||||
.queryParam("search", search).build(this.deployment.getRealm(), clientId);
|
||||
|
||||
final int processedRoles = this.processEntityBatch(uri, roleProcessor, RoleRepresentation.class);
|
||||
return processedRoles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and processes a batch of generic entities from Keycloak.
|
||||
*
|
||||
|
@@ -19,6 +19,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -73,6 +74,7 @@ public class AggregateRoleNameMapper implements InitializingBean, RoleNameMapper
|
||||
@Override
|
||||
public Optional<String> mapRoleName(final String roleName)
|
||||
{
|
||||
ParameterCheck.mandatoryString("roleName", roleName);
|
||||
LOGGER.debug("Mapping role {} using granular mappers {}", roleName, this.granularMappers);
|
||||
Optional<String> mappedName = Optional.empty();
|
||||
for (final RoleNameMapper mapper : this.granularMappers)
|
||||
@@ -87,4 +89,24 @@ public class AggregateRoleNameMapper implements InitializingBean, RoleNameMapper
|
||||
return mappedName;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> mapAuthorityName(final String authorityName)
|
||||
{
|
||||
ParameterCheck.mandatoryString("authorityName", authorityName);
|
||||
LOGGER.debug("Mapping authority name {} using granular mappers {}", authorityName, this.granularMappers);
|
||||
Optional<String> mappedName = Optional.empty();
|
||||
for (final RoleNameMapper mapper : this.granularMappers)
|
||||
{
|
||||
mappedName = mapper.mapAuthorityName(authorityName).map(name -> this.upperCaseRoles ? name.toLowerCase(Locale.ENGLISH) : name);
|
||||
if (mappedName.isPresent())
|
||||
{
|
||||
LOGGER.debug("Mapped authority name {} to {} using granular mapper {}", authorityName, mappedName, mapper);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return mappedName;
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ package de.acosix.alfresco.keycloak.repo.roles;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* This no-op implementation class of a role service may be used as a default implemenation in a subsystem proxy to avoid failing if no
|
||||
@@ -87,4 +88,33 @@ public class NoOpRoleServiceImpl implements RoleService
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isMappedFromKeycloak(final String authorityName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> getRoleName(final String authorityName)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> getClientFromRole(final String authorityName)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ package de.acosix.alfresco.keycloak.repo.roles;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.slf4j.Logger;
|
||||
@@ -35,6 +36,8 @@ public class PatternRoleNameMapper implements RoleNameMapper
|
||||
|
||||
protected Map<String, String> patternMappings;
|
||||
|
||||
protected Map<String, String> patternInverseMappings;
|
||||
|
||||
protected boolean upperCaseRoles;
|
||||
|
||||
/**
|
||||
@@ -46,6 +49,15 @@ public class PatternRoleNameMapper implements RoleNameMapper
|
||||
this.patternMappings = patternMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param patternInverseMappings
|
||||
* the patternInverseMappings to set
|
||||
*/
|
||||
public void setPatternInverseMappings(final Map<String, String> patternInverseMappings)
|
||||
{
|
||||
this.patternInverseMappings = patternInverseMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param upperCaseRoles
|
||||
* the upperCaseRoles to set
|
||||
@@ -75,7 +87,6 @@ public class PatternRoleNameMapper implements RoleNameMapper
|
||||
LOGGER.debug("Mapped role {} to {}", roleName, mappedName);
|
||||
return mappedName;
|
||||
}).map(name -> this.upperCaseRoles ? name.toUpperCase(Locale.ENGLISH) : name);
|
||||
;
|
||||
|
||||
if (!result.isPresent())
|
||||
{
|
||||
@@ -86,4 +97,32 @@ public class PatternRoleNameMapper implements RoleNameMapper
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> mapAuthorityName(final String authorityName)
|
||||
{
|
||||
ParameterCheck.mandatoryString("authorityName", authorityName);
|
||||
|
||||
Optional<String> result = Optional.empty();
|
||||
|
||||
if (this.patternInverseMappings != null)
|
||||
{
|
||||
final Optional<String> matchingPattern = this.patternMappings.keySet().stream().filter(pattern -> Pattern
|
||||
.compile(pattern, this.upperCaseRoles ? Pattern.CASE_INSENSITIVE : 0).matcher(authorityName).matches()).findFirst();
|
||||
|
||||
result = matchingPattern.map(pattern -> {
|
||||
final String replacement = this.patternMappings.get(pattern);
|
||||
LOGGER.debug("Authority name {} matches inverse mapping pattern {} - applying replacement pattern {}", authorityName,
|
||||
pattern, replacement);
|
||||
final String mappedName = Pattern.compile(pattern, this.upperCaseRoles ? Pattern.CASE_INSENSITIVE : 0)
|
||||
.matcher(authorityName).replaceAll(replacement);
|
||||
LOGGER.debug("Mapped authority name {} to {}", authorityName, mappedName);
|
||||
return mappedName;
|
||||
}).map(name -> this.upperCaseRoles ? name.toLowerCase(Locale.ENGLISH) : name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@@ -70,10 +70,30 @@ public class PrefixAttachingRoleNameMapper implements RoleNameMapper
|
||||
final String mappedName = this.prefix + roleName;
|
||||
LOGGER.debug("Mapped role {} to {} using prefix attachment", roleName, mappedName);
|
||||
result = Optional.of(mappedName).map(name -> this.upperCaseRoles ? name.toUpperCase(Locale.ENGLISH) : name);
|
||||
;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> mapAuthorityName(final String authorityName)
|
||||
{
|
||||
ParameterCheck.mandatoryString("authorityName", authorityName);
|
||||
|
||||
Optional<String> result = Optional.empty();
|
||||
|
||||
if (this.prefix != null)
|
||||
{
|
||||
final String ciAuthorityName = authorityName.toLowerCase(Locale.ENGLISH);
|
||||
final String ciPrefix = this.prefix.toLowerCase(Locale.ENGLISH);
|
||||
if (ciAuthorityName.startsWith(ciPrefix))
|
||||
{
|
||||
final String mappedName = authorityName.substring(this.prefix.length());
|
||||
LOGGER.debug("Mapped authority name {} to {} using prefix removal", authorityName, mappedName);
|
||||
result = Optional.of(mappedName);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@@ -37,4 +37,14 @@ public interface RoleNameMapper
|
||||
* operation
|
||||
*/
|
||||
Optional<String> mapRoleName(String roleName);
|
||||
|
||||
/**
|
||||
* Maps the name of an Alfresco authority to the name of a Keycloak role. This operation should act like the inverse of the
|
||||
* {@link #mapRoleName(String) original inbound mapping}.
|
||||
*
|
||||
* @param authorityName
|
||||
* the Alfresco authority name
|
||||
* @return the name of the Keycloak role
|
||||
*/
|
||||
Optional<String> mapAuthorityName(String authorityName);
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
package de.acosix.alfresco.keycloak.repo.roles;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Instances of this interface allow for lookup / retrieval of Keycloak roles.
|
||||
@@ -88,4 +89,31 @@ public interface RoleService
|
||||
*/
|
||||
List<Role> findRoles(String resourceName, String shortNameFilter);
|
||||
|
||||
/**
|
||||
* Checks whether the specified authority name is a role mapped from Keycloak.
|
||||
*
|
||||
* @param authorityName
|
||||
* the Alfresco authority name to check
|
||||
* @return {@code true} if the authority name matches any expected patterns of roles mapped from Keycloak, {@code false} otherwise
|
||||
*/
|
||||
boolean isMappedFromKeycloak(String authorityName);
|
||||
|
||||
/**
|
||||
* Retrieves the name of the original Keycloak role from which the specified authority name was mapped from within Keycloak.
|
||||
*
|
||||
* @param authorityName
|
||||
* the Alfresco authority name to process
|
||||
* @return the name of the Keycloak role from which the authority name was mapped unless the role was not mapped from Keycloak
|
||||
*/
|
||||
Optional<String> getRoleName(String authorityName);
|
||||
|
||||
/**
|
||||
* Retrieves the name of the client the specified authority name was mapped from within Keycloak.
|
||||
*
|
||||
* @param authorityName
|
||||
* the Alfresco authority name to process
|
||||
* @return the name of the client which defines the role unless the role is either not mapped from Keycloak or mapped from the realm
|
||||
* scope
|
||||
*/
|
||||
Optional<String> getClientFromRole(String authorityName);
|
||||
}
|
||||
|
@@ -18,11 +18,16 @@ package de.acosix.alfresco.keycloak.repo.roles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.service.cmr.security.AuthorityType;
|
||||
@@ -36,7 +41,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import de.acosix.alfresco.keycloak.repo.client.IDMClient;
|
||||
|
||||
public class RoleServiceImpl implements InitializingBean, RoleService
|
||||
public class RoleServiceImpl implements RoleService, InitializingBean
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RoleServiceImpl.class);
|
||||
@@ -280,6 +285,134 @@ public class RoleServiceImpl implements InitializingBean, RoleService
|
||||
return this.doFindRoles(resourceName, shortNameFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isMappedFromKeycloak(final String authorityName)
|
||||
{
|
||||
ParameterCheck.mandatoryString("authorityName", authorityName);
|
||||
|
||||
Optional<String> role = Optional.empty();
|
||||
|
||||
if (this.processRealmRoles)
|
||||
{
|
||||
role = this.realmRoleNameMapper.mapAuthorityName(authorityName);
|
||||
}
|
||||
if (this.processResourceRoles)
|
||||
{
|
||||
final Iterator<String> resourceIterator = this.resourceRoleNameMapper.keySet().iterator();
|
||||
while (!role.isPresent() && resourceIterator.hasNext())
|
||||
{
|
||||
final RoleNameMapper roleNameMapper = this.resourceRoleNameMapper.get(resourceIterator.next());
|
||||
role = roleNameMapper.mapAuthorityName(authorityName);
|
||||
}
|
||||
}
|
||||
return role.isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> getRoleName(final String authorityName)
|
||||
{
|
||||
ParameterCheck.mandatoryString("authorityName", authorityName);
|
||||
|
||||
Optional<String> role = Optional.empty();
|
||||
|
||||
if (this.processRealmRoles)
|
||||
{
|
||||
final UnaryOperator<String> realmRoleResolver = rn -> {
|
||||
final Set<String> matchingRoles = new HashSet<>();
|
||||
this.idmClient.processRealmRoles(rn, 0, Integer.MAX_VALUE, roleResult -> {
|
||||
if (roleResult.getName().equalsIgnoreCase(rn))
|
||||
{
|
||||
matchingRoles.add(roleResult.getName());
|
||||
}
|
||||
});
|
||||
|
||||
String matchingRole = null;
|
||||
if (matchingRoles.size() == 1)
|
||||
{
|
||||
matchingRole = matchingRoles.iterator().next();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("Failed to match apparent Keycloak realm role {} to unique role via admin API", rn);
|
||||
}
|
||||
return matchingRole;
|
||||
};
|
||||
role = this.realmRoleNameMapper.mapAuthorityName(authorityName).map(realmRoleResolver);
|
||||
}
|
||||
if (this.processResourceRoles)
|
||||
{
|
||||
final BinaryOperator<String> clientRoleResolver = (client, rn) -> {
|
||||
final Set<String> matchingRoles = new HashSet<>();
|
||||
this.idmClient.processClientRoles(client, rn, 0, Integer.MAX_VALUE, roleResult -> {
|
||||
if (roleResult.getName().equalsIgnoreCase(rn))
|
||||
{
|
||||
matchingRoles.add(roleResult.getName());
|
||||
}
|
||||
});
|
||||
|
||||
String matchingRole = null;
|
||||
if (matchingRoles.size() == 1)
|
||||
{
|
||||
matchingRole = matchingRoles.iterator().next();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("Failed to match apparent Keycloak role {} from client {} to unique role via admin API", rn, client);
|
||||
}
|
||||
return matchingRole;
|
||||
};
|
||||
final Iterator<String> resourceIterator = this.resourceRoleNameMapper.keySet().iterator();
|
||||
while (!role.isPresent() && resourceIterator.hasNext())
|
||||
{
|
||||
final String resource = resourceIterator.next();
|
||||
final RoleNameMapper roleNameMapper = this.resourceRoleNameMapper.get(resource);
|
||||
role = roleNameMapper.mapAuthorityName(authorityName).map(rn -> clientRoleResolver.apply(resource, rn));
|
||||
}
|
||||
}
|
||||
return role;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> getClientFromRole(final String authorityName)
|
||||
{
|
||||
ParameterCheck.mandatoryString("authorityName", authorityName);
|
||||
Optional<String> client = Optional.empty();
|
||||
Optional<String> role = Optional.empty();
|
||||
|
||||
if (this.processRealmRoles)
|
||||
{
|
||||
role = this.realmRoleNameMapper.mapAuthorityName(authorityName);
|
||||
}
|
||||
if (!role.isPresent() && this.processResourceRoles)
|
||||
{
|
||||
final Iterator<String> resourceIterator = this.resourceRoleNameMapper.keySet().iterator();
|
||||
while (!role.isPresent() && resourceIterator.hasNext())
|
||||
{
|
||||
final String resource = resourceIterator.next();
|
||||
final RoleNameMapper roleNameMapper = this.resourceRoleNameMapper.get(resource);
|
||||
role = roleNameMapper.mapAuthorityName(authorityName);
|
||||
if (role.isPresent())
|
||||
{
|
||||
client = Optional.of(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
protected List<Role> doFindRoles(final String shortNameFilter, final boolean realmOnly)
|
||||
{
|
||||
final List<Role> roles;
|
||||
@@ -480,11 +613,11 @@ public class RoleServiceImpl implements InitializingBean, RoleService
|
||||
|
||||
if (clientId != null)
|
||||
{
|
||||
this.idmClient.processRoles(clientId, 0, Integer.MAX_VALUE, processor);
|
||||
this.idmClient.processClientRoles(clientId, 0, Integer.MAX_VALUE, processor);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.idmClient.processRoles(0, Integer.MAX_VALUE, processor);
|
||||
this.idmClient.processRealmRoles(0, Integer.MAX_VALUE, processor);
|
||||
}
|
||||
|
||||
return results;
|
||||
@@ -508,7 +641,6 @@ public class RoleServiceImpl implements InitializingBean, RoleService
|
||||
{
|
||||
LOGGER.debug("Excluding role {} as it maps to group authority name {}", role.getName(), r);
|
||||
}
|
||||
;
|
||||
return allowed;
|
||||
}).map(r -> new Role(r, role.getName(), role.getDescription()));
|
||||
|
||||
|
@@ -145,6 +145,31 @@ public class ScriptRoleService extends BaseScopableProcessorExtension implements
|
||||
return roleArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the specified authority name is a role mapped from Keycloak.
|
||||
*
|
||||
* @param authorityName
|
||||
* the Alfresco authority name to check
|
||||
* @return {@code true} if the authority name matches any expected patterns of roles mapped from Keycloak, {@code false} otherwise
|
||||
*/
|
||||
public boolean isMappedFromKeycloak(final String authorityName)
|
||||
{
|
||||
return this.roleService.isMappedFromKeycloak(authorityName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the name of the client the specified authority name was mapped from within Keycloak.
|
||||
*
|
||||
* @param authorityName
|
||||
* the Alfresco authority name to process
|
||||
* @return the name of the client which defines the role unless the role is either not mapped from Keycloak or mapped from the realm
|
||||
* scope
|
||||
*/
|
||||
public String getClientFromRole(final String authorityName)
|
||||
{
|
||||
return this.roleService.getClientFromRole(authorityName).orElse(null);
|
||||
}
|
||||
|
||||
protected Scriptable makeRoleArray(final List<Role> roles)
|
||||
{
|
||||
final Scriptable sitesArray = Context.getCurrentContext().newArray(this.getScope(), roles.toArray(new Object[0]));
|
||||
|
@@ -17,6 +17,7 @@ package de.acosix.alfresco.keycloak.repo.roles;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
@@ -82,4 +83,34 @@ public class StaticRoleNameMapper implements RoleNameMapper
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> mapAuthorityName(final String authorityName)
|
||||
{
|
||||
ParameterCheck.mandatoryString("authorityName", authorityName);
|
||||
|
||||
Optional<String> result = Optional.empty();
|
||||
|
||||
if (this.nameMappings != null)
|
||||
{
|
||||
for (final Entry<String, String> entry : this.nameMappings.entrySet())
|
||||
{
|
||||
if (entry.getValue().equals(authorityName) || (this.upperCaseRoles && entry.getValue().equalsIgnoreCase(authorityName)))
|
||||
{
|
||||
final String mappedName = entry.getKey();
|
||||
LOGGER.debug("Mapped authority name {} to {} using static mapping", authorityName, mappedName);
|
||||
result = Optional.of(mappedName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!result.isPresent())
|
||||
{
|
||||
LOGGER.debug("No static mapping applies to authority name {}", authorityName);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user