From 8842e4ff602c5c7766c509d1c895b8e7e67fb732 Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Thu, 1 Jun 2023 16:36:34 +0200 Subject: fix(proxyservice): use requested SubjectNameIdFormat in eIDAS SAML2 response --- .../protocol/ProxyServiceAuthenticationAction.java | 39 ++++- .../ProxyServiceAuthenticationActionTest.java | 170 +++++++++++++++++++-- 2 files changed, 194 insertions(+), 15 deletions(-) (limited to 'modules/eidas_proxy-sevice/src') diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java index d3c93421..8fc54e39 100644 --- a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java @@ -92,15 +92,17 @@ public class ProxyServiceAuthenticationAction implements IAction { .statusCode(EidasConstants.SUCCESS_URI) .build()); - // TODO: check if we can use transient subjectNameIds - lightRespBuilder.subject(UUID.randomUUID().toString()); - lightRespBuilder.subjectNameIdFormat(NameIDType.TRANSIENT); + // build eIDAS attribute result + ImmutableAttributeMap eidasAttributes = buildAttributesFromAuthData(authData, eidasReq); + + injectSubjectNameId(lightRespBuilder, eidasAttributes, eidasReq); // TODO: lightRespBuilder.issuer(basicConfig.getBasicConfiguration( MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID)); lightRespBuilder.levelOfAssurance(authData.getEidasQaaLevel()); - lightRespBuilder.attributes(buildAttributesFromAuthData(authData, eidasReq)); + + lightRespBuilder.attributes(eidasAttributes); // set SLO response object of EAAF framework final SloInformationImpl sloInformation = new SloInformationImpl(); @@ -126,6 +128,7 @@ public class ProxyServiceAuthenticationAction implements IAction { } } + @Override public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { return true; @@ -422,4 +425,32 @@ public class ProxyServiceAuthenticationAction implements IAction { } } + private void injectSubjectNameId(Builder lightRespBuilder, ImmutableAttributeMap eidasAttributes, + ILightRequest eidasReq) { + if (NameIDType.PERSISTENT.equals(eidasReq.getNameIdFormat())) { + lightRespBuilder.subjectNameIdFormat(NameIDType.PERSISTENT); + final AttributeDefinition attrDefPersonalId = + attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByFriendlyName( + EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition attrDefJurPersonalId = + attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByFriendlyName( + EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first(); + + // set SubjectNameId as same as PersonalIdentifier + String subjectNameId = (String) eidasAttributes.getFirstValue(attrDefPersonalId); + if (subjectNameId != null) { + lightRespBuilder.subject(subjectNameId); + + } else { + lightRespBuilder.subject((String) eidasAttributes.getFirstValue(attrDefJurPersonalId)); + + } + + } else { + lightRespBuilder.subject(UUID.randomUUID().toString()); + lightRespBuilder.subjectNameIdFormat(NameIDType.TRANSIENT); + + } + } + } diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java index 50ce4033..333a823e 100644 --- a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java +++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java @@ -166,6 +166,36 @@ public class ProxyServiceAuthenticationActionTest { } @Test + public void responseWithoutMandatePersistentNameId() throws EaafException, SpecificCommunicationException { + Map attr = new HashMap<>(); + attr.put(PvpAttributeDefinitions.BPK_NAME, RandomStringUtils.randomAlphanumeric(10)); + IAuthData authData = generateDummyAuthData(attr, EaafConstants.EIDAS_LOA_HIGH, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", + false); + + LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); + eidasRequestBuilder.nameIdFormat(NameIDType.PERSISTENT); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + // perform test + SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); + + // validate state + Assert.assertNotNull("Result should be not null", result); + + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData, + (String) attr.get(PvpAttributeDefinitions.BPK_NAME), NameIDType.PERSISTENT); + assertEquals("wrong attr. size", 4, respAttr.size()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER, + (String) attr.get(PvpAttributeDefinitions.BPK_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH, + authData.getDateOfBirth()); + + } + + @Test public void responseWithoutMandateAndOptionalAttributesExist() throws EaafException, SpecificCommunicationException { LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder() @@ -287,6 +317,56 @@ public class ProxyServiceAuthenticationActionTest { } @Test + public void responseWithNatMandatePersistentNameId() throws EaafException, SpecificCommunicationException { + Map attr = new HashMap<>(); + attr.put(PvpAttributeDefinitions.BPK_NAME, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, + "1985-11-15"); + + LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); + eidasRequestBuilder.nameIdFormat(NameIDType.PERSISTENT); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + IAuthData authData = generateDummyAuthData(attr, EaafConstants.EIDAS_LOA_HIGH, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", + true); + + // perform test + SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); + + // validate state + Assert.assertNotNull("Result should be not null", result); + + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME), NameIDType.PERSISTENT); + assertEquals("wrong attr. size", 8, respAttr.size()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER, + (String) attr.get(PvpAttributeDefinitions.BPK_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData + .getFamilyName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData + .getGivenName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getDateOfBirth()); + + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME)); + + } + + @Test public void responseWithNatMandateButJurRequested() throws EaafException, SpecificCommunicationException { Map attr = new HashMap<>(); attr.put(PvpAttributeDefinitions.BPK_NAME, @@ -437,6 +517,63 @@ public class ProxyServiceAuthenticationActionTest { } @Test + public void responseWithJurMandatePersistentNameId() throws EaafException, SpecificCommunicationException { + Map attr = new HashMap<>(); + attr.put(PvpAttributeDefinitions.BPK_NAME, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, + RandomStringUtils.randomAlphabetic(10)); + + IAuthData authData = generateDummyAuthData(attr, EaafConstants.EIDAS_LOA_HIGH, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", + true); + + LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); + eidasRequestBuilder.nameIdFormat(NameIDType.PERSISTENT); + eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALNAME) + .first()) + .build()); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + // perform test + SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); + + // validate state + Assert.assertNotNull("Result should be not null", result); + + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData, + (String) attr.get(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME), NameIDType.PERSISTENT); + assertEquals("wrong attr. size", 6, respAttr.size()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER, + (String) attr.get(PvpAttributeDefinitions.BPK_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData + .getFamilyName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData + .getGivenName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getDateOfBirth()); + + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER, + (String) attr.get(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_LEGALNAME, + (String) attr.get(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME)); + + assertNull("find nat. person subject: personalId", + getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER)); + assertNull("find nat. person subject: familyName", + getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME)); + assertNull("find nat. person subject: givenName", + getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME)); + assertNull("find nat. person subject: dateOfBirth", + getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH)); + + } + + @Test public void borisModeResponseWithJurMandate() throws EaafException, SpecificCommunicationException { Map attr = new HashMap<>(); attr.put(PvpAttributeDefinitions.BPK_NAME, @@ -835,26 +972,37 @@ public class ProxyServiceAuthenticationActionTest { } private ImmutableAttributeMap validateBasicEidasResponse(IAuthData authData) throws SpecificCommunicationException { + return validateBasicEidasResponse(authData, null, NameIDType.TRANSIENT); + + } + + private ImmutableAttributeMap validateBasicEidasResponse(IAuthData authData, String subjectNameId, + String persistent) throws SpecificCommunicationException { assertNotNull("not redirct Header", httpResp.getHeader("Location")); - assertTrue("wrong redirect URL", httpResp.getHeader("Location").startsWith("http://eidas.proxy/endpoint?token=")); + assertTrue("wrong redirect URL", httpResp.getHeader("Location").startsWith( + "http://eidas.proxy/endpoint?token=")); String token = httpResp.getHeader("Location").substring("http://eidas.proxy/endpoint?token=".length()); - - ILightResponse resp = springManagedSpecificConnectorCommunicationService.getAndRemoveResponse(URLDecoder.decode(token), - ImmutableSortedSet.copyOf(attrRegistry.getCoreAttributeRegistry().getAttributes())); - + + ILightResponse resp = springManagedSpecificConnectorCommunicationService.getAndRemoveResponse(URLDecoder + .decode(token), + ImmutableSortedSet.copyOf(attrRegistry.getCoreAttributeRegistry().getAttributes())); + assertNotNull("responseId", resp.getId()); assertEquals("inResponseTo", pendingReq.getEidasRequest().getId(), resp.getInResponseToId()); assertEquals("relayState", pendingReq.getEidasRequest().getRelayState(), resp.getRelayState()); assertEquals("LoA", authData.getEidasQaaLevel(), resp.getLevelOfAssurance()); - + assertNotNull("subjectNameId", resp.getSubject()); - assertEquals("subjectNameIdFormat", NameIDType.TRANSIENT, resp.getSubjectNameIdFormat()); - - assertFalse("not attributes", resp.getAttributes().isEmpty()); + if (subjectNameId != null) { + assertEquals("subjectNameId", subjectNameId, resp.getSubject()); + } + assertEquals("subjectNameIdFormat", persistent, resp.getSubjectNameIdFormat()); + + assertFalse("not attributes", resp.getAttributes().isEmpty()); return resp.getAttributes(); - + } - + private Builder generateBasicLightRequest() { return LightRequest.builder() .id(UUID.randomUUID().toString()) -- cgit v1.2.3