diff options
Diffstat (limited to 'eidas_modules/authmodule-eIDAS-v2/src')
4 files changed, 146 insertions, 17 deletions
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java index cfaecfbb..234d52dd 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java @@ -79,7 +79,8 @@ public class AuthBlockSigningService { EidasAuchBlock authBlock = new EidasAuchBlock(); authBlock.setChallenge(UUID.randomUUID().toString()); authBlock.setTimestamp(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS)); - authBlock.setUniqueId(pendingReq.getRawData(MsEidasNodeConstants.DATA_REQUESTERID, String.class)); + authBlock.setUniqueId(pendingReq.getRawData(MsEidasNodeConstants.DATA_REQUESTERID, String.class)); + authBlock.setPiiTransactionId(pendingReq.getUniquePiiTransactionIdentifier()); String jwsPayload = mapper.writeValueAsString(authBlock); log.debug("Building and sign authBlock with data: {}", jwsPayload); @@ -185,6 +186,9 @@ public class AuthBlockSigningService { @JsonProperty("appId") private String uniqueId; + @JsonProperty("piiTransactionId") + private String piiTransactionId; + } diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java index 69b993a4..6de5dae9 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java @@ -45,6 +45,7 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; +import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import javax.xml.namespace.QName; @@ -58,8 +59,6 @@ import javax.xml.ws.BindingProvider; import javax.xml.ws.Dispatch; import javax.xml.ws.handler.Handler; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.StringUtils; import org.apache.cxf.configuration.jsse.TLSClientParameters; import org.apache.cxf.endpoint.Client; @@ -75,6 +74,9 @@ import org.springframework.stereotype.Service; import org.w3c.dom.Document; import org.w3c.dom.Element; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException; import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.LoggingHandler; @@ -229,7 +231,7 @@ public class SzrClient { final String resp; try { - resp = this.szr.getStammzahlEncrypted(personInfo, false); + resp = this.szr.getStammzahlEncrypted(personInfo, true); } catch (SZRException_Exception e) { throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e); } @@ -488,6 +490,7 @@ public class SzrClient { private byte[] sourceToByteArray(Source result) throws TransformerException { final TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); final Transformer transformer = factory.newTransformer(); transformer.setOutputProperty("omit-xml-declaration", "yes"); transformer.setOutputProperty("method", "xml"); diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java index f9142f8e..11f8fc04 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java @@ -162,6 +162,7 @@ public class CreateIdentityLinkTask extends AbstractAuthServletTask { //inject personal-data into session authProcessData.setGenericDataToSession(Constants.SZR_AUTHBLOCK, jwsSignature); authProcessData.setGenericDataToSession(Constants.EIDAS_BIND, signedEidasBind); + authProcessData.setEidProcess(true); } else { //request SZR @@ -182,6 +183,7 @@ public class CreateIdentityLinkTask extends AbstractAuthServletTask { //inject personal-data into session authProcessData.setIdentityLink(idlResult.getIdentityLink()); + authProcessData.setEidProcess(false); // set bPK and bPKType into auth session authProcessData.setGenericDataToSession(PvpAttributeDefinitions.BPK_NAME, extendBpkByPrefix( diff --git a/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java index dd485ee6..44fa01e8 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java @@ -2,6 +2,8 @@ package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; import static at.asitplus.eidas.specific.connector.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.powermock.api.mockito.PowerMockito.when; import java.io.IOException; @@ -13,6 +15,7 @@ import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -29,6 +32,7 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.powermock.core.classloader.annotations.PrepareForTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mock.web.MockHttpServletRequest; @@ -39,18 +43,22 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.skjolberg.mockito.soap.SoapServiceRule; import at.asitplus.eidas.specific.connector.MsEidasNodeConstants; import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException; -import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.AuthBlockSigningService; 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.auth.eidas.v2.utils.JoseUtils; import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.JoseUtils.JwsResult; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.IRequestStorage; 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.idp.IConfiguration; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; import at.gv.egiz.eaaf.core.exceptions.EaafException; @@ -64,11 +72,14 @@ import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; import at.gv.egiz.eaaf.core.impl.idp.module.test.DummySpConfiguration; import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import at.gv.egiz.eaaf.core.impl.utils.Random; import eu.eidas.auth.commons.attribute.AttributeDefinition; import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; import eu.eidas.auth.commons.attribute.PersonType; import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; import lombok.val; +import szrservices.JwsHeaderParam; +import szrservices.PersonInfoType; import szrservices.SZR; import szrservices.SignContentEntry; import szrservices.SignContentResponseType; @@ -93,7 +104,7 @@ public class CreateIdentityLinkTaskEidNewTest { EaafKeyStoreFactory keyStoreFactory; @Autowired - private AuthBlockSigningService authBlockSigner; + private IRequestStorage requestStorage; final ExecutionContext executionContext = new ExecutionContextImpl(); private MockHttpServletRequest httpReq; @@ -110,6 +121,10 @@ public class CreateIdentityLinkTaskEidNewTest { AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512, AlgorithmIdentifiers.RSA_PSS_USING_SHA256, AlgorithmIdentifiers.RSA_PSS_USING_SHA512)); + private static ObjectMapper mapper = new ObjectMapper(); + + private AuthenticationResponse response; + @Rule public final SoapServiceRule soap = SoapServiceRule.newInstance(); @@ -143,7 +158,7 @@ public class CreateIdentityLinkTaskEidNewTest { oaParam = new DummySpConfiguration(spConfig, basicConfig); pendingReq = new TestRequestImpl(); - final AuthenticationResponse response = buildDummyAuthResponse(); + response = buildDummyAuthResponse(); pendingReq.getSessionData(AuthProcessDataWrapper.class) .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); @@ -151,7 +166,8 @@ public class CreateIdentityLinkTaskEidNewTest { pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); pendingReq.setAuthUrl("http://test.com/"); pendingReq.setTransactionId("avaasbav"); - + pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "XX"); executionContext.put(EaafConstants.PROCESS_ENGINE_REQUIRES_NO_POSTAUTH_REDIRECT, true); @@ -161,32 +177,129 @@ public class CreateIdentityLinkTaskEidNewTest { @Test public void successfulProcess() throws Exception { //initialize test - when(szrMock, "getStammzahlEncrypted", any(), any()).thenReturn(RandomStringUtils.randomNumeric(10)); + String vsz = RandomStringUtils.randomNumeric(10); + when(szrMock, "getStammzahlEncrypted", any(), any()).thenReturn(vsz); val signContentResp = new SignContentResponseType(); final SignContentEntry signContentEntry = new SignContentEntry(); signContentEntry.setValue(RandomStringUtils.randomAlphanumeric(10)); signContentResp.getOut().add(signContentEntry); when(szrMock, "signContent", any(), any(), any()).thenReturn(signContentResp); + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + //perform test task.execute(pendingReq, executionContext); - //validate state - final AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class); + //validate state + // check if pendingRequest was stored + IRequest storedPendingReq = requestStorage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedPendingReq); + + //check data in session + final AuthProcessDataWrapper authProcessData = storedPendingReq.getSessionData(AuthProcessDataWrapper.class); Assert.assertNotNull("AuthProcessData", authProcessData); Assert.assertNotNull("eidasBind", authProcessData.getGenericDataFromSession(Constants.EIDAS_BIND, String.class)); String authBlock = authProcessData.getGenericDataFromSession(Constants.SZR_AUTHBLOCK, String.class); Assert.assertNotNull("AuthBlock", authBlock); - - //check authblock signature + + Assert.assertTrue("EID process", authProcessData.isEidProcess()); + Assert.assertTrue("foreigner process", authProcessData.isForeigner()); + Assert.assertEquals("EID-ISSUING_NATION", "LU", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class)); + Assert.assertNotNull("LoA is null", authProcessData.getQaaLevel()); + Assert.assertEquals("LoA", response.getLevelOfAssurance(), + authProcessData.getQaaLevel()); + + + // check authblock signature final AlgorithmConstraints constraints = new AlgorithmConstraints(ConstraintType.PERMIT, BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.toArray(new String[BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.size()])); Pair<KeyStore, Provider> keyStore = getKeyStore(); X509Certificate[] trustedCerts = EaafKeyStoreUtils .getPrivateKeyAndCertificates(keyStore.getFirst(), ALIAS, PW.toCharArray(), true, "junit").getSecond(); JwsResult result = JoseUtils.validateSignature(authBlock, Arrays.asList(trustedCerts), constraints); - Assert.assertTrue("AuthBlock not valid", result.isValid()); + Assert.assertTrue("AuthBlock not valid", result.isValid()); + JsonNode authBlockJson = mapper.readTree(result.getPayLoad()); + Assert.assertNotNull("deserialized AuthBlock", authBlockJson); + + Assert.assertNotNull("no piiTransactionId in pendingRequesdt", + storedPendingReq.getUniquePiiTransactionIdentifier()); + Assert.assertEquals("piiTransactionId", storedPendingReq.getUniquePiiTransactionIdentifier(), + authBlockJson.get("piiTransactionId").asText()); + Assert.assertEquals("appId", randomTestSp, authBlockJson.get("appId").asText()); + Assert.assertFalse("'challenge' is null", authBlockJson.get("challenge").asText().isEmpty()); + Assert.assertFalse("'timestamp' is null", authBlockJson.get("timestamp").asText().isEmpty()); + + + // check vsz request + ArgumentCaptor<PersonInfoType> argument4 = ArgumentCaptor.forClass(PersonInfoType.class); + ArgumentCaptor<Boolean> argument5 = ArgumentCaptor.forClass(Boolean.class); + verify(szrMock, times(1)).getStammzahlEncrypted(argument4.capture(), argument5.capture()); + + Boolean param5 = argument5.getValue(); + Assert.assertTrue("insertERnP flag", param5); + PersonInfoType person = argument4.getValue(); + Assert.assertEquals("FamilyName", + response.getAttributes().getAttributeValuesByFriendlyName("FamilyName").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("FamilyName").iterator().next()), + person.getPerson().getName().getFamilyName()); + Assert.assertEquals("GivenName", + response.getAttributes().getAttributeValuesByFriendlyName("FirstName").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("FirstName").iterator().next()), + person.getPerson().getName().getGivenName()); + Assert.assertEquals("DateOfBirth", + response.getAttributes().getAttributeValuesByFriendlyName("DateOfBirth").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("DateOfBirth").iterator().next()) + .toString().split("T")[0], + person.getPerson().getDateOfBirth()); + + Assert.assertEquals("CitizenCountry", "LU", person.getTravelDocument().getIssuingCountry()); + Assert.assertEquals("DocumentType", "ELEKTR_DOKUMENT", person.getTravelDocument().getDocumentType()); + + Assert.assertEquals("Identifier", + response.getAttributes().getAttributeValuesByFriendlyName("PersonIdentifier").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("PersonIdentifier").iterator().next()) + .toString().split("/")[2], + person.getTravelDocument().getDocumentNumber()); + + // check bcBind singing request + ArgumentCaptor<Boolean> argument1 = ArgumentCaptor.forClass(Boolean.class); + ArgumentCaptor<List<JwsHeaderParam>> argument2 = ArgumentCaptor.forClass(List.class); + ArgumentCaptor<List<SignContentEntry>> argument3 = ArgumentCaptor.forClass(List.class); + verify(szrMock, times(1)).signContent(argument1.capture(), argument2.capture(), argument3.capture()); + Boolean param1 = argument1.getValue(); + Assert.assertFalse("addCert flag", param1); + + List<JwsHeaderParam> param2 = argument2.getValue(); + Assert.assertNotNull("JWS Headers", param2); + Assert.assertFalse("JWS Headers empty", param2.isEmpty()); + Assert.assertEquals("Wrong JWS header size", 1, param2.size()); + Assert.assertEquals("Missing JWS header key", "urn:at.gv.eid:bindtype", param2.get(0).getKey()); + Assert.assertEquals("Missing JWS header value", "urn:at.gv.eid:eidasBind", param2.get(0).getValue()); + + List<SignContentEntry> param3 = argument3.getValue(); + Assert.assertNotNull("sign Payload", param3); + Assert.assertEquals("wrong sign-payload size", 1, param3.size()); + Assert.assertNotNull("payload", param3.get(0).getValue().getBytes()); + JsonNode bcBind = mapper.readTree(param3.get(0).getValue().getBytes()); + Assert.assertNotNull("bcbind req", bcBind); + + Assert.assertEquals("vsz", vsz, bcBind.get("urn:eidgvat:attributes.vsz.value").asText()); + Assert.assertEquals("eid status", "urn:eidgvat:eid.status.eidas", + bcBind.get("urn:eidgvat:attributes.eid.status").asText()); + Assert.assertTrue("pubKeys", bcBind.has("urn:eidgvat:attributes.user.pubkeys")); + Assert.assertTrue("pubKeys", bcBind.get("urn:eidgvat:attributes.user.pubkeys").isArray()); + Iterator<JsonNode> pubKeys = bcBind.get("urn:eidgvat:attributes.user.pubkeys").elements(); + Assert.assertTrue("No PubKey", pubKeys.hasNext()); + Assert.assertEquals("Wrong pubKey", + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmxcB5jnrAwGn7xjgVFv1UBUv1pluwDRFQx7x5O6rSn7pblYfwaWeKa8y" + + "jS5BDDaZ00mhhnSlm2XByNrkg5yBGetTgBGtQVAxV5apfuAWN8TS3uSXgdZol7Khd6kraUITtnulvLe8tNaboom5P0zN6UxbJN" + + "NVLishVp80HiRXiDbplCTUk8b5cYtmivdb0+5JBTa7L5N/anRVnHHoJCXgNPTouO8daUHZbG1mPk0HgqD8rhZ+OBzE+APKH9No" + + "agedSrGRDLdIgZxkrg0mxmfsZQIi2wdJSi3y0PAjEps/s4j0nmw9bPRgCMNLBqqjxtN5JKC8E1yyLm7YefXv/nPaMwIDAQAB", + pubKeys.next().asText()); + Assert.assertFalse("More than one PubKey", pubKeys.hasNext()); } @@ -261,12 +374,19 @@ public class CreateIdentityLinkTaskEidNewTest { .attributeValueMarshaller("eu.eidas.auth.commons.attribute.impl.DateTimeAttributeValueMarshaller").build(); final ImmutableAttributeMap attributeMap = ImmutableAttributeMap.builder() - .put(attributeDef, "de/st/" + RandomStringUtils.randomNumeric(64)) + .put(attributeDef, "LU/ST/" + RandomStringUtils.randomNumeric(64)) .put(attributeDef2, RandomStringUtils.randomAlphabetic(10)) .put(attributeDef3, RandomStringUtils.randomAlphabetic(10)).put(attributeDef4, "2001-01-01").build(); val b = new AuthenticationResponse.Builder(); - return b.id("aasdf").issuer("asd").subject("asf").statusCode("200").inResponseTo("asdf").subjectNameIdFormat("afaf") - .attributes(attributeMap).build(); + return b.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode("200") + .inResponseTo("_".concat(Random.nextHexRandom16())) + .subjectNameIdFormat("afaf") + .levelOfAssurance(EaafConstants.EIDAS_LOA_PREFIX + RandomStringUtils.randomAlphabetic(5)) + .attributes(attributeMap) + .build(); } } |