/* * (C) Copyright 2015 Netcentric AG. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package biz.netcentric.cq.tools.actool.authorizableinstaller.impl; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.regex.Pattern; import javax.jcr.AccessDeniedException; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.UnsupportedRepositoryOperationException; import javax.jcr.ValueFactory; import javax.jcr.ValueFormatException; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.apache.jackrabbit.api.security.user.Authorizable; import org.apache.jackrabbit.api.security.user.AuthorizableExistsException; import org.apache.jackrabbit.api.security.user.Group; import org.apache.jackrabbit.api.security.user.User; import org.apache.jackrabbit.api.security.user.UserManager; import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import biz.netcentric.cq.tools.actool.authorizableinstaller.AuthorizableCreatorException; import biz.netcentric.cq.tools.actool.authorizableinstaller.AuthorizableInstallerService; import biz.netcentric.cq.tools.actool.configmodel.AuthorizableConfigBean; import biz.netcentric.cq.tools.actool.configmodel.AuthorizablesConfig; import biz.netcentric.cq.tools.actool.helper.AcHelper; import biz.netcentric.cq.tools.actool.helper.AccessControlUtils; import biz.netcentric.cq.tools.actool.helper.Constants; import biz.netcentric.cq.tools.actool.helper.ContentHelper; import biz.netcentric.cq.tools.actool.history.AcInstallationLog; @Service @Component(metatype = true, label = "AC AuthorizableCreatorService", description = "Service that installs groups according to textual configuration files") public class AuthorizableInstallerServiceImpl implements AuthorizableInstallerService { private static final Logger LOG = LoggerFactory.getLogger(AuthorizableInstallerServiceImpl.class); private static final String PATH_SEGMENT_SYSTEMUSERS = "system"; private static final String PRINCIPAL_EVERYONE = "everyone"; // not using org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncContext.REP_EXTERNAL_ID since it is an // optional dependency and not available in AEM 6.1 public static final String REP_EXTERNAL_ID = "rep:externalId"; @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY) ExternalGroupInstallerServiceImpl externalGroupCreatorService; @Override public void createNewAuthorizables( AuthorizablesConfig authorizablesConfigBeans, final Session session, AcInstallationLog installLog) throws RepositoryException, AuthorizableCreatorException { Set<String> authorizablesFromConfigurations = authorizablesConfigBeans.getAuthorizableIds(); for (AuthorizableConfigBean authorizableConfigBean : authorizablesConfigBeans) { installAuthorizableConfigurationBean(session, authorizableConfigBean, installLog, authorizablesFromConfigurations); } } private void installAuthorizableConfigurationBean(final Session session, AuthorizableConfigBean authorizableConfigBean, AcInstallationLog installLog, Set<String> authorizablesFromConfigurations) throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException, AuthorizableExistsException, AuthorizableCreatorException { String authorizableId = authorizableConfigBean.getAuthorizableId(); LOG.debug("- start installation of authorizable: {}", authorizableId); UserManager userManager = AccessControlUtils.getUserManagerAutoSaveDisabled(session); ValueFactory vf = session.getValueFactory(); // if current authorizable from config doesn't exist yet Authorizable authorizableToInstall = userManager.getAuthorizable(authorizableId); if (authorizableToInstall == null) { authorizableToInstall = createNewAuthorizable(authorizableConfigBean, installLog, userManager, session); } // if current authorizable from config already exists in repository else { // update name for both groups and users setAuthorizableProperties(authorizableToInstall, authorizableConfigBean, session); // update password for users if (!authorizableToInstall.isGroup() && !authorizableConfigBean.isSystemUser() && StringUtils.isNotBlank(authorizableConfigBean.getPassword())) { ((User) authorizableToInstall).changePassword(authorizableConfigBean.getPassword()); } // move authorizable if path changed (retaining existing members) handleRecreationOfAuthorizableIfNecessary(session, authorizableConfigBean, installLog, userManager); applyGroupMembershipConfigIsMemberOf(installLog, authorizableConfigBean, userManager, session); } applyGroupMembershipConfigMembers(authorizableConfigBean, installLog, authorizableId, userManager, authorizablesFromConfigurations); if (StringUtils.isNotBlank(authorizableConfigBean.getMigrateFrom()) && authorizableConfigBean.isGroup()) { migrateFromOldGroup(authorizableConfigBean, userManager, installLog); } } /** This is only relevant for members that point to groups/users not contained in configuration. * {@link biz.netcentric.cq.tools.actool.configreader.YamlConfigurationMerger#ensureIsMemberOfIsUsedWherePossible()} ensures that * regular relationships between groups contained in config are kept in isMemberOf */ @SuppressWarnings("unchecked") void applyGroupMembershipConfigMembers(AuthorizableConfigBean authorizableConfigBean, AcInstallationLog installLog, String principalId, UserManager userManager, Set<String> authorizablesFromConfigurations) throws RepositoryException { if (authorizableConfigBean.isGroup()) { String[] membersInConfigArr = authorizableConfigBean.getMembers(); Group installedGroup = (Group) userManager.getAuthorizable(principalId); Set<String> membersInConfig = membersInConfigArr != null ? new HashSet<String>(Arrays.asList(membersInConfigArr)) : new HashSet<String>(); Set<String> relevantMembersInRepo = getDeclaredMembers(installedGroup); // ensure authorizables from config itself that are added via isMemberOf are not deleted relevantMembersInRepo = new HashSet<String>(CollectionUtils.subtract(relevantMembersInRepo, authorizablesFromConfigurations)); // ensure regular users are never removed relevantMembersInRepo = removeRegularUsers(relevantMembersInRepo, userManager); // take configuration 'allowExternalGroupNamesRegEx' into account (and remove matching groups from further handling) relevantMembersInRepo = removeExternalGroupsThatAreUntouchedByConfiguration(relevantMembersInRepo, installLog); Set<String> membersToAdd = new HashSet<String>(CollectionUtils.subtract(membersInConfig, relevantMembersInRepo)); Set<String> membersToRemove = new HashSet<String>(CollectionUtils.subtract(relevantMembersInRepo, membersInConfig)); if (!membersToAdd.isEmpty()) { installLog.addVerboseMessage(LOG, "Adding " + membersToAdd.size() + " external members to group " + authorizableConfigBean.getAuthorizableId()); for (String member : membersToAdd) { Authorizable memberGroup = userManager.getAuthorizable(member); if (memberGroup == null) { throw new IllegalStateException( "Member " + member + " does not exist and cannot be added as external member to group " + authorizableConfigBean.getAuthorizableId()); } installedGroup.addMember(memberGroup); installLog.addVerboseMessage(LOG, "Adding " + member + " as external member to group " + authorizableConfigBean.getAuthorizableId()); } } if (!membersToRemove.isEmpty()) { installLog.addVerboseMessage(LOG, "Removing " + membersToRemove.size() + " external members to group " + authorizableConfigBean.getAuthorizableId()); for (String member : membersToRemove) { Authorizable memberGroup = userManager.getAuthorizable(member); installedGroup.removeMember(memberGroup); installLog.addVerboseMessage(LOG, "Removing " + member + " as external member to group " + authorizableConfigBean.getAuthorizableId()); } } } } private Set<String> removeRegularUsers(Set<String> allMembersFromRepo, UserManager userManager) throws RepositoryException { Set<String> relevantMembers = new HashSet<String>(allMembersFromRepo); Iterator<String> relevantMembersIt = relevantMembers.iterator(); while (relevantMembersIt.hasNext()) { String memberId = relevantMembersIt.next(); Authorizable member = userManager.getAuthorizable(memberId); if (member != null && !member.isGroup() // if user && !member.getPath().startsWith(Constants.USERS_ROOT + "/system/") // but not system user && !member.getID().equals(Constants.USER_ANONYMOUS) // and not anonymous ) { // not relevant for further handling relevantMembersIt.remove(); } } return relevantMembers; } private Set<String> removeExternalGroupsThatAreUntouchedByConfiguration(Set<String> relevantMembersInRepo, AcInstallationLog installLog) { Set<String> relevantMembers = new HashSet<String>(relevantMembersInRepo); Pattern keepExistingMembershipsForGroupNamesRegEx = installLog.getAcConfiguration().getGlobalConfiguration().getKeepExistingMembershipsForGroupNamesRegEx(); if (keepExistingMembershipsForGroupNamesRegEx != null) { Iterator<String> relevantMembersIt = relevantMembers.iterator(); while (relevantMembersIt.hasNext()) { String member = relevantMembersIt.next(); if (keepExistingMembershipsForGroupNamesRegEx.matcher(member).matches()) { relevantMembersIt.remove(); } } } return relevantMembers; } private Set<String> getDeclaredMembers(Group installedGroup) throws RepositoryException { Set<String> membersInRepo = new HashSet<String>(); Iterator<Authorizable> currentMemberInRepo = installedGroup.getDeclaredMembers(); while (currentMemberInRepo.hasNext()) { membersInRepo.add(currentMemberInRepo.next().getID()); } return membersInRepo; } private void migrateFromOldGroup(AuthorizableConfigBean authorizableConfigBean, UserManager userManager, AcInstallationLog installLog) throws RepositoryException { Authorizable groupForMigration = userManager.getAuthorizable(authorizableConfigBean.getMigrateFrom()); String authorizableId = authorizableConfigBean.getAuthorizableId(); if (groupForMigration == null) { installLog.addMessage(LOG, "Group " + authorizableConfigBean.getMigrateFrom() + " does not exist (specified as migrateFrom in group " + authorizableId + ") - no action taken"); return; } if (!groupForMigration.isGroup()) { installLog.addWarning(LOG, "Specifying a user in 'migrateFrom' does not make sense (migrateFrom=" + authorizableConfigBean.getMigrateFrom() + " in " + authorizableId + ")"); return; } installLog.addMessage(LOG, "Migrating from group " + authorizableConfigBean.getMigrateFrom() + " to " + authorizableId); Set<Authorizable> usersFromGroupToTakeOver = new HashSet<Authorizable>(); Iterator<Authorizable> membersIt = ((Group) groupForMigration).getMembers(); while (membersIt.hasNext()) { Authorizable member = membersIt.next(); if (!member.isGroup()) { usersFromGroupToTakeOver.add(member); } } if (!usersFromGroupToTakeOver.isEmpty()) { installLog.addMessage(LOG, "- Taking over " + usersFromGroupToTakeOver.size() + " member users from group " + authorizableConfigBean.getMigrateFrom() + " to group " + authorizableId); Group currentGroup = (Group) userManager.getAuthorizable(authorizableId); for (Authorizable user : usersFromGroupToTakeOver) { currentGroup.addMember(user); } } groupForMigration.remove(); installLog.addMessage(LOG, "- Deleted group " + authorizableConfigBean.getMigrateFrom()); } private void handleRecreationOfAuthorizableIfNecessary(final Session session, AuthorizableConfigBean principalConfigBean, AcInstallationLog installLog, UserManager userManager) throws RepositoryException, AuthorizableCreatorException { String authorizableId = principalConfigBean.getAuthorizableId(); // compare intermediate paths Authorizable existingAuthorizable = userManager.getAuthorizable(authorizableId); String intermediatedPathOfExistingAuthorizable = existingAuthorizable.getPath() .substring(0, existingAuthorizable.getPath().lastIndexOf("/")); // Relative paths need to be prefixed with /home/groups (issue #10) String authorizablePathFromBean = principalConfigBean.getPath(); if (StringUtils.isNotEmpty(authorizablePathFromBean) && (authorizablePathFromBean.charAt(0) != '/')) { authorizablePathFromBean = (principalConfigBean.isGroup() ? Constants.GROUPS_ROOT : Constants.USERS_ROOT) + (principalConfigBean.isSystemUser() && !authorizablePathFromBean.startsWith(PATH_SEGMENT_SYSTEMUSERS) ? "/" + PATH_SEGMENT_SYSTEMUSERS : "") + "/" + authorizablePathFromBean; } boolean pathHasChanged = !StringUtils.equals(intermediatedPathOfExistingAuthorizable, authorizablePathFromBean) && StringUtils.isNotBlank(principalConfigBean.getPath()); if (pathHasChanged) { installLog.addMessage(LOG, "Found change of intermediate path for " + existingAuthorizable.getID() + ": " + intermediatedPathOfExistingAuthorizable + " -> " + authorizablePathFromBean); } // using "" to compare non-external (both sides) to true String externalIdExistingAuthorizable = StringUtils .defaultIfEmpty(AcHelper.valuesToString(existingAuthorizable.getProperty(REP_EXTERNAL_ID)), ""); String externalIdConfig = StringUtils.defaultIfEmpty(principalConfigBean.getExternalId(), ""); boolean externalIdHasChanged = !StringUtils.equals(externalIdExistingAuthorizable, externalIdConfig); if (externalIdHasChanged) { installLog.addMessage(LOG, "Found change of external id of " + existingAuthorizable.getID() + ": '" + externalIdExistingAuthorizable + "' (current) is not '" + externalIdConfig + "' (in config)"); } if (pathHasChanged || externalIdHasChanged) { // save members of existing group before deletion Set<Authorizable> membersOfDeletedGroup = new HashSet<Authorizable>(); if (existingAuthorizable.isGroup()) { Group existingGroup = (Group) existingAuthorizable; Iterator<Authorizable> memberIt = existingGroup.getDeclaredMembers(); while (memberIt.hasNext()) { membersOfDeletedGroup.add(memberIt.next()); } } // delete existingAuthorizable; existingAuthorizable.remove(); // create group again using values form config ValueFactory vf = session.getValueFactory(); Authorizable newAuthorizable = createNewAuthorizable(principalConfigBean, installLog, userManager, session); int countMovedMembersOfGroup = 0; if (newAuthorizable.isGroup()) { Group newGroup = (Group) newAuthorizable; // add members of deleted group for (Authorizable authorizable : membersOfDeletedGroup) { newGroup.addMember(authorizable); countMovedMembersOfGroup++; } } deleteOldIntermediatePath(session, session.getNode(intermediatedPathOfExistingAuthorizable)); installLog.addMessage(LOG, "Recreated authorizable " + newAuthorizable + " at path " + newAuthorizable.getPath() + (newAuthorizable.isGroup() ? "(retained " + countMovedMembersOfGroup + " members of group)" : "")); } } /** Deletes old intermediatePath parent node and all empty parent nodes up to /home/groups or /home/user. * * @param session * @param oldIntermediateNode * @throws RepositoryException */ private void deleteOldIntermediatePath(final Session session, Node oldIntermediateNode) throws RepositoryException { // if '/home/groups' or '/home/users' was intermediatedNode, these must // not get deleted! // also node to be deleted has to be empty, so no other authorizables // stored under this path get deleted while (!StringUtils.equals(Constants.GROUPS_ROOT, oldIntermediateNode.getPath()) && !StringUtils.equals(Constants.USERS_ROOT, oldIntermediateNode.getPath()) && !oldIntermediateNode.hasNodes()) { // delete old intermediatedPath Node parent = oldIntermediateNode.getParent(); session.removeItem(oldIntermediateNode.getPath()); // go one path level back for next iteration oldIntermediateNode = parent; } } private void applyGroupMembershipConfigIsMemberOf(AcInstallationLog installLog, AuthorizableConfigBean authorizableConfigBean, UserManager userManager, Session session) throws RepositoryException, ValueFormatException, UnsupportedRepositoryOperationException, AuthorizableExistsException, AuthorizableCreatorException { String[] memberOf = authorizableConfigBean.getMemberOf(); String authorizableId = authorizableConfigBean.getAuthorizableId(); Authorizable currentGroupFromRepository = userManager.getAuthorizable(authorizableId); Set<String> membershipGroupsFromConfig = getMembershipGroupsFromConfig(memberOf); Set<String> membershipGroupsFromRepository = getMembershipGroupsFromRepository(currentGroupFromRepository); applyGroupMembershipConfigIsMemberOf(authorizableId, installLog, userManager, session, membershipGroupsFromConfig, membershipGroupsFromRepository); } private Authorizable createNewAuthorizable( AuthorizableConfigBean principalConfigBean, AcInstallationLog installLog, UserManager userManager, Session session) throws AuthorizableExistsException, RepositoryException, AuthorizableCreatorException { boolean isGroup = principalConfigBean.isGroup(); String authorizableId = principalConfigBean.getAuthorizableId(); Authorizable newAuthorizable = null; if (isGroup) { newAuthorizable = createNewGroup(userManager, principalConfigBean, installLog, session); LOG.info("Successfully created new group: {}", authorizableId); } else { if (StringUtils.isNotEmpty(principalConfigBean.getExternalId())) { throw new IllegalStateException("External IDs are not supported for users (" + principalConfigBean.getAuthorizableId() + " is using '" + principalConfigBean.getExternalId() + "') - use a ootb sync handler to have users automatically created."); } newAuthorizable = createNewUser(userManager, principalConfigBean, installLog, session); LOG.info("Successfully created new user: {}", authorizableId); } return newAuthorizable; } private Set<String> getMembershipGroupsFromRepository(Authorizable currentGroupFromRepository) throws RepositoryException { Set<String> membershipGroupsFromRepository = new HashSet<String>(); Iterator<Group> memberOfGroupsIterator = currentGroupFromRepository.declaredMemberOf(); // build Set which contains the all Groups of which the existingGroup is // a member of while (memberOfGroupsIterator.hasNext()) { Authorizable memberOfGroup = memberOfGroupsIterator.next(); membershipGroupsFromRepository.add(memberOfGroup.getID()); } return membershipGroupsFromRepository; } private Set<String> getMembershipGroupsFromConfig(String[] memberOf) { // Set which holds all other groups which the current Group from config // is a member of Set<String> membershipGroupsFromConfig = new HashSet<String>(); if (memberOf != null) { // member of at least one other groups for (String s : memberOf) { membershipGroupsFromConfig.add(s); } } return membershipGroupsFromConfig; } @SuppressWarnings("unchecked") void applyGroupMembershipConfigIsMemberOf(String authorizableId, AcInstallationLog installLog, UserManager userManager, Session session, Set<String> membershipGroupsFromConfig, Set<String> membershipGroupsFromRepository) throws RepositoryException, AuthorizableExistsException, AuthorizableCreatorException { LOG.debug("mergeMemberOfGroups() for {}", authorizableId); // membership to everyone cannot be removed or added => take it out from both lists membershipGroupsFromConfig.remove(PRINCIPAL_EVERYONE); membershipGroupsFromRepository.remove(PRINCIPAL_EVERYONE); installLog.addVerboseMessage(LOG, "Authorizable " + authorizableId + " isMemberOf(repo)=" + membershipGroupsFromRepository); installLog.addVerboseMessage(LOG, "Authorizable " + authorizableId + " isMemberOf(conifg)=" + membershipGroupsFromConfig); Set<String> validatedMembershipGroupsFromConfig = validateAssignedGroups(userManager, session, authorizableId, membershipGroupsFromConfig, installLog); Collection<String> unChangedMembers = CollectionUtils.intersection(membershipGroupsFromRepository, validatedMembershipGroupsFromConfig); installLog.addVerboseMessage(LOG, "Authorizable " + authorizableId + " remains member of groups " + unChangedMembers); Collection<String> toBeAddedMembers = CollectionUtils.subtract(validatedMembershipGroupsFromConfig, membershipGroupsFromRepository); installLog.addVerboseMessage(LOG, "Authorizable " + authorizableId + " will be added as member of " + toBeAddedMembers); Collection<String> toBeRemovedMembers = CollectionUtils.subtract(membershipGroupsFromRepository, validatedMembershipGroupsFromConfig); Set<String> toBeSkippedFromRemovalMembers = new HashSet<String>(); Pattern ignoredMembershipsPattern = installLog.getAcConfiguration().getGlobalConfiguration().getKeepExistingMembershipsForGroupNamesRegEx(); Iterator<String> toBeRemovedMembersIt = toBeRemovedMembers.iterator(); while (toBeRemovedMembersIt.hasNext()) { String groupId = toBeRemovedMembersIt.next(); if ((ignoredMembershipsPattern != null) && ignoredMembershipsPattern.matcher(groupId).find()) { toBeSkippedFromRemovalMembers.add(groupId); toBeRemovedMembersIt.remove(); } } installLog.addVerboseMessage(LOG, "Authorizable " + authorizableId + " will be removed from members of " + toBeRemovedMembers); if (!toBeSkippedFromRemovalMembers.isEmpty()) { installLog.addVerboseMessage(LOG, "Authorizable " + authorizableId + " remains member of groups " + toBeSkippedFromRemovalMembers + " (due to configured ignoredMembershipsPattern=" + ignoredMembershipsPattern + ")"); } // perform changes Authorizable currentAuthorizable = userManager.getAuthorizable(authorizableId); for (String groupId : toBeAddedMembers) { LOG.debug("Membership Change: Adding {} to members of group {} in repository", authorizableId, groupId); Authorizable targetAuthorizable = userManager.getAuthorizable(groupId); ((Group) targetAuthorizable).addMember(currentAuthorizable); } for (String groupId : toBeRemovedMembers) { LOG.debug("Membership Change: Removing {} from members of group {} in repository", authorizableId, groupId); Authorizable targetAuthorizable = userManager.getAuthorizable(groupId); ((Group) targetAuthorizable).removeMember(currentAuthorizable); } if (!toBeAddedMembers.isEmpty() && !toBeAddedMembers.isEmpty()) { installLog.addVerboseMessage(LOG, "Membership Change: Authorizable " + authorizableId + " was added to " + toBeAddedMembers.size() + " and removed from " + toBeRemovedMembers.size() + " groups"); } } private Authorizable createNewGroup( final UserManager userManager, AuthorizableConfigBean principalConfigBean, AcInstallationLog installLog, Session session) throws AuthorizableExistsException, RepositoryException, AuthorizableCreatorException { String groupID = principalConfigBean.getAuthorizableId(); String intermediatePath = principalConfigBean.getPath(); // create new Group Group newGroup = null; try { if (StringUtils.isNotEmpty(principalConfigBean.getExternalId())) { if (externalGroupCreatorService == null) { throw new IllegalStateException("External IDs are not availabe for your AEM version (" + principalConfigBean.getAuthorizableId() + " is using '" + principalConfigBean.getExternalId() + "')"); } newGroup = (Group) externalGroupCreatorService.createGroupWithExternalId(userManager, principalConfigBean, installLog, session); LOG.info("Successfully created new external group: {}", groupID); } else { PrincipalImpl principalForNewGroup = new PrincipalImpl(groupID); if (StringUtils.isNotBlank(intermediatePath)) { newGroup = userManager.createGroup(principalForNewGroup, intermediatePath); } else { newGroup = userManager.createGroup(principalForNewGroup); } } } catch (AuthorizableExistsException e) { LOG.warn("Group {} already exists in system!", groupID); newGroup = (Group) userManager.getAuthorizable(groupID); } addMembersToReferencingAuthorizables(newGroup, principalConfigBean, userManager, session, installLog); setAuthorizableProperties(newGroup, principalConfigBean, session); return newGroup; } private void setAuthorizableProperties(Authorizable authorizable, AuthorizableConfigBean principalConfigBean, Session session) throws RepositoryException { String profileContent = principalConfigBean.getProfileContent(); if (StringUtils.isNotBlank(profileContent)) { ContentHelper.importContent(session, authorizable.getPath() + "/profile", profileContent); } String preferencesContent = principalConfigBean.getPreferencesContent(); if (StringUtils.isNotBlank(preferencesContent)) { ContentHelper.importContent(session, authorizable.getPath() + "/preferences", preferencesContent); } ValueFactory vf = session.getValueFactory(); String name = principalConfigBean.getName(); if (StringUtils.isNotBlank(name)) { if (authorizable.isGroup()) { authorizable.setProperty("profile/givenName", vf.createValue(name)); } else { String givenName = StringUtils.substringBeforeLast(name, " "); String familyName = StringUtils.substringAfterLast(name, " "); authorizable.setProperty("profile/givenName", vf.createValue(givenName)); authorizable.setProperty("profile/familyName", vf.createValue(familyName)); } } String description = principalConfigBean.getDescription(); if (StringUtils.isNotBlank(description)) { authorizable.setProperty("profile/aboutMe", vf.createValue(description)); } } private Authorizable createNewUser( final UserManager userManager, AuthorizableConfigBean principalConfigBean, AcInstallationLog installLog, Session session) throws AuthorizableExistsException, RepositoryException, AuthorizableCreatorException { String authorizableId = principalConfigBean.getAuthorizableId(); String password = principalConfigBean.getPassword(); boolean isSystemUser = principalConfigBean.isSystemUser(); String intermediatePath = principalConfigBean.getPath(); User newUser = null; if (isSystemUser) { // make sure all relative intermediate paths get the prefix suffix (but don't touch absolute paths) String systemPrefix = "system/"; if ((intermediatePath != null) && !intermediatePath.startsWith(systemPrefix) && !intermediatePath.startsWith("/")) { intermediatePath = systemPrefix + intermediatePath; } newUser = userManager.createSystemUser(authorizableId, intermediatePath); } else { newUser = userManager.createUser(authorizableId, password, new PrincipalImpl(authorizableId), intermediatePath); } setAuthorizableProperties(newUser, principalConfigBean, session); addMembersToReferencingAuthorizables(newUser, principalConfigBean, userManager, session, installLog); return newUser; } private void addMembersToReferencingAuthorizables(Authorizable authorizable, AuthorizableConfigBean principalConfigBean, final UserManager userManager, Session session, AcInstallationLog installLog) throws RepositoryException, AuthorizableCreatorException { String authorizableId = principalConfigBean.getAuthorizableId(); String[] memberOf = principalConfigBean.getMemberOf(); if ((authorizable != null) && (memberOf != null) && (memberOf.length > 0)) { // add group to groups according to configuration Set<String> referencingAuthorizablesToBeChanged = validateAssignedGroups(userManager, session, authorizableId, new HashSet<String>(Arrays.asList(memberOf)), installLog); if (!referencingAuthorizablesToBeChanged.isEmpty()) { LOG.debug("start adding {} to assignedGroups", authorizableId); for (String referencingAuthorizableToBeChangedId : referencingAuthorizablesToBeChanged) { Group referencingAuthorizableToBeChanged = (Group) userManager.getAuthorizable(referencingAuthorizableToBeChangedId); referencingAuthorizableToBeChanged.addMember(authorizable); LOG.debug("added to {} ", referencingAuthorizableToBeChanged); } } } } /** Validates the authorizables in 'membersOf' array of a given authorizable. Validation fails if an authorizable is a user. * * If an authorizable contained in membersOf array doesn't exist it gets created and the current authorizable gets added as a member. * * @param userManager * @param session * @param authorizablelId the ID of authorizable to validate * @param isMemberOf String array that contains the groups which the authorizable should be a member of * @param installLog * @return Set of authorizables which the current authorizable is a member of * @throws RepositoryException * @throws AuthorizableCreatorException if one of the authorizables contained in membersOf array is a user */ Set<String> validateAssignedGroups( final UserManager userManager, Session session, final String authorizablelId, final Set<String> isMemberOf, AcInstallationLog installLog) throws RepositoryException, AuthorizableCreatorException { Set<String> authorizableSet = new HashSet<String>(); for (String memberOfAuthorizable : isMemberOf) { if (StringUtils.equals(authorizablelId, memberOfAuthorizable)) { throw new AuthorizableCreatorException("Cannot add authorizable " + authorizablelId + " as member of itself."); } Authorizable authorizable = userManager.getAuthorizable(memberOfAuthorizable); // validation // if authorizable is existing in system if (authorizable != null) { // check if authorizable is a group if (authorizable.isGroup()) { authorizableSet.add(authorizable.getID()); } else { String message = "Failed to add authorizable " + authorizablelId + " to autorizable " + memberOfAuthorizable + "! Authorizable is not a group"; throw new AuthorizableCreatorException(message); } // if authorizable doesn't exist yet, it gets created and the // current authorizable gets added as a member } else { // check if authorizable is contained in any of the // configurations AuthorizableConfigBean configBeanForIsMemberOf = installLog.getAcConfiguration().getAuthorizablesConfig() .getAuthorizableConfig(memberOfAuthorizable); if (configBeanForIsMemberOf != null) { Group newGroup = (Group) createNewGroup(userManager, configBeanForIsMemberOf, installLog, session); authorizableSet.add(newGroup.getID()); LOG.info("Created group to be able to add {} to group {} ", authorizablelId, memberOfAuthorizable); } else { String message = "Failed to add group: " + authorizablelId + " as member to authorizable: " + memberOfAuthorizable + ". Neither found this authorizable (" + memberOfAuthorizable + ") in any of the configurations nor installed in the system!"; LOG.error(message); throw new AuthorizableCreatorException(message); } } } return authorizableSet; } }