mirror of
https://github.com/bmlong137/alfresco-keycloak.git
synced 2025-05-12 21:24:43 +00:00
Handle user and group name synchronisation consistently, and fix resource role exposure
- user names can now also be custom mapped from attributes - introduced priority in user/group processors - introduced operation dedicated to mapping authority name for use in user/group name collection operations
This commit is contained in:
parent
ab95cdc2f9
commit
96d01b34fe
@ -466,7 +466,7 @@ public class RoleServiceImpl implements RoleService, InitializingBean
|
||||
{
|
||||
List<Role> roles;
|
||||
|
||||
if (this.enabled && !this.processResourceRoles)
|
||||
if (this.enabled && this.processResourceRoles)
|
||||
{
|
||||
final RoleNameFilter roleNameFilter = this.resourceRoleNameFilter.get(resourceName);
|
||||
final RoleNameMapper roleNameMapper = this.resourceRoleNameMapper.get(resourceName);
|
||||
|
@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.alfresco.repo.security.sync.NodeDescription;
|
||||
@ -38,6 +39,8 @@ public abstract class BaseAttributeProcessor implements InitializingBean
|
||||
|
||||
protected NamespaceService namespaceService;
|
||||
|
||||
protected int priority = 50;
|
||||
|
||||
protected boolean mapBlankString;
|
||||
|
||||
protected boolean mapNull;
|
||||
@ -71,6 +74,15 @@ public abstract class BaseAttributeProcessor implements InitializingBean
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param priority
|
||||
* the priority to set
|
||||
*/
|
||||
public void setPriority(final int priority)
|
||||
{
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attributes
|
||||
* the attributes to set
|
||||
@ -169,4 +181,34 @@ public abstract class BaseAttributeProcessor implements InitializingBean
|
||||
nodeDescription.getProperties().put(propertyQName, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected Optional<String> mapAuthorityName(final QName authorityNameProperty, final Map<String, List<String>> attributes)
|
||||
{
|
||||
final Optional<String> result;
|
||||
final String attribute = this.attributePropertyQNameMappings.entrySet().stream()
|
||||
.filter((final Map.Entry<String, QName> e) -> authorityNameProperty.equals(e.getValue())).findFirst().map(Map.Entry::getKey)
|
||||
.orElse(null);
|
||||
if (attribute != null)
|
||||
{
|
||||
List<String> attrValues = attributes.get(attribute);
|
||||
if (attrValues != null && !this.mapBlankString)
|
||||
{
|
||||
attrValues = attrValues.stream().filter(Predicate.not(String::isBlank)).toList();
|
||||
}
|
||||
|
||||
if (attrValues != null && attrValues.size() == 1)
|
||||
{
|
||||
result = Optional.of(attrValues.get(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Optional.empty();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Optional.empty();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,10 @@
|
||||
*/
|
||||
package de.acosix.alfresco.keycloak.repo.sync;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.sync.NodeDescription;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.util.PropertyMap;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
|
||||
@ -40,6 +41,16 @@ public class DefaultGroupProcessor implements GroupProcessor
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
@ -50,20 +61,18 @@ public class DefaultGroupProcessor implements GroupProcessor
|
||||
if (this.enabled)
|
||||
{
|
||||
final PropertyMap properties = groupNode.getProperties();
|
||||
|
||||
final String existingName = DefaultTypeConverter.INSTANCE.convert(String.class,
|
||||
properties.get(ContentModel.PROP_AUTHORITY_NAME));
|
||||
final String existingDisplayName = DefaultTypeConverter.INSTANCE.convert(String.class,
|
||||
properties.get(ContentModel.PROP_AUTHORITY_DISPLAY_NAME));
|
||||
|
||||
if (existingName == null || existingName.isBlank())
|
||||
{
|
||||
properties.put(ContentModel.PROP_AUTHORITY_NAME, group.getId());
|
||||
}
|
||||
if (existingDisplayName == null || existingDisplayName.isBlank())
|
||||
{
|
||||
properties.put(ContentModel.PROP_AUTHORITY_DISPLAY_NAME, group.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> mapGroupName(final GroupRepresentation group)
|
||||
{
|
||||
return this.enabled ? Optional.of(group.getId()) : Optional.empty();
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package de.acosix.alfresco.keycloak.repo.sync;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.sync.NodeDescription;
|
||||
@ -99,6 +100,16 @@ public class DefaultPersonProcessor implements UserProcessor
|
||||
this.mapEnabledState = mapEnabledState;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
@ -110,6 +121,7 @@ public class DefaultPersonProcessor implements UserProcessor
|
||||
{
|
||||
final PropertyMap properties = person.getProperties();
|
||||
|
||||
properties.put(ContentModel.PROP_USERNAME, user.getUsername());
|
||||
if ((this.mapNull || user.getFirstName() != null) && this.mapFirstName)
|
||||
{
|
||||
properties.put(ContentModel.PROP_FIRSTNAME, user.getFirstName());
|
||||
@ -140,6 +152,7 @@ public class DefaultPersonProcessor implements UserProcessor
|
||||
if (this.enabled)
|
||||
{
|
||||
mappedProperties = new ArrayList<>(4);
|
||||
mappedProperties.add(ContentModel.PROP_USERNAME);
|
||||
if (this.mapFirstName)
|
||||
{
|
||||
mappedProperties.add(ContentModel.PROP_FIRSTNAME);
|
||||
@ -164,4 +177,14 @@ public class DefaultPersonProcessor implements UserProcessor
|
||||
|
||||
return mappedProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> mapUserName(final UserRepresentation user)
|
||||
{
|
||||
return this.enabled ? Optional.of(user.getUsername()) : Optional.empty();
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package de.acosix.alfresco.keycloak.repo.sync;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.alfresco.repo.security.sync.NodeDescription;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
|
||||
@ -25,9 +27,34 @@ import org.keycloak.representations.idm.GroupRepresentation;
|
||||
*
|
||||
* @author Axel Faust
|
||||
*/
|
||||
public interface GroupProcessor
|
||||
public interface GroupProcessor extends Comparable<GroupProcessor>
|
||||
{
|
||||
|
||||
/**
|
||||
* Retrieves the priority of this processor. A lower value specifies a higher priority and the mapped properties / group name of
|
||||
* processors with higher priorities may override those of lower priorities.
|
||||
*
|
||||
* @return the priority as an integer with {@code 50} as the default priority.
|
||||
*/
|
||||
default int getPriority()
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default int compareTo(final GroupProcessor other)
|
||||
{
|
||||
int res = Integer.compare(this.getPriority(), other.getPriority());
|
||||
if (res == 0)
|
||||
{
|
||||
res = this.getClass().getName().compareTo(other.getClass().getName());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps data from a Keycloak group representation to a description of an Alfresco node for the authority container.
|
||||
*
|
||||
@ -37,4 +64,16 @@ public interface GroupProcessor
|
||||
* the Alfresco node description
|
||||
*/
|
||||
void mapGroup(GroupRepresentation group, NodeDescription groupNodeDescription);
|
||||
|
||||
/**
|
||||
* Maps a Keycloak group representation to the group name to use in Alfresco.
|
||||
*
|
||||
* @param group
|
||||
* the Keycloak group representation
|
||||
* @return the Alfresco group name
|
||||
*/
|
||||
default Optional<String> mapGroupName(final GroupRepresentation group)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
@ -24,18 +24,19 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.management.subsystems.ActivateableBean;
|
||||
import org.alfresco.repo.security.sync.NodeDescription;
|
||||
import org.alfresco.repo.security.sync.UserRegistry;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.cmr.security.AuthorityType;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
@ -198,7 +199,7 @@ public class KeycloakUserRegistry implements UserRegistry, InitializingBean, Act
|
||||
if (this.active)
|
||||
{
|
||||
personNames = new UserCollection<>(this.personLoadBatchSize, this.identitiesClient.countUsers(),
|
||||
UserRepresentation::getUsername);
|
||||
this::determineEffectiveUserName);
|
||||
}
|
||||
|
||||
return personNames;
|
||||
@ -215,7 +216,7 @@ public class KeycloakUserRegistry implements UserRegistry, InitializingBean, Act
|
||||
if (this.active)
|
||||
{
|
||||
groupNames = new GroupCollection<>(this.groupLoadBatchSize, this.identitiesClient.countGroups(),
|
||||
group -> AuthorityType.GROUP.getPrefixString() + group.getId());
|
||||
this::determineEffectiveGroupName);
|
||||
}
|
||||
|
||||
return groupNames;
|
||||
@ -244,14 +245,17 @@ public class KeycloakUserRegistry implements UserRegistry, InitializingBean, Act
|
||||
protected NodeDescription mapUser(final UserRepresentation user)
|
||||
{
|
||||
final NodeDescription person = new NodeDescription(user.getId());
|
||||
|
||||
LOGGER.debug("Mapping user {} ({})", user.getUsername(), user.getId());
|
||||
|
||||
// reverse ordered so higher priority mappers may override properties of lower priority ones
|
||||
this.userProcessors.stream().sorted((o1, o2) -> -o1.compareTo(o2)).forEach(processor -> processor.mapUser(user, person));
|
||||
|
||||
final PropertyMap personProperties = person.getProperties();
|
||||
final String userName = this.determineEffectiveUserName(user);
|
||||
personProperties.put(ContentModel.PROP_USERNAME, userName);
|
||||
|
||||
LOGGER.debug("Mapping user {}", user.getUsername());
|
||||
|
||||
this.userProcessors.forEach(processor -> processor.mapUser(user, person));
|
||||
|
||||
// always wins against user-defined mappings for cm:userName
|
||||
personProperties.put(ContentModel.PROP_USERNAME, user.getUsername());
|
||||
LOGGER.debug("Mapped user {} ({}) as {}", user.getUsername(), user.getId(), userName);
|
||||
|
||||
return person;
|
||||
}
|
||||
@ -266,28 +270,20 @@ public class KeycloakUserRegistry implements UserRegistry, InitializingBean, Act
|
||||
protected NodeDescription mapGroup(final GroupRepresentation group)
|
||||
{
|
||||
final NodeDescription groupD = new NodeDescription(group.getId());
|
||||
final PropertyMap groupProperties = groupD.getProperties();
|
||||
|
||||
LOGGER.debug("Mapping group {} ({})", group.getName(), group.getId());
|
||||
|
||||
this.groupProcessors.forEach(processor -> processor.mapGroup(group, groupD));
|
||||
|
||||
// make sure groupName is mapped + prefixed
|
||||
String groupName = DefaultTypeConverter.INSTANCE.convert(String.class, groupProperties.get(ContentModel.PROP_AUTHORITY_NAME));
|
||||
if (groupName == null || groupName.isBlank())
|
||||
{
|
||||
// should never happen due to DefaultGroupProcessor
|
||||
groupName = group.getId();
|
||||
}
|
||||
if (AuthorityType.getAuthorityType(groupName) != AuthorityType.GROUP)
|
||||
{
|
||||
groupName = AuthorityType.GROUP.getPrefixString() + group.getId();
|
||||
}
|
||||
final PropertyMap groupProperties = groupD.getProperties();
|
||||
final String groupName = this.determineEffectiveGroupName(group);
|
||||
groupProperties.put(ContentModel.PROP_AUTHORITY_NAME, groupName);
|
||||
|
||||
LOGGER.debug("Mapped group {} ({}) as {}", group.getName(), group.getId(), groupName);
|
||||
|
||||
final Set<String> childAssociations = groupD.getChildAssociations();
|
||||
group.getSubGroups().stream().filter(subGroup -> isGroupAllowed(this.groupFilters, subGroup))
|
||||
.forEach(subGroup -> childAssociations.add(AuthorityType.GROUP.getPrefixString() + subGroup.getId()));
|
||||
.forEach(subGroup -> childAssociations.add(this.determineEffectiveGroupName(subGroup)));
|
||||
|
||||
int offset = 0;
|
||||
int processedMembers = 1;
|
||||
@ -296,7 +292,7 @@ public class KeycloakUserRegistry implements UserRegistry, InitializingBean, Act
|
||||
processedMembers = this.identitiesClient.processMembers(group.getId(), offset, this.personLoadBatchSize, user -> {
|
||||
if (KeycloakUserRegistry.isUserAllowed(this.userFilters, user))
|
||||
{
|
||||
childAssociations.add(user.getUsername());
|
||||
childAssociations.add(this.determineEffectiveUserName(user));
|
||||
}
|
||||
});
|
||||
offset += processedMembers;
|
||||
@ -307,6 +303,40 @@ public class KeycloakUserRegistry implements UserRegistry, InitializingBean, Act
|
||||
return groupD;
|
||||
}
|
||||
|
||||
private String determineEffectiveUserName(final UserRepresentation user)
|
||||
{
|
||||
final List<String> userNameCandidates = this.userProcessors.stream().sorted().map(gp -> gp.mapUserName(user))
|
||||
.filter(Predicate.not(Optional::isEmpty)).map(Optional::get).toList();
|
||||
|
||||
String userName = userNameCandidates.isEmpty() ? null : userNameCandidates.get(0);
|
||||
if (userName == null || userName.isBlank())
|
||||
{
|
||||
// should never happen due to DefaultPersonProcessor
|
||||
userName = user.getUsername();
|
||||
}
|
||||
return userName;
|
||||
}
|
||||
|
||||
private String determineEffectiveGroupName(final GroupRepresentation group)
|
||||
{
|
||||
final List<String> groupNameCandidates = this.groupProcessors.stream().sorted().map(gp -> gp.mapGroupName(group))
|
||||
.filter(Predicate.not(Optional::isEmpty)).map(Optional::get).toList();
|
||||
|
||||
String groupName = groupNameCandidates.isEmpty() ? null : groupNameCandidates.get(0);
|
||||
if (groupName == null || groupName.isBlank())
|
||||
{
|
||||
// should never happen due to DefaultGroupProcessor
|
||||
groupName = group.getId();
|
||||
}
|
||||
|
||||
// make sure groupName is prefixed
|
||||
if (AuthorityType.getAuthorityType(groupName) != AuthorityType.GROUP)
|
||||
{
|
||||
groupName = AuthorityType.GROUP.getPrefixString() + groupName;
|
||||
}
|
||||
return groupName;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class provides common basic functionalities for a collection of Keycloak authority-based data elements, supporting basic batch
|
||||
* load-based pagination / iterative traversal.
|
||||
@ -558,9 +588,12 @@ public class KeycloakUserRegistry implements UserRegistry, InitializingBean, Act
|
||||
final List<GroupRepresentation> subGroups = group.getSubGroups();
|
||||
if (subGroups == null || subGroups.isEmpty())
|
||||
{
|
||||
final List<GroupRepresentation> newSubGroups = new ArrayList<>();
|
||||
group.setSubGroups(newSubGroups);
|
||||
try
|
||||
{
|
||||
final int loadedChilren = KeycloakUserRegistry.this.identitiesClient.processSubGroups(group.getId(), subGroup -> {
|
||||
newSubGroups.add(subGroup);
|
||||
this.processGroupsRecursively(subGroup, filteredHandler, authorityProcessor, count);
|
||||
});
|
||||
count.addAndGet(loadedChilren);
|
||||
|
@ -15,6 +15,9 @@
|
||||
*/
|
||||
package de.acosix.alfresco.keycloak.repo.sync;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.sync.NodeDescription;
|
||||
import org.keycloak.representations.idm.GroupRepresentation;
|
||||
|
||||
@ -23,8 +26,7 @@ import org.keycloak.representations.idm.GroupRepresentation;
|
||||
*
|
||||
* @author Axel Faust
|
||||
*/
|
||||
public class SimpleGroupAttributeProcessor extends BaseAttributeProcessor
|
||||
implements GroupProcessor
|
||||
public class SimpleGroupAttributeProcessor extends BaseAttributeProcessor implements GroupProcessor
|
||||
{
|
||||
|
||||
protected boolean enabled;
|
||||
@ -38,6 +40,16 @@ public class SimpleGroupAttributeProcessor extends BaseAttributeProcessor
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
@ -51,4 +63,13 @@ public class SimpleGroupAttributeProcessor extends BaseAttributeProcessor
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> mapGroupName(final GroupRepresentation group)
|
||||
{
|
||||
return this.enabled ? this.mapAuthorityName(ContentModel.PROP_AUTHORITY_NAME, group.getAttributes()) : Optional.empty();
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,9 @@ package de.acosix.alfresco.keycloak.repo.sync;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.sync.NodeDescription;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
@ -28,8 +30,7 @@ import org.keycloak.representations.idm.UserRepresentation;
|
||||
*
|
||||
* @author Axel Faust
|
||||
*/
|
||||
public class SimpleUserAttributeProcessor extends BaseAttributeProcessor
|
||||
implements UserProcessor
|
||||
public class SimpleUserAttributeProcessor extends BaseAttributeProcessor implements UserProcessor
|
||||
{
|
||||
|
||||
protected boolean enabled;
|
||||
@ -43,6 +44,16 @@ public class SimpleUserAttributeProcessor extends BaseAttributeProcessor
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int getPriority()
|
||||
{
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
@ -66,4 +77,14 @@ public class SimpleUserAttributeProcessor extends BaseAttributeProcessor
|
||||
return this.enabled ? new HashSet<>(this.attributePropertyQNameMappings.values()) : Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Optional<String> mapUserName(final UserRepresentation user)
|
||||
{
|
||||
return this.enabled ? this.mapAuthorityName(ContentModel.PROP_USERNAME, user.getAttributes()) : Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
package de.acosix.alfresco.keycloak.repo.sync;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.alfresco.repo.security.sync.NodeDescription;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
@ -28,9 +29,34 @@ import org.keycloak.representations.idm.UserRepresentation;
|
||||
*
|
||||
* @author Axel Faust
|
||||
*/
|
||||
public interface UserProcessor
|
||||
public interface UserProcessor extends Comparable<UserProcessor>
|
||||
{
|
||||
|
||||
/**
|
||||
* Retrieves the priority of this processor. A lower value specifies a higher priority and the mapped properties / user name of
|
||||
* processors with higher priorities may override those of lower priorities.
|
||||
*
|
||||
* @return the priority as an integer with {@code 50} as the default priority.
|
||||
*/
|
||||
default int getPriority()
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
default int compareTo(final UserProcessor other)
|
||||
{
|
||||
int res = Integer.compare(this.getPriority(), other.getPriority());
|
||||
if (res == 0)
|
||||
{
|
||||
res = this.getClass().getName().compareTo(other.getClass().getName());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps data from a Keycloak user representation to a description of an Alfresco node for the person.
|
||||
*
|
||||
@ -47,4 +73,16 @@ public interface UserProcessor
|
||||
* @return the set of person node properties mapped by this instance
|
||||
*/
|
||||
Collection<QName> getMappedProperties();
|
||||
|
||||
/**
|
||||
* Maps a Keycloak user representation to the user name to use in Alfresco.
|
||||
*
|
||||
* @param group
|
||||
* the Keycloak user representation
|
||||
* @return the Alfresco user name
|
||||
*/
|
||||
default Optional<String> mapUserName(final UserRepresentation group)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user