diff --git a/bwreg-service/src/main/java/edu/kit/scc/webreg/service/impl/UserCreateServiceImpl.java b/bwreg-service/src/main/java/edu/kit/scc/webreg/service/impl/UserCreateServiceImpl.java index f6ee027a6dcf0c1b00c4a02de423f525ab3d6e98..9bf83262a087b150eea818d3f7d6809a88265bdb 100644 --- a/bwreg-service/src/main/java/edu/kit/scc/webreg/service/impl/UserCreateServiceImpl.java +++ b/bwreg-service/src/main/java/edu/kit/scc/webreg/service/impl/UserCreateServiceImpl.java @@ -51,7 +51,7 @@ import edu.kit.scc.webreg.event.exc.EventSubmitException; import edu.kit.scc.webreg.exc.UserUpdateException; import edu.kit.scc.webreg.service.SamlIdpMetadataService; import edu.kit.scc.webreg.service.UserCreateService; -import edu.kit.scc.webreg.service.group.HomeOrgGroupUpdater; +import edu.kit.scc.webreg.service.group.SamlGroupUpdater; import edu.kit.scc.webreg.service.identity.IdentityCreater; import edu.kit.scc.webreg.service.saml.Saml2AssertionService; import edu.kit.scc.webreg.service.saml.SamlIdentifier; @@ -81,7 +81,7 @@ public class UserCreateServiceImpl implements UserCreateService { private SamlUserUpdater userUpdater; @Inject - private HomeOrgGroupUpdater homeOrgGroupUpdater; + private SamlGroupUpdater homeOrgGroupUpdater; @Inject private RoleDao roleDao; diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/AbstractHomeOrgGroupUpdater.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/AbstractHomeOrgGroupUpdater.java new file mode 100644 index 0000000000000000000000000000000000000000..d25e917604eb8d8d591e7feb374f7eac95fa46f0 --- /dev/null +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/AbstractHomeOrgGroupUpdater.java @@ -0,0 +1,19 @@ +package edu.kit.scc.webreg.service.group; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import edu.kit.scc.webreg.audit.Auditor; +import edu.kit.scc.webreg.entity.GroupEntity; +import edu.kit.scc.webreg.entity.UserEntity; +import edu.kit.scc.webreg.exc.UserUpdateException; + +public abstract class AbstractHomeOrgGroupUpdater<T extends UserEntity> implements HomeOrgGroupUpdater<T>, Serializable { + + private static final long serialVersionUID = 1L; + + public abstract Set<GroupEntity> updateGroupsForUser(T user, Map<String, List<Object>> attributeMap, Auditor auditor) + throws UserUpdateException; +} diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/HomeOrgGroupUpdater.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/HomeOrgGroupUpdater.java index 59c628efa2e7c2eaf7f3607e5df5509c05ee5b9b..c9b1fedfe14675909d41823b58a3ba940c8bf249 100644 --- a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/HomeOrgGroupUpdater.java +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/HomeOrgGroupUpdater.java @@ -1,385 +1,16 @@ -/******************************************************************************* - * Copyright (c) 2014 Michael Simon. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - * - * Contributors: - * Michael Simon - initial - ******************************************************************************/ package edu.kit.scc.webreg.service.group; -import java.io.Serializable; -import java.text.Normalizer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.slf4j.Logger; - import edu.kit.scc.webreg.audit.Auditor; -import edu.kit.scc.webreg.dao.GroupDao; -import edu.kit.scc.webreg.dao.HomeOrgGroupDao; -import edu.kit.scc.webreg.dao.SerialDao; -import edu.kit.scc.webreg.dao.ServiceGroupFlagDao; -import edu.kit.scc.webreg.entity.EventType; import edu.kit.scc.webreg.entity.GroupEntity; -import edu.kit.scc.webreg.entity.HomeOrgGroupEntity; -import edu.kit.scc.webreg.entity.SamlUserEntity; -import edu.kit.scc.webreg.entity.ServiceBasedGroupEntity; -import edu.kit.scc.webreg.entity.ServiceGroupFlagEntity; -import edu.kit.scc.webreg.entity.ServiceGroupStatus; -import edu.kit.scc.webreg.entity.UserGroupEntity; -import edu.kit.scc.webreg.entity.audit.AuditStatus; -import edu.kit.scc.webreg.event.EventSubmitter; -import edu.kit.scc.webreg.event.MultipleGroupEvent; -import edu.kit.scc.webreg.event.exc.EventSubmitException; +import edu.kit.scc.webreg.entity.UserEntity; import edu.kit.scc.webreg.exc.UserUpdateException; -import edu.kit.scc.webreg.hook.GroupServiceHook; -import edu.kit.scc.webreg.hook.HookManager; -import edu.kit.scc.webreg.service.identity.HomeIdResolver; -import edu.kit.scc.webreg.service.impl.AttributeMapHelper; - -@ApplicationScoped -public class HomeOrgGroupUpdater implements Serializable { - - private static final long serialVersionUID = 1L; - - @Inject - private Logger logger; - - @Inject - private HookManager hookManager; - - @Inject - private HomeOrgGroupDao dao; - - @Inject - private GroupDao groupDao; - - @Inject - private ServiceGroupFlagDao groupFlagDao; - - @Inject - private AttributeMapHelper attrHelper; - - @Inject - private SerialDao serialDao; - - @Inject - private EventSubmitter eventSubmitter; - - @Inject - private HomeIdResolver homeIdResolver; - - public Set<GroupEntity> updateGroupsForUser(SamlUserEntity user, Map<String, List<Object>> attributeMap, Auditor auditor) - throws UserUpdateException { - - HashSet<GroupEntity> changedGroups = new HashSet<GroupEntity>(); - - changedGroups.addAll(updatePrimary(user, attributeMap, auditor)); - changedGroups.addAll(updateSecondary(user, attributeMap, auditor)); - - // Also add parent groups, to reflect changes - HashSet<GroupEntity> allChangedGroups = new HashSet<GroupEntity>(changedGroups.size()); - for (GroupEntity group : changedGroups) { - allChangedGroups.add(group); - if (group.getParents() != null) { - for (GroupEntity parent : group.getParents()) { - logger.debug("Adding parent group to changed groups: {}", parent.getName()); - allChangedGroups.add(parent); - } - } - } - - for (GroupEntity group : allChangedGroups) { - if (group instanceof ServiceBasedGroupEntity) { - List<ServiceGroupFlagEntity> groupFlagList = groupFlagDao.findByGroup((ServiceBasedGroupEntity) group); - for (ServiceGroupFlagEntity groupFlag : groupFlagList) { - groupFlag.setStatus(ServiceGroupStatus.DIRTY); - groupFlagDao.persist(groupFlag); - } - } - } - - // do not send group event, if there are not changed groups - if (allChangedGroups.size() > 0) { - MultipleGroupEvent mge = new MultipleGroupEvent(allChangedGroups); - try { - eventSubmitter.submit(mge, EventType.GROUP_UPDATE, auditor.getActualExecutor()); - } catch (EventSubmitException e) { - logger.warn("Exeption", e); - } - } - - return allChangedGroups; - } - - protected Set<GroupEntity> updatePrimary(SamlUserEntity user, Map<String, List<Object>> attributeMap, Auditor auditor) - throws UserUpdateException { - Set<GroupEntity> changedGroups = new HashSet<GroupEntity>(); - - GroupServiceHook completeOverrideHook = null; - Set<GroupServiceHook> activeHooks = new HashSet<GroupServiceHook>(); - - GroupEntity group = null; - - for (GroupServiceHook hook : hookManager.getGroupHooks()) { - if (hook.isPrimaryResponsible(user, attributeMap)) { - group = hook.preUpdateUserPrimaryGroupFromAttribute(dao, groupDao, group, user, attributeMap, auditor, changedGroups); - activeHooks.add(hook); - - if (hook.isPrimaryCompleteOverride()) { - completeOverrideHook = hook; - } - } - } - - if (completeOverrideHook == null) { - - String homeId = homeIdResolver.resolveHomeId(user, attributeMap); - - if (homeId == null) { - logger.warn("No Home ID is set for User {}, resetting primary group", user.getEppn()); - } - else { - //Filter all non character from homeid - homeId = homeId.toLowerCase(); - homeId = homeId.replaceAll("[^a-z0-9]", ""); - - String groupName = homeIdResolver.resolvePrimaryGroup(homeId, user, attributeMap); - - if (groupName == null) { - groupName = attrHelper.getSingleStringFirst(attributeMap, "http://bwidm.de/bwidmCC"); - } - - if (groupName == null) { - groupName = homeId; - } - else { - //Filter all non character from groupName - groupName = Normalizer.normalize(groupName, Normalizer.Form.NFD); - groupName = groupName.toLowerCase(); - groupName = groupName.replaceAll("[^a-z0-9\\-_]", ""); - } - - logger.info("Setting standard HomeID group {} for user {}", homeId, user.getEppn()); - group = dao.findByNameAndPrefix(groupName, homeId); - - if (group == null) { - HomeOrgGroupEntity homeGroup = dao.createNew(); - homeGroup.setUsers(new HashSet<UserGroupEntity>()); - homeGroup.setName(groupName); - auditor.logAction(homeGroup.getName(), "SET FIELD", "name", homeGroup.getName(), AuditStatus.SUCCESS); - homeGroup.setPrefix(homeId); - auditor.logAction(homeGroup.getName(), "SET FIELD", "prefix", homeGroup.getPrefix(), AuditStatus.SUCCESS); - homeGroup.setGidNumber(serialDao.next("gid-number-serial").intValue()); - auditor.logAction(homeGroup.getName(), "SET FIELD", "gidNumber", "" + homeGroup.getGidNumber(), AuditStatus.SUCCESS); - homeGroup.setIdp(user.getIdp()); - auditor.logAction(homeGroup.getName(), "SET FIELD", "idpEntityId", "" + user.getIdp().getEntityId(), AuditStatus.SUCCESS); - group = groupDao.persistWithServiceFlags(homeGroup); - auditor.logAction(group.getName(), "CREATE GROUP", null, "Group created", AuditStatus.SUCCESS); - - changedGroups.add(group); - } - } - } - else { - logger.info("Overriding standard Primary Group Update Mechanism! Activator: {}", completeOverrideHook.getClass().getName()); - } - - if (group == null) { - logger.warn("No Primary Group for user {}", user.getEppn()); - } - - for (GroupServiceHook hook : activeHooks) { - group = hook.postUpdateUserPrimaryGroupFromAttribute(dao, groupDao, group, user, attributeMap, auditor, changedGroups); - } - - if (user.getPrimaryGroup() != null && (! user.getPrimaryGroup().equals(group))) { - if (group == null) { - auditor.logAction(user.getEppn(), "UPDATE FIELD", "primaryGroup", - user.getPrimaryGroup().getName() + " (" + user.getPrimaryGroup().getGidNumber() + ") -> " + - "null", AuditStatus.SUCCESS); - } - else { - auditor.logAction(user.getEppn(), "UPDATE FIELD", "primaryGroup", - user.getPrimaryGroup().getName() + " (" + user.getPrimaryGroup().getGidNumber() + ") -> " + - group.getName() + " (" + group.getGidNumber() + ")", AuditStatus.SUCCESS); - changedGroups.add(group); - } - } - else if (user.getPrimaryGroup() == null && group != null) { - auditor.logAction(user.getEppn(), "UPDATE FIELD", "primaryGroup", - "null -> " + - group.getName() + " (" + group.getGidNumber() + ")", AuditStatus.SUCCESS); - changedGroups.add(group); - } - - user.setPrimaryGroup(group); - - return changedGroups; - } - - protected Set<GroupEntity> updateSecondary(SamlUserEntity user, Map<String, List<Object>> attributeMap, Auditor auditor) - throws UserUpdateException { - Set<GroupEntity> changedGroups = new HashSet<GroupEntity>(); - - GroupServiceHook completeOverrideHook = null; - Set<GroupServiceHook> activeHooks = new HashSet<GroupServiceHook>(); - - for (GroupServiceHook hook : hookManager.getGroupHooks()) { - if (hook.isSecondaryResponsible(user, attributeMap)) { - hook.preUpdateUserSecondaryGroupFromAttribute(dao, groupDao, user, attributeMap, auditor, changedGroups); - activeHooks.add(hook); - - if (hook.isSecondaryCompleteOverride()) { - completeOverrideHook = hook; - } - } - } - - if (completeOverrideHook == null) { - - String homeId = homeIdResolver.resolveHomeId(user, attributeMap); - - List<String> groupList = new ArrayList<String>(); - - if (homeId == null) { - logger.warn("No Home ID is set for User {}, resetting secondary groups", user.getEppn()); - } - else if (attributeMap.get("http://bwidm.de/bwidmMemberOf") == null) { - logger.info("No http://bwidm.de/bwidmMemberOf is set. Resetting secondary groups"); - } - else { - List<String> groupsFromAttr = attrHelper.attributeListToStringList(attributeMap, "http://bwidm.de/bwidmMemberOf"); - - //Check if a group name contains a ';', and divide this group - for (String group : groupsFromAttr) { - if (group.contains(";")) { - String[] splitGroups = group.split(";"); - for (String g : splitGroups) { - groupList.add(filterGroup(g)); - } - } - else { - groupList.add(filterGroup(group)); - } - } - } - - if (user.getGroups() == null) - user.setGroups(new HashSet<UserGroupEntity>()); - - Set<GroupEntity> groupsFromAssertion = new HashSet<GroupEntity>(); - - logger.debug("Looking up groups from database"); - Map<String, HomeOrgGroupEntity> dbGroupMap = new HashMap<String, HomeOrgGroupEntity>(); - logger.debug("Indexing groups from database"); - for (HomeOrgGroupEntity dbGroup : dao.findByNameListAndPrefix(groupList, homeId)) { - dbGroupMap.put(dbGroup.getName(), dbGroup); - } - - for (String group : groupList) { - if (group != null && (!group.equals(""))) { - - logger.debug("Analyzing group {}", group); - HomeOrgGroupEntity groupEntity = dbGroupMap.get(group); - - try { - if (groupEntity == null) { - int gidNumber = serialDao.next("gid-number-serial").intValue(); - logger.info("Creating group {} with gidNumber {}", group, gidNumber); - groupEntity = dao.createNew(); - - groupEntity.setUsers(new HashSet<UserGroupEntity>()); - groupEntity.setParents(new HashSet<GroupEntity>()); - groupEntity.setName(group); - auditor.logAction(groupEntity.getName(), "SET FIELD", "name", groupEntity.getName(), AuditStatus.SUCCESS); - groupEntity.setPrefix(homeId); - auditor.logAction(groupEntity.getName(), "SET FIELD", "prefix", groupEntity.getPrefix(), AuditStatus.SUCCESS); - groupEntity.setGidNumber(gidNumber); - auditor.logAction(groupEntity.getName(), "SET FIELD", "gidNumber", "" + groupEntity.getGidNumber(), AuditStatus.SUCCESS); - groupEntity.setIdp(user.getIdp()); - auditor.logAction(groupEntity.getName(), "SET FIELD", "idpEntityId", "" + user.getIdp().getEntityId(), AuditStatus.SUCCESS); - groupEntity = (HomeOrgGroupEntity) groupDao.persistWithServiceFlags(groupEntity); - auditor.logAction(groupEntity.getName(), "CREATE GROUP", null, "Group created", AuditStatus.SUCCESS); - - changedGroups.add(groupEntity); - } - - if (groupEntity != null) { - groupsFromAssertion.add(groupEntity); - - if (! groupDao.isUserInGroup(user, groupEntity)) { - logger.debug("Adding user {} to group {}", user.getEppn(), groupEntity.getName()); - groupDao.addUserToGroup(user, groupEntity); - changedGroups.remove(groupEntity); - //groupEntity = dao.persist(groupEntity); - auditor.logAction(user.getEppn(), "ADD TO GROUP", groupEntity.getName(), null, AuditStatus.SUCCESS); - - changedGroups.add(groupEntity); - } - } - - } catch (NumberFormatException e) { - logger.warn("GidNumber has a bad number format: {}", e.getMessage()); - } - } - } - - Set<GroupEntity> groupsToRemove = new HashSet<GroupEntity>(groupDao.findByUser(user)); - groupsToRemove.removeAll(groupsFromAssertion); - for (GroupEntity removeGroup : groupsToRemove) { - if (removeGroup instanceof HomeOrgGroupEntity) { - if (! removeGroup.equals(user.getPrimaryGroup())) { - logger.debug("Removing user {} from group {}", user.getEppn(), removeGroup.getName()); - groupDao.removeUserGromGroup(user, removeGroup); - - auditor.logAction(user.getEppn(), "REMOVE FROM GROUP", removeGroup.getName(), null, AuditStatus.SUCCESS); - - changedGroups.add(removeGroup); - } - } - else { - logger.debug("Group {} of type {}. Doing nothing.", removeGroup.getName(), removeGroup.getClass().getSimpleName()); - } - } +public interface HomeOrgGroupUpdater<T extends UserEntity> { - /* - * Add Primary group to secondary as well - */ - if (user.getPrimaryGroup() != null && (! groupDao.isUserInGroup(user, user.getPrimaryGroup()))) { - logger.debug("Adding user {} to his primary group {} as secondary", user.getEppn(), user.getPrimaryGroup().getName()); - groupDao.addUserToGroup(user, user.getPrimaryGroup()); - changedGroups.add(user.getPrimaryGroup()); - } - } - else { - logger.info("Overriding standard Secondary Group Update Mechanism! Activator: {}", completeOverrideHook.getClass().getName()); - } - - for (GroupServiceHook hook : activeHooks) { - hook.postUpdateUserSecondaryGroupFromAttribute(dao, groupDao, user, attributeMap, auditor, changedGroups); - } - - return changedGroups; - } - - private String filterGroup(String groupName) { - //Filter all non character from groupName - groupName = Normalizer.normalize(groupName, Normalizer.Form.NFD); - groupName = groupName.toLowerCase(); - groupName = groupName.replaceAll("[^a-z0-9\\-_]", ""); - - return groupName; - } + public Set<GroupEntity> updateGroupsForUser(T user, Map<String, List<Object>> attributeMap, Auditor auditor) + throws UserUpdateException; } diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/OAuthGroupUpdater.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/OAuthGroupUpdater.java index bc3c5c7eece00b9cd408830600eb4589a811378f..1607d2ecd9b649476d18f6ad23a116c489bcd1d0 100644 --- a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/OAuthGroupUpdater.java +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/OAuthGroupUpdater.java @@ -34,7 +34,9 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @ApplicationScoped -public class OAuthGroupUpdater { +public class OAuthGroupUpdater extends AbstractHomeOrgGroupUpdater<OAuthUserEntity> { + + private static final long serialVersionUID = 1L; @Inject private Logger logger; diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/OidcGroupUpdater.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/OidcGroupUpdater.java index ee3454edf4c6fe3dfc3d709ad5cb37c895d9bfda..f259fc869e6e546c8b80507b2b8dfead7c34c4c9 100644 --- a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/OidcGroupUpdater.java +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/OidcGroupUpdater.java @@ -34,7 +34,9 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @ApplicationScoped -public class OidcGroupUpdater { +public class OidcGroupUpdater extends AbstractHomeOrgGroupUpdater<OidcUserEntity> { + + private static final long serialVersionUID = 1L; @Inject private Logger logger; diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/SamlGroupUpdater.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/SamlGroupUpdater.java new file mode 100644 index 0000000000000000000000000000000000000000..45aa2b976736e211fc5ef7e6b48848c39bc355de --- /dev/null +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/group/SamlGroupUpdater.java @@ -0,0 +1,383 @@ +/******************************************************************************* + * Copyright (c) 2014 Michael Simon. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Michael Simon - initial + ******************************************************************************/ +package edu.kit.scc.webreg.service.group; + +import java.text.Normalizer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; + +import edu.kit.scc.webreg.audit.Auditor; +import edu.kit.scc.webreg.dao.GroupDao; +import edu.kit.scc.webreg.dao.HomeOrgGroupDao; +import edu.kit.scc.webreg.dao.SerialDao; +import edu.kit.scc.webreg.dao.ServiceGroupFlagDao; +import edu.kit.scc.webreg.entity.EventType; +import edu.kit.scc.webreg.entity.GroupEntity; +import edu.kit.scc.webreg.entity.HomeOrgGroupEntity; +import edu.kit.scc.webreg.entity.SamlUserEntity; +import edu.kit.scc.webreg.entity.ServiceBasedGroupEntity; +import edu.kit.scc.webreg.entity.ServiceGroupFlagEntity; +import edu.kit.scc.webreg.entity.ServiceGroupStatus; +import edu.kit.scc.webreg.entity.UserGroupEntity; +import edu.kit.scc.webreg.entity.audit.AuditStatus; +import edu.kit.scc.webreg.event.EventSubmitter; +import edu.kit.scc.webreg.event.MultipleGroupEvent; +import edu.kit.scc.webreg.event.exc.EventSubmitException; +import edu.kit.scc.webreg.exc.UserUpdateException; +import edu.kit.scc.webreg.hook.GroupServiceHook; +import edu.kit.scc.webreg.hook.HookManager; +import edu.kit.scc.webreg.service.identity.HomeIdResolver; +import edu.kit.scc.webreg.service.impl.AttributeMapHelper; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class SamlGroupUpdater extends AbstractHomeOrgGroupUpdater<SamlUserEntity> { + + private static final long serialVersionUID = 1L; + + @Inject + private Logger logger; + + @Inject + private HookManager hookManager; + + @Inject + private HomeOrgGroupDao dao; + + @Inject + private GroupDao groupDao; + + @Inject + private ServiceGroupFlagDao groupFlagDao; + + @Inject + private AttributeMapHelper attrHelper; + + @Inject + private SerialDao serialDao; + + @Inject + private EventSubmitter eventSubmitter; + + @Inject + private HomeIdResolver homeIdResolver; + + public Set<GroupEntity> updateGroupsForUser(SamlUserEntity user, Map<String, List<Object>> attributeMap, Auditor auditor) + throws UserUpdateException { + + HashSet<GroupEntity> changedGroups = new HashSet<GroupEntity>(); + + changedGroups.addAll(updatePrimary(user, attributeMap, auditor)); + changedGroups.addAll(updateSecondary(user, attributeMap, auditor)); + + // Also add parent groups, to reflect changes + HashSet<GroupEntity> allChangedGroups = new HashSet<GroupEntity>(changedGroups.size()); + for (GroupEntity group : changedGroups) { + allChangedGroups.add(group); + if (group.getParents() != null) { + for (GroupEntity parent : group.getParents()) { + logger.debug("Adding parent group to changed groups: {}", parent.getName()); + allChangedGroups.add(parent); + } + } + } + + for (GroupEntity group : allChangedGroups) { + if (group instanceof ServiceBasedGroupEntity) { + List<ServiceGroupFlagEntity> groupFlagList = groupFlagDao.findByGroup((ServiceBasedGroupEntity) group); + for (ServiceGroupFlagEntity groupFlag : groupFlagList) { + groupFlag.setStatus(ServiceGroupStatus.DIRTY); + groupFlagDao.persist(groupFlag); + } + } + } + + // do not send group event, if there are not changed groups + if (allChangedGroups.size() > 0) { + MultipleGroupEvent mge = new MultipleGroupEvent(allChangedGroups); + try { + eventSubmitter.submit(mge, EventType.GROUP_UPDATE, auditor.getActualExecutor()); + } catch (EventSubmitException e) { + logger.warn("Exeption", e); + } + } + + return allChangedGroups; + } + + protected Set<GroupEntity> updatePrimary(SamlUserEntity user, Map<String, List<Object>> attributeMap, Auditor auditor) + throws UserUpdateException { + Set<GroupEntity> changedGroups = new HashSet<GroupEntity>(); + + GroupServiceHook completeOverrideHook = null; + Set<GroupServiceHook> activeHooks = new HashSet<GroupServiceHook>(); + + GroupEntity group = null; + + for (GroupServiceHook hook : hookManager.getGroupHooks()) { + if (hook.isPrimaryResponsible(user, attributeMap)) { + group = hook.preUpdateUserPrimaryGroupFromAttribute(dao, groupDao, group, user, attributeMap, auditor, changedGroups); + activeHooks.add(hook); + + if (hook.isPrimaryCompleteOverride()) { + completeOverrideHook = hook; + } + } + } + + if (completeOverrideHook == null) { + + String homeId = homeIdResolver.resolveHomeId(user, attributeMap); + + if (homeId == null) { + logger.warn("No Home ID is set for User {}, resetting primary group", user.getEppn()); + } + else { + //Filter all non character from homeid + homeId = homeId.toLowerCase(); + homeId = homeId.replaceAll("[^a-z0-9]", ""); + + String groupName = homeIdResolver.resolvePrimaryGroup(homeId, user, attributeMap); + + if (groupName == null) { + groupName = attrHelper.getSingleStringFirst(attributeMap, "http://bwidm.de/bwidmCC"); + } + + if (groupName == null) { + groupName = homeId; + } + else { + //Filter all non character from groupName + groupName = Normalizer.normalize(groupName, Normalizer.Form.NFD); + groupName = groupName.toLowerCase(); + groupName = groupName.replaceAll("[^a-z0-9\\-_]", ""); + } + + logger.info("Setting standard HomeID group {} for user {}", homeId, user.getEppn()); + group = dao.findByNameAndPrefix(groupName, homeId); + + if (group == null) { + HomeOrgGroupEntity homeGroup = dao.createNew(); + homeGroup.setUsers(new HashSet<UserGroupEntity>()); + homeGroup.setName(groupName); + auditor.logAction(homeGroup.getName(), "SET FIELD", "name", homeGroup.getName(), AuditStatus.SUCCESS); + homeGroup.setPrefix(homeId); + auditor.logAction(homeGroup.getName(), "SET FIELD", "prefix", homeGroup.getPrefix(), AuditStatus.SUCCESS); + homeGroup.setGidNumber(serialDao.next("gid-number-serial").intValue()); + auditor.logAction(homeGroup.getName(), "SET FIELD", "gidNumber", "" + homeGroup.getGidNumber(), AuditStatus.SUCCESS); + homeGroup.setIdp(user.getIdp()); + auditor.logAction(homeGroup.getName(), "SET FIELD", "idpEntityId", "" + user.getIdp().getEntityId(), AuditStatus.SUCCESS); + group = groupDao.persistWithServiceFlags(homeGroup); + auditor.logAction(group.getName(), "CREATE GROUP", null, "Group created", AuditStatus.SUCCESS); + + changedGroups.add(group); + } + } + } + else { + logger.info("Overriding standard Primary Group Update Mechanism! Activator: {}", completeOverrideHook.getClass().getName()); + } + + if (group == null) { + logger.warn("No Primary Group for user {}", user.getEppn()); + } + + for (GroupServiceHook hook : activeHooks) { + group = hook.postUpdateUserPrimaryGroupFromAttribute(dao, groupDao, group, user, attributeMap, auditor, changedGroups); + } + + if (user.getPrimaryGroup() != null && (! user.getPrimaryGroup().equals(group))) { + if (group == null) { + auditor.logAction(user.getEppn(), "UPDATE FIELD", "primaryGroup", + user.getPrimaryGroup().getName() + " (" + user.getPrimaryGroup().getGidNumber() + ") -> " + + "null", AuditStatus.SUCCESS); + } + else { + auditor.logAction(user.getEppn(), "UPDATE FIELD", "primaryGroup", + user.getPrimaryGroup().getName() + " (" + user.getPrimaryGroup().getGidNumber() + ") -> " + + group.getName() + " (" + group.getGidNumber() + ")", AuditStatus.SUCCESS); + changedGroups.add(group); + } + } + else if (user.getPrimaryGroup() == null && group != null) { + auditor.logAction(user.getEppn(), "UPDATE FIELD", "primaryGroup", + "null -> " + + group.getName() + " (" + group.getGidNumber() + ")", AuditStatus.SUCCESS); + changedGroups.add(group); + } + + user.setPrimaryGroup(group); + + return changedGroups; + } + + protected Set<GroupEntity> updateSecondary(SamlUserEntity user, Map<String, List<Object>> attributeMap, Auditor auditor) + throws UserUpdateException { + Set<GroupEntity> changedGroups = new HashSet<GroupEntity>(); + + GroupServiceHook completeOverrideHook = null; + Set<GroupServiceHook> activeHooks = new HashSet<GroupServiceHook>(); + + for (GroupServiceHook hook : hookManager.getGroupHooks()) { + if (hook.isSecondaryResponsible(user, attributeMap)) { + hook.preUpdateUserSecondaryGroupFromAttribute(dao, groupDao, user, attributeMap, auditor, changedGroups); + activeHooks.add(hook); + + if (hook.isSecondaryCompleteOverride()) { + completeOverrideHook = hook; + } + } + } + + if (completeOverrideHook == null) { + + String homeId = homeIdResolver.resolveHomeId(user, attributeMap); + + List<String> groupList = new ArrayList<String>(); + + if (homeId == null) { + logger.warn("No Home ID is set for User {}, resetting secondary groups", user.getEppn()); + } + else if (attributeMap.get("http://bwidm.de/bwidmMemberOf") == null) { + logger.info("No http://bwidm.de/bwidmMemberOf is set. Resetting secondary groups"); + } + else { + List<String> groupsFromAttr = attrHelper.attributeListToStringList(attributeMap, "http://bwidm.de/bwidmMemberOf"); + + //Check if a group name contains a ';', and divide this group + for (String group : groupsFromAttr) { + if (group.contains(";")) { + String[] splitGroups = group.split(";"); + for (String g : splitGroups) { + groupList.add(filterGroup(g)); + } + } + else { + groupList.add(filterGroup(group)); + } + } + } + + if (user.getGroups() == null) + user.setGroups(new HashSet<UserGroupEntity>()); + + Set<GroupEntity> groupsFromAssertion = new HashSet<GroupEntity>(); + + logger.debug("Looking up groups from database"); + Map<String, HomeOrgGroupEntity> dbGroupMap = new HashMap<String, HomeOrgGroupEntity>(); + logger.debug("Indexing groups from database"); + for (HomeOrgGroupEntity dbGroup : dao.findByNameListAndPrefix(groupList, homeId)) { + dbGroupMap.put(dbGroup.getName(), dbGroup); + } + + for (String group : groupList) { + if (group != null && (!group.equals(""))) { + + logger.debug("Analyzing group {}", group); + HomeOrgGroupEntity groupEntity = dbGroupMap.get(group); + + try { + if (groupEntity == null) { + int gidNumber = serialDao.next("gid-number-serial").intValue(); + logger.info("Creating group {} with gidNumber {}", group, gidNumber); + groupEntity = dao.createNew(); + + groupEntity.setUsers(new HashSet<UserGroupEntity>()); + groupEntity.setParents(new HashSet<GroupEntity>()); + groupEntity.setName(group); + auditor.logAction(groupEntity.getName(), "SET FIELD", "name", groupEntity.getName(), AuditStatus.SUCCESS); + groupEntity.setPrefix(homeId); + auditor.logAction(groupEntity.getName(), "SET FIELD", "prefix", groupEntity.getPrefix(), AuditStatus.SUCCESS); + groupEntity.setGidNumber(gidNumber); + auditor.logAction(groupEntity.getName(), "SET FIELD", "gidNumber", "" + groupEntity.getGidNumber(), AuditStatus.SUCCESS); + groupEntity.setIdp(user.getIdp()); + auditor.logAction(groupEntity.getName(), "SET FIELD", "idpEntityId", "" + user.getIdp().getEntityId(), AuditStatus.SUCCESS); + groupEntity = (HomeOrgGroupEntity) groupDao.persistWithServiceFlags(groupEntity); + auditor.logAction(groupEntity.getName(), "CREATE GROUP", null, "Group created", AuditStatus.SUCCESS); + + changedGroups.add(groupEntity); + } + + if (groupEntity != null) { + groupsFromAssertion.add(groupEntity); + + if (! groupDao.isUserInGroup(user, groupEntity)) { + logger.debug("Adding user {} to group {}", user.getEppn(), groupEntity.getName()); + groupDao.addUserToGroup(user, groupEntity); + changedGroups.remove(groupEntity); + //groupEntity = dao.persist(groupEntity); + auditor.logAction(user.getEppn(), "ADD TO GROUP", groupEntity.getName(), null, AuditStatus.SUCCESS); + + changedGroups.add(groupEntity); + } + } + + } catch (NumberFormatException e) { + logger.warn("GidNumber has a bad number format: {}", e.getMessage()); + } + } + } + + Set<GroupEntity> groupsToRemove = new HashSet<GroupEntity>(groupDao.findByUser(user)); + groupsToRemove.removeAll(groupsFromAssertion); + + for (GroupEntity removeGroup : groupsToRemove) { + if (removeGroup instanceof HomeOrgGroupEntity) { + if (! removeGroup.equals(user.getPrimaryGroup())) { + logger.debug("Removing user {} from group {}", user.getEppn(), removeGroup.getName()); + groupDao.removeUserGromGroup(user, removeGroup); + + auditor.logAction(user.getEppn(), "REMOVE FROM GROUP", removeGroup.getName(), null, AuditStatus.SUCCESS); + + changedGroups.add(removeGroup); + } + } + else { + logger.debug("Group {} of type {}. Doing nothing.", removeGroup.getName(), removeGroup.getClass().getSimpleName()); + } + } + + /* + * Add Primary group to secondary as well + */ + if (user.getPrimaryGroup() != null && (! groupDao.isUserInGroup(user, user.getPrimaryGroup()))) { + logger.debug("Adding user {} to his primary group {} as secondary", user.getEppn(), user.getPrimaryGroup().getName()); + groupDao.addUserToGroup(user, user.getPrimaryGroup()); + changedGroups.add(user.getPrimaryGroup()); + } + } + else { + logger.info("Overriding standard Secondary Group Update Mechanism! Activator: {}", completeOverrideHook.getClass().getName()); + } + + for (GroupServiceHook hook : activeHooks) { + hook.postUpdateUserSecondaryGroupFromAttribute(dao, groupDao, user, attributeMap, auditor, changedGroups); + } + + return changedGroups; + } + + private String filterGroup(String groupName) { + //Filter all non character from groupName + groupName = Normalizer.normalize(groupName, Normalizer.Form.NFD); + groupName = groupName.toLowerCase(); + groupName = groupName.replaceAll("[^a-z0-9\\-_]", ""); + + return groupName; + } +} diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/AbstractUserUpdater.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/AbstractUserUpdater.java index 2661a5a1efd42c7b002779e97dd5c646bbcb19e0..0afb7410654da1da1997a3fb37a7bbd81aafbc7d 100644 --- a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/AbstractUserUpdater.java +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/AbstractUserUpdater.java @@ -1,21 +1,64 @@ package edu.kit.scc.webreg.service.impl; +import static edu.kit.scc.webreg.dao.ops.RqlExpressions.equal; + import java.io.Serializable; import java.lang.reflect.InvocationTargetException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; - -import jakarta.inject.Inject; +import java.util.Map.Entry; +import java.util.Random; +import java.util.Set; import org.slf4j.Logger; +import org.slf4j.MDC; +import edu.kit.scc.webreg.as.AttributeSourceUpdater; +import edu.kit.scc.webreg.audit.Auditor; +import edu.kit.scc.webreg.audit.RegistryAuditor; +import edu.kit.scc.webreg.audit.UserUpdateAuditor; +import edu.kit.scc.webreg.bootstrap.ApplicationConfig; +import edu.kit.scc.webreg.dao.RegistryDao; +import edu.kit.scc.webreg.dao.ServiceDao; +import edu.kit.scc.webreg.dao.as.ASUserAttrDao; +import edu.kit.scc.webreg.dao.as.AttributeSourceDao; +import edu.kit.scc.webreg.dao.audit.AuditDetailDao; +import edu.kit.scc.webreg.dao.audit.AuditEntryDao; +import edu.kit.scc.webreg.entity.EventType; +import edu.kit.scc.webreg.entity.GroupEntity; +import edu.kit.scc.webreg.entity.RegistryEntity; +import edu.kit.scc.webreg.entity.RegistryStatus; import edu.kit.scc.webreg.entity.ServiceEntity; +import edu.kit.scc.webreg.entity.ServiceEntity_; import edu.kit.scc.webreg.entity.UserEntity; +import edu.kit.scc.webreg.entity.UserStatus; +import edu.kit.scc.webreg.entity.as.ASUserAttrEntity_; +import edu.kit.scc.webreg.entity.as.AttributeSourceEntity; +import edu.kit.scc.webreg.entity.as.AttributeSourceEntity_; +import edu.kit.scc.webreg.entity.as.AttributeSourceServiceEntity; +import edu.kit.scc.webreg.entity.attribute.IncomingAttributeSetEntity; +import edu.kit.scc.webreg.entity.audit.AuditDetailEntity; +import edu.kit.scc.webreg.entity.audit.AuditStatus; +import edu.kit.scc.webreg.entity.audit.AuditUserUpdateEntity; +import edu.kit.scc.webreg.event.EventSubmitter; +import edu.kit.scc.webreg.event.UserEvent; +import edu.kit.scc.webreg.event.exc.EventSubmitException; +import edu.kit.scc.webreg.exc.RegisterException; import edu.kit.scc.webreg.exc.UserUpdateException; import edu.kit.scc.webreg.hook.IdentityScriptingHookWorkflow; import edu.kit.scc.webreg.hook.UserUpdateHook; import edu.kit.scc.webreg.hook.UserUpdateHookException; +import edu.kit.scc.webreg.service.attribute.IncomingAttributesHandler; +import edu.kit.scc.webreg.service.group.HomeOrgGroupUpdater; import edu.kit.scc.webreg.service.identity.IdentityScriptingEnv; +import edu.kit.scc.webreg.service.identity.IdentityUpdater; +import edu.kit.scc.webreg.service.reg.impl.Registrator; +import jakarta.inject.Inject; public abstract class AbstractUserUpdater<T extends UserEntity> implements UserUpdater<T>, Serializable { @@ -24,49 +67,217 @@ public abstract class AbstractUserUpdater<T extends UserEntity> implements UserU @Inject private Logger logger; + @Inject + private IdentityUpdater identityUpdater; + @Inject private IdentityScriptingEnv scriptingEnv; + + @Inject + private RegistryDao registryDao; + + @Inject + private ServiceDao serviceDao; + + @Inject + private AttributeSourceDao attributeSourceDao; + + @Inject + private ASUserAttrDao asUserAttrDao; + + @Inject + private AttributeSourceUpdater attributeSourceUpdater; + + @Inject + private AuditEntryDao auditDao; + + @Inject + private AuditDetailDao auditDetailDao; + + @Inject + private AttributeMapHelper attrHelper; + + @Inject + private Registrator registrator; + + @Inject + private ApplicationConfig appConfig; + + @Inject + private EventSubmitter eventSubmitter; + + public abstract boolean updateUserFromAttribute(T user, Map<String, List<Object>> attributeMap, + boolean withoutUidNumber, Auditor auditor) throws UserUpdateException; + + public abstract Map<String, String> resolveHomeOrgGenericStore(T user); + public abstract IncomingAttributesHandler<?> resolveIncomingAttributeHandler(T user); - public abstract T updateUser(T user, Map<String, List<Object>> attributeMap, String executor, StringBuffer debugLog, String lastLoginHost) - throws UserUpdateException; + public boolean updateUserFromAttribute(T user, Map<String, List<Object>> attributeMap, Auditor auditor) + throws UserUpdateException { + return updateUserFromAttribute(user, attributeMap, false, auditor); + } + + public T updateUser(T user, Map<String, List<Object>> attributeMap, String executor, StringBuffer debugLog, + String lastLoginHost) throws UserUpdateException { + return updateUser(user, attributeMap, executor, null, debugLog, lastLoginHost); + } + + public T updateUser(T user, Map<String, List<Object>> attributeMap, String executor, ServiceEntity service, + StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { + MDC.put("userId", "" + user.getId()); + logger.debug("Updating user {} (class: {})", user.getId(), user.getClass().getSimpleName()); + + boolean changed = false; + + UserUpdateAuditor auditor = new UserUpdateAuditor(auditDao, auditDetailDao, appConfig); + auditor.startAuditTrail(executor); + auditor.setName(getClass().getName() + "-UserUpdate-Audit"); + auditor.setDetail("Update user " + user.getEppn()); + + changed |= preUpdateUser(user, attributeMap, resolveHomeOrgGenericStore(user), executor, service, debugLog); + + // List to store parent services, that are not registered. Need to be registered + // later, when attribute map is populated + List<ServiceEntity> delayedRegisterList = new ArrayList<ServiceEntity>(); + + /** + * put no_assertion_count in generic store if assertion is missing. Else reset + * no assertion count and put last valid assertion date in + */ + if (attributeMap == null) { + if (!user.getGenericStore().containsKey("no_assertion_count")) { + user.getGenericStore().put("no_assertion_count", "1"); + } else { + user.getGenericStore().put("no_assertion_count", + "" + (Long.parseLong(user.getGenericStore().get("no_assertion_count")) + 1L)); + } + + logger.info("No attribute for user {}, skipping updateFromAttribute", user.getEppn()); + + user.getAttributeStore().clear(); + + // user empty attribute map in order to remove all existing values + IncomingAttributeSetEntity incomingAttributeSet = resolveIncomingAttributeHandler(user).createOrUpdateAttributes(user, new HashMap<>()); + resolveIncomingAttributeHandler(user).processIncomingAttributeSet(incomingAttributeSet); + + // sets user account on ON_HOLD, if it's in state ACTIVE + deactivateUser(user, auditor); + + } else { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + user.getGenericStore().put("no_assertion_count", "0"); + user.getGenericStore().put("last_valid_assertion", df.format(new Date())); + + changed |= updateUserFromAttribute(user, attributeMap, auditor); + + // if a user is in state ON_HOLD, this reactivates the user to ACTIVE + // and sets all registries to LOST_ACCESS in order to be checked again + changed |= reactivateUser(user, delayedRegisterList, auditor); + + changed |= updateAttributeSources(user, service, executor, auditor); + + changed |= updateGroups(user, attributeMap, auditor); + + Map<String, String> attributeStore = user.getAttributeStore(); + attributeStore.clear(); + for (Entry<String, List<Object>> entry : attributeMap.entrySet()) { + attributeStore.put(entry.getKey(), attrHelper.attributeListToString(entry.getValue())); + } + + IncomingAttributeSetEntity incomingAttributeSet = resolveIncomingAttributeHandler(user).createOrUpdateAttributes(user, attributeMap); + resolveIncomingAttributeHandler(user).processIncomingAttributeSet(incomingAttributeSet); + + identityUpdater.updateIdentity(user); + + if (appConfig.getConfigValue("create_missing_eppn_scope") != null) { + if (user.getEppn() == null) { + String scope = appConfig.getConfigValue("create_missing_eppn_scope"); + user.setEppn(user.getIdentity().getGeneratedLocalUsername() + "@" + scope); + changed = true; + } + } + } + + for (ServiceEntity delayedService : delayedRegisterList) { + try { + registrator.registerUser(user, delayedService, "user-" + user.getId(), false); + } catch (RegisterException e) { + logger.warn("Parent registration didn't work out like it should", e); + } + } - public abstract T updateUser(T user, Map<String, List<Object>> attributeMap, String executor, ServiceEntity service, StringBuffer debugLog, String lastLoginHost) - throws UserUpdateException; + changed |= postUpdateUser(user, attributeMap, resolveHomeOrgGenericStore(user), executor, service, debugLog, + lastLoginHost); - protected boolean preUpdateUser(UserEntity user, Map<String, List<Object>> attributeMap, Map<String,String> homeOrgGenericStore, - String executor, ServiceEntity service, StringBuffer debugLog) + user.setLastUpdate(new Date()); + user.setLastFailedUpdate(null); + user.setExpireWarningSent(null); + user.setExpiredSent(null); + user.setScheduledUpdate(getNextScheduledUpdate()); + + if (changed) { + fireUserChangeEvent(user, auditor.getActualExecutor(), auditor); + } + + auditor.setUser(user); + auditor.finishAuditTrail(); + auditor.commitAuditTrail(); + + if (debugLog != null) { + AuditUserUpdateEntity audit = auditor.getAudit(); + debugLog.append("\n\nPrinting audit from user update process:\n\nName: ").append(audit.getName()) + .append("\nDetail: ").append(audit.getDetail()).append("\n"); + for (AuditDetailEntity detail : audit.getAuditDetails()) { + debugLog.append(detail.getEndTime()).append(" | ").append(detail.getSubject()).append(" | ") + .append(detail.getObject()).append(" | ").append(detail.getAction()).append(" | ") + .append(detail.getLog()).append(" | ").append(detail.getAuditStatus()).append("\n"); + } + + if (audit.getAuditDetails().size() == 0) { + debugLog.append("Nothing seems to have changed.\n"); + } + } + + return user; + } + public abstract HomeOrgGroupUpdater<T> getGroupUpdater(); + + protected boolean preUpdateUser(T user, Map<String, List<Object>> attributeMap, + Map<String, String> homeOrgGenericStore, String executor, ServiceEntity service, StringBuffer debugLog) throws UserUpdateException { boolean returnValue = false; - + UserUpdateHook updateHook = resolveUpdateHook(homeOrgGenericStore); - + if (updateHook != null) { try { - returnValue |= updateHook.preUpdateUser(user, homeOrgGenericStore, attributeMap, executor, service, null); + returnValue |= updateHook.preUpdateUser(user, homeOrgGenericStore, attributeMap, executor, service, + null); } catch (UserUpdateHookException e) { logger.warn("An exception happened while calling UserUpdateHook!", e); } } - + return returnValue; } - protected boolean postUpdateUser(UserEntity user, Map<String, List<Object>> attributeMap, Map<String,String> homeOrgGenericStore, - String executor, ServiceEntity service, StringBuffer debugLog, String lastLoginHost) - throws UserUpdateException { + protected boolean postUpdateUser(T user, Map<String, List<Object>> attributeMap, + Map<String, String> homeOrgGenericStore, String executor, ServiceEntity service, StringBuffer debugLog, + String lastLoginHost) throws UserUpdateException { boolean returnValue = false; if (lastLoginHost != null) { user.setLastLoginHost(lastLoginHost); } - + UserUpdateHook updateHook = resolveUpdateHook(homeOrgGenericStore); if (updateHook != null) { try { - returnValue |= updateHook.postUpdateUser(user, homeOrgGenericStore, attributeMap, executor, service, null); + returnValue |= updateHook.postUpdateUser(user, homeOrgGenericStore, attributeMap, executor, service, + null); } catch (UserUpdateHookException e) { logger.warn("An exception happened while calling UserUpdateHook!", e); } @@ -74,7 +285,7 @@ public abstract class AbstractUserUpdater<T extends UserEntity> implements UserU return returnValue; } - private UserUpdateHook resolveUpdateHook(Map<String,String> homeOrgGenericStore) { + private UserUpdateHook resolveUpdateHook(Map<String, String> homeOrgGenericStore) { UserUpdateHook updateHook = null; if (homeOrgGenericStore.containsKey("user_update_hook")) { String hookClass = homeOrgGenericStore.get("user_update_hook"); @@ -89,7 +300,151 @@ public abstract class AbstractUserUpdater<T extends UserEntity> implements UserU logger.warn("Cannot instantiate updateHook class. This is probably a misconfiguration."); } } - + return updateHook; } + + protected void deactivateUser(T user, Auditor auditor) { + if (UserStatus.ACTIVE.equals(user.getUserStatus())) { + changeUserStatus(user, UserStatus.ON_HOLD, auditor); + + identityUpdater.updateIdentity(user); + + /* + * Also flag all registries for user ON_HOLD + */ + List<RegistryEntity> registryList = registryDao.findByUserAndStatus(user, RegistryStatus.ACTIVE, + RegistryStatus.LOST_ACCESS, RegistryStatus.INVALID); + for (RegistryEntity registry : registryList) { + changeRegistryStatus(registry, RegistryStatus.ON_HOLD, "user-on-hold", auditor); + } + } + } + + protected boolean reactivateUser(T user, List<ServiceEntity> delayedRegisterList, Auditor auditor) { + Boolean changed = false; + if (UserStatus.ON_HOLD.equals(user.getUserStatus())) { + changeUserStatus(user, UserStatus.ACTIVE, auditor); + + /* + * Also reenable all registries for user to LOST_ACCESS. They are rechecked then + */ + List<RegistryEntity> registryList = registryDao.findByUserAndStatus(user, RegistryStatus.ON_HOLD); + for (RegistryEntity registry : registryList) { + changeRegistryStatus(registry, RegistryStatus.LOST_ACCESS, "user-reactivated", auditor); + + /* + * check if parent registry is missing + */ + if (registry.getService().getParentService() != null) { + List<RegistryEntity> parentRegistryList = registryDao.findByServiceAndIdentityAndNotStatus( + registry.getService().getParentService(), user.getIdentity(), RegistryStatus.DELETED, + RegistryStatus.DEPROVISIONED); + if (parentRegistryList.size() == 0) { + delayedRegisterList.add(registry.getService().getParentService()); + } + } + } + + /* + * fire a user changed event to be sure, when the user is activated + */ + changed = true; + } + + return changed; + } + + protected boolean updateGroups(T user, Map<String, List<Object>> attributeMap, Auditor auditor) + throws UserUpdateException { + Set<GroupEntity> changedGroups = getGroupUpdater().updateGroupsForUser(user, attributeMap, auditor); + + if (changedGroups.size() > 0) { + return true; + } else { + return false; + } + } + + protected boolean updateAttributeSources(T user, ServiceEntity service, String executor, Auditor auditor) + throws UserUpdateException { + Boolean changed = false; + + /* + * if service is set, update only attribute sources spcific for this service. + * Else update all (login via web or generic attribute query) + */ + if (service != null) { + service = serviceDao.find(equal(ServiceEntity_.id, service.getId()), ServiceEntity_.attributeSourceService); + + for (AttributeSourceServiceEntity asse : service.getAttributeSourceService()) { + changed |= attributeSourceUpdater.updateUserAttributes(user, asse.getAttributeSource(), executor); + } + } else { + // find all user sources to update + Set<AttributeSourceEntity> asList = new HashSet<>( + attributeSourceDao.findAll(equal(AttributeSourceEntity_.userSource, true))); + // and add all sources which are already connected to the user + asList.addAll(asUserAttrDao.findAll(equal(ASUserAttrEntity_.user, user)).stream() + .map(a -> a.getAttributeSource()).toList()); + for (AttributeSourceEntity as : asList) { + changed |= attributeSourceUpdater.updateUserAttributes(user, as, executor); + } + } + return changed; + } + + protected void changeUserStatus(T user, UserStatus toStatus, Auditor auditor) { + UserStatus fromStatus = user.getUserStatus(); + user.setUserStatus(toStatus); + user.setLastStatusChange(new Date()); + + logger.debug("{}: change user status from {} to {}", user.getEppn(), fromStatus, toStatus); + auditor.logAction(user.getEppn(), "CHANGE STATUS", fromStatus + " -> " + toStatus, + "Change status " + fromStatus + " -> " + toStatus, AuditStatus.SUCCESS); + } + + protected void changeRegistryStatus(RegistryEntity registry, RegistryStatus toStatus, String statusMessage, + Auditor parentAuditor) { + RegistryStatus fromStatus = registry.getRegistryStatus(); + registry.setRegistryStatus(toStatus); + registry.setStatusMessage(statusMessage); + registry.setLastStatusChange(new Date()); + + logger.debug("{} {} {}: change registry status from {} to {}", new Object[] { registry.getUser().getEppn(), + registry.getService().getShortName(), registry.getId(), fromStatus, toStatus }); + RegistryAuditor registryAuditor = new RegistryAuditor(auditDao, auditDetailDao, appConfig); + registryAuditor.setParent(parentAuditor); + registryAuditor.startAuditTrail(parentAuditor.getActualExecutor()); + registryAuditor.setName(getClass().getName() + "-UserUpdate-Registry-Audit"); + registryAuditor.setDetail("Update registry " + registry.getId() + " for user " + registry.getUser().getEppn()); + registryAuditor.setRegistry(registry); + registryAuditor.logAction(registry.getUser().getEppn(), "CHANGE STATUS", "registry-" + registry.getId(), + "Change status " + fromStatus + " -> " + toStatus, AuditStatus.SUCCESS); + registryAuditor.finishAuditTrail(); + } + + protected Date getNextScheduledUpdate() { + Long futureMillis = 30L * 24L * 60L * 60L * 1000L; + if (appConfig.getConfigOptions().containsKey("update_schedule_future")) { + futureMillis = Long.decode(appConfig.getConfigValue("update_schedule_future")); + } + Integer futureMillisRandom = 6 * 60 * 60 * 1000; + if (appConfig.getConfigOptions().containsKey("update_schedule_future_random")) { + futureMillisRandom = Integer.decode(appConfig.getConfigValue("update_schedule_future_random")); + } + Random r = new Random(); + return new Date(System.currentTimeMillis() + futureMillis + r.nextInt(futureMillisRandom)); + } + + protected void fireUserChangeEvent(T user, String executor, Auditor auditor) { + + UserEvent userEvent = new UserEvent(user, auditor.getAudit()); + + try { + eventSubmitter.submit(userEvent, EventType.USER_UPDATE, executor); + } catch (EventSubmitException e) { + logger.warn("Could not submit event", e); + } + } } diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/OAuthUserUpdater.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/OAuthUserUpdater.java index ef9fb8ec8a8156d6e799d73efd1bc652c962b5c7..6c816bcd77e8dc49eac51ddcdc60ec544f445f8a 100644 --- a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/OAuthUserUpdater.java +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/OAuthUserUpdater.java @@ -1,56 +1,30 @@ package edu.kit.scc.webreg.service.impl; import java.lang.reflect.InvocationTargetException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import java.util.Random; import java.util.Set; import org.apache.commons.beanutils.PropertyUtils; import org.slf4j.Logger; -import org.slf4j.MDC; -import edu.kit.scc.webreg.as.AttributeSourceUpdater; import edu.kit.scc.webreg.audit.Auditor; -import edu.kit.scc.webreg.audit.RegistryAuditor; -import edu.kit.scc.webreg.audit.UserUpdateAuditor; -import edu.kit.scc.webreg.bootstrap.ApplicationConfig; -import edu.kit.scc.webreg.dao.RegistryDao; import edu.kit.scc.webreg.dao.SerialDao; -import edu.kit.scc.webreg.dao.ServiceDao; -import edu.kit.scc.webreg.dao.as.ASUserAttrDao; -import edu.kit.scc.webreg.dao.audit.AuditDetailDao; -import edu.kit.scc.webreg.dao.audit.AuditEntryDao; -import edu.kit.scc.webreg.dao.jpa.oauth.OAuthUserDao; -import edu.kit.scc.webreg.entity.EventType; -import edu.kit.scc.webreg.entity.GroupEntity; -import edu.kit.scc.webreg.entity.RegistryEntity; -import edu.kit.scc.webreg.entity.RegistryStatus; import edu.kit.scc.webreg.entity.ServiceEntity; import edu.kit.scc.webreg.entity.UserEntity; -import edu.kit.scc.webreg.entity.UserStatus; -import edu.kit.scc.webreg.entity.as.ASUserAttrEntity; -import edu.kit.scc.webreg.entity.as.AttributeSourceServiceEntity; -import edu.kit.scc.webreg.entity.attribute.IncomingAttributeSetEntity; +import edu.kit.scc.webreg.entity.attribute.IncomingOAuthAttributeEntity; import edu.kit.scc.webreg.entity.audit.AuditStatus; import edu.kit.scc.webreg.entity.oauth.OAuthUserEntity; -import edu.kit.scc.webreg.event.EventSubmitter; -import edu.kit.scc.webreg.event.UserEvent; -import edu.kit.scc.webreg.event.exc.EventSubmitException; -import edu.kit.scc.webreg.exc.RegisterException; import edu.kit.scc.webreg.exc.UserUpdateException; import edu.kit.scc.webreg.hook.HookManager; import edu.kit.scc.webreg.hook.UserServiceHook; +import edu.kit.scc.webreg.service.attribute.IncomingAttributesHandler; import edu.kit.scc.webreg.service.attribute.IncomingOAuthAttributesHandler; +import edu.kit.scc.webreg.service.group.HomeOrgGroupUpdater; import edu.kit.scc.webreg.service.group.OAuthGroupUpdater; -import edu.kit.scc.webreg.service.identity.IdentityUpdater; -import edu.kit.scc.webreg.service.reg.impl.Registrator; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -62,21 +36,6 @@ public class OAuthUserUpdater extends AbstractUserUpdater<OAuthUserEntity> { @Inject private Logger logger; - @Inject - private AuditEntryDao auditDao; - - @Inject - private AuditDetailDao auditDetailDao; - - @Inject - private OAuthUserDao userDao; - - @Inject - private ServiceDao serviceDao; - - @Inject - private RegistryDao registryDao; - @Inject private SerialDao serialDao; @@ -86,27 +45,6 @@ public class OAuthUserUpdater extends AbstractUserUpdater<OAuthUserEntity> { @Inject private OAuthGroupUpdater oauthGroupUpdater; - @Inject - private ASUserAttrDao asUserAttrDao; - - @Inject - private AttributeSourceUpdater attributeSourceUpdater; - - @Inject - private EventSubmitter eventSubmitter; - - @Inject - private ApplicationConfig appConfig; - - @Inject - private Registrator registrator; - - @Inject - private AttributeMapHelper attrHelper; - - @Inject - private IdentityUpdater identityUpdater; - @Inject private IncomingOAuthAttributesHandler incomingAttributeHandler; @@ -120,198 +58,6 @@ public class OAuthUserUpdater extends AbstractUserUpdater<OAuthUserEntity> { throw new UserUpdateException("Not implemented"); } - @Override - public OAuthUserEntity updateUser(OAuthUserEntity user, Map<String, List<Object>> attributeMap, String executor, - StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { - return updateUser(user, attributeMap, executor, null, null, lastLoginHost); - } - - @Override - public OAuthUserEntity updateUser(OAuthUserEntity user, Map<String, List<Object>> attributeMap, String executor, - ServiceEntity service, StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { - MDC.put("userId", "" + user.getId()); - logger.debug("Updating OIDC user {}", user.getEppn()); - - boolean changed = false; - - UserUpdateAuditor auditor = new UserUpdateAuditor(auditDao, auditDetailDao, appConfig); - auditor.startAuditTrail(executor); - auditor.setName(getClass().getName() + "-UserUpdate-Audit"); - auditor.setDetail("Update OAuth user " + user.getOauthId()); - - changed |= preUpdateUser(user, attributeMap, user.getOauthIssuer().getGenericStore(), executor, service, debugLog); - - // List to store parent services, that are not registered. Need to be registered - // later, when attribute map is populated - List<ServiceEntity> delayedRegisterList = new ArrayList<ServiceEntity>(); - - /** - * put no_assertion_count in generic store if assertion is missing. Else reset - * no assertion count and put last valid assertion date in - */ - if (attributeMap == null) { - if (!user.getGenericStore().containsKey("no_assertion_count")) { - user.getGenericStore().put("no_assertion_count", "1"); - } else { - user.getGenericStore().put("no_assertion_count", - "" + (Long.parseLong(user.getGenericStore().get("no_assertion_count")) + 1L)); - } - - logger.info("No attribute for user {}, skipping updateFromAttribute", user.getEppn()); - - user.getAttributeStore().clear(); - - if (UserStatus.ACTIVE.equals(user.getUserStatus())) { - changeUserStatus(user, UserStatus.ON_HOLD, auditor); - - /* - * Also flag all registries for user ON_HOLD - */ - List<RegistryEntity> registryList = registryDao.findByUserAndStatus(user, RegistryStatus.ACTIVE, - RegistryStatus.LOST_ACCESS, RegistryStatus.INVALID); - for (RegistryEntity registry : registryList) { - changeRegistryStatus(registry, RegistryStatus.ON_HOLD, "user-on-hold", auditor); - } - } - } else { - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - user.getGenericStore().put("no_assertion_count", "0"); - user.getGenericStore().put("last_valid_assertion", df.format(new Date())); - - changed |= updateUserFromAttribute(user, attributeMap, auditor); - - if (UserStatus.ON_HOLD.equals(user.getUserStatus())) { - changeUserStatus(user, UserStatus.ACTIVE, auditor); - - /* - * Also reenable all registries for user to LOST_ACCESS. They are rechecked then - */ - List<RegistryEntity> registryList = registryDao.findByUserAndStatus(user, RegistryStatus.ON_HOLD); - for (RegistryEntity registry : registryList) { - changeRegistryStatus(registry, RegistryStatus.LOST_ACCESS, "user-reactivated", auditor); - - /* - * check if parent registry is missing - */ - if (registry.getService().getParentService() != null) { - List<RegistryEntity> parentRegistryList = registryDao.findByServiceAndIdentityAndNotStatus( - registry.getService().getParentService(), user.getIdentity(), RegistryStatus.DELETED, - RegistryStatus.DEPROVISIONED); - if (parentRegistryList.size() == 0) { - delayedRegisterList.add(registry.getService().getParentService()); - } - } - } - - /* - * fire a user changed event to be sure, when the user is activated - */ - changed = true; - } - - /* - * if service is set, update only attribute sources spcific for this service. - * Else update all (login via web or generic attribute query) - */ - if (service != null) { - service = serviceDao.fetch(service.getId()); - - for (AttributeSourceServiceEntity asse : service.getAttributeSourceService()) { - changed |= attributeSourceUpdater.updateUserAttributes(user, asse.getAttributeSource(), - executor); - } - } else { - List<ASUserAttrEntity> asUserAttrList = asUserAttrDao.findForUser(user); - for (ASUserAttrEntity asUserAttr : asUserAttrList) { - changed |= attributeSourceUpdater.updateUserAttributes(user, asUserAttr.getAttributeSource(), - executor); - } - } - - Set<GroupEntity> changedGroups = oauthGroupUpdater.updateGroupsForUser(user, attributeMap, auditor); - - if (changedGroups.size() > 0) { - changed = true; - } - - Map<String, String> attributeStore = user.getAttributeStore(); - for (Entry<String, List<Object>> entry : attributeMap.entrySet()) { - attributeStore.put(entry.getKey(), attrHelper.attributeListToString(entry.getValue())); - } - - IncomingAttributeSetEntity incomingAttributeSet = incomingAttributeHandler.createOrUpdateAttributes(user, attributeMap); - incomingAttributeHandler.processIncomingAttributeSet(incomingAttributeSet); - - identityUpdater.updateIdentity(user); - - if (appConfig.getConfigValue("create_missing_eppn_scope") != null) { - if (user.getEppn() == null) { - String scope = appConfig.getConfigValue("create_missing_eppn_scope"); - user.setEppn(user.getIdentity().getGeneratedLocalUsername() + "@" + scope); - changed = true; - } - } - } - - for (ServiceEntity delayedService : delayedRegisterList) { - try { - registrator.registerUser(user, delayedService, "user-" + user.getId(), false); - } catch (RegisterException e) { - logger.warn("Parent registrytion didn't work out like it should", e); - } - } - - changed |= postUpdateUser(user, attributeMap, user.getOauthIssuer().getGenericStore(), executor, service, debugLog, - lastLoginHost); - - user.setLastUpdate(new Date()); - user.setLastFailedUpdate(null); - user.setExpireWarningSent(null); - user.setExpiredSent(null); - user.setScheduledUpdate(getNextScheduledUpdate()); - - if (changed) { - fireUserChangeEvent(user, auditor.getActualExecutor(), auditor); - } - - auditor.setUser(user); - auditor.finishAuditTrail(); - auditor.commitAuditTrail(); - - return user; - } - -// public OAuthUserEntity updateUser(OAuthUserEntity user, IDTokenClaimsSet claims, UserInfo userInfo, -// RefreshToken refreshToken, BearerAccessToken bat, String executor, ServiceEntity service, -// StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { -// -// Map<String, List<Object>> attributeMap = oidcTokenHelper.convertToAttributeMap(claims, userInfo, refreshToken, -// bat); -// -// if (service != null) -// return updateUser(user, attributeMap, executor, service, debugLog, lastLoginHost); -// else -// return updateUser(user, attributeMap, executor, debugLog, lastLoginHost); -// } - -// public OAuthUserEntity updateUser(OAuthUserEntity user, IDTokenClaimsSet claims, UserInfo userInfo, -// RefreshToken refreshToken, BearerAccessToken bat, String executor, StringBuffer debugLog, -// String lastLoginHost) throws UserUpdateException { -// -// return updateUser(user, claims, userInfo, refreshToken, bat, executor, null, debugLog, lastLoginHost); -// } - - protected void fireUserChangeEvent(UserEntity user, String executor, Auditor auditor) { - - UserEvent userEvent = new UserEvent(user, auditor.getAudit()); - - try { - eventSubmitter.submit(userEvent, EventType.USER_UPDATE, executor); - } catch (EventSubmitException e) { - logger.warn("Could not submit event", e); - } - } - public boolean updateUserNew(OAuthUserEntity user, Map<String, List<Object>> attributeMap, String executor, Auditor auditor, StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { boolean changed = false; @@ -324,12 +70,7 @@ public class OAuthUserUpdater extends AbstractUserUpdater<OAuthUserEntity> { return changed; } - public boolean updateUserFromAttribute(UserEntity user, Map<String, List<Object>> attributeMap, Auditor auditor) - throws UserUpdateException { - return updateUserFromAttribute(user, attributeMap, false, auditor); - } - - public boolean updateUserFromAttribute(UserEntity user, Map<String, List<Object>> attributeMap, + public boolean updateUserFromAttribute(OAuthUserEntity user, Map<String, List<Object>> attributeMap, boolean withoutUidNumber, Auditor auditor) throws UserUpdateException { boolean changed = false; @@ -428,51 +169,29 @@ public class OAuthUserUpdater extends AbstractUserUpdater<OAuthUserEntity> { return true; } - protected void changeUserStatus(UserEntity user, UserStatus toStatus, Auditor auditor) { - UserStatus fromStatus = user.getUserStatus(); - user.setUserStatus(toStatus); - user.setLastStatusChange(new Date()); + protected void updateFail(OAuthUserEntity user) { + user.setLastFailedUpdate(new Date()); + user.setScheduledUpdate(getNextScheduledUpdate()); + } - logger.debug("{}: change user status from {} to {}", user.getEppn(), fromStatus, toStatus); - auditor.logAction(user.getEppn(), "CHANGE STATUS", fromStatus + " -> " + toStatus, - "Change status " + fromStatus + " -> " + toStatus, AuditStatus.SUCCESS); + @Override + public OAuthUserEntity expireUser(OAuthUserEntity user) throws UserUpdateException { + // TODO Auto-generated method stub + return null; } - protected void changeRegistryStatus(RegistryEntity registry, RegistryStatus toStatus, String statusMessage, - Auditor parentAuditor) { - RegistryStatus fromStatus = registry.getRegistryStatus(); - registry.setRegistryStatus(toStatus); - registry.setStatusMessage(statusMessage); - registry.setLastStatusChange(new Date()); - - logger.debug("{} {} {}: change registry status from {} to {}", new Object[] { registry.getUser().getEppn(), - registry.getService().getShortName(), registry.getId(), fromStatus, toStatus }); - RegistryAuditor registryAuditor = new RegistryAuditor(auditDao, auditDetailDao, appConfig); - registryAuditor.setParent(parentAuditor); - registryAuditor.startAuditTrail(parentAuditor.getActualExecutor()); - registryAuditor.setName(getClass().getName() + "-UserUpdate-Registry-Audit"); - registryAuditor.setDetail("Update registry " + registry.getId() + " for user " + registry.getUser().getEppn()); - registryAuditor.setRegistry(registry); - registryAuditor.logAction(registry.getUser().getEppn(), "CHANGE STATUS", "registry-" + registry.getId(), - "Change status " + fromStatus + " -> " + toStatus, AuditStatus.SUCCESS); - registryAuditor.finishAuditTrail(); + @Override + public HomeOrgGroupUpdater<OAuthUserEntity> getGroupUpdater() { + return oauthGroupUpdater; } - private Date getNextScheduledUpdate() { - Long futureMillis = 30L * 24L * 60L * 60L * 1000L; - if (appConfig.getConfigOptions().containsKey("update_schedule_future")) { - futureMillis = Long.decode(appConfig.getConfigValue("update_schedule_future")); - } - Integer futureMillisRandom = 6 * 60 * 60 * 1000; - if (appConfig.getConfigOptions().containsKey("update_schedule_future_random")) { - futureMillisRandom = Integer.decode(appConfig.getConfigValue("update_schedule_future_random")); - } - Random r = new Random(); - return new Date(System.currentTimeMillis() + futureMillis + r.nextInt(futureMillisRandom)); + @Override + public Map<String, String> resolveHomeOrgGenericStore(OAuthUserEntity user) { + return user.getOauthIssuer().getGenericStore(); } - protected void updateFail(OAuthUserEntity user) { - user.setLastFailedUpdate(new Date()); - user.setScheduledUpdate(getNextScheduledUpdate()); + @Override + public IncomingAttributesHandler<IncomingOAuthAttributeEntity> resolveIncomingAttributeHandler(OAuthUserEntity user) { + return incomingAttributeHandler; } } diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/OidcUserUpdater.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/OidcUserUpdater.java index f8de47079c5af54ae83ecf8da19038cf7d2da47b..9103738f25c3c8f3319fbad3343d92778cf8305c 100644 --- a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/OidcUserUpdater.java +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/OidcUserUpdater.java @@ -2,19 +2,14 @@ package edu.kit.scc.webreg.service.impl; import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import java.util.Random; import java.util.Set; import org.apache.commons.beanutils.PropertyUtils; import org.slf4j.Logger; -import org.slf4j.MDC; import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.JWSAlgorithm; @@ -46,42 +41,21 @@ import com.nimbusds.openid.connect.sdk.validators.IDTokenValidator; import edu.kit.scc.regapp.oidc.tools.OidcOpMetadataSingletonBean; import edu.kit.scc.regapp.oidc.tools.OidcTokenHelper; -import edu.kit.scc.webreg.as.AttributeSourceUpdater; import edu.kit.scc.webreg.audit.Auditor; -import edu.kit.scc.webreg.audit.RegistryAuditor; -import edu.kit.scc.webreg.audit.UserUpdateAuditor; -import edu.kit.scc.webreg.bootstrap.ApplicationConfig; -import edu.kit.scc.webreg.dao.RegistryDao; import edu.kit.scc.webreg.dao.SerialDao; -import edu.kit.scc.webreg.dao.ServiceDao; -import edu.kit.scc.webreg.dao.as.ASUserAttrDao; -import edu.kit.scc.webreg.dao.audit.AuditDetailDao; -import edu.kit.scc.webreg.dao.audit.AuditEntryDao; -import edu.kit.scc.webreg.dao.oidc.OidcUserDao; -import edu.kit.scc.webreg.entity.EventType; -import edu.kit.scc.webreg.entity.GroupEntity; -import edu.kit.scc.webreg.entity.RegistryEntity; -import edu.kit.scc.webreg.entity.RegistryStatus; import edu.kit.scc.webreg.entity.ServiceEntity; import edu.kit.scc.webreg.entity.UserEntity; -import edu.kit.scc.webreg.entity.UserStatus; -import edu.kit.scc.webreg.entity.as.ASUserAttrEntity; -import edu.kit.scc.webreg.entity.as.AttributeSourceServiceEntity; -import edu.kit.scc.webreg.entity.attribute.IncomingAttributeSetEntity; +import edu.kit.scc.webreg.entity.attribute.IncomingOidcAttributeEntity; import edu.kit.scc.webreg.entity.audit.AuditStatus; import edu.kit.scc.webreg.entity.oidc.OidcRpConfigurationEntity; import edu.kit.scc.webreg.entity.oidc.OidcUserEntity; -import edu.kit.scc.webreg.event.EventSubmitter; -import edu.kit.scc.webreg.event.UserEvent; -import edu.kit.scc.webreg.event.exc.EventSubmitException; -import edu.kit.scc.webreg.exc.RegisterException; import edu.kit.scc.webreg.exc.UserUpdateException; import edu.kit.scc.webreg.hook.HookManager; import edu.kit.scc.webreg.hook.UserServiceHook; +import edu.kit.scc.webreg.service.attribute.IncomingAttributesHandler; import edu.kit.scc.webreg.service.attribute.IncomingOidcAttributesHandler; +import edu.kit.scc.webreg.service.group.HomeOrgGroupUpdater; import edu.kit.scc.webreg.service.group.OidcGroupUpdater; -import edu.kit.scc.webreg.service.identity.IdentityUpdater; -import edu.kit.scc.webreg.service.reg.impl.Registrator; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -93,21 +67,6 @@ public class OidcUserUpdater extends AbstractUserUpdater<OidcUserEntity> { @Inject private Logger logger; - @Inject - private AuditEntryDao auditDao; - - @Inject - private AuditDetailDao auditDetailDao; - - @Inject - private OidcUserDao userDao; - - @Inject - private ServiceDao serviceDao; - - @Inject - private RegistryDao registryDao; - @Inject private SerialDao serialDao; @@ -117,33 +76,12 @@ public class OidcUserUpdater extends AbstractUserUpdater<OidcUserEntity> { @Inject private OidcGroupUpdater oidcGroupUpdater; - @Inject - private ASUserAttrDao asUserAttrDao; - - @Inject - private AttributeSourceUpdater attributeSourceUpdater; - - @Inject - private EventSubmitter eventSubmitter; - - @Inject - private ApplicationConfig appConfig; - - @Inject - private Registrator registrator; - - @Inject - private AttributeMapHelper attrHelper; - @Inject private OidcTokenHelper oidcTokenHelper; @Inject private OidcOpMetadataSingletonBean opMetadataBean; - - @Inject - private IdentityUpdater identityUpdater; - + @Inject private IncomingOidcAttributesHandler incomingAttributeHandler; @@ -248,167 +186,6 @@ public class OidcUserUpdater extends AbstractUserUpdater<OidcUserEntity> { return user; } - @Override - public OidcUserEntity updateUser(OidcUserEntity user, Map<String, List<Object>> attributeMap, String executor, - StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { - return updateUser(user, attributeMap, executor, null, null, lastLoginHost); - } - - @Override - public OidcUserEntity updateUser(OidcUserEntity user, Map<String, List<Object>> attributeMap, String executor, - ServiceEntity service, StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { - MDC.put("userId", "" + user.getId()); - logger.debug("Updating OIDC user {}", user.getEppn()); - - boolean changed = false; - - UserUpdateAuditor auditor = new UserUpdateAuditor(auditDao, auditDetailDao, appConfig); - auditor.startAuditTrail(executor); - auditor.setName(getClass().getName() + "-UserUpdate-Audit"); - auditor.setDetail("Update OIDC user " + user.getSubjectId()); - - changed |= preUpdateUser(user, attributeMap, user.getIssuer().getGenericStore(), executor, service, debugLog); - - // List to store parent services, that are not registered. Need to be registered - // later, when attribute map is populated - List<ServiceEntity> delayedRegisterList = new ArrayList<ServiceEntity>(); - - /** - * put no_assertion_count in generic store if assertion is missing. Else reset - * no assertion count and put last valid assertion date in - */ - if (attributeMap == null) { - if (!user.getGenericStore().containsKey("no_assertion_count")) { - user.getGenericStore().put("no_assertion_count", "1"); - } else { - user.getGenericStore().put("no_assertion_count", - "" + (Long.parseLong(user.getGenericStore().get("no_assertion_count")) + 1L)); - } - - logger.info("No attribute for user {}, skipping updateFromAttribute", user.getEppn()); - - user.getAttributeStore().clear(); - - if (UserStatus.ACTIVE.equals(user.getUserStatus())) { - changeUserStatus(user, UserStatus.ON_HOLD, auditor); - - /* - * Also flag all registries for user ON_HOLD - */ - List<RegistryEntity> registryList = registryDao.findByUserAndStatus(user, RegistryStatus.ACTIVE, - RegistryStatus.LOST_ACCESS, RegistryStatus.INVALID); - for (RegistryEntity registry : registryList) { - changeRegistryStatus(registry, RegistryStatus.ON_HOLD, "user-on-hold", auditor); - } - } - } else { - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - user.getGenericStore().put("no_assertion_count", "0"); - user.getGenericStore().put("last_valid_assertion", df.format(new Date())); - - changed |= updateUserFromAttribute(user, attributeMap, auditor); - - if (UserStatus.ON_HOLD.equals(user.getUserStatus())) { - changeUserStatus(user, UserStatus.ACTIVE, auditor); - - /* - * Also reenable all registries for user to LOST_ACCESS. They are rechecked then - */ - List<RegistryEntity> registryList = registryDao.findByUserAndStatus(user, RegistryStatus.ON_HOLD); - for (RegistryEntity registry : registryList) { - changeRegistryStatus(registry, RegistryStatus.LOST_ACCESS, "user-reactivated", auditor); - - /* - * check if parent registry is missing - */ - if (registry.getService().getParentService() != null) { - List<RegistryEntity> parentRegistryList = registryDao.findByServiceAndIdentityAndNotStatus( - registry.getService().getParentService(), user.getIdentity(), RegistryStatus.DELETED, - RegistryStatus.DEPROVISIONED); - if (parentRegistryList.size() == 0) { - delayedRegisterList.add(registry.getService().getParentService()); - } - } - } - - /* - * fire a user changed event to be sure, when the user is activated - */ - changed = true; - } - - /* - * if service is set, update only attribute sources spcific for this service. - * Else update all (login via web or generic attribute query) - */ - if (service != null) { - service = serviceDao.fetch(service.getId()); - - for (AttributeSourceServiceEntity asse : service.getAttributeSourceService()) { - changed |= attributeSourceUpdater.updateUserAttributes(user, asse.getAttributeSource(), - executor); - } - } else { - List<ASUserAttrEntity> asUserAttrList = asUserAttrDao.findForUser(user); - for (ASUserAttrEntity asUserAttr : asUserAttrList) { - changed |= attributeSourceUpdater.updateUserAttributes(user, asUserAttr.getAttributeSource(), - executor); - } - } - - Set<GroupEntity> changedGroups = oidcGroupUpdater.updateGroupsForUser(user, attributeMap, auditor); - - if (changedGroups.size() > 0) { - changed = true; - } - - Map<String, String> attributeStore = user.getAttributeStore(); - for (Entry<String, List<Object>> entry : attributeMap.entrySet()) { - attributeStore.put(entry.getKey(), attrHelper.attributeListToString(entry.getValue())); - } - - IncomingAttributeSetEntity incomingAttributeSet = incomingAttributeHandler.createOrUpdateAttributes(user, attributeMap); - incomingAttributeHandler.processIncomingAttributeSet(incomingAttributeSet); - - identityUpdater.updateIdentity(user); - - if (appConfig.getConfigValue("create_missing_eppn_scope") != null) { - if (user.getEppn() == null) { - String scope = appConfig.getConfigValue("create_missing_eppn_scope"); - user.setEppn(user.getIdentity().getGeneratedLocalUsername() + "@" + scope); - changed = true; - } - } - } - - for (ServiceEntity delayedService : delayedRegisterList) { - try { - registrator.registerUser(user, delayedService, "user-" + user.getId(), false); - } catch (RegisterException e) { - logger.warn("Parent registrytion didn't work out like it should", e); - } - } - - changed |= postUpdateUser(user, attributeMap, user.getIssuer().getGenericStore(), executor, service, debugLog, - lastLoginHost); - - user.setLastUpdate(new Date()); - user.setLastFailedUpdate(null); - user.setExpireWarningSent(null); - user.setExpiredSent(null); - user.setScheduledUpdate(getNextScheduledUpdate()); - - if (changed) { - fireUserChangeEvent(user, auditor.getActualExecutor(), auditor); - } - - auditor.setUser(user); - auditor.finishAuditTrail(); - auditor.commitAuditTrail(); - - return user; - } - public OidcUserEntity updateUser(OidcUserEntity user, IDTokenClaimsSet claims, UserInfo userInfo, RefreshToken refreshToken, BearerAccessToken bat, String executor, ServiceEntity service, StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { @@ -429,17 +206,6 @@ public class OidcUserUpdater extends AbstractUserUpdater<OidcUserEntity> { return updateUser(user, claims, userInfo, refreshToken, bat, executor, null, debugLog, lastLoginHost); } - protected void fireUserChangeEvent(UserEntity user, String executor, Auditor auditor) { - - UserEvent userEvent = new UserEvent(user, auditor.getAudit()); - - try { - eventSubmitter.submit(userEvent, EventType.USER_UPDATE, executor); - } catch (EventSubmitException e) { - logger.warn("Could not submit event", e); - } - } - public boolean updateUserNew(OidcUserEntity user, Map<String, List<Object>> attributeMap, String executor, Auditor auditor, StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { boolean changed = false; @@ -452,12 +218,7 @@ public class OidcUserUpdater extends AbstractUserUpdater<OidcUserEntity> { return changed; } - public boolean updateUserFromAttribute(UserEntity user, Map<String, List<Object>> attributeMap, Auditor auditor) - throws UserUpdateException { - return updateUserFromAttribute(user, attributeMap, false, auditor); - } - - public boolean updateUserFromAttribute(UserEntity user, Map<String, List<Object>> attributeMap, + public boolean updateUserFromAttribute(OidcUserEntity user, Map<String, List<Object>> attributeMap, boolean withoutUidNumber, Auditor auditor) throws UserUpdateException { boolean changed = false; @@ -559,51 +320,29 @@ public class OidcUserUpdater extends AbstractUserUpdater<OidcUserEntity> { return true; } - protected void changeUserStatus(UserEntity user, UserStatus toStatus, Auditor auditor) { - UserStatus fromStatus = user.getUserStatus(); - user.setUserStatus(toStatus); - user.setLastStatusChange(new Date()); + protected void updateFail(OidcUserEntity user) { + user.setLastFailedUpdate(new Date()); + user.setScheduledUpdate(getNextScheduledUpdate()); + } - logger.debug("{}: change user status from {} to {}", user.getEppn(), fromStatus, toStatus); - auditor.logAction(user.getEppn(), "CHANGE STATUS", fromStatus + " -> " + toStatus, - "Change status " + fromStatus + " -> " + toStatus, AuditStatus.SUCCESS); + @Override + public OidcUserEntity expireUser(OidcUserEntity user) throws UserUpdateException { + // TODO Auto-generated method stub + return null; } - protected void changeRegistryStatus(RegistryEntity registry, RegistryStatus toStatus, String statusMessage, - Auditor parentAuditor) { - RegistryStatus fromStatus = registry.getRegistryStatus(); - registry.setRegistryStatus(toStatus); - registry.setStatusMessage(statusMessage); - registry.setLastStatusChange(new Date()); - - logger.debug("{} {} {}: change registry status from {} to {}", new Object[] { registry.getUser().getEppn(), - registry.getService().getShortName(), registry.getId(), fromStatus, toStatus }); - RegistryAuditor registryAuditor = new RegistryAuditor(auditDao, auditDetailDao, appConfig); - registryAuditor.setParent(parentAuditor); - registryAuditor.startAuditTrail(parentAuditor.getActualExecutor()); - registryAuditor.setName(getClass().getName() + "-UserUpdate-Registry-Audit"); - registryAuditor.setDetail("Update registry " + registry.getId() + " for user " + registry.getUser().getEppn()); - registryAuditor.setRegistry(registry); - registryAuditor.logAction(registry.getUser().getEppn(), "CHANGE STATUS", "registry-" + registry.getId(), - "Change status " + fromStatus + " -> " + toStatus, AuditStatus.SUCCESS); - registryAuditor.finishAuditTrail(); + @Override + public HomeOrgGroupUpdater<OidcUserEntity> getGroupUpdater() { + return oidcGroupUpdater; } - private Date getNextScheduledUpdate() { - Long futureMillis = 30L * 24L * 60L * 60L * 1000L; - if (appConfig.getConfigOptions().containsKey("update_schedule_future")) { - futureMillis = Long.decode(appConfig.getConfigValue("update_schedule_future")); - } - Integer futureMillisRandom = 6 * 60 * 60 * 1000; - if (appConfig.getConfigOptions().containsKey("update_schedule_future_random")) { - futureMillisRandom = Integer.decode(appConfig.getConfigValue("update_schedule_future_random")); - } - Random r = new Random(); - return new Date(System.currentTimeMillis() + futureMillis + r.nextInt(futureMillisRandom)); + @Override + public Map<String, String> resolveHomeOrgGenericStore(OidcUserEntity user) { + return user.getIssuer().getGenericStore(); } - protected void updateFail(OidcUserEntity user) { - user.setLastFailedUpdate(new Date()); - user.setScheduledUpdate(getNextScheduledUpdate()); + @Override + public IncomingAttributesHandler<IncomingOidcAttributeEntity> resolveIncomingAttributeHandler(OidcUserEntity user) { + return incomingAttributeHandler; } } diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/SamlUserUpdater.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/SamlUserUpdater.java index 88709b639beb2f5eb530b0e773f24e68ed513dc5..33eff071799972b393dcca50576c21013bdf5614 100644 --- a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/SamlUserUpdater.java +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/SamlUserUpdater.java @@ -1,18 +1,12 @@ package edu.kit.scc.webreg.service.impl; -import static edu.kit.scc.webreg.dao.ops.RqlExpressions.equal; - import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Random; import java.util.Set; import org.apache.commons.beanutils.PropertyUtils; @@ -22,58 +16,34 @@ import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.opensaml.soap.common.SOAPException; import org.opensaml.xmlsec.encryption.support.DecryptionException; import org.slf4j.Logger; -import org.slf4j.MDC; -import edu.kit.scc.webreg.as.AttributeSourceUpdater; import edu.kit.scc.webreg.audit.Auditor; import edu.kit.scc.webreg.audit.IdpCommunicationAuditor; -import edu.kit.scc.webreg.audit.RegistryAuditor; -import edu.kit.scc.webreg.audit.UserUpdateAuditor; import edu.kit.scc.webreg.bootstrap.ApplicationConfig; -import edu.kit.scc.webreg.dao.RegistryDao; import edu.kit.scc.webreg.dao.SamlAssertionDao; import edu.kit.scc.webreg.dao.SamlIdpMetadataDao; import edu.kit.scc.webreg.dao.SamlSpConfigurationDao; import edu.kit.scc.webreg.dao.SamlUserDao; import edu.kit.scc.webreg.dao.SerialDao; -import edu.kit.scc.webreg.dao.ServiceDao; -import edu.kit.scc.webreg.dao.as.ASUserAttrDao; -import edu.kit.scc.webreg.dao.as.AttributeSourceDao; import edu.kit.scc.webreg.dao.audit.AuditDetailDao; import edu.kit.scc.webreg.dao.audit.AuditEntryDao; -import edu.kit.scc.webreg.entity.EventType; -import edu.kit.scc.webreg.entity.GroupEntity; -import edu.kit.scc.webreg.entity.RegistryEntity; -import edu.kit.scc.webreg.entity.RegistryStatus; import edu.kit.scc.webreg.entity.SamlAssertionEntity; import edu.kit.scc.webreg.entity.SamlIdpMetadataEntity; import edu.kit.scc.webreg.entity.SamlIdpMetadataEntityStatus; import edu.kit.scc.webreg.entity.SamlSpConfigurationEntity; import edu.kit.scc.webreg.entity.SamlUserEntity; import edu.kit.scc.webreg.entity.ServiceEntity; -import edu.kit.scc.webreg.entity.ServiceEntity_; import edu.kit.scc.webreg.entity.UserEntity; -import edu.kit.scc.webreg.entity.UserStatus; -import edu.kit.scc.webreg.entity.as.ASUserAttrEntity_; -import edu.kit.scc.webreg.entity.as.AttributeSourceEntity; -import edu.kit.scc.webreg.entity.as.AttributeSourceEntity_; -import edu.kit.scc.webreg.entity.as.AttributeSourceServiceEntity; -import edu.kit.scc.webreg.entity.attribute.IncomingAttributeSetEntity; -import edu.kit.scc.webreg.entity.audit.AuditDetailEntity; +import edu.kit.scc.webreg.entity.attribute.IncomingSamlAttributeEntity; import edu.kit.scc.webreg.entity.audit.AuditStatus; -import edu.kit.scc.webreg.entity.audit.AuditUserUpdateEntity; -import edu.kit.scc.webreg.event.EventSubmitter; -import edu.kit.scc.webreg.event.UserEvent; -import edu.kit.scc.webreg.event.exc.EventSubmitException; -import edu.kit.scc.webreg.exc.RegisterException; import edu.kit.scc.webreg.exc.UserUpdateException; import edu.kit.scc.webreg.hook.HookManager; import edu.kit.scc.webreg.hook.UserServiceHook; import edu.kit.scc.webreg.logging.LogHelper; +import edu.kit.scc.webreg.service.attribute.IncomingAttributesHandler; import edu.kit.scc.webreg.service.attribute.IncomingSamlAttributesHandler; import edu.kit.scc.webreg.service.group.HomeOrgGroupUpdater; -import edu.kit.scc.webreg.service.identity.IdentityUpdater; -import edu.kit.scc.webreg.service.reg.impl.Registrator; +import edu.kit.scc.webreg.service.group.SamlGroupUpdater; import edu.kit.scc.webreg.service.saml.AttributeQueryHelper; import edu.kit.scc.webreg.service.saml.Saml2AssertionService; import edu.kit.scc.webreg.service.saml.SamlHelper; @@ -108,13 +78,7 @@ public class SamlUserUpdater extends AbstractUserUpdater<SamlUserEntity> { private SamlUserDao userDao; @Inject - private ServiceDao serviceDao; - - @Inject - private RegistryDao registryDao; - - @Inject - private HomeOrgGroupUpdater homeOrgGroupUpdater; + private SamlGroupUpdater homeOrgGroupUpdater; @Inject private SamlHelper samlHelper; @@ -132,238 +96,19 @@ public class SamlUserUpdater extends AbstractUserUpdater<SamlUserEntity> { private HookManager hookManager; @Inject - private AttributeSourceDao attributeSourceDao; - - @Inject - private ASUserAttrDao asUserAttrDao; + private IncomingSamlAttributesHandler incomingAttributeHandler; @Inject private SamlAssertionDao samlAsserionDao; - @Inject - private AttributeSourceUpdater attributeSourceUpdater; - @Inject private AttributeMapHelper attrHelper; - @Inject - private EventSubmitter eventSubmitter; - - @Inject - private ApplicationConfig appConfig; - - @Inject - private Registrator registrator; - - @Inject - private IdentityUpdater identityUpdater; + @Inject ApplicationConfig appConfig; - @Inject - private IncomingSamlAttributesHandler incomingAttributeHandler; - @Inject private LogHelper logHelper; - @Override - public SamlUserEntity updateUser(SamlUserEntity user, Map<String, List<Object>> attributeMap, String executor, - StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { - return updateUser(user, attributeMap, executor, null, debugLog, lastLoginHost); - } - - @Override - public SamlUserEntity updateUser(SamlUserEntity user, Map<String, List<Object>> attributeMap, String executor, - ServiceEntity service, StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { - MDC.put("userId", "" + user.getId()); - logger.debug("Updating SAML user {}", user.getEppn()); - - boolean changed = false; - - UserUpdateAuditor auditor = new UserUpdateAuditor(auditDao, auditDetailDao, appConfig); - auditor.startAuditTrail(executor); - auditor.setName(getClass().getName() + "-UserUpdate-Audit"); - auditor.setDetail("Update user " + user.getEppn()); - - changed |= preUpdateUser(user, attributeMap, user.getIdp().getGenericStore(), executor, service, debugLog); - - // List to store parent services, that are not registered. Need to be registered - // later, when attribute map is populated - List<ServiceEntity> delayedRegisterList = new ArrayList<ServiceEntity>(); - - /** - * put no_assertion_count in generic store if assertion is missing. Else reset - * no assertion count and put last valid assertion date in - */ - if (attributeMap == null) { - if (!user.getGenericStore().containsKey("no_assertion_count")) { - user.getGenericStore().put("no_assertion_count", "1"); - } else { - user.getGenericStore().put("no_assertion_count", - "" + (Long.parseLong(user.getGenericStore().get("no_assertion_count")) + 1L)); - } - - logger.info("No attribute for user {}, skipping updateFromAttribute", user.getEppn()); - - user.getAttributeStore().clear(); - - // user empty attribute map in order to remove all existing values - IncomingAttributeSetEntity incomingAttributeSet = incomingAttributeHandler.createOrUpdateAttributes(user, new HashMap<>()); - incomingAttributeHandler.processIncomingAttributeSet(incomingAttributeSet); - - if (UserStatus.ACTIVE.equals(user.getUserStatus())) { - changeUserStatus(user, UserStatus.ON_HOLD, auditor); - - identityUpdater.updateIdentity(user); - - /* - * Also flag all registries for user ON_HOLD - */ - List<RegistryEntity> registryList = registryDao.findByUserAndStatus(user, RegistryStatus.ACTIVE, - RegistryStatus.LOST_ACCESS, RegistryStatus.INVALID); - for (RegistryEntity registry : registryList) { - changeRegistryStatus(registry, RegistryStatus.ON_HOLD, "user-on-hold", auditor); - } - } - } else { - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - user.getGenericStore().put("no_assertion_count", "0"); - user.getGenericStore().put("last_valid_assertion", df.format(new Date())); - - changed |= updateUserFromAttribute(user, attributeMap, auditor); - - if (UserStatus.ON_HOLD.equals(user.getUserStatus())) { - changeUserStatus(user, UserStatus.ACTIVE, auditor); - - /* - * Also reenable all registries for user to LOST_ACCESS. They are rechecked then - */ - List<RegistryEntity> registryList = registryDao.findByUserAndStatus(user, RegistryStatus.ON_HOLD); - for (RegistryEntity registry : registryList) { - changeRegistryStatus(registry, RegistryStatus.LOST_ACCESS, "user-reactivated", auditor); - - /* - * check if parent registry is missing - */ - if (registry.getService().getParentService() != null) { - List<RegistryEntity> parentRegistryList = registryDao.findByServiceAndIdentityAndNotStatus( - registry.getService().getParentService(), user.getIdentity(), RegistryStatus.DELETED, - RegistryStatus.DEPROVISIONED); - if (parentRegistryList.size() == 0) { - delayedRegisterList.add(registry.getService().getParentService()); - } - } - } - - /* - * fire a user changed event to be sure, when the user is activated - */ - changed = true; - } - - /* - * if service is set, update only attribute sources spcific for this service. - * Else update all (login via web or generic attribute query) - */ - if (service != null) { - service = serviceDao.find(equal(ServiceEntity_.id, service.getId()), - ServiceEntity_.attributeSourceService); - - for (AttributeSourceServiceEntity asse : service.getAttributeSourceService()) { - changed |= attributeSourceUpdater.updateUserAttributes(user, asse.getAttributeSource(), executor); - } - } else { - // find all user sources to update - Set<AttributeSourceEntity> asList = new HashSet<>(attributeSourceDao - .findAll(equal(AttributeSourceEntity_.userSource, true))); - // and add all sources which are already connected to the user - asList.addAll(asUserAttrDao.findAll(equal(ASUserAttrEntity_.user, user)).stream() - .map(a -> a.getAttributeSource()).toList()); - for (AttributeSourceEntity as : asList) { - changed |= attributeSourceUpdater.updateUserAttributes(user, as, executor); - } - } - - Set<GroupEntity> changedGroups = homeOrgGroupUpdater.updateGroupsForUser(user, attributeMap, auditor); - - if (changedGroups.size() > 0) { - changed = true; - } - - Map<String, String> attributeStore = user.getAttributeStore(); - attributeStore.clear(); - for (Entry<String, List<Object>> entry : attributeMap.entrySet()) { - attributeStore.put(entry.getKey(), attrHelper.attributeListToString(entry.getValue())); - } - - IncomingAttributeSetEntity incomingAttributeSet = incomingAttributeHandler.createOrUpdateAttributes(user, attributeMap); - incomingAttributeHandler.processIncomingAttributeSet(incomingAttributeSet); - - identityUpdater.updateIdentity(user); - - if (appConfig.getConfigValue("create_missing_eppn_scope") != null) { - if (user.getEppn() == null) { - String scope = appConfig.getConfigValue("create_missing_eppn_scope"); - user.setEppn(user.getIdentity().getGeneratedLocalUsername() + "@" + scope); - changed = true; - } - } - } - - for (ServiceEntity delayedService : delayedRegisterList) { - try { - registrator.registerUser(user, delayedService, "user-" + user.getId(), false); - } catch (RegisterException e) { - logger.warn("Parent registration didn't work out like it should", e); - } - } - - changed |= postUpdateUser(user, attributeMap, user.getIdp().getGenericStore(), executor, service, debugLog, - lastLoginHost); - - user.setLastUpdate(new Date()); - user.setLastFailedUpdate(null); - user.setExpireWarningSent(null); - user.setExpiredSent(null); - user.setScheduledUpdate(getNextScheduledUpdate()); - - if (changed) { - fireUserChangeEvent(user, auditor.getActualExecutor(), auditor); - } - - auditor.setUser(user); - auditor.finishAuditTrail(); - auditor.commitAuditTrail(); - - if (debugLog != null) { - AuditUserUpdateEntity audit = auditor.getAudit(); - debugLog.append("\n\nPrinting audit from user update process:\n\nName: ").append(audit.getName()) - .append("\nDetail: ").append(audit.getDetail()).append("\n"); - for (AuditDetailEntity detail : audit.getAuditDetails()) { - debugLog.append(detail.getEndTime()).append(" | ").append(detail.getSubject()).append(" | ") - .append(detail.getObject()).append(" | ").append(detail.getAction()).append(" | ") - .append(detail.getLog()).append(" | ").append(detail.getAuditStatus()).append("\n"); - } - - if (audit.getAuditDetails().size() == 0) { - debugLog.append("Nothing seems to have changed.\n"); - } - } - - return user; - } - - private Date getNextScheduledUpdate() { - Long futureMillis = 30L * 24L * 60L * 60L * 1000L; - if (appConfig.getConfigOptions().containsKey("update_schedule_future")) { - futureMillis = Long.decode(appConfig.getConfigValue("update_schedule_future")); - } - Integer futureMillisRandom = 6 * 60 * 60 * 1000; - if (appConfig.getConfigOptions().containsKey("update_schedule_future_random")) { - futureMillisRandom = Integer.decode(appConfig.getConfigValue("update_schedule_future_random")); - } - Random r = new Random(); - return new Date(System.currentTimeMillis() + futureMillis + r.nextInt(futureMillisRandom)); - } - public SamlUserEntity updateUser(SamlUserEntity user, Assertion assertion, String executor, ServiceEntity service, StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { @@ -539,16 +284,7 @@ public class SamlUserUpdater extends AbstractUserUpdater<SamlUserEntity> { user = userDao.persist(user); } - protected void fireUserChangeEvent(UserEntity user, String executor, Auditor auditor) { - UserEvent userEvent = new UserEvent(user, auditor.getAudit()); - - try { - eventSubmitter.submit(userEvent, EventType.USER_UPDATE, executor); - } catch (EventSubmitException e) { - logger.warn("Could not submit event", e); - } - } public boolean updateUserNew(SamlUserEntity user, Map<String, List<Object>> attributeMap, String executor, Auditor auditor, StringBuffer debugLog, String lastLoginHost) throws UserUpdateException { @@ -562,11 +298,6 @@ public class SamlUserUpdater extends AbstractUserUpdater<SamlUserEntity> { return changed; } - public boolean updateUserFromAttribute(SamlUserEntity user, Map<String, List<Object>> attributeMap, Auditor auditor) - throws UserUpdateException { - return updateUserFromAttribute(user, attributeMap, false, auditor); - } - public boolean updateUserFromAttribute(SamlUserEntity user, Map<String, List<Object>> attributeMap, boolean withoutUidNumber, Auditor auditor) throws UserUpdateException { @@ -677,33 +408,24 @@ public class SamlUserUpdater extends AbstractUserUpdater<SamlUserEntity> { return true; } - protected void changeUserStatus(UserEntity user, UserStatus toStatus, Auditor auditor) { - UserStatus fromStatus = user.getUserStatus(); - user.setUserStatus(toStatus); - user.setLastStatusChange(new Date()); + @Override + public SamlUserEntity expireUser(SamlUserEntity user) throws UserUpdateException { + // TODO Auto-generated method stub + return null; + } + + @Override + public HomeOrgGroupUpdater<SamlUserEntity> getGroupUpdater() { + return homeOrgGroupUpdater; + } - logger.debug("{}: change user status from {} to {}", user.getEppn(), fromStatus, toStatus); - auditor.logAction(user.getEppn(), "CHANGE STATUS", fromStatus + " -> " + toStatus, - "Change status " + fromStatus + " -> " + toStatus, AuditStatus.SUCCESS); + @Override + public Map<String, String> resolveHomeOrgGenericStore(SamlUserEntity user) { + return user.getIdp().getGenericStore(); } - protected void changeRegistryStatus(RegistryEntity registry, RegistryStatus toStatus, String statusMessage, - Auditor parentAuditor) { - RegistryStatus fromStatus = registry.getRegistryStatus(); - registry.setRegistryStatus(toStatus); - registry.setStatusMessage(statusMessage); - registry.setLastStatusChange(new Date()); - - logger.debug("{} {} {}: change registry status from {} to {}", new Object[] { registry.getUser().getEppn(), - registry.getService().getShortName(), registry.getId(), fromStatus, toStatus }); - RegistryAuditor registryAuditor = new RegistryAuditor(auditDao, auditDetailDao, appConfig); - registryAuditor.setParent(parentAuditor); - registryAuditor.startAuditTrail(parentAuditor.getActualExecutor()); - registryAuditor.setName(getClass().getName() + "-UserUpdate-Registry-Audit"); - registryAuditor.setDetail("Update registry " + registry.getId() + " for user " + registry.getUser().getEppn()); - registryAuditor.setRegistry(registry); - registryAuditor.logAction(registry.getUser().getEppn(), "CHANGE STATUS", "registry-" + registry.getId(), - "Change status " + fromStatus + " -> " + toStatus, AuditStatus.SUCCESS); - registryAuditor.finishAuditTrail(); + @Override + public IncomingAttributesHandler<IncomingSamlAttributeEntity> resolveIncomingAttributeHandler(SamlUserEntity user) { + return incomingAttributeHandler; } } diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/UserUpdater.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/UserUpdater.java index 5a943e3bd0582f74d14d0e108a4efa5290ff492e..858a3e714713e181cfa5b8fc6ee8dd96bcb86db4 100644 --- a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/UserUpdater.java +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/impl/UserUpdater.java @@ -18,4 +18,5 @@ public interface UserUpdater<T extends UserEntity> { public T updateUserFromHomeOrg(T user, ServiceEntity service, String executor, StringBuffer debugLog) throws UserUpdateException; + public T expireUser(T user) throws UserUpdateException; }