* @param userMod bean containing update request
* @return updated user + propagation by resource
* @see PropagationByResource
*/
public PropagationByResource update(final SyncopeUser user, final UserMod userMod) {
PropagationByResource propByRes = new PropagationByResource();
SyncopeClientCompositeErrorException scce = new SyncopeClientCompositeErrorException(HttpStatus.BAD_REQUEST);
Set<String> currentResources = user.getResourceNames();
// password
if (StringUtils.isNotBlank(userMod.getPassword())) {
setPassword(user, userMod.getPassword(), scce);
user.setChangePwdDate(new Date());
propByRes.addAll(ResourceOperation.UPDATE, currentResources);
}
// username
if (userMod.getUsername() != null && !userMod.getUsername().equals(user.getUsername())) {
String oldUsername = user.getUsername();
user.setUsername(userMod.getUsername());
propByRes.addAll(ResourceOperation.UPDATE, currentResources);
for (ExternalResource resource : user.getResources()) {
for (AbstractMappingItem mapItem : resource.getUmapping().getItems()) {
if (mapItem.isAccountid() && mapItem.getIntMappingType() == IntMappingType.Username) {
propByRes.addOldAccountId(resource.getName(), oldUsername);
}
}
}
}
// attributes, derived attributes, virtual attributes and resources
propByRes.merge(fill(user, userMod, AttributableUtil.getInstance(AttributableType.USER), scce));
// store the role ids of membership required to be added
Set<Long> membershipToBeAddedRoleIds = new HashSet<Long>();
for (MembershipMod membToBeAdded : userMod.getMembershipsToBeAdded()) {
membershipToBeAddedRoleIds.add(membToBeAdded.getRole());
}
final Set<String> toBeDeprovisioned = new HashSet<String>();
final Set<String> toBeProvisioned = new HashSet<String>();
// memberships to be removed
for (Long membershipId : userMod.getMembershipsToBeRemoved()) {
LOG.debug("Membership to be removed: {}", membershipId);
Membership membership = membershipDAO.find(membershipId);
if (membership == null) {
LOG.debug("Invalid membership id specified to be removed: {}", membershipId);
} else {
if (!membershipToBeAddedRoleIds.contains(membership.getSyncopeRole().getId())) {
toBeDeprovisioned.addAll(membership.getSyncopeRole().getResourceNames());
}
// In order to make the removeMembership() below to work,
// we need to be sure to take exactly the same membership
// of the user object currently in memory (which has potentially
// some modifications compared to the one stored in the DB
membership = user.getMembership(membership.getSyncopeRole().getId());
if (membershipToBeAddedRoleIds.contains(membership.getSyncopeRole().getId())) {
Set<Long> attributeIds = new HashSet<Long>(membership.getAttributes().size());
for (AbstractAttr attribute : membership.getAttributes()) {
attributeIds.add(attribute.getId());
}
for (Long attributeId : attributeIds) {
attrDAO.delete(attributeId, MAttr.class);
}
attributeIds.clear();
// remove derived attributes
for (AbstractDerAttr derAttr : membership.getDerivedAttributes()) {
attributeIds.add(derAttr.getId());
}
for (Long derAttrId : attributeIds) {
derAttrDAO.delete(derAttrId, MDerAttr.class);
}
attributeIds.clear();
// remove virtual attributes
for (AbstractVirAttr virAttr : membership.getVirtualAttributes()) {
attributeIds.add(virAttr.getId());
}
for (Long virAttrId : attributeIds) {
virAttrDAO.delete(virAttrId, MVirAttr.class);
}
attributeIds.clear();
} else {
user.removeMembership(membership);
membershipDAO.delete(membershipId);
}
}
}
// memberships to be added
for (MembershipMod membershipMod : userMod.getMembershipsToBeAdded()) {
LOG.debug("Membership to be added: role({})", membershipMod.getRole());
SyncopeRole role = roleDAO.find(membershipMod.getRole());
if (role == null) {
LOG.debug("Ignoring invalid role {}", membershipMod.getRole());
} else {
Membership membership = user.getMembership(role.getId());
if (membership == null) {
membership = new Membership();
membership.setSyncopeRole(role);
membership.setSyncopeUser(user);
user.addMembership(membership);
toBeProvisioned.addAll(role.getResourceNames());
}
propByRes.merge(fill(membership, membershipMod,
AttributableUtil.getInstance(AttributableType.MEMBERSHIP), scce));
}
}
propByRes.addAll(ResourceOperation.DELETE, toBeDeprovisioned);
propByRes.addAll(ResourceOperation.UPDATE, toBeProvisioned);
/**
* In case of new memberships all the current resources have to be updated in order to propagate new role and
* membership attribute values.
*/
if (!toBeDeprovisioned.isEmpty() || !toBeProvisioned.isEmpty()) {
currentResources.removeAll(toBeDeprovisioned);
propByRes.addAll(ResourceOperation.UPDATE, currentResources);
}
return propByRes;
}