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);
}
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;
}
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);
}
}
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;
}
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);
}
}
Aggregations