Search in sources :

Example 1 with SCIMUserOperationListener

use of org.wso2.carbon.identity.scim2.common.listener.SCIMUserOperationListener in project identity-inbound-provisioning-scim2 by wso2-extensions.

the class SCIMUserManager method patchGroup.

@Override
public Group patchGroup(String groupId, String currentGroupName, Map<String, List<PatchOperation>> patchOperations, Map<String, Boolean> requiredAttributes) throws NotImplementedException, BadRequestException, CharonException, NotFoundException {
    if (log.isDebugEnabled()) {
        log.debug("Updating group: " + currentGroupName);
    }
    try {
        List<PatchOperation> displayNameOperations = new ArrayList<>();
        List<PatchOperation> memberOperations = new ArrayList<>();
        String newGroupName = currentGroupName;
        for (List<PatchOperation> patchOperationList : patchOperations.values()) {
            for (PatchOperation patchOperation : patchOperationList) {
                if (StringUtils.equals(SCIMConstants.GroupSchemaConstants.DISPLAY_NAME, patchOperation.getAttributeName())) {
                    displayNameOperations.add(patchOperation);
                } else if (StringUtils.equals(SCIMConstants.GroupSchemaConstants.MEMBERS, patchOperation.getAttributeName())) {
                    memberOperations.add(patchOperation);
                }
            }
        }
        Collections.reverse(displayNameOperations);
        if (CollectionUtils.isNotEmpty(displayNameOperations)) {
            newGroupName = (String) displayNameOperations.get(0).getValues();
            setGroupDisplayName(currentGroupName, newGroupName);
        }
        Collections.sort(memberOperations);
        Set<String> addedMembers = new HashSet<>();
        Set<String> deletedMembers = new HashSet<>();
        Set<Object> newlyAddedMemberIds = new HashSet<>();
        Set<Object> deletedMemberIds = new HashSet<>();
        for (PatchOperation memberOperation : memberOperations) {
            if (memberOperation.getValues() instanceof Map) {
                Map<String, String> memberObject = (Map<String, String>) memberOperation.getValues();
                prepareAddedRemovedMemberLists(addedMembers, deletedMembers, newlyAddedMemberIds, deletedMemberIds, memberOperation, memberObject);
            } else if (memberOperation.getValues() instanceof List) {
                List<Map<String, String>> memberOperationValues = (List<Map<String, String>>) memberOperation.getValues();
                for (Map<String, String> memberObject : memberOperationValues) {
                    prepareAddedRemovedMemberLists(addedMembers, deletedMembers, newlyAddedMemberIds, deletedMemberIds, memberOperation, memberObject);
                }
            }
        }
        String userStoreDomainForGroup = IdentityUtil.extractDomainFromName(newGroupName);
        Set<String> temporaryMembers = new HashSet<>();
        if (isNotInternalOrApplicationGroup(userStoreDomainForGroup) && (!addedMembers.isEmpty() || !deletedMembers.isEmpty())) {
            for (String member : addedMembers) {
                String username = UserCoreUtil.addDomainToName(UserCoreUtil.removeDomainFromName(member), userStoreDomainForGroup);
                temporaryMembers.add(username);
            }
            addedMembers.clear();
            addedMembers.addAll(temporaryMembers);
            temporaryMembers.clear();
            for (String member : deletedMembers) {
                String username = UserCoreUtil.addDomainToName(UserCoreUtil.removeDomainFromName(member), userStoreDomainForGroup);
                temporaryMembers.add(username);
            }
            deletedMembers.clear();
            deletedMembers.addAll(temporaryMembers);
        }
        // Check for deleted members.
        Set<String> deletedMemberIdsFromUserstore = getMemberValuesFromUserstore(deletedMembers, userStoreDomainForGroup, newGroupName);
        // Check for added members.
        Set<String> addedMemberIdsFromUserstore = getMemberValuesFromUserstore(addedMembers, userStoreDomainForGroup, newGroupName);
        // Validate the memberIds sent in the update request against the Ids retrieved from the user store.
        if (isNotEmpty(addedMembers)) {
            validateUserIds(addedMemberIdsFromUserstore, newlyAddedMemberIds);
        }
        if (isNotEmpty(deletedMemberIds)) {
            validateUserIds(deletedMemberIdsFromUserstore, deletedMemberIds);
        }
        /*
            Set thread local property to signal the downstream SCIMUserOperationListener
            about the provisioning route.
            */
        SCIMCommonUtils.setThreadLocalIsManagedThroughSCIMEP(true);
        /*
            We do not update Identity_SCIM DB here since it is updated in SCIMUserOperationListener's methods.
            Update the group with added members and deleted members.
            */
        if (isNotEmpty(addedMembers) || isNotEmpty(deletedMembers)) {
            carbonUM.updateUserListOfRoleWithID(newGroupName, deletedMemberIdsFromUserstore.toArray(new String[0]), addedMemberIdsFromUserstore.toArray(new String[0]));
        }
    } catch (UserStoreException e) {
        throw resolveError(e, e.getMessage());
    } catch (IdentitySCIMException e) {
        throw new CharonException(e.getMessage(), e);
    } catch (IdentityApplicationManagementException e) {
        throw new CharonException("Error retrieving User Store name. ", e);
    } catch (BadRequestException e) {
        throw new CharonException("Error in updating the group", e);
    }
    return getGroup(groupId, requiredAttributes);
}
Also used : IdentityApplicationManagementException(org.wso2.carbon.identity.application.common.IdentityApplicationManagementException) ArrayList(java.util.ArrayList) IdentitySCIMException(org.wso2.carbon.identity.scim2.common.exceptions.IdentitySCIMException) PatchOperation(org.wso2.charon3.core.utils.codeutils.PatchOperation) UserStoreException(org.wso2.carbon.user.api.UserStoreException) SCIMUserStoreException(org.wso2.carbon.identity.scim2.common.extenstion.SCIMUserStoreException) BadRequestException(org.wso2.charon3.core.exceptions.BadRequestException) ArrayList(java.util.ArrayList) List(java.util.List) CharonException(org.wso2.charon3.core.exceptions.CharonException) Map(java.util.Map) HashMap(java.util.HashMap) AbstractMap(java.util.AbstractMap) LinkedHashSet(java.util.LinkedHashSet) HashSet(java.util.HashSet)

Example 2 with SCIMUserOperationListener

use of org.wso2.carbon.identity.scim2.common.listener.SCIMUserOperationListener in project identity-inbound-provisioning-scim2 by wso2-extensions.

the class SCIMUserManager method createGroup.

@Override
public Group createGroup(Group group, Map<String, Boolean> requiredAttributes) throws CharonException, ConflictException, BadRequestException {
    if (log.isDebugEnabled()) {
        log.debug("Creating group: " + group.getDisplayName());
    }
    try {
        // Modify display name if no domain is specified, in order to support multiple user store feature.
        String originalName = group.getDisplayName();
        String roleNameWithDomain = null;
        String domainName = "";
        try {
            if (getUserStoreDomainFromSP() != null) {
                domainName = getUserStoreDomainFromSP();
                roleNameWithDomain = IdentityUtil.addDomainToName(UserCoreUtil.removeDomainFromName(originalName), domainName);
            } else if (originalName.indexOf(CarbonConstants.DOMAIN_SEPARATOR) > 0) {
                domainName = IdentityUtil.extractDomainFromName(originalName);
                roleNameWithDomain = IdentityUtil.addDomainToName(UserCoreUtil.removeDomainFromName(originalName), domainName);
            } else {
                domainName = UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME;
                roleNameWithDomain = SCIMCommonUtils.getGroupNameWithDomain(originalName);
            }
        } catch (IdentityApplicationManagementException e) {
            throw new CharonException("Error retrieving User Store name. ", e);
        }
        if (!isInternalOrApplicationGroup(domainName) && StringUtils.isNotBlank(domainName) && !isSCIMEnabled(domainName)) {
            CharonException charonException = new CharonException();
            charonException.setDetail("Cannot create group through in userstore. SCIM is not " + "enabled for user store: " + domainName);
            charonException.setStatus(HttpStatus.SC_BAD_REQUEST);
            throw charonException;
        }
        group.setDisplayName(roleNameWithDomain);
        // check if the group already exists
        if (carbonUM.isExistingRole(group.getDisplayName(), false)) {
            String error = "Group with name: " + group.getDisplayName() + " already exists in the system.";
            throw new ConflictException(error);
        }
        // Set thread local property to signal the downstream SCIMUserOperationListener about the
        // provisioning route.
        SCIMCommonUtils.setThreadLocalIsManagedThroughSCIMEP(true);
        // If members are sent when creating the group, check whether users already exist in the user store.
        List<Object> userIds = group.getMembers();
        List<String> userDisplayNames = group.getMembersWithDisplayName();
        if (isNotEmpty(userIds)) {
            List<String> members = new ArrayList<>();
            for (Object userId : userIds) {
                String userIdLocalClaim = SCIMCommonUtils.getSCIMtoLocalMappings().get(SCIMConstants.CommonSchemaConstants.ID_URI);
                org.wso2.carbon.user.core.common.User coreUser = null;
                if (StringUtils.isNotBlank(userIdLocalClaim)) {
                    coreUser = carbonUM.getUserWithID((String) userId, null, UserCoreConstants.DEFAULT_PROFILE);
                }
                if (coreUser == null) {
                    String error = "User: " + userId + " doesn't exist in the user store. " + "Hence, can not create the group: " + group.getDisplayName();
                    throw new IdentitySCIMException(error);
                } else if (coreUser.getUsername().indexOf(UserCoreConstants.DOMAIN_SEPARATOR) > 0 && !StringUtils.containsIgnoreCase(coreUser.getUsername(), domainName)) {
                    String error = "User: " + userId + " doesn't exist in the same user store. " + "Hence, can not create the group: " + group.getDisplayName();
                    throw new IdentitySCIMException(error);
                } else {
                    members.add(coreUser.getUserID());
                    if (isNotEmpty(userDisplayNames)) {
                        boolean userContains = false;
                        for (String user : userDisplayNames) {
                            user = user.indexOf(UserCoreConstants.DOMAIN_SEPARATOR) > 0 ? user.split(UserCoreConstants.DOMAIN_SEPARATOR)[1] : user;
                            if (isUserContains(coreUser, user)) {
                                userContains = true;
                                break;
                            }
                        }
                        if (!userContains) {
                            throw new IdentitySCIMException("Given SCIM user Id and name does not match..");
                        }
                    }
                }
            }
            // Add other scim attributes in the identity DB since user store doesn't support some attributes.
            SCIMGroupHandler scimGroupHandler = new SCIMGroupHandler(carbonUM.getTenantId());
            scimGroupHandler.createSCIMAttributes(group);
            carbonUM.addRoleWithID(group.getDisplayName(), members.toArray(new String[0]), null, false);
            if (log.isDebugEnabled()) {
                log.debug("Group: " + group.getDisplayName() + " is created through SCIM.");
            }
        } else {
            // Add other scim attributes in the identity DB since user store doesn't support some attributes.
            SCIMGroupHandler scimGroupHandler = new SCIMGroupHandler(carbonUM.getTenantId());
            scimGroupHandler.createSCIMAttributes(group);
            carbonUM.addRoleWithID(group.getDisplayName(), null, null, false);
            if (log.isDebugEnabled()) {
                log.debug("Group: " + group.getDisplayName() + " is created through SCIM.");
            }
        }
    } catch (UserStoreException e) {
        try {
            SCIMGroupHandler scimGroupHandler = new SCIMGroupHandler(carbonUM.getTenantId());
            scimGroupHandler.deleteGroupAttributes(group.getDisplayName());
        } catch (UserStoreException | IdentitySCIMException ex) {
            throw resolveError(e, "Error occurred while doing rollback operation of the SCIM " + "table entry for role: " + group.getDisplayName());
        }
        handleErrorsOnRoleNamePolicy(e);
        throw resolveError(e, "Error occurred while adding role : " + group.getDisplayName());
    } catch (IdentitySCIMException | BadRequestException e) {
        String error = "One or more group members do not exist in the same user store. " + "Hence, can not create the group: " + group.getDisplayName();
        if (log.isDebugEnabled()) {
            log.debug(error, e);
        }
        throw new BadRequestException(error, ResponseCodeConstants.INVALID_VALUE);
    }
    return group;
}
Also used : ConflictException(org.wso2.charon3.core.exceptions.ConflictException) IdentityApplicationManagementException(org.wso2.carbon.identity.application.common.IdentityApplicationManagementException) ArrayList(java.util.ArrayList) IdentitySCIMException(org.wso2.carbon.identity.scim2.common.exceptions.IdentitySCIMException) UserStoreException(org.wso2.carbon.user.api.UserStoreException) SCIMUserStoreException(org.wso2.carbon.identity.scim2.common.extenstion.SCIMUserStoreException) BadRequestException(org.wso2.charon3.core.exceptions.BadRequestException) CharonException(org.wso2.charon3.core.exceptions.CharonException) SCIMGroupHandler(org.wso2.carbon.identity.scim2.common.group.SCIMGroupHandler)

Example 3 with SCIMUserOperationListener

use of org.wso2.carbon.identity.scim2.common.listener.SCIMUserOperationListener in project identity-inbound-provisioning-scim2 by wso2-extensions.

the class SCIMCommonComponent method activate.

@Activate
protected void activate(ComponentContext ctx) {
    try {
        String filePath = IdentityUtil.getIdentityConfigDirPath() + File.separator + SCIMCommonConstants.CHARON_CONFIG_NAME;
        SCIMConfigProcessor scimConfigProcessor = SCIMConfigProcessor.getInstance();
        scimConfigProcessor.buildConfigFromFile(filePath);
        // reading user schema extension
        if (Boolean.parseBoolean(scimConfigProcessor.getProperty("user-schema-extension-enabled"))) {
            String schemaFilePath = CarbonUtils.getCarbonConfigDirPath() + File.separator + SCIMConfigConstants.SCIM_SCHEMA_EXTENSION_CONFIG;
            SCIMUserSchemaExtensionBuilder.getInstance().buildUserSchemaExtension(schemaFilePath);
        }
        // If custom schema is enabled, read it root attribute URI from the file config if it is configured.
        if (SCIMCommonUtils.isCustomSchemaEnabled()) {
            SCIMCustomSchemaExtensionBuilder.getInstance().setURI(SCIMCommonUtils.getCustomSchemaURI());
        }
        // register UserOperationEventListener implementation
        SCIMUserOperationListener scimUserOperationListener = new SCIMUserOperationListener();
        userOperationEventListenerServiceReg = ctx.getBundleContext().registerService(UserOperationEventListener.class, scimUserOperationListener, null);
        // register scimTenantMgtListener implementation
        SCIMTenantMgtListener scimTenantMgtListener = new SCIMTenantMgtListener();
        tenantMgtListenerServiceReg = ctx.getBundleContext().registerService(TenantMgtListener.class, scimTenantMgtListener, null);
        // Register claim operation event handler implementation.
        ctx.getBundleContext().registerService(AbstractEventHandler.class.getName(), new SCIMClaimOperationEventHandler(), null);
        if (logger.isDebugEnabled()) {
            logger.debug("SCIMClaimOperationEventHandler is successfully registered.");
        }
        // Register default implementation of SCIMUserStoreErrorResolver
        ctx.getBundleContext().registerService(SCIMUserStoreErrorResolver.class.getName(), new DefaultSCIMUserStoreErrorResolver(), null);
        // Register default implementation of SCIMGroupResolver.
        ctx.getBundleContext().registerService(GroupResolver.class.getName(), new SCIMGroupResolver(), null);
        // Update super tenant user/group attributes.
        AdminAttributeUtil.updateAdminUser(MultitenantConstants.SUPER_TENANT_ID, true);
        AdminAttributeUtil.updateAdminGroup(MultitenantConstants.SUPER_TENANT_ID);
        if (logger.isDebugEnabled()) {
            logger.debug("SCIM Common component activated successfully.");
        }
    } catch (CharonException e) {
        logger.error("Error in reading information from identity tables at SCIMCommonComponentStartup.", e);
    } catch (InternalErrorException e) {
        logger.error("Error in reading information from identity tables at SCIMCommonComponentStartup.", e);
    }
}
Also used : UserOperationEventListener(org.wso2.carbon.user.core.listener.UserOperationEventListener) SCIMUserOperationListener(org.wso2.carbon.identity.scim2.common.listener.SCIMUserOperationListener) InternalErrorException(org.wso2.charon3.core.exceptions.InternalErrorException) SCIMConfigProcessor(org.wso2.carbon.identity.scim2.common.utils.SCIMConfigProcessor) SCIMTenantMgtListener(org.wso2.carbon.identity.scim2.common.listener.SCIMTenantMgtListener) TenantMgtListener(org.wso2.carbon.stratos.common.listeners.TenantMgtListener) SCIMTenantMgtListener(org.wso2.carbon.identity.scim2.common.listener.SCIMTenantMgtListener) DefaultSCIMUserStoreErrorResolver(org.wso2.carbon.identity.scim2.common.impl.DefaultSCIMUserStoreErrorResolver) SCIMUserStoreErrorResolver(org.wso2.carbon.identity.scim2.common.extenstion.SCIMUserStoreErrorResolver) AbstractEventHandler(org.wso2.carbon.identity.event.handler.AbstractEventHandler) SCIMClaimOperationEventHandler(org.wso2.carbon.identity.scim2.common.handlers.SCIMClaimOperationEventHandler) SCIMGroupResolver(org.wso2.carbon.identity.scim2.common.listener.SCIMGroupResolver) SCIMGroupResolver(org.wso2.carbon.identity.scim2.common.listener.SCIMGroupResolver) GroupResolver(org.wso2.carbon.user.core.listener.GroupResolver) CharonException(org.wso2.charon3.core.exceptions.CharonException) DefaultSCIMUserStoreErrorResolver(org.wso2.carbon.identity.scim2.common.impl.DefaultSCIMUserStoreErrorResolver) Activate(org.osgi.service.component.annotations.Activate)

Example 4 with SCIMUserOperationListener

use of org.wso2.carbon.identity.scim2.common.listener.SCIMUserOperationListener in project identity-inbound-provisioning-scim2 by wso2-extensions.

the class SCIMUserManager method createUser.

@Override
public User createUser(User user, Map<String, Boolean> requiredAttributes) throws CharonException, ConflictException, BadRequestException, ForbiddenException {
    String userStoreName = null;
    try {
        String userStoreDomainFromSP = getUserStoreDomainFromSP();
        if (userStoreDomainFromSP != null) {
            userStoreName = userStoreDomainFromSP;
        }
    } catch (IdentityApplicationManagementException e) {
        throw new CharonException("Error retrieving User Store name. ", e);
    }
    StringBuilder userName = new StringBuilder();
    if (StringUtils.isNotBlank(userStoreName)) {
        // If we have set a user store under provisioning configuration - we should only use that.
        String currentUserName = user.getUserName();
        currentUserName = UserCoreUtil.removeDomainFromName(currentUserName);
        user.setUserName(userName.append(userStoreName).append(CarbonConstants.DOMAIN_SEPARATOR).append(currentUserName).toString());
    }
    String userStoreDomainName = IdentityUtil.extractDomainFromName(user.getUserName());
    if (!user.getUserName().contains(CarbonConstants.DOMAIN_SEPARATOR) && !UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME.equalsIgnoreCase(userStoreDomainName)) {
        user.setUserName(IdentityUtil.addDomainToName(user.getUserName(), userStoreDomainName));
    }
    if (StringUtils.isNotBlank(userStoreDomainName) && !isSCIMEnabled(userStoreDomainName)) {
        throw new CharonException("Cannot add user through scim to user store " + ". SCIM is not " + "enabled for user store " + userStoreDomainName);
    }
    try {
        // Persist in carbon user store.
        if (log.isDebugEnabled()) {
            log.debug("Creating user: " + user.getUserName());
        }
        // Remove the existing SCIM id attribute as we are going to use the one generated from the user core.
        user.getAttributeList().remove(SCIMConstants.CommonSchemaConstants.ID);
        // Set thread local property to signal the downstream SCIMUserOperationListener
        // about the provisioning route.
        SCIMCommonUtils.setThreadLocalIsManagedThroughSCIMEP(true);
        Map<String, String> claimsMap = AttributeMapper.getClaimsMap(user);
        // Skip groups attribute since we map groups attribute to actual groups in ldap.
        // and do not update it as an attribute in user schema.
        claimsMap.remove(SCIMConstants.UserSchemaConstants.GROUP_URI);
        // changes must be applied via Group Resource.
        if (claimsMap.containsKey(SCIMConstants.UserSchemaConstants.ROLES_URI + "." + SCIMConstants.DEFAULT)) {
            claimsMap.remove(SCIMConstants.UserSchemaConstants.ROLES_URI);
        }
        // If we have the user id, we can check the user from it instead of username.
        boolean isExistingUser = false;
        if (StringUtils.isNotEmpty(user.getId())) {
            isExistingUser = carbonUM.isExistingUserWithID(user.getId());
        } else {
            if (isLoginIdentifiersEnabled() && StringUtils.isNotBlank(getPrimaryLoginIdentifierClaim())) {
                String[] existingUserList = carbonUM.getUserList(getPrimaryLoginIdentifierClaim(), UserCoreUtil.removeDomainFromName(user.getUserName()), null);
                if (ArrayUtils.isNotEmpty(existingUserList)) {
                    isExistingUser = true;
                }
            } else {
                isExistingUser = carbonUM.isExistingUser(user.getUserName());
            }
        }
        if (isExistingUser) {
            String error = "User with the name: " + user.getUserName() + " already exists in the system.";
            throw new ConflictException(error);
        }
        claimsMap.remove(SCIMConstants.UserSchemaConstants.USER_NAME_URI);
        Map<String, String> claimsInLocalDialect = SCIMCommonUtils.convertSCIMtoLocalDialect(claimsMap);
        org.wso2.carbon.user.core.common.User coreUser = null;
        /*Provide a preferred primary login identifier.Generate a unique user id as the immutable identifier of
             the user instead of human readable username. The primary login identifier claim value will be the
             human readable username.*/
        if (isLoginIdentifiersEnabled()) {
            String immutableUserIdentifier = getUniqueUserID();
            String primaryLoginIdentifier = getPrimaryLoginIdentifierClaim();
            if (StringUtils.isNotBlank(primaryLoginIdentifier)) {
                if (claimsInLocalDialect.containsKey(primaryLoginIdentifier)) {
                    if (claimsInLocalDialect.get(primaryLoginIdentifier).equals(UserCoreUtil.removeDomainFromName(user.getUserName()))) {
                        coreUser = carbonUM.addUserWithID(immutableUserIdentifier, user.getPassword(), null, claimsInLocalDialect, null);
                    } else {
                        throw new BadRequestException("The claim value for " + primaryLoginIdentifier + " " + "and username should be same.");
                    }
                } else {
                    claimsInLocalDialect.put(getPrimaryLoginIdentifierClaim(), UserCoreUtil.removeDomainFromName(user.getUserName()));
                    coreUser = carbonUM.addUserWithID(immutableUserIdentifier, user.getPassword(), null, claimsInLocalDialect, null);
                }
            }
        } else {
            // Create the user in the user core.
            coreUser = carbonUM.addUserWithID(user.getUserName(), user.getPassword(), null, claimsInLocalDialect, null);
        }
        if (coreUser == null) {
            coreUser = carbonUM.getUser(null, user.getUserName());
            // engagement exists. Please check issue : https://github.com/wso2/product-is/issues/10442
            if (coreUser != null && StringUtils.isBlank(coreUser.getUserID())) {
                return user;
            }
        }
        // We use the generated unique ID of the user core user as the SCIM ID.
        user.setId(coreUser.getUserID());
        if (log.isDebugEnabled()) {
            log.debug("User: " + user.getUserName() + " and with ID " + user.getId() + "  is created through SCIM.");
        }
        // Get Claims related to SCIM claim dialect
        Map<String, String> scimToLocalClaimsMap = SCIMCommonUtils.getSCIMtoLocalMappings();
        // Get required SCIM Claims in local claim dialect.
        List<String> requiredClaimsInLocalDialect = getRequiredClaimsInLocalDialect(scimToLocalClaimsMap, requiredAttributes);
        // Get the user from the user store in order to get the default attributes during the user creation
        // response.
        user = this.getSCIMUser(coreUser, requiredClaimsInLocalDialect, scimToLocalClaimsMap, claimsInLocalDialect);
        // Set the schemas of the SCIM user.
        user.setSchemas(this);
    } catch (UserStoreClientException e) {
        String errorMessage = String.format("Error in adding the user: " + user.getUserName() + ". %s", e.getMessage());
        if (log.isDebugEnabled()) {
            log.debug(errorMessage, e);
        }
        if (isResourceLimitReachedError(e)) {
            handleResourceLimitReached();
        }
        throw new BadRequestException(errorMessage, ResponseCodeConstants.INVALID_VALUE);
    } catch (UserStoreException e) {
        // Sometimes client exceptions are wrapped in the super class.
        // Therefore checking for possible client exception.
        Throwable ex = ExceptionUtils.getRootCause(e);
        if (ex instanceof UserStoreClientException) {
            String errorMessage = String.format("Error in adding the user: " + user.getUserName() + ". %s", ex.getMessage());
            if (log.isDebugEnabled()) {
                log.debug(errorMessage, ex);
            }
            if (isResourceLimitReachedError((UserStoreClientException) ex)) {
                handleResourceLimitReached();
            }
            throw new BadRequestException(errorMessage, ResponseCodeConstants.INVALID_VALUE);
        }
        handleErrorsOnUserNameAndPasswordPolicy(e);
    } catch (NotImplementedException e) {
        throw new CharonException("Error in getting user information from Carbon User Store", e);
    }
    return user;
}
Also used : ConflictException(org.wso2.charon3.core.exceptions.ConflictException) UserStoreClientException(org.wso2.carbon.user.core.UserStoreClientException) IdentityApplicationManagementException(org.wso2.carbon.identity.application.common.IdentityApplicationManagementException) NotImplementedException(org.wso2.charon3.core.exceptions.NotImplementedException) UserStoreException(org.wso2.carbon.user.api.UserStoreException) SCIMUserStoreException(org.wso2.carbon.identity.scim2.common.extenstion.SCIMUserStoreException) BadRequestException(org.wso2.charon3.core.exceptions.BadRequestException) CharonException(org.wso2.charon3.core.exceptions.CharonException)

Example 5 with SCIMUserOperationListener

use of org.wso2.carbon.identity.scim2.common.listener.SCIMUserOperationListener in project identity-inbound-provisioning-scim2 by wso2-extensions.

the class SCIMUserManager method updateUser.

@Override
public User updateUser(User user, Map<String, Boolean> requiredAttributes) throws CharonException, BadRequestException {
    try {
        if (log.isDebugEnabled()) {
            log.debug("Updating user: " + user.getUserName());
        }
        // Set thread local property to signal the downstream SCIMUserOperationListener
        // about the provisioning route.
        SCIMCommonUtils.setThreadLocalIsManagedThroughSCIMEP(true);
        // get user claim values
        Map<String, String> claims = AttributeMapper.getClaimsMap(user);
        // Check if username of the updating user existing in the userstore.
        try {
            String userStoreDomainFromSP = getUserStoreDomainFromSP();
            SCIMResourceTypeSchema schema = SCIMResourceSchemaManager.getInstance().getUserResourceSchema();
            User oldUser = this.getUser(user.getId(), ResourceManagerUtil.getAllAttributeURIs(schema));
            if (userStoreDomainFromSP != null && !userStoreDomainFromSP.equalsIgnoreCase(IdentityUtil.extractDomainFromName(oldUser.getUserName()))) {
                throw new CharonException("User :" + oldUser.getUserName() + "is not belong to user store " + userStoreDomainFromSP + "Hence user updating fail");
            }
            if (getUserStoreDomainFromSP() != null && !UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME.equalsIgnoreCase(getUserStoreDomainFromSP())) {
                user.setUserName(IdentityUtil.addDomainToName(UserCoreUtil.removeDomainFromName(user.getUserName()), getUserStoreDomainFromSP()));
            }
            String username = user.getUsername();
            String oldUsername = oldUser.getUsername();
            if (!IdentityUtil.isUserStoreInUsernameCaseSensitive(oldUser.getUsername())) {
                username = username.toLowerCase();
                oldUsername = oldUsername.toLowerCase();
            }
            /*If primary login identifier configuration is enabled,username value can be another claim and it
                could be modifiable.*/
            if (!(isLoginIdentifiersEnabled() && StringUtils.isNotBlank(getPrimaryLoginIdentifierClaim()))) {
                // This is handled here as the IS is still not capable of updating the username via SCIM.
                if (!StringUtils.equals(username, oldUsername)) {
                    if (log.isDebugEnabled()) {
                        log.debug("Failing the request as attempting to modify username. Old username: " + oldUser.getUserName() + ", new username: " + user.getUserName());
                    }
                    throw new BadRequestException("Attribute userName cannot be modified.", ResponseCodeConstants.MUTABILITY);
                }
            }
        } catch (IdentityApplicationManagementException e) {
            throw new CharonException("Error retrieving User Store name. ", e);
        }
        boolean isExistingUser;
        if (StringUtils.isNotEmpty(user.getId())) {
            isExistingUser = carbonUM.isExistingUserWithID(user.getId());
        } else {
            isExistingUser = carbonUM.isExistingUser(user.getUserName());
        }
        if (!isExistingUser) {
            throw new CharonException("User name is immutable in carbon user store.");
        }
        // Skip groups attribute since we map groups attribute to actual groups in ldap.
        // and do not update it as an attribute in user schema.
        claims.remove(SCIMConstants.UserSchemaConstants.GROUP_URI);
        // changes must be applied via Group Resource.
        if (claims.containsKey(SCIMConstants.UserSchemaConstants.ROLES_URI + "." + SCIMConstants.DEFAULT)) {
            claims.remove(SCIMConstants.UserSchemaConstants.ROLES_URI);
        }
        claims.remove(SCIMConstants.UserSchemaConstants.USER_NAME_URI);
        // Since we are already populating last_modified claim value from SCIMUserOperationListener, we need to
        // remove this claim value which is coming from charon-level.
        claims.remove(SCIMConstants.CommonSchemaConstants.LAST_MODIFIED_URI);
        // Location is a meta attribute of user object.
        claims.remove(SCIMConstants.CommonSchemaConstants.LOCATION_URI);
        // Resource-Type is a meta attribute of user object.
        claims.remove(SCIMConstants.CommonSchemaConstants.RESOURCE_TYPE_URI);
        Map<String, String> scimToLocalClaimsMap = SCIMCommonUtils.getSCIMtoLocalMappings();
        List<String> requiredClaims = getOnlyRequiredClaims(scimToLocalClaimsMap.keySet(), requiredAttributes);
        List<String> requiredClaimsInLocalDialect;
        if (MapUtils.isNotEmpty(scimToLocalClaimsMap)) {
            scimToLocalClaimsMap.keySet().retainAll(requiredClaims);
            requiredClaimsInLocalDialect = new ArrayList<>(scimToLocalClaimsMap.values());
        } else {
            if (log.isDebugEnabled()) {
                log.debug("SCIM to Local Claim mappings list is empty.");
            }
            requiredClaimsInLocalDialect = new ArrayList<>();
        }
        // Get existing user claims.
        Map<String, String> oldClaimList = carbonUM.getUserClaimValuesWithID(user.getId(), requiredClaimsInLocalDialect.toArray(new String[0]), null);
        oldClaimList.remove(LOCATION_CLAIM);
        oldClaimList.remove(LAST_MODIFIED_CLAIM);
        oldClaimList.remove(RESOURCE_TYPE_CLAIM);
        // Get user claims mapped from SCIM dialect to WSO2 dialect.
        Map<String, String> claimValuesInLocalDialect = SCIMCommonUtils.convertSCIMtoLocalDialect(claims);
        // If the primary login identifier claim is enabled, pass that as a claim for userstoremanger.
        if (isLoginIdentifiersEnabled() && StringUtils.isNotBlank(getPrimaryLoginIdentifierClaim())) {
            claimValuesInLocalDialect.put(getPrimaryLoginIdentifierClaim(), UserCoreUtil.removeDomainFromName(user.getUsername()));
        }
        // If password is updated, set it separately.
        if (user.getPassword() != null) {
            carbonUM.updateCredentialByAdminWithID(user.getId(), user.getPassword());
        }
        updateUserClaims(user, oldClaimList, claimValuesInLocalDialect);
        if (log.isDebugEnabled()) {
            log.debug("User: " + user.getUserName() + " updated through SCIM.");
        }
        return getUser(user.getId(), requiredAttributes);
    } catch (UserStoreClientException e) {
        String errorMessage = String.format("Error while updating attributes of user. %s", e.getMessage());
        if (log.isDebugEnabled()) {
            log.debug(errorMessage, e);
        }
        throw new BadRequestException(errorMessage, ResponseCodeConstants.INVALID_VALUE);
    } catch (UserStoreException e) {
        String errMsg = "Error while updating attributes of user: " + user.getUserName();
        log.error(errMsg, e);
        // Sometimes client exceptions are wrapped in the super class.
        // Therefore checking for possible client exception.
        Throwable ex = ExceptionUtils.getRootCause(e);
        if (ex instanceof UserStoreClientException) {
            String errorMessage = String.format("Error while updating attributes of user. %s", ex.getMessage());
            if (log.isDebugEnabled()) {
                log.debug(errorMessage, ex);
            }
            throw new BadRequestException(errorMessage, ResponseCodeConstants.INVALID_VALUE);
        }
        handleErrorsOnUserNameAndPasswordPolicy(e);
        if (isNotifyUserstoreStatusEnabled()) {
            throw resolveError(e, errMsg + ". " + e.getMessage());
        } else {
            throw resolveError(e, errMsg);
        }
    } catch (BadRequestException e) {
        // This is needed as most BadRequests are thrown to charon as
        // CharonExceptions but if there are any bad requests handled
        // due to MUTABILITY at this level we need to properly notify
        // the end party.
        reThrowMutabilityBadRequests(e);
        log.error("Error occurred while trying to update the user", e);
        throw new CharonException("Error occurred while trying to update the user", e);
    } catch (CharonException e) {
        log.error("Error occurred while trying to update the user", e);
        throw new CharonException("Error occurred while trying to update the user", e);
    }
}
Also used : User(org.wso2.charon3.core.objects.User) UserStoreClientException(org.wso2.carbon.user.core.UserStoreClientException) IdentityApplicationManagementException(org.wso2.carbon.identity.application.common.IdentityApplicationManagementException) UserStoreException(org.wso2.carbon.user.api.UserStoreException) SCIMUserStoreException(org.wso2.carbon.identity.scim2.common.extenstion.SCIMUserStoreException) BadRequestException(org.wso2.charon3.core.exceptions.BadRequestException) SCIMResourceTypeSchema(org.wso2.charon3.core.schema.SCIMResourceTypeSchema) CharonException(org.wso2.charon3.core.exceptions.CharonException)

Aggregations

CharonException (org.wso2.charon3.core.exceptions.CharonException)8 IdentityApplicationManagementException (org.wso2.carbon.identity.application.common.IdentityApplicationManagementException)7 SCIMUserStoreException (org.wso2.carbon.identity.scim2.common.extenstion.SCIMUserStoreException)6 UserStoreException (org.wso2.carbon.user.api.UserStoreException)6 BadRequestException (org.wso2.charon3.core.exceptions.BadRequestException)6 IdentitySCIMException (org.wso2.carbon.identity.scim2.common.exceptions.IdentitySCIMException)3 UserStoreClientException (org.wso2.carbon.user.core.UserStoreClientException)3 User (org.wso2.charon3.core.objects.User)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 SCIMGroupHandler (org.wso2.carbon.identity.scim2.common.group.SCIMGroupHandler)2 ConflictException (org.wso2.charon3.core.exceptions.ConflictException)2 NotFoundException (org.wso2.charon3.core.exceptions.NotFoundException)2 SCIMResourceTypeSchema (org.wso2.charon3.core.schema.SCIMResourceTypeSchema)2 AbstractMap (java.util.AbstractMap)1 HashSet (java.util.HashSet)1 LinkedHashSet (java.util.LinkedHashSet)1 List (java.util.List)1 Map (java.util.Map)1 Activate (org.osgi.service.component.annotations.Activate)1