diff options
17 files changed, 1160 insertions, 103 deletions
diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/builder/AuthenticationDataBuilder.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/builder/AuthenticationDataBuilder.java index 2e70893b..629d015e 100644 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/builder/AuthenticationDataBuilder.java +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/builder/AuthenticationDataBuilder.java @@ -24,19 +24,31 @@ package at.asitplus.eidas.specific.connector.builder; import java.util.Date; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import org.springframework.stereotype.Service; +import com.google.common.collect.Streams; + import at.asitplus.eidas.specific.connector.MsEidasNodeConstants; +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; +import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions.EidIdentityStatusLevelValues; import at.gv.egiz.eaaf.core.api.idp.IAuthData; import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; import at.gv.egiz.eaaf.core.api.idp.auth.data.IAuthProcessDataContainer; +import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; import at.gv.egiz.eaaf.core.exceptions.EaafBuilderException; import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.impl.builder.BpkBuilder; import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.data.Triple; import at.gv.egiz.eaaf.core.impl.idp.AuthenticationData; import at.gv.egiz.eaaf.core.impl.idp.EidAuthenticationData; import at.gv.egiz.eaaf.core.impl.idp.auth.builder.AbstractAuthenticationDataBuilder; @@ -46,55 +58,59 @@ import lombok.extern.slf4j.Slf4j; @Service("AuthenticationDataBuilder") @Slf4j public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder { - + + private static final String ERROR_B11 = "builder.11"; + @Override - protected IAuthData buildDeprecatedAuthData(IRequest pendingReq) throws EaafException { + protected IAuthData buildDeprecatedAuthData(IRequest pendingReq) throws EaafException { final EidAuthProcessDataWrapper authProcessData = - pendingReq.getSessionData(EidAuthProcessDataWrapper.class); - EidAuthenticationData authData = new EidAuthenticationData(); - - //set basis infos + pendingReq.getSessionData(EidAuthProcessDataWrapper.class); + final EidAuthenticationData authData = new EidAuthenticationData(); + + // set basis infos super.generateDeprecatedBasicAuthData(authData, pendingReq, authProcessData); - + // set specific informations authData.setSsoSessionValidTo( new Date(new Date().getTime() + MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60 * 1000)); - - authData.setEidStatus(authProcessData.isTestIdentity() - ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY); - + + authData.setEidStatus(authProcessData.isTestIdentity() + ? EidIdentityStatusLevelValues.TESTIDENTITY + : EidIdentityStatusLevelValues.IDENTITY); + return authData; } @Override - protected void buildServiceSpecificAuthenticationData(IAuthData authData, IRequest pendingReq) + protected void buildServiceSpecificAuthenticationData(IAuthData authData, IRequest pendingReq) throws EaafException { if (authData instanceof EidAuthenticationData) { - ((EidAuthenticationData)authData).setGenericData( - ExtendedPvpAttributeDefinitions.EID_PII_TRANSACTION_ID_NAME, + ((EidAuthenticationData) authData).setGenericData( + ExtendedPvpAttributeDefinitions.EID_PII_TRANSACTION_ID_NAME, pendingReq.getUniquePiiTransactionIdentifier()); log.trace("Inject piiTransactionId: {} into AuthData", pendingReq.getUniquePiiTransactionIdentifier()); - + // set specific informations - ((EidAuthenticationData)authData).setSsoSessionValidTo( + ((EidAuthenticationData) authData).setSsoSessionValidTo( new Date(new Date().getTime() + MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60 * 1000)); - //set E-ID status-level + // set E-ID status-level final EidAuthProcessDataWrapper authProcessData = - pendingReq.getSessionData(EidAuthProcessDataWrapper.class); - ((EidAuthenticationData)authData).setEidStatus(authProcessData.isTestIdentity() - ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY); - - - - + pendingReq.getSessionData(EidAuthProcessDataWrapper.class); + ((EidAuthenticationData) authData).setEidStatus(authProcessData.isTestIdentity() + ? EidIdentityStatusLevelValues.TESTIDENTITY + : EidIdentityStatusLevelValues.IDENTITY); + + // handle mandate informations + buildMandateInformation((EidAuthenticationData) authData, pendingReq, authProcessData); + } else { - throw new RuntimeException("Can not inject PiiTransactionId because AuthData is of unknown type: " + throw new RuntimeException("Can not inject PiiTransactionId because AuthData is of unknown type: " + authData.getClass().getName()); - + } - + } @Override @@ -123,4 +139,116 @@ public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder } + private void buildMandateInformation(EidAuthenticationData authData, IRequest pendingReq, + EidAuthProcessDataWrapper authProcessData) throws EaafAuthenticationException, EaafBuilderException, + EaafStorageException { + authData.setUseMandate(authProcessData.isMandateUsed()); + if (authProcessData.isMandateUsed()) { + log.debug("Build mandate-releated authentication data ... "); + if (authProcessData.isForeigner()) { + buildMandateInformationForEidasIncoming(); + + } else { + buildMandateInformationForEidasOutgoing(authData, pendingReq, authProcessData); + + } + + // inject mandate information into authdata + final Set<String> mandateAttributes = Streams.concat( + IdAustriaAuthConstants.DEFAULT_REQUIRED_MANDATE_NAT_PVP_ATTRIBUTES.stream(), + IdAustriaAuthConstants.DEFAULT_REQUIRED_MANDATE_JUR_PVP_ATTRIBUTES.stream()) + .map(el -> el.getFirst()) + .collect(Collectors.toSet()); + + authProcessData.getGenericSessionDataStream() + .filter(el -> mandateAttributes.contains(el.getKey())) + .forEach(el -> { + try { + authData.setGenericData(el.getKey(), el.getValue()); + + } catch (final EaafStorageException e) { + log.error("Can not store attribute: {} into session.", el.getKey(), e); + throw new RuntimeException(e); + + } + }); + } + } + + private void buildMandateInformationForEidasIncoming() { + log.debug("Find eIDAS incoming process. Generated mandate-information for ID-Austria system ... "); + + // TODO: implement IDA specific processing of foreign mandate + + } + + private void buildMandateInformationForEidasOutgoing(EidAuthenticationData authData, IRequest pendingReq, + EidAuthProcessDataWrapper authProcessData) throws EaafAuthenticationException, EaafBuilderException, + EaafStorageException { + log.debug("Find eIDAS outgoing process. Generated mandate-information for other country ... "); + if (authProcessData.getGenericDataFromSession( + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME) != null) { + final Optional<Triple<String, String, Boolean>> missingAttribute = + IdAustriaAuthConstants.DEFAULT_REQUIRED_MANDATE_NAT_PVP_ATTRIBUTES.stream() + .filter(el -> authProcessData.getGenericDataFromSession(el.getFirst()) == null) + .findFirst(); + if (missingAttribute.isPresent()) { + log.error("ID-Austria response contains not all attributes for nat. person mandator. Missing: {}", + missingAttribute.get().getFirst()); + throw new EaafAuthenticationException(ERROR_B11, new Object[] { "Nat. person mandate" }); + + } else { + log.trace("Find nat. person mandate. Mandate can be used as it is "); + authData.setGenericData(MsProxyServiceConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, + extractBpkFromResponse(authProcessData.getGenericDataFromSession( + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, String.class))); + + } + + } else { + final Optional<Triple<String, String, Boolean>> missingAttribute = + IdAustriaAuthConstants.DEFAULT_REQUIRED_MANDATE_JUR_PVP_ATTRIBUTES.stream() + .filter(el -> authProcessData.getGenericDataFromSession(el.getFirst()) == null) + .findFirst(); + if (missingAttribute.isPresent()) { + log.error("ID-Austria response contains not all attributes for legal. person mandator. Missing: {}", + missingAttribute.get().getFirst()); + throw new EaafAuthenticationException(ERROR_B11, new Object[] { "Legal. person mandate" }); + + } else { + log.trace( + "Find jur. person mandate. Generate eIDAS identifier from legal-person sourcePin and type ... "); + final String sourcePin = authProcessData.getGenericDataFromSession( + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, String.class); + final String sourcePinType = authProcessData.getGenericDataFromSession( + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, String.class); + + // TODO: check if we should to this in such a way! + final Pair<String, String> leagalPersonIdentifier = + BpkBuilder.generateAreaSpecificPersonIdentifier( + sourcePinType + sourcePin, + sourcePinType, + pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()); + + log.debug("Use legal-person eIDAS identifer: {} from baseId: {} and baseIdType: {}", + leagalPersonIdentifier.getFirst(), sourcePin, sourcePinType); + authData.setGenericData(MsProxyServiceConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, + leagalPersonIdentifier.getFirst()); + + } + } + } + + private String extractBpkFromResponse(String pvpBpkAttrValue) { + final String[] split = pvpBpkAttrValue.split(":", 2); + if (split.length == 2) { + return split[1]; + + } else { + log.warn("PVP bPK attribute: {} has wrong format. Use it as it is.", pvpBpkAttrValue); + return pvpBpkAttrValue; + + } + } + } diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthenticationDataBuilderTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthenticationDataBuilderTest.java index 552c448e..277138ef 100644 --- a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthenticationDataBuilderTest.java +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/utils/AuthenticationDataBuilderTest.java @@ -1,6 +1,10 @@ package at.asitplus.eidas.specific.connector.test.utils; import static at.asitplus.eidas.specific.connector.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.security.PublicKey; @@ -176,9 +180,169 @@ public class AuthenticationDataBuilderTest { Assert.assertEquals("testIdentity flag", isTestIdentity ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY, - ((EidAuthenticationData)authData).getEidStatus()); + ((EidAuthenticationData)authData).getEidStatus()); + assertFalse("mandate flag", ((EidAuthenticationData)authData).isUseMandate()); + + } + + @Test + public void eidasProxyModeWithJurMandate() throws EaafAuthenticationException, EaafStorageException { + // initialize state + injectRepresentativeInfosIntoSession(); + + String commonMandate = RandomStringUtils.randomAlphabetic(10); + + // set constant country-code and sourcePin to check hashed eIDAS identifier + String sourcePinMandate = "asfdsadfsadfsafsdafsadfasr"; + spConfig.put("target", EaafConstants.URN_PREFIX_EIDAS + "AT+EE"); + + // set nat. person mandate information + pendingReq.getSessionData(AuthProcessDataWrapper.class).setUseMandates(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, commonMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, sourcePinMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, + EaafConstants.URN_PREFIX_BASEID + "+XFN"); + + // execute test + IAuthData authData = authenticationDataBuilder.buildAuthenticationData(pendingReq); + + + // validate state + Assert.assertNotNull("AuthData null", authData); + assertTrue("mandate flag", ((EidAuthenticationData)authData).isUseMandate()); + + //check mandate informations + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, commonMandate); + checkGenericAttribute(authData, MsProxyServiceConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, + "AT/EE/oaAGaV/zIHSf6rcB0TIOqjWPoOU="); + + } + + @Test + public void eidasProxyModeWithJurMandateMissingAttribute() throws EaafAuthenticationException, EaafStorageException { + // initialize state + injectRepresentativeInfosIntoSession(); + + // set constant country-code and sourcePin to check hashed eIDAS identifier + String sourcePinMandate = "asfdsadfsadfsafsdafsadfasr"; + spConfig.put("target", EaafConstants.URN_PREFIX_EIDAS + "AT+EE"); + + // set nat. person mandate information + pendingReq.getSessionData(AuthProcessDataWrapper.class).setUseMandates(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, sourcePinMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, + EaafConstants.URN_PREFIX_BASEID + "+XFN"); + + // execute test + // execute test + EaafAuthenticationException error = assertThrows(EaafAuthenticationException.class, + () -> authenticationDataBuilder.buildAuthenticationData(pendingReq)); + Assert.assertEquals("wrong errorId", "builder.11", error.getErrorId()); + + } + + @Test + public void eidasProxyModeWithNatMandate() throws EaafAuthenticationException, EaafStorageException { + // initialize state + injectRepresentativeInfosIntoSession(); + + String givenNameMandate = RandomStringUtils.randomAlphabetic(10); + String familyNameMandate = RandomStringUtils.randomAlphabetic(10); + String dateOfBirthMandate = "1957-09-15"; + String bpkMandate = RandomStringUtils.randomAlphanumeric(10); + + // set nat. person mandate information + pendingReq.getSessionData(AuthProcessDataWrapper.class).setUseMandates(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, givenNameMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, familyNameMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, dateOfBirthMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, "AT+XX:" + bpkMandate); + + // execute test + IAuthData authData = authenticationDataBuilder.buildAuthenticationData(pendingReq); + + + // validate state + Assert.assertNotNull("AuthData null", authData); + assertTrue("mandate flag", ((EidAuthenticationData)authData).isUseMandate()); + + //check mandate informations + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, givenNameMandate); + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, familyNameMandate); + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, "1957-09-15"); + checkGenericAttribute(authData, MsProxyServiceConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, bpkMandate); + + } + + @Test + public void eidasProxyModeWithNatMandateWrongBpkFormat() throws EaafAuthenticationException, EaafStorageException { + // initialize state + injectRepresentativeInfosIntoSession(); + + String givenNameMandate = RandomStringUtils.randomAlphabetic(10); + String familyNameMandate = RandomStringUtils.randomAlphabetic(10); + String dateOfBirthMandate = "1957-09-15"; + String bpkMandate = RandomStringUtils.randomAlphanumeric(10); + + // set nat. person mandate information + pendingReq.getSessionData(AuthProcessDataWrapper.class).setUseMandates(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, givenNameMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, familyNameMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, dateOfBirthMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, bpkMandate); + + // execute test + IAuthData authData = authenticationDataBuilder.buildAuthenticationData(pendingReq); + + + // validate state + Assert.assertNotNull("AuthData null", authData); + assertTrue("mandate flag", ((EidAuthenticationData)authData).isUseMandate()); + //check mandate informations + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, givenNameMandate); + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, familyNameMandate); + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, "1957-09-15"); + checkGenericAttribute(authData, MsProxyServiceConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, bpkMandate); + + } + + @Test + public void eidasProxyModeWithNatMandateMissingAttribute() throws EaafAuthenticationException, EaafStorageException { + // initialize state + injectRepresentativeInfosIntoSession(); + + String familyNameMandate = RandomStringUtils.randomAlphabetic(10); + String dateOfBirthMandate = "1957-09-15"; + String bpkMandate = RandomStringUtils.randomAlphanumeric(10); + + // set nat. person mandate information + pendingReq.getSessionData(AuthProcessDataWrapper.class).setUseMandates(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, familyNameMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, dateOfBirthMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, bpkMandate); + // execute test + EaafAuthenticationException error = assertThrows(EaafAuthenticationException.class, + () -> authenticationDataBuilder.buildAuthenticationData(pendingReq)); + Assert.assertEquals("wrong errorId", "builder.11", error.getErrorId()); + } @Test @@ -203,7 +367,7 @@ public class AuthenticationDataBuilderTest { Assert.assertEquals("testIdentity flag", isTestIdentity ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY, ((EidAuthenticationData)authData).getEidStatus()); - + String authBlock = authData.getGenericData(Constants.SZR_AUTHBLOCK, String.class); String eidasBind = authData.getGenericData(Constants.EIDAS_BIND, String.class); @@ -276,6 +440,44 @@ public class AuthenticationDataBuilderTest { } + private void injectRepresentativeInfosIntoSession() throws EaafStorageException { + boolean isTestIdentity = RandomUtils.nextBoolean(); + pendingReq.getSessionData(EidAuthProcessDataWrapper.class).setTestIdentity(isTestIdentity); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setEidProcess(true); + + String givenName = RandomStringUtils.randomAlphabetic(10); + String familyName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = "1956-12-08"; + String bpk = RandomStringUtils.randomAlphanumeric(10); + String cc = pendingReq.getSessionData(AuthProcessDataWrapper.class) + .getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class); + String spC = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + spConfig.put("target", EaafConstants.URN_PREFIX_EIDAS + cc + "+" + spC); + + pendingReq.getSessionData(AuthProcessDataWrapper.class).setEidProcess(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setForeigner(false); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.GIVEN_NAME_NAME, givenName); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, familyName); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.BIRTHDATE_NAME, dateOfBirth); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, bpk); + + //set LoA level attribute instead of explicit session-data + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, + pendingReq.getSessionData(AuthProcessDataWrapper.class).getQaaLevel()); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setQaaLevel(null); + + } + + private void checkGenericAttribute(IAuthData authData, String attrName, String expected) { + assertEquals("Wrong: " + attrName, expected, authData.getGenericData(attrName, String.class)); + + } + private IIdentityLink buildDummyIdl() { return new IIdentityLink() { diff --git a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/config/ServiceProviderConfiguration.java b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/config/ServiceProviderConfiguration.java index 362d0244..0f72203b 100644 --- a/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/config/ServiceProviderConfiguration.java +++ b/connector_lib/src/main/java/at/asitplus/eidas/specific/connector/config/ServiceProviderConfiguration.java @@ -37,6 +37,8 @@ import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.impl.idp.conf.SpConfigurationImpl; +import lombok.Getter; +import lombok.Setter; public class ServiceProviderConfiguration extends SpConfigurationImpl { private static final long serialVersionUID = 1L; @@ -46,6 +48,10 @@ public class ServiceProviderConfiguration extends SpConfigurationImpl { private String bpkTargetIdentifier; private String loaMachtingMode = EaafConstants.EIDAS_LOA_MATCHING_MINIMUM; + @Setter + @Getter + private List<String> mandateProfiles; + public ServiceProviderConfiguration(Map<String, String> spConfig, IConfiguration authConfig) { super(spConfig, authConfig); diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java index e2200ed1..f0d57229 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java @@ -156,6 +156,12 @@ public class Constants { public static final String eIDAS_ATTR_LEGALPERSONIDENTIFIER = "LegalPersonIdentifier"; public static final String eIDAS_ATTR_LEGALNAME = "LegalName"; + public static final String eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER = "RepresentativePersonIdentifier"; + public static final String eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH = "RepresentativeDateOfBirth"; + public static final String eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME = "RepresentativeFirstName"; + public static final String eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME = "RepresentativeFamilyName"; + + public static final String eIDAS_REQ_PARAM_SECTOR_PUBLIC = "public"; public static final String eIDAS_REQ_PARAM_SECTOR_PRIVATE = "private"; diff --git a/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthConstants.java b/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthConstants.java index 18eaee4b..982bfb4f 100644 --- a/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthConstants.java +++ b/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthConstants.java @@ -3,6 +3,8 @@ package at.asitplus.eidas.specific.modules.auth.idaustria; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; import at.gv.egiz.eaaf.core.impl.data.Triple; @@ -69,6 +71,36 @@ public class IdAustriaAuthConstants { public static final String CONFIG_PROPS_REQUIRED_PVP_ATTRIBUTES_LIST = CONFIG_PROPS_PREFIX + "required.additional.attributes"; + public static final List<Triple<String, String, Boolean>> DEFAULT_REQUIRED_MANDATE_NAT_PVP_ATTRIBUTES = + Collections.unmodifiableList(new ArrayList<Triple<String, String, Boolean>>() { + private static final long serialVersionUID = 1L; + { + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_FRIENDLY_NAME, false)); + + } + }); + + public static final List<Triple<String, String, Boolean>> DEFAULT_REQUIRED_MANDATE_JUR_PVP_ATTRIBUTES = + Collections.unmodifiableList(new ArrayList<Triple<String, String, Boolean>>() { + private static final long serialVersionUID = 1L; + { + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, + PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_FRIENDLY_NAME, false)); + + } + }); + public static final List<Triple<String, String, Boolean>> DEFAULT_REQUIRED_PVP_ATTRIBUTES = Collections.unmodifiableList(new ArrayList<Triple<String, String, Boolean>>() { private static final long serialVersionUID = 1L; @@ -93,19 +125,21 @@ public class IdAustriaAuthConstants { add(Triple.newInstance(PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_FRIENDLY_NAME, false)); + // mandate attributes + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_TYPE_NAME, + PvpAttributeDefinitions.MANDATE_TYPE_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_TYPE_OID_NAME, + PvpAttributeDefinitions.MANDATE_TYPE_OID_FRIENDLY_NAME, false)); + addAll(DEFAULT_REQUIRED_MANDATE_JUR_PVP_ATTRIBUTES); + addAll(DEFAULT_REQUIRED_MANDATE_NAT_PVP_ATTRIBUTES); + } }); - public static final List<String> DEFAULT_REQUIRED_PVP_ATTRIBUTE_NAMES = - Collections.unmodifiableList(new ArrayList<String>() { - private static final long serialVersionUID = 1L; - { - for (final Triple<String, String, Boolean> el : DEFAULT_REQUIRED_PVP_ATTRIBUTES) { - if (el.getThird()) { - add(el.getFirst()); - - } - } - } - }); + public static final Set<String> DEFAULT_REQUIRED_PVP_ATTRIBUTE_NAMES = + DEFAULT_REQUIRED_PVP_ATTRIBUTES.stream() + .filter(el -> el.getThird()) + .map(el -> el.getFirst()) + .collect(Collectors.toSet()); + } diff --git a/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/ReceiveFromIdAustriaSystemTask.java b/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/ReceiveFromIdAustriaSystemTask.java index 5dc04800..2141fee8 100644 --- a/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/ReceiveFromIdAustriaSystemTask.java +++ b/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/ReceiveFromIdAustriaSystemTask.java @@ -1,7 +1,6 @@ package at.asitplus.eidas.specific.modules.auth.idaustria.tasks; import java.io.IOException; -import java.util.List; import java.util.Set; import javax.naming.ConfigurationException; @@ -211,7 +210,7 @@ public class ReceiveFromIdAustriaSystemTask extends AbstractAuthServletTask { private void getAuthDataFromInterfederation(AssertionAttributeExtractor extractor) throws EaafBuilderException, ConfigurationException { - final List<String> requiredEidasNodeAttributes = + final Set<String> requiredEidasNodeAttributes = IdAustriaAuthConstants.DEFAULT_REQUIRED_PVP_ATTRIBUTE_NAMES; try { // check if all attributes are include @@ -238,7 +237,7 @@ public class ReceiveFromIdAustriaSystemTask extends AbstractAuthServletTask { extractor.getSingleAttributeValue(attrName)); } - + // set foreigner flag session.setForeigner(false); @@ -248,7 +247,9 @@ public class ReceiveFromIdAustriaSystemTask extends AbstractAuthServletTask { // set IssuerInstant from Assertion session.setIssueInstant(extractor.getAssertionIssuingDate()); - // TODO: add mandates if SEMPER are integrated + // set mandate flag + session.setUseMandates(checkIfMandateInformationIsAvailable(extractor)); + } catch (final EaafException | IOException e) { throw new EaafBuilderException(ERROR_PVP_06, null, e.getMessage(), e); @@ -256,6 +257,20 @@ public class ReceiveFromIdAustriaSystemTask extends AbstractAuthServletTask { } } + + /** + * Check if mandate information is available. + * + * @param extractor Assertion from ID Austria system. + * @return <code>true</code> if mandate was used, otherwise <code>false</code> + */ + private boolean checkIfMandateInformationIsAvailable(AssertionAttributeExtractor extractor) { + boolean isMandateIncluded = extractor.containsAttribute(PvpAttributeDefinitions.MANDATE_TYPE_NAME); + log.debug("Response from ID-Austria system contains mandate information. Switch to mandate-mode ... "); + return isMandateIncluded; + + } + private void validateResponseAttributes(AssertionAttributeExtractor extractor) throws EaafAuthenticationException { final String bpkTarget = extractor.getSingleAttributeValue( @@ -295,14 +310,14 @@ public class ReceiveFromIdAustriaSystemTask extends AbstractAuthServletTask { log.trace("Find bPK attribute. Extract eIDAS identifier ... "); session.setGenericDataToSession(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, extractBpkFromResponse(attrValue)); - - } else { + + } else { session.setGenericDataToSession(attrName, attrValue); } } - + private String extractBpkFromResponse(String pvpBpkAttrValue) { final String[] split = pvpBpkAttrValue.split(":", 2); if (split.length == 2) { diff --git a/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java b/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java index fc46ac8b..8151b429 100644 --- a/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java +++ b/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java @@ -14,6 +14,7 @@ import org.opensaml.saml.saml2.core.Attribute; import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.springframework.beans.factory.annotation.Autowired; +import at.asitplus.eidas.specific.connector.config.ServiceProviderConfiguration; import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; import at.asitplus.eidas.specific.modules.auth.idaustria.config.IdAustriaAuthRequestBuilderConfiguration; import at.asitplus.eidas.specific.modules.auth.idaustria.utils.IdAustriaAuthCredentialProvider; @@ -147,63 +148,52 @@ public class RequestIdAustriaSystemTask extends AbstractAuthServletTask { final List<EaafRequestedAttribute> attributs = new ArrayList<>(); //build attribute that contains the unique identifier of the eIDAS-Connector - final Attribute attrEidasConnectorId = PvpAttributeBuilder.buildEmptyAttribute( - ExtendedPvpAttributeDefinitions.EIDAS_CONNECTOR_UNIQUEID_NAME); - final EaafRequestedAttribute attrEidasConnectorIdReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( - attrEidasConnectorId, - true, + injectAttribute(attributs, ExtendedPvpAttributeDefinitions.EIDAS_CONNECTOR_UNIQUEID_NAME, pendingReq.getServiceProviderConfiguration().getUniqueIdentifier()); - attributs.add(attrEidasConnectorIdReqAttr); - - + // build EID sector for identification attribute - final Attribute attr = PvpAttributeBuilder.buildEmptyAttribute( - PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME); - final EaafRequestedAttribute bpkTargetReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( - attr, - true, + injectAttribute(attributs, PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME, pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()); - attributs.add(bpkTargetReqAttr); - // set requested LoA as attribute - final Attribute loaAttr = PvpAttributeBuilder.buildEmptyAttribute( - PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME); - final EaafRequestedAttribute loaReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( - loaAttr, - true, + injectAttribute(attributs, PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, selectHighestLoa(pendingReq.getServiceProviderConfiguration().getRequiredLoA())); - attributs.add(loaReqAttr); - - + //set ProviderName if available String providerName = ((ProxyServicePendingRequest)pendingReq).getEidasRequest().getProviderName(); if (StringUtils.isNotEmpty(providerName)) { - final Attribute providerNameAttr = PvpAttributeBuilder.buildEmptyAttribute( - ExtendedPvpAttributeDefinitions.SP_FRIENDLYNAME_NAME); - final EaafRequestedAttribute providerNameReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( - providerNameAttr, - true, - providerName); - attributs.add(providerNameReqAttr); + injectAttribute(attributs, ExtendedPvpAttributeDefinitions.SP_FRIENDLYNAME_NAME, providerName); } - - + //set ProviderName if available String requesterId = ((ProxyServicePendingRequest)pendingReq).getEidasRequest().getRequesterId(); if (StringUtils.isNotEmpty(requesterId)) { - final Attribute requesterIdAttr = PvpAttributeBuilder.buildEmptyAttribute( - ExtendedPvpAttributeDefinitions.SP_UNIQUEID_NAME); - final EaafRequestedAttribute requesterIdReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( - requesterIdAttr, - true, - requesterId); - attributs.add(requesterIdReqAttr); + injectAttribute(attributs, ExtendedPvpAttributeDefinitions.SP_UNIQUEID_NAME, requesterId); } + //set mandate profiles + List<String> mandateProfiles = + pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).getMandateProfiles(); + if (mandateProfiles != null && !mandateProfiles.isEmpty()) { + log.debug("Set mandate-profiles attribute into ID-Austria request"); + injectAttribute(attributs, ExtendedPvpAttributeDefinitions.SP_USED_MANDATE_PROFILES_NAME, + StringUtils.join(mandateProfiles, ",")); + + } + return attributs; } + private void injectAttribute(List<EaafRequestedAttribute> attributs, String attributeName, String attributeValue) { + final Attribute requesterIdAttr = PvpAttributeBuilder.buildEmptyAttribute(attributeName); + final EaafRequestedAttribute requesterIdReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( + requesterIdAttr, + true, + attributeValue); + attributs.add(requesterIdReqAttr); + + } + } diff --git a/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthMetadataControllerFirstTest.java b/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthMetadataControllerFirstTest.java index ef0c4da0..d2a2556b 100644 --- a/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthMetadataControllerFirstTest.java +++ b/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthMetadataControllerFirstTest.java @@ -94,7 +94,7 @@ public class IdAustriaAuthMetadataControllerFirstTest { controller.getSpMetadata(httpReq, httpResp); //check result - validateResponse(7); + validateResponse(16); } @@ -117,7 +117,7 @@ public class IdAustriaAuthMetadataControllerFirstTest { controller.getSpMetadata(httpReq, httpResp); //check result - validateResponse(8); + validateResponse(17); } diff --git a/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/ReceiveAuthnResponseTaskTest.java b/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/ReceiveAuthnResponseTaskTest.java index a0446ad9..b3a5130f 100644 --- a/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/ReceiveAuthnResponseTaskTest.java +++ b/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/ReceiveAuthnResponseTaskTest.java @@ -1,6 +1,9 @@ package at.asitplus.eidas.specific.modules.auth.idaustria.test.task; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.Arrays; @@ -536,6 +539,8 @@ public class ReceiveAuthnResponseTaskTest { Assert.assertNotNull("pendingReq not stored", storedReq); final AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); Assert.assertFalse("foreigner flag", session.isForeigner()); + assertTrue("eidProcess flag", session.isEidProcess()); + assertFalse("useMandate flag", session.isMandateUsed()); checkAttributeInSession(session,PvpAttributeDefinitions.GIVEN_NAME_NAME, "Max"); checkAttributeInSession(session,PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Mustermann"); @@ -662,6 +667,103 @@ public class ReceiveAuthnResponseTaskTest { } + @Test + public void httpPostValidSignedAssertionEidValidWithJurMandate() throws IOException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException, TaskExecutionException, EaafException { + + oaParam.setBpkTargetIdentifier(EaafConstants.URN_PREFIX_EIDAS + "AT+XX"); + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_with_EID_with_mandate_jur.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + // perform task + task.execute(pendingReq, executionContext); + + // validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + final AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertFalse("foreigner flag", session.isForeigner()); + assertTrue("eidProcess flag", session.isEidProcess()); + assertTrue("useMandate flag", session.isMandateUsed()); + + checkAttributeInSession(session, PvpAttributeDefinitions.GIVEN_NAME_NAME, "Max"); + checkAttributeInSession(session, PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Mustermann"); + checkAttributeInSession(session, PvpAttributeDefinitions.BIRTHDATE_NAME, "1940-01-01"); + checkAttributeInSession(session, PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, "http://eidas.europa.eu/LoA/high"); + checkAttributeInSession(session, PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, "AT"); + + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_TYPE_NAME, "Generalvollmacht"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, "Testfirma"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, "999999m"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, "urn:publicid:gv.at:baseid+XERSB"); + + //pre-generated eIDAS identifer + checkAttributeInSession(session, MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, "QVGm48cqcM4UcyhDTNGYmVdrIoY="); + assertNull("find nat. person bpk for mandator", session.getGenericDataFromSession( + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, String.class)); + + + } + + @Test + public void httpPostValidSignedAssertionEidValidWithNatMandate() throws IOException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException, TaskExecutionException, EaafException { + + oaParam.setBpkTargetIdentifier(EaafConstants.URN_PREFIX_EIDAS + "AT+XX"); + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_with_EID_with_mandate_nat.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + // perform task + task.execute(pendingReq, executionContext); + + // validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + final AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertFalse("foreigner flag", session.isForeigner()); + assertTrue("eidProcess flag", session.isEidProcess()); + assertTrue("useMandate flag", session.isMandateUsed()); + + checkAttributeInSession(session, PvpAttributeDefinitions.GIVEN_NAME_NAME, "Max"); + checkAttributeInSession(session, PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Mustermann"); + checkAttributeInSession(session, PvpAttributeDefinitions.BIRTHDATE_NAME, "1940-01-01"); + checkAttributeInSession(session, PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, "http://eidas.europa.eu/LoA/high"); + checkAttributeInSession(session, PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, "AT"); + + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_TYPE_NAME, "GeneralvollmachtBilateral"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, "Gerti"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, "Musterfrau"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, "01-02-1941"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, "AT+XX:AFSDAFSDFDSFCSDAFASDF="); + + + //pre-generated eIDAS identifer + checkAttributeInSession(session, MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + "QVGm48cqcM4UcyhDTNGYmVdrIoY="); + + + } + private void checkAttributeInSession(AuthProcessDataWrapper session, String attrName, String expected) { String value = session.getGenericDataFromSession(attrName, String.class); Assert.assertEquals("wrong attr. value", expected, value); diff --git a/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/RequestIdAustriaSystemTaskTest.java b/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/RequestIdAustriaSystemTaskTest.java index e5493332..6dc8d415 100644 --- a/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/RequestIdAustriaSystemTaskTest.java +++ b/eidas_modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/RequestIdAustriaSystemTaskTest.java @@ -1,12 +1,14 @@ package at.asitplus.eidas.specific.modules.auth.idaustria.test.task; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.Arrays; import java.util.Base64; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; @@ -45,6 +47,7 @@ import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; import at.gv.egiz.eaaf.core.impl.idp.module.gui.DummyGuiBuilderConfigurationFactory; import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttributes; import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException; @@ -290,6 +293,48 @@ public class RequestIdAustriaSystemTaskTest { } + @Test + public void successWithMandates() throws Pvp2InternalErrorException, SecurityException, Exception { + metadataProvider.addMetadataResolverIntoChain( + metadataFactory.createMetadataProvider(METADATA_PATH, null, "jUnitTest", null)); + + LightRequest.Builder eidasRequestBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .spType("public") + .requesterId(RandomStringUtils.randomAlphanumeric(10)) + .providerName(RandomStringUtils.randomAlphanumeric(10)); + LightRequest eidasReq = eidasRequestBuilder.build(); + pendingReq.setEidasRequest(eidasReq); + + List<String> mandateProfiles = Arrays.asList( + RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + oaParam.setMandateProfiles(mandateProfiles); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + final EaafRequestedAttributes reqAttr = validate(); + Assert.assertEquals("#Req Attribute", 6, reqAttr.getAttributes().size()); + + Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.ServiceProviderMandateProfiles", + reqAttr.getAttributes().get(5).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(1).getAttributeValues()); + Assert.assertEquals("#Req. Attr value", 1, + reqAttr.getAttributes().get(5).getAttributeValues().size()); + org.springframework.util.Assert.isInstanceOf(XSString.class, + reqAttr.getAttributes().get(5).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + + List<String> reqProfiles = KeyValueUtils.getListOfCsvValues( + ((XSString)reqAttr.getAttributes().get(5).getAttributeValues().get(0)).getValue()); + reqProfiles.stream().forEach(el -> assertTrue("missing profile: " + el, mandateProfiles.contains(el))); + + } + private EaafRequestedAttributes validate() throws Pvp2InternalErrorException, SecurityException, Exception { Assert.assertEquals("HTTP Statuscode", 200, httpResp.getStatus()); Assert.assertEquals("ContentType", "text/html;charset=UTF-8", httpResp.getContentType()); diff --git a/eidas_modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_jur.xml b/eidas_modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_jur.xml new file mode 100644 index 00000000..da97bbf4 --- /dev/null +++ b/eidas_modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_jur.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://localhost/authhandler/sp/idaustria/eidas/post" InResponseTo="_aeebfae3ce681fe3ddcaf213a42f01d3" IssueInstant="2014-03-05T06:39:51.017Z" Version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">classpath:/data/idp_metadata_classpath_entity.xml</saml2:Issuer> + <saml2p:Status> + <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> + </saml2p:Status> + <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_602c3236bffaf71ac3ac88674e76ff9f" IssueInstant="2014-03-05T06:39:51.017Z" Version="2.0"> + <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata</saml2:Issuer> + <saml2:Subject> + <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" NameQualifier="urn:publicid:gv.at:cdid+BF">QVGm48cqcM4UcyhDTNGYmVdrIoY=</saml2:NameID> + <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> + <saml2:SubjectConfirmationData InResponseTo="_aeebfae3ce681fe3ddcaf213a42f01d3" NotOnOrAfter="2014-03-05T06:44:51.017Z" Recipient="https://localhost/authhandler/sp/eidas/post"/> + </saml2:SubjectConfirmation> + </saml2:Subject> + <saml2:Conditions NotBefore="2014-03-05T06:39:51.017Z" NotOnOrAfter="2035-03-05T06:44:51.017Z"> + <saml2:AudienceRestriction> + <saml2:Audience>https://localhost/authhandler/sp/idaustria/eidas/metadata</saml2:Audience> + </saml2:AudienceRestriction> + </saml2:Conditions> + <saml2:AuthnStatement AuthnInstant="2014-03-05T06:39:51.017Z" SessionIndex="_c0c683509a8ff6ac372a9cf9c5c5a406"> + <saml2:AuthnContext> + <saml2:AuthnContextClassRef>http://eidas.europa.eu/LoA/high</saml2:AuthnContextClassRef> + </saml2:AuthnContext> + </saml2:AuthnStatement> + <saml2:AttributeStatement> + <saml2:Attribute FriendlyName="PVP-VERSION" Name="urn:oid:1.2.40.0.10.2.1.1.261.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">2.1</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="EID-CITIZEN-QAA- EIDAS-LEVEL" Name="urn:oid:1.2.40.0.10.2.1.1.261.108" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">http://eidas.europa.eu/LoA/high</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="EID-ISSUING-NATION" Name="urn:oid:1.2.40.0.10.2.1.1.261.32" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">AT</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="PRINCIPAL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.20" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Mustermann</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="GIVEN-NAME" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Max</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.55" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">1940-01-01</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="BPK" Name="urn:oid:1.2.40.0.10.2.1.1.149" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">AT+XX:QVGm48cqcM4UcyhDTNGYmVdrIoY=</saml2:AttributeValue> + </saml2:Attribute> + + <saml2:Attribute FriendlyName="MANDATE-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.68" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Generalvollmacht</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN" Name="urn:oid:1.2.40.0.10.2.1.1.261.100" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">999999m</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="MANDATOR-LEGAL-PERSON-SOURCE-PIN-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.76" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">urn:publicid:gv.at:baseid+XERSB</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="MANDATOR-LEGAL-PERSON-FULL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.84" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Testfirma</saml2:AttributeValue> + </saml2:Attribute> + + </saml2:AttributeStatement> + </saml2:Assertion> +</saml2p:Response> diff --git a/eidas_modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_nat.xml b/eidas_modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_nat.xml new file mode 100644 index 00000000..8a84503d --- /dev/null +++ b/eidas_modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_nat.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://localhost/authhandler/sp/idaustria/eidas/post" InResponseTo="_aeebfae3ce681fe3ddcaf213a42f01d3" IssueInstant="2014-03-05T06:39:51.017Z" Version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">classpath:/data/idp_metadata_classpath_entity.xml</saml2:Issuer> + <saml2p:Status> + <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> + </saml2p:Status> + <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_602c3236bffaf71ac3ac88674e76ff9f" IssueInstant="2014-03-05T06:39:51.017Z" Version="2.0"> + <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata</saml2:Issuer> + <saml2:Subject> + <saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" NameQualifier="urn:publicid:gv.at:cdid+BF">QVGm48cqcM4UcyhDTNGYmVdrIoY=</saml2:NameID> + <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> + <saml2:SubjectConfirmationData InResponseTo="_aeebfae3ce681fe3ddcaf213a42f01d3" NotOnOrAfter="2014-03-05T06:44:51.017Z" Recipient="https://localhost/authhandler/sp/eidas/post"/> + </saml2:SubjectConfirmation> + </saml2:Subject> + <saml2:Conditions NotBefore="2014-03-05T06:39:51.017Z" NotOnOrAfter="2035-03-05T06:44:51.017Z"> + <saml2:AudienceRestriction> + <saml2:Audience>https://localhost/authhandler/sp/idaustria/eidas/metadata</saml2:Audience> + </saml2:AudienceRestriction> + </saml2:Conditions> + <saml2:AuthnStatement AuthnInstant="2014-03-05T06:39:51.017Z" SessionIndex="_c0c683509a8ff6ac372a9cf9c5c5a406"> + <saml2:AuthnContext> + <saml2:AuthnContextClassRef>http://eidas.europa.eu/LoA/high</saml2:AuthnContextClassRef> + </saml2:AuthnContext> + </saml2:AuthnStatement> + <saml2:AttributeStatement> + <saml2:Attribute FriendlyName="PVP-VERSION" Name="urn:oid:1.2.40.0.10.2.1.1.261.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">2.1</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="EID-CITIZEN-QAA- EIDAS-LEVEL" Name="urn:oid:1.2.40.0.10.2.1.1.261.108" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">http://eidas.europa.eu/LoA/high</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="EID-ISSUING-NATION" Name="urn:oid:1.2.40.0.10.2.1.1.261.32" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">AT</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="PRINCIPAL-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.20" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Mustermann</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="GIVEN-NAME" Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Max</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.55" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">1940-01-01</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="BPK" Name="urn:oid:1.2.40.0.10.2.1.1.149" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">AT+XX:QVGm48cqcM4UcyhDTNGYmVdrIoY=</saml2:AttributeValue> + </saml2:Attribute> + + <saml2:Attribute FriendlyName="MANDATE-TYPE" Name="urn:oid:1.2.40.0.10.2.1.1.261.68" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">GeneralvollmachtBilateral</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="MANDATOR-NATURAL-PERSON-BPK" Name="urn:oid:1.2.40.0.10.2.1.1.261.98" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">AT+XX:AFSDAFSDFDSFCSDAFASDF=</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="MANDATOR-NATURAL-PERSON-GIVEN-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.78" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Gerti</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="MANDATOR-NATURAL-PERSON-FAMILY-NAME" Name="urn:oid:1.2.40.0.10.2.1.1.261.80" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Musterfrau</saml2:AttributeValue> + </saml2:Attribute> + <saml2:Attribute FriendlyName="MANDATOR-NATURAL-PERSON-BIRTHDATE" Name="urn:oid:1.2.40.0.10.2.1.1.261.82" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"> + <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">01-02-1941</saml2:AttributeValue> + </saml2:Attribute> + + </saml2:AttributeStatement> + </saml2:Assertion> +</saml2p:Response> diff --git a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java index e5d4d33e..336e6c05 100644 --- a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java +++ b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java @@ -18,12 +18,26 @@ public class MsProxyServiceConstants { public static final String ATTR_EIDAS_PERSONAL_IDENTIFIER = AbstractAuthenticationDataBuilder.GENERIC_AUTHDATA_IDENTIFIER + PvpAttributeDefinitions.BPK_NAME; + public static final String ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER = + AbstractAuthenticationDataBuilder.GENERIC_AUTHDATA_IDENTIFIER + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME; + public static final String ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER = + AbstractAuthenticationDataBuilder.GENERIC_AUTHDATA_IDENTIFIER + + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME; + //configuration constants public static final String CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID = Constants.CONIG_PROPS_EIDAS_NODE + ".proxy.entityId"; public static final String CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_URL = Constants.CONIG_PROPS_EIDAS_NODE + ".proxy.forward.endpoint"; - + + // mandate configuration + public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED = Constants.CONIG_PROPS_EIDAS_PREFIX + + ".proxy.mandates.enabled"; + public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT = Constants.CONIG_PROPS_EIDAS_PREFIX + + ".proxy.mandates.profiles.default"; + public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_SPECIFIC = Constants.CONIG_PROPS_EIDAS_PREFIX + + ".proxy.mandates.profiles.specific."; + //http end-points public static final String EIDAS_HTTP_ENDPOINT_IDP_POST = "/eidas/light/idp/post"; diff --git a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java index aafe57e7..8e417c36 100644 --- a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java +++ b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java @@ -2,7 +2,9 @@ package at.asitplus.eidas.specific.modules.msproxyservice.protocol; import java.io.IOException; import java.text.MessageFormat; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -30,6 +32,7 @@ import at.gv.egiz.eaaf.core.api.idp.IModulInfo; import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractController; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; import eu.eidas.auth.commons.EidasParameterKeys; import eu.eidas.auth.commons.light.ILightRequest; import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames; @@ -221,7 +224,10 @@ public class EidasProxyServiceController extends AbstractController implements I EaafConstants.URN_PREFIX_EIDAS + ccCountry + "+" + spCountry); spConfig.setRequiredLoA( eidasRequest.getLevelsOfAssurance().stream().map(el -> el.getValue()).collect(Collectors.toList())); - + + spConfig.setMandateProfiles(buildMandateProfileConfiguration(eidasRequest)); + + return spConfig; } catch (EaafException e) { @@ -230,4 +236,28 @@ public class EidasProxyServiceController extends AbstractController implements I } } + private List<String> buildMandateProfileConfiguration(ILightRequest eidasRequest) { + if (authConfig.getBasicConfigurationBoolean( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, false)) { + log.trace("eIDAS Proxy-Service allows mandates. Selecting profiles ... "); + List<String> spMandateProfiles = authConfig.getBasicConfigurationWithPrefix( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_SPECIFIC) + .entrySet().stream() + .filter(el -> el.getKey().endsWith(eidasRequest.getSpCountryCode().toLowerCase())) + .findFirst() + .map(el -> KeyValueUtils.getListOfCsvValues(el.getValue())) + .orElse(KeyValueUtils.getListOfCsvValues( + authConfig.getBasicConfiguration( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT))); + + log.debug("Set mandate-profiles: {} to request from country: {}", + spMandateProfiles, eidasRequest.getSpCountryCode()); + return spMandateProfiles; + + } + + return Collections.emptyList(); + + } + } diff --git a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java index c51db460..9de2eb79 100644 --- a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java +++ b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java @@ -21,10 +21,12 @@ import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRe import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants; import at.asitplus.eidas.specific.modules.msproxyservice.exception.EidasProxyServiceException; import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; import at.gv.egiz.eaaf.core.api.gui.ISpringMvcGuiFormBuilder; import at.gv.egiz.eaaf.core.api.idp.IAction; import at.gv.egiz.eaaf.core.api.idp.IAuthData; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IEidAuthData; import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface; import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; import at.gv.egiz.eaaf.core.exceptions.EaafException; @@ -143,6 +145,80 @@ public class ProxyServiceAuthenticationAction implements IAction { private ImmutableAttributeMap buildAttributesFromAuthData(IAuthData authData) { + IEidAuthData eidAuthData = (IEidAuthData) authData; + if (eidAuthData.isUseMandate()) { + log.debug("Building eIDAS Proxy-Service response with mandate ... "); + final ImmutableAttributeMap.Builder attributeMap = ImmutableAttributeMap.builder(); + injectRepesentativeInformation(attributeMap, eidAuthData); + injectMandatorInformation(attributeMap, eidAuthData); + return attributeMap.build(); + + } else { + log.debug("Building eIDAS Proxy-Service response without mandates ... "); + return buildAttributesWithoutMandate(eidAuthData); + + } + } + + private void injectMandatorInformation( + ImmutableAttributeMap.Builder attributeMap, IEidAuthData eidAuthData) { + String natMandatorId = eidAuthData.getGenericData( + MsProxyServiceConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, String.class); + + if (StringUtils.isNotEmpty(natMandatorId)) { + log.debug("Injecting natural mandator informations ... "); + final AttributeDefinition<?> attrDefPersonalId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition<?> attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition<?> attrDefGivenName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition<?> attrDefDateOfBirth = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + + attributeMap.put(attrDefPersonalId, natMandatorId); + attributeMap.put(attrDefFamilyName, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, String.class)); + attributeMap.put(attrDefGivenName, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, String.class)); + attributeMap.put(attrDefDateOfBirth, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, String.class)); + + } else { + log.debug("Injecting legal mandator informations ... "); + final AttributeDefinition<?> commonName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_LEGALNAME).first(); + final AttributeDefinition<?> legalPersonId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first(); + + attributeMap.put(commonName, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, String.class)); + attributeMap.put(legalPersonId, eidAuthData.getGenericData( + MsProxyServiceConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, String.class)); + + } + } + + private void injectRepesentativeInformation( + ImmutableAttributeMap.Builder attributeMap, IEidAuthData eidAuthData) { + final AttributeDefinition<?> attrDefPersonalId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER).first(); + final AttributeDefinition<?> attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME).first(); + final AttributeDefinition<?> attrDefGivenName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME).first(); + final AttributeDefinition<?> attrDefDateOfBirth = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH).first(); + + attributeMap.put(attrDefPersonalId, + eidAuthData.getGenericData(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, String.class)); + attributeMap.put(attrDefFamilyName, eidAuthData.getFamilyName()); + attributeMap.put(attrDefGivenName, eidAuthData.getGivenName()); + attributeMap.put(attrDefDateOfBirth, eidAuthData.getFormatedDateOfBirth()); + + } + + private ImmutableAttributeMap buildAttributesWithoutMandate(IEidAuthData eidAuthData) { final AttributeDefinition<?> attrDefPersonalId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); final AttributeDefinition<?> attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( @@ -153,16 +229,17 @@ public class ProxyServiceAuthenticationAction implements IAction { Constants.eIDAS_ATTR_DATEOFBIRTH).first(); final ImmutableAttributeMap.Builder attributeMap = - ImmutableAttributeMap.builder().put(attrDefPersonalId, - authData.getGenericData(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, String.class)) - .put(attrDefFamilyName, authData.getFamilyName()) - .put(attrDefGivenName, authData.getGivenName()) - .put(attrDefDateOfBirth, authData.getFormatedDateOfBirth()); + ImmutableAttributeMap.builder() + .put(attrDefPersonalId, + eidAuthData.getGenericData(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, String.class)) + .put(attrDefFamilyName, eidAuthData.getFamilyName()) + .put(attrDefGivenName, eidAuthData.getGivenName()) + .put(attrDefDateOfBirth, eidAuthData.getFormatedDateOfBirth()); return attributeMap.build(); } - + private BinaryLightToken putResponseInCommunicationCache(ILightResponse lightResponse) throws ServletException { final BinaryLightToken binaryLightToken; diff --git a/eidas_modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/EidasProxyServiceControllerTest.java b/eidas_modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/EidasProxyServiceControllerTest.java index 9ce7115a..1a19b723 100644 --- a/eidas_modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/EidasProxyServiceControllerTest.java +++ b/eidas_modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/EidasProxyServiceControllerTest.java @@ -1,13 +1,20 @@ package at.asitplus.eidas.specific.modules.auth.idaustria.test.protocol; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.URISyntaxException; import java.text.MessageFormat; +import java.util.Arrays; +import java.util.List; import java.util.UUID; import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -23,6 +30,7 @@ import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import at.asitplus.eidas.specific.connector.config.ServiceProviderConfiguration; +import at.asitplus.eidas.specific.connector.test.config.dummy.MsConnectorDummyConfigMap; import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask; import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy.DummySpecificCommunicationService; import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants; @@ -51,6 +59,8 @@ public class EidasProxyServiceControllerTest { @Autowired private DummySpecificCommunicationService proxyService; @Autowired private DummyProtocolAuthService authService; + @Autowired MsConnectorDummyConfigMap config; + private MockHttpServletRequest httpReq; private MockHttpServletResponse httpResp; @@ -167,6 +177,91 @@ public class EidasProxyServiceControllerTest { EaafConstants.URN_PREFIX_EIDAS + "AT+" + spCountryCode, spConfig.getAreaSpecificTargetIdentifier()); + assertNotNull("mandateprofiles", spConfig.getMandateProfiles()); + assertTrue("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty()); + } + @Test + public void validAuthnRequestWithMandatesDefaultProfiles() throws IOException, EaafException { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(spCountryCode) + .spType("public"); + + proxyService.setiLightRequest(authnReqBuilder.build()); + + List<String> mandateProfiles = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true"); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT, + StringUtils.join(mandateProfiles, ",")); + + //execute + controller.receiveEidasAuthnRequest(httpReq, httpResp); + + //validate state + ServiceProviderConfiguration spConfig = + authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class); + assertNotNull("mandateprofiles", spConfig.getMandateProfiles()); + assertFalse("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty()); + assertEquals("mandateprofile size", mandateProfiles.size(), spConfig.getMandateProfiles().size()); + spConfig.getMandateProfiles().stream() + .forEach(el -> assertTrue("missing mandateProfile: " + el, mandateProfiles.contains(el))); + + } + + @Test + public void validAuthnRequestWithMandatesCountryProfiles() throws IOException, EaafException { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(spCountryCode) + .spType("public"); + + proxyService.setiLightRequest(authnReqBuilder.build()); + + List<String> mandateProfiles = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + List<String> mandateProfilesCc1 = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + List<String> mandateProfilesCc2 = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true"); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT, + StringUtils.join(mandateProfiles, ",")); + + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_SPECIFIC + + RandomStringUtils.randomAlphabetic(2).toLowerCase(), + StringUtils.join(mandateProfilesCc1, ",")); + config.putConfigValue( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_SPECIFIC + spCountryCode.toLowerCase(), + StringUtils.join(mandateProfilesCc2, ",")); + + + //execute + controller.receiveEidasAuthnRequest(httpReq, httpResp); + + //validate state + ServiceProviderConfiguration spConfig = + authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class); + assertNotNull("mandateprofiles", spConfig.getMandateProfiles()); + assertFalse("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty()); + assertEquals("mandateprofile size", mandateProfiles.size(), spConfig.getMandateProfiles().size()); + spConfig.getMandateProfiles().stream() + .forEach(el -> assertTrue("missing mandateProfile: " + el, mandateProfilesCc2.contains(el))); + + } + } diff --git a/eidas_modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/ProxyServiceAuthenticationActionTest.java b/eidas_modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/ProxyServiceAuthenticationActionTest.java index 96429d71..3236bbf0 100644 --- a/eidas_modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/ProxyServiceAuthenticationActionTest.java +++ b/eidas_modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/ProxyServiceAuthenticationActionTest.java @@ -1,9 +1,14 @@ package at.asitplus.eidas.specific.modules.auth.idaustria.test.protocol; import static at.asitplus.eidas.specific.connector.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import java.net.URISyntaxException; +import java.net.URLDecoder; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -12,10 +17,12 @@ import java.util.Map; import java.util.UUID; import org.apache.commons.lang3.RandomStringUtils; +import org.joda.time.DateTime; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.opensaml.saml.saml2.core.NameIDType; import org.powermock.core.classloader.annotations.PrepareForTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -26,20 +33,33 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; +import com.google.common.collect.ImmutableSortedSet; + import at.asitplus.eidas.specific.connector.test.config.dummy.MsConnectorDummyConfigMap; import at.asitplus.eidas.specific.connector.test.config.dummy.MsConnectorDummySpConfiguration; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask; import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants; import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServiceAuthenticationAction; import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServicePendingRequest; import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions.EidIdentityStatusLevelValues; import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.IEidAuthData; import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink; import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.light.ILightResponse; import eu.eidas.auth.commons.light.impl.LightRequest; +import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; +import eu.eidas.specificcommunication.protocol.SpecificCommunicationService; @RunWith(SpringJUnit4ClassRunner.class) @PrepareForTest(CreateIdentityLinkTask.class) @@ -52,11 +72,13 @@ public class ProxyServiceAuthenticationActionTest { @Autowired private MsConnectorDummyConfigMap basicConfig; @Autowired private ProxyServiceAuthenticationAction action; @Autowired private ApplicationContext context; + @Autowired EidasAttributeRegistry attrRegistry; private MockHttpServletRequest httpReq; private MockHttpServletResponse httpResp; private ProxyServicePendingRequest pendingReq; private MsConnectorDummySpConfiguration oaParam; + private SpecificCommunicationService springManagedSpecificConnectorCommunicationService; /** @@ -95,6 +117,12 @@ public class ProxyServiceAuthenticationActionTest { .providerName(RandomStringUtils.randomAlphanumeric(10)); pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + springManagedSpecificConnectorCommunicationService = + (SpecificCommunicationService) context.getBean( + SpecificCommunicationDefinitionBeanNames.SPECIFIC_PROXYSERVICE_COMMUNICATION_SERVICE + .toString()); + } @Test @@ -114,7 +142,7 @@ public class ProxyServiceAuthenticationActionTest { attr.put(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, - RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18"); + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", false); basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint"); EaafException exception = assertThrows(EaafException.class, @@ -124,12 +152,86 @@ public class ProxyServiceAuthenticationActionTest { } @Test - public void dummyResponseActionTest() throws EaafException { + public void responseWithoutMandate() throws EaafException, SpecificCommunicationException { + Map<String, Object> attr = new HashMap<>(); + attr.put(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", false); + + //perform test + SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); + + //validate state + Assert.assertNotNull("Result should be not null", result); + + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); + assertEquals("wrong attr. size", 4, respAttr.size()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + (String) attr.get(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_DATEOFBIRTH, + authData.getFormatedDateOfBirth()); + + } + + @Test + public void responseWithNatMandate() throws EaafException, SpecificCommunicationException { + Map<String, Object> attr = new HashMap<>(); + attr.put(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + + attr.put(MsProxyServiceConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, + 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"); + + + 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); + assertEquals("wrong attr. size", 8, respAttr.size()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER, + (String) attr.get(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData.getFamilyName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData.getGivenName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getFormatedDateOfBirth()); + + checkAttrValue(respAttr, Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + (String) attr.get(MsProxyServiceConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTFAMILYNAME, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTGIVENNAME, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_DATEOFBIRTH, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME)); + + } + + @Test + public void responseWithJurMandate() throws EaafException, SpecificCommunicationException { Map<String, Object> attr = new HashMap<>(); attr.put(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, - RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18"); + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true); + + attr.put(MsProxyServiceConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, + RandomStringUtils.randomAlphabetic(10)); //perform test SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); @@ -137,6 +239,20 @@ public class ProxyServiceAuthenticationActionTest { //validate state Assert.assertNotNull("Result should be not null", result); + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); + assertEquals("wrong attr. size", 6, respAttr.size()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER, + (String) attr.get(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData.getFamilyName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData.getGivenName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getFormatedDateOfBirth()); + + checkAttrValue(respAttr, Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER, + (String) attr.get(MsProxyServiceConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_LEGALNAME, + (String) attr.get(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME)); + + } @Test @@ -151,12 +267,50 @@ public class ProxyServiceAuthenticationActionTest { private IAuthData generateDummyAuthData() { return generateDummyAuthData(Collections.emptyMap(), EaafConstants.EIDAS_LOA_LOW, - RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1940-01-01"); + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1940-01-01", false); } - private IAuthData generateDummyAuthData(Map<String, Object> attrs, String loa, String familyName, String givenName, String dateOfBirth) { - return new IAuthData() { + private void checkAttrValue(ImmutableAttributeMap respAttr, String attrName, String expected) { + final AttributeDefinition<?> attrDef = + attrRegistry.getCoreAttributeRegistry().getByFriendlyName(attrName).first(); + Object value = respAttr.getFirstValue(attrDef); + assertNotNull("not attr value: " + attrName, value); + + if (value instanceof String) { + assertEquals("wrong attr. value: " + attrName, expected, value); + + } else if ( value instanceof DateTime) { + assertEquals("wrong attr. value: " + attrName, expected, ((DateTime)value).toString("yyyy-MM-dd")); + + } + + } + + private ImmutableAttributeMap validateBasicEidasResponse(IAuthData authData) throws SpecificCommunicationException { + assertNotNull("not redirct Header", httpResp.getHeader("Location")); + 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())); + + 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()); + return resp.getAttributes(); + + } + + private IAuthData generateDummyAuthData(Map<String, Object> attrs, String loa, String familyName, String givenName, String dateOfBirth, + boolean useMandates) { + return new IEidAuthData() { @Override public boolean isSsoSession() { @@ -303,6 +457,36 @@ public class ProxyServiceAuthenticationActionTest { // TODO Auto-generated method stub return null; } + + @Override + public byte[] getSignerCertificate() { + // TODO Auto-generated method stub + return null; + } + + @Override + public byte[] getEidToken() { + // TODO Auto-generated method stub + return null; + } + + @Override + public EidIdentityStatusLevelValues getEidStatus() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getVdaEndPointUrl() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isUseMandate() { + return useMandates; + + } }; } |