diff --git a/bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/attribute/value/ValueEntity.java b/bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/attribute/value/ValueEntity.java index a37d8e317222cb692d97befe37e881f3599c969b..e976a36d7676cfacf4663e90f01d66b5f0d6dff8 100644 --- a/bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/attribute/value/ValueEntity.java +++ b/bwreg-entities/src/main/java/edu/kit/scc/webreg/entity/attribute/value/ValueEntity.java @@ -1,5 +1,6 @@ package edu.kit.scc.webreg.entity.attribute.value; +import java.util.Date; import java.util.HashSet; import java.util.Set; @@ -44,6 +45,9 @@ public class ValueEntity extends AbstractBaseEntity { @ManyToMany(mappedBy = "nextValues") private Set<ValueEntity> prevValues = new HashSet<>(); + @Column(name = "last_update") + protected Date lastUpdate; + @Transient private Boolean changed; @@ -102,4 +106,12 @@ public class ValueEntity extends AbstractBaseEntity { public void setChanged(Boolean changed) { this.changed = changed; } + + public Date getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(Date lastUpdate) { + this.lastUpdate = lastUpdate; + } } diff --git a/bwreg-webapp/src/main/webapp/user/show-identity.xhtml b/bwreg-webapp/src/main/webapp/user/show-identity.xhtml index a61c979255b9e8690d4e101d03348bd84d6c80d6..1feee5db9ea8c03ab0b0176165962734220fa0e6 100644 --- a/bwreg-webapp/src/main/webapp/user/show-identity.xhtml +++ b/bwreg-webapp/src/main/webapp/user/show-identity.xhtml @@ -49,6 +49,7 @@ <li><h:outputText value="#{prev.id} (#{prev.attributeSet.user.id})" /></li> </ui:repeat> </ul> + <div style="font-size: 0.7rem;"><h:outputText value="#{value.lastUpdate}" /></div> </p:column> </p:dataTable> @@ -73,6 +74,7 @@ <li><h:outputText value="#{item}"/></li> </ui:repeat></ul> </p:outputPanel> + <div style="font-size: 0.7rem;"><h:outputText value="#{value.lastUpdate}" /></div> </p:column> </p:dataTable> </p:panel> diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/IncomingAttributesHandler.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/IncomingAttributesHandler.java index 7652a093055d5b9354b9381d53d0c7b1d8af16a9..35a67b54755a56541baf7c2da6d2579a4ca796e2 100644 --- a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/IncomingAttributesHandler.java +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/IncomingAttributesHandler.java @@ -3,6 +3,7 @@ package edu.kit.scc.webreg.service.attribute; import static edu.kit.scc.webreg.dao.ops.RqlExpressions.equal; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -133,6 +134,7 @@ public abstract class IncomingAttributesHandler<T extends IncomingAttributeEntit } ((StringValueEntity) value).setValueString(attributeValue); + value.setLastUpdate(new Date()); return ((StringValueEntity) value); } @@ -157,6 +159,7 @@ public abstract class IncomingAttributesHandler<T extends IncomingAttributeEntit } ((LongValueEntity) value).setValueLong(attributeValue); + value.setLastUpdate(new Date()); return ((LongValueEntity) value); } @@ -191,6 +194,7 @@ public abstract class IncomingAttributesHandler<T extends IncomingAttributeEntit } } + value.setLastUpdate(new Date()); return listValue; } diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/proc/SingleStringMergeValueProcessor.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/proc/SingleStringMergeValueProcessor.java index 36cb3637944cc58272bb19276030097faafe37b4..b2d0f60657aae3612eaf5eecd125b227d39b019b 100644 --- a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/proc/SingleStringMergeValueProcessor.java +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/proc/SingleStringMergeValueProcessor.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -57,6 +58,7 @@ public class SingleStringMergeValueProcessor extends AbstractListProcessor { if (valueMap.isEmpty()) { NullValueEntity targetValue = (NullValueEntity) getValueUpdater().resolveValue(attribute, attributeSet, NullValueEntity.class); + targetValue.setLastUpdate(new Date()); targetValue.setEndValue(true); } else { @@ -65,6 +67,7 @@ public class SingleStringMergeValueProcessor extends AbstractListProcessor { StringValueEntity targetValue = (StringValueEntity) getValueUpdater().resolveValue(attribute, attributeSet, StringValueEntity.class); targetValue.setValueString(name); valueMap.get(name).stream().forEach(v -> v.getNextValues().add(targetValue)); + targetValue.setLastUpdate(new Date()); targetValue.setEndValue(true); } } diff --git a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/proc/ValueUpdater.java b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/proc/ValueUpdater.java index 402ee5dd5734aca7b20749d4c119304c19a566f8..a2f0977ca03f343336963b843332d8441ed6e77f 100644 --- a/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/proc/ValueUpdater.java +++ b/regapp-idty/src/main/java/edu/kit/scc/webreg/service/attribute/proc/ValueUpdater.java @@ -7,6 +7,7 @@ import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -65,6 +66,7 @@ public class ValueUpdater { targetValue.setValueList(new ArrayList<>()); targetValue.getValueList().clear(); targetValue.getValueList().addAll(values); + targetValue.setLastUpdate(new Date()); targetValue.setEndValue(true); } @@ -119,6 +121,7 @@ public class ValueUpdater { value.getNextValues().add(targetValue); } targetValue.setValueList(new ArrayList<>(values)); + targetValue.setLastUpdate(new Date()); targetValue.setEndValue(true); } @@ -169,7 +172,7 @@ public class ValueUpdater { copyStringListValue((StringListValueEntity) in, (StringListValueEntity) out); else if (in instanceof LongValueEntity) ((LongValueEntity) out).setValueLong(((LongValueEntity) in).getValueLong()); - + out.setLastUpdate(in.getLastUpdate()); } private void copyStringValue(StringValueEntity in, StringValueEntity out) { diff --git a/regapp-saml-idp/src/main/java/edu/kit/scc/webreg/saml/idp/AttributeAuthorityService.java b/regapp-saml-idp/src/main/java/edu/kit/scc/webreg/saml/idp/AttributeAuthorityService.java index 813da7f17120f0dbc4624ab7daea2a4928f19906..82ac68e2b606251428391fec55bc8ff5613de0f6 100644 --- a/regapp-saml-idp/src/main/java/edu/kit/scc/webreg/saml/idp/AttributeAuthorityService.java +++ b/regapp-saml-idp/src/main/java/edu/kit/scc/webreg/saml/idp/AttributeAuthorityService.java @@ -31,12 +31,20 @@ import edu.kit.scc.webreg.dao.SamlSpMetadataDao; import edu.kit.scc.webreg.dao.ScriptDao; import edu.kit.scc.webreg.entity.SamlAAConfigurationEntity; import edu.kit.scc.webreg.entity.SamlSpMetadataEntity; +import edu.kit.scc.webreg.entity.SamlUserEntity; import edu.kit.scc.webreg.entity.ScriptEntity; import edu.kit.scc.webreg.entity.UserEntity; import edu.kit.scc.webreg.entity.attribute.AttributeReleaseEntity; +import edu.kit.scc.webreg.entity.identity.IdentityEntity; +import edu.kit.scc.webreg.entity.oauth.OAuthUserEntity; +import edu.kit.scc.webreg.entity.oidc.OidcUserEntity; +import edu.kit.scc.webreg.exc.UserUpdateException; import edu.kit.scc.webreg.script.ScriptingEnv; import edu.kit.scc.webreg.service.attribute.release.AttributeBuilder; import edu.kit.scc.webreg.service.identity.IdentityAttributeResolver; +import edu.kit.scc.webreg.service.impl.OAuthUserUpdater; +import edu.kit.scc.webreg.service.impl.OidcUserUpdater; +import edu.kit.scc.webreg.service.impl.SamlUserUpdater; import edu.kit.scc.webreg.service.saml.Saml2ResponseValidationService; import edu.kit.scc.webreg.service.saml.SamlHelper; import edu.kit.scc.webreg.service.saml.SsoHelper; @@ -77,6 +85,15 @@ public class AttributeAuthorityService { @Inject private SamlAttributeTranscoder attributeTranscoder; + @Inject + private SamlUserUpdater samlUserUpdater; + + @Inject + private OidcUserUpdater oidcUserUpdater; + + @Inject + private OAuthUserUpdater oauthUserUpdater; + public Envelope processAttributeQuery(SamlAAConfigurationEntity aaConfig, AttributeQuery query) throws SamlAuthenticationException { @@ -133,12 +150,18 @@ public class AttributeAuthorityService { String nameIdValue = query.getSubject().getNameID().getValue(); String nameIdFormat = query.getSubject().getNameID().getFormat(); - UserEntity user = (UserEntity) invocable.invokeFunction("resolveUser", scriptingEnv, nameIdFormat, - nameIdValue, logger, spEntity, aaConfig); - if (user != null) { + final UserEntity user = resolveUser(invocable, nameIdFormat, nameIdValue, spEntity, aaConfig); + final IdentityEntity identity = resolveIdentity(user, invocable, nameIdFormat, nameIdValue, spEntity, + aaConfig); + if (identity != null) { + + // only update all user objects when configured, because this can take some time + if (spEntity.getGenericStore().containsKey("update_identity") + && spEntity.getGenericStore().get("update_identity").equalsIgnoreCase("true")) + identity.getUsers().stream().forEach(u -> updateUser(u)); AttributeReleaseEntity attributeRelease = attributeBuilder.requestAttributeRelease(spEntity, - user.getIdentity()); + identity); script = scriptDao.findByName(resolveAttributeScript); if (script == null) @@ -210,26 +233,44 @@ public class AttributeAuthorityService { return envelope; } - private AttributeStatement buildAttributeStatement(UserEntity user) { - AttributeStatement attributeStatement = samlHelper.create(AttributeStatement.class, - AttributeStatement.DEFAULT_ELEMENT_NAME); - attributeStatement.getAttributes().add(buildAttribute("urn:oid:1.3.6.1.4.1.5923.1.1.1.6", - "eduPersonPrincipalName", Attribute.URI_REFERENCE, user.getEppn())); - return attributeStatement; - } + private IdentityEntity resolveIdentity(UserEntity user, Invocable invocable, String nameIdFormat, + String nameIdValue, SamlSpMetadataEntity spEntity, SamlAAConfigurationEntity aaConfig) + throws ScriptException { + if (user != null) { + return user.getIdentity(); + } + + try { + return (IdentityEntity) invocable.invokeFunction("resolveIdentity", scriptingEnv, nameIdFormat, nameIdValue, + logger, spEntity, aaConfig); + } catch (NoSuchMethodException e) { + // Ignore exception. Better would be a check for method existance + return null; + } - private Attribute buildAttribute(String name, String friendlyName, String nameFormat, String... values) { - Attribute attribute = samlHelper.create(Attribute.class, Attribute.DEFAULT_ELEMENT_NAME); - attribute.setName(name); - attribute.setFriendlyName(friendlyName); - attribute.setNameFormat(nameFormat); + } - for (String value : values) { - XSString xsany = samlHelper.create(XSString.class, XSString.TYPE_NAME, AttributeValue.DEFAULT_ELEMENT_NAME); - xsany.setValue(value); - attribute.getAttributeValues().add(xsany); + private UserEntity resolveUser(Invocable invocable, String nameIdFormat, String nameIdValue, + SamlSpMetadataEntity spEntity, SamlAAConfigurationEntity aaConfig) throws ScriptException { + try { + return (UserEntity) invocable.invokeFunction("resolveUser", scriptingEnv, nameIdFormat, nameIdValue, logger, + spEntity, aaConfig); + } catch (NoSuchMethodException e) { + // Ignore exception. Better would be a check for method existance + return null; } - return attribute; + } + + private void updateUser(UserEntity user) { + try { + if (user instanceof SamlUserEntity) + samlUserUpdater.updateUserFromHomeOrg((SamlUserEntity) user, null, "attribue-query", null); + else if (user instanceof OidcUserEntity) + oidcUserUpdater.updateUserFromHomeOrg((OidcUserEntity) user, null, "attribue-query", null); + else if (user instanceof OAuthUserEntity) + oauthUserUpdater.updateUserFromHomeOrg((OAuthUserEntity) user, null, "attribue-query", null); + } catch (UserUpdateException e) { + } } } diff --git a/regapp-saml-idp/src/main/java/edu/kit/scc/webreg/saml/idp/SamlAttributeTranscoder.java b/regapp-saml-idp/src/main/java/edu/kit/scc/webreg/saml/idp/SamlAttributeTranscoder.java index 5a0267b7abc2d3817c1dc91afa0ef43bea56f4c5..8f3f254abb4b3823ae815c357cb33bffb8c86cdd 100644 --- a/regapp-saml-idp/src/main/java/edu/kit/scc/webreg/saml/idp/SamlAttributeTranscoder.java +++ b/regapp-saml-idp/src/main/java/edu/kit/scc/webreg/saml/idp/SamlAttributeTranscoder.java @@ -43,10 +43,16 @@ public class SamlAttributeTranscoder { new SingleStringValueTranscoder(samlHelper, "urn:oid:2.5.4.4", "sn", Attribute.BASIC)); transcoderMap.put("given_name", new SingleStringValueTranscoder(samlHelper, "urn:oid:2.5.4.42", "givenName", Attribute.BASIC)); + transcoderMap.put("email", + new SingleStringValueTranscoder(samlHelper, "urn:oid:0.9.2342.19200300.100.1.3", "email", Attribute.BASIC)); transcoderMap.put("eduperson_principal_name", new SingleStringValueTranscoder(samlHelper, "urn:oid:1.3.6.1.4.1.5923.1.1.1.6", "eduPersonPrincipalName", Attribute.URI_REFERENCE)); transcoderMap.put("eduperson_entitlement", new SingleStringValueTranscoder(samlHelper, "urn:oid:1.3.6.1.4.1.5923.1.1.1.7", "eduPersonEntitlement", Attribute.BASIC)); + transcoderMap.put("eduperson_assurance", new SingleStringValueTranscoder(samlHelper, + "urn:oid:1.3.6.1.4.1.5923.1.1.1.11", "edupersonAssurance", Attribute.BASIC)); + transcoderMap.put("voperson_external_affiliation", new SingleStringValueTranscoder(samlHelper, + "urn:oid:1.3.6.1.4.1.25178.4.1.11", "voPersonExternalAffiliation", Attribute.BASIC)); } public Assertion convertAttributes(AttributeReleaseEntity attributeRelease, SamlAAConfigurationEntity aaConfig,