diff options
Diffstat (limited to 'modules/authmodule-eIDAS-v2/src/test/java/at')
45 files changed, 14656 insertions, 0 deletions
diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthSpringResourceProviderTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthSpringResourceProviderTest.java new file mode 100644 index 00000000..aef290f5 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthSpringResourceProviderTest.java @@ -0,0 +1,56 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.springframework.core.io.Resource; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.EidasAuthenticationSpringResourceProvider; +import at.gv.egiz.eaaf.core.test.TestConstants; + + + +@RunWith(BlockJUnit4ClassRunner.class) +public class EidasAuthSpringResourceProviderTest { + + @Test + public void testSpringConfig() { + final EidasAuthenticationSpringResourceProvider test = + new EidasAuthenticationSpringResourceProvider(); + for (final Resource el : test.getResourcesToLoad()) { + try { + IOUtils.toByteArray(el.getInputStream()); + + } catch (final IOException e) { + Assert.fail("Ressouce: " + el.getFilename() + " not found"); + } + + } + + Assert.assertNotNull("no Name", test.getName()); + Assert.assertNull("Find package definitions", test.getPackagesToScan()); + + } + + @Test + public void testSpILoaderConfig() { + final InputStream el = this.getClass().getResourceAsStream(TestConstants.TEST_SPI_LOADER_PATH); + try { + final String spiFile = IOUtils.toString(el, "UTF-8"); + + Assert.assertEquals("Wrong classpath in SPI file", + EidasAuthenticationSpringResourceProvider.class.getName(), spiFile); + + + } catch (final IOException e) { + Assert.fail("Ressouce: " + TestConstants.TEST_SPI_LOADER_PATH + " not found"); + + } + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthenticationModulImplTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthenticationModulImplTest.java new file mode 100644 index 00000000..86af87ad --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthenticationModulImplTest.java @@ -0,0 +1,121 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.EidasAuthenticationModulImpl; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +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.impl.idp.auth.modules.ModuleRegistration; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyConfiguration; +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; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class EidasAuthenticationModulImplTest { + + @Autowired ModuleRegistration moduleReg; + @Autowired ResourceLoader loader; + + private final ExecutionContext executionContext = new ExecutionContextImpl(); + private DummySpConfiguration oaParam; + private TestRequestImpl pendingReq; + private EidasAuthenticationModulImpl authProcess = new EidasAuthenticationModulImpl(); + + /** + * jUnit class initializer. + * + */ + @BeforeClass + public static void classInitializer() throws IOException { + final String current = new java.io.File(".").toURI().toString(); + System.setProperty("eidas.ms.configuration", current + "../../basicConfig/default_config.properties"); + + } + + /** + * jUnit test set-up. + * + */ + @Before + public void initialize() { + Map<String, String> configMap = new HashMap<String, String>(); + configMap.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "http://test.com/test"); + IConfiguration basicConfig = new DummyConfiguration(); + oaParam = new DummySpConfiguration(configMap, basicConfig); + pendingReq = new TestRequestImpl(); + pendingReq.setSpConfig(oaParam); + } + + @Test + public void checkProcessDefinition() { + Assert.assertNotNull("AuthModule is null", authProcess); + Assert.assertNotNull("AuthModule process is null", authProcess.getProcessDefinitions()); + + for (String el : authProcess.getProcessDefinitions()) { + Resource res = loader.getResource(el); + Assert.assertTrue("AuthProcess description not extist", res.exists()); + + } + } + + @Test + public void countrySelected() throws Exception { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, RandomStringUtils.randomAlphanumeric(2)); + final String result = + moduleReg.selectProcess(executionContext, pendingReq); + Assert.assertNotNull("Process is null", result); + Assert.assertEquals("Process Id not match", "eIDASAuthentication_v2", result); + + } + + @Test + public void noCountryValid() throws Exception { + final String result = + moduleReg.selectProcess(executionContext, pendingReq); + + Assert.assertNull("Select wrong process", result); + + } + + @Test + public void selectCountryWrongType() throws Exception { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, 1); + final String result = + moduleReg.selectProcess(executionContext, pendingReq); + Assert.assertNull("Select wrong process", result); + + } + + @Test + public void selectCountryEmpty() throws Exception { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, ""); + final String result = + moduleReg.selectProcess(executionContext, pendingReq); + Assert.assertNull("Select wrong process", result); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasDataStoreTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasDataStoreTest.java new file mode 100644 index 00000000..1051bd9f --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasDataStoreTest.java @@ -0,0 +1,118 @@ +/* + * Copyright 2018 A-SIT Plus GmbH AT-specific eIDAS Connector has been developed + * in a cooperation between EGIZ, A-SIT Plus GmbH, A-SIT, and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. You may + * obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. The "NOTICE" text file + * is part of the distribution. Any derivative works that you distribute must + * include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test; + +//import java.security.MessageDigest; +// +//import org.apache.commons.lang3.StringUtils; +//import org.junit.Test; +//import org.junit.runner.RunWith; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.test.context.ContextConfiguration; +//import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +//import org.springframework.util.Base64Utils; +// +//import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SQLiteServiceException; +//import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.eIDASAuthenticationException; +//import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.eIDASResponseUtils; +//import at.gv.egiz.eaaf.core.impl.data.Trible; +// +//@RunWith(SpringJUnit4ClassRunner.class) +//@ContextConfiguration("/SpringTest-context_basic_test.xml") +//public class EidasDataStoreTest { +// +// @Autowired +// private EidasDataStore dataStore; +// +// private static final String P1_TRANSID = "123456789"; +// private static final String P1_eIDASID = +// "DE/AT/121asdf1as5f1as6f1asd2f1asdf1asdf1asd23f1asdf1asdf4sd7fsdf1asdf1asd2f1asd56f7asdf4asdfasdf1"; +// +// private static final String P2_TRANSID = "987654321"; +// private static final String P2_eIDASID = +// "EE/AT/asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd"; +// +// @Test +// public void dummyTest() { +// +// } +// +// @Test +// public void insertTestOne() throws SQLiteServiceException, eIDASAuthenticationException { +// Trible<String, String, String> eidasId = eIDASResponseUtils.parseEidasPersonalIdentifier(P1_eIDASID); +// String ernbId = createHashFromUniqueId(eidasId.getThird()); +// dataStore.storeNationalId( +// P1_TRANSID, +// eidasId, +// ernbId); +// +// if (StringUtils.isEmpty(dataStore.getEidasRawNationalId(ernbId)) { +// && dataStore.getEidasRawNationalId(ernbId).equals(eidasId.getThird())) +// throw new SQLiteServiceException("No eIDAS RAW Id in SQLite DB", null); +// +// } +// +// if (StringUtils.isEmpty(dataStore.getErnbNationalId(eidasId)) { +// && dataStore.getErnbNationalId(eidasId).equals(ernbId)) +// throw new SQLiteServiceException("No ERnB Id in SQLite DB", null); +// } +// +// } +// +// @Test +// public void insertTestTwo() throws SQLiteServiceException, eIDASAuthenticationException { +// Trible<String, String, String> eidasId = eIDASResponseUtils.parseEidasPersonalIdentifier(P2_eIDASID); +// String ernbId = createHashFromUniqueId(eidasId.getThird()); +// dataStore.storeNationalId( +// P2_TRANSID, +// eidasId, +// ernbId); +// +// if (StringUtils.isEmpty(dataStore.getEidasRawNationalId(ernbId)) { +// && dataStore.getEidasRawNationalId(ernbId).equals(eidasId.getThird())) +// throw new SQLiteServiceException("No eIDAS RAW Id in SQLite DB", null); +// +// } +// +// if (StringUtils.isEmpty(dataStore.getErnbNationalId(eidasId)) { +// && dataStore.getErnbNationalId(eidasId).equals(ernbId)) +// throw new SQLiteServiceException("No ERnB Id in SQLite DB", null); +// +// } +// +// } +// +// private String createHashFromUniqueId(String uniqueId) throws eIDASAuthenticationException { +// try { +// MessageDigest md = MessageDigest.getInstance("SHA-256"); +// byte[] hash = md.digest(uniqueId.getBytes("UTF-8")); +// String hashBase64 = new String(Base64Utils.encode(hash), "UTF-8").replaceAll("\r\n", ""); +// return hashBase64; +// +// } catch (Exception ex) { +// throw new eIDASAuthenticationException("internal.03", new Object[] {}, ex); +// +// } +// } +//} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasSignalServletTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasSignalServletTest.java new file mode 100644 index 00000000..4d4ac47d --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasSignalServletTest.java @@ -0,0 +1,241 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummySpConfiguration; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.EidasSignalServlet; +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.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.storage.ITransactionStorage; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyProtocolAuthService; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import eu.eidas.auth.commons.EidasParameterKeys; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse.Builder; +import eu.eidas.auth.commons.tx.BinaryLightToken; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; + +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class EidasSignalServletTest { + + @Autowired private MsConnectorDummyConfigMap basicConfig; + @Autowired private EidasSignalServlet controller; + @Autowired private IRequestStorage storage; + @Autowired private ITransactionStorage transStore; + @Autowired private DummyProtocolAuthService protAuthService; + @Autowired private DummySpecificCommunicationService connector; + + + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private MsConnectorDummySpConfiguration oaParam; + + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException { + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + final Map<String, String> spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); + oaParam = new MsConnectorDummySpConfiguration(spConfig, basicConfig); + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH)); + pendingReq = new TestRequestImpl(); + + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + pendingReq.setTransactionId("avaasbav"); + pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + + connector.setiLightResponse(null); + + + } + + @Test + public void noResponsToken() throws IOException, EaafException { + //set-up + + //execute test + controller.restoreEidasAuthProcess(httpReq, httpResp); + + //validate state + Assert.assertNull("eIDAS response", httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertNotNull("missing error", protAuthService.getException()); + Assert.assertEquals("Wrong errorId", "auth.26", + ((EaafException) protAuthService.getException()).getErrorId()); + + } + + @Test + public void unknownResponseToken() throws IOException, EaafException { + //set-up + httpReq.setParameter(EidasParameterKeys.TOKEN.toString(), + RandomStringUtils.randomAlphanumeric(10)); + + //execute test + controller.restoreEidasAuthProcess(httpReq, httpResp); + + //validate state + Assert.assertNull("eIDAS response", httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertNotNull("missing error", protAuthService.getException()); + Assert.assertEquals("Wrong errorId", "auth.26", + ((EaafException) protAuthService.getException()).getErrorId()); + + } + + @Test + public void withRelayState() throws IOException, EaafException, SpecificCommunicationException { + //set-up + String relayState = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setPendingReqId(relayState); + storage.storePendingRequest(pendingReq); + + Builder iLightResponse = new AuthenticationResponse.Builder(); + iLightResponse.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(Constants.SUCCESS_URI) + .inResponseTo("_".concat(Random.nextHexRandom16())) + .subjectNameIdFormat("afaf") + .relayState(relayState); + + AuthenticationResponse eidasResp = iLightResponse.build(); + BinaryLightToken token = connector.putResponse(eidasResp); + httpReq.setParameter(EidasParameterKeys.TOKEN.toString(), + Base64.getEncoder().encodeToString(token.getTokenBytes())); + + + //execute test + controller.restoreEidasAuthProcess(httpReq, httpResp); + + + //validate state + Assert.assertNotNull("eIDAS response", httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertEquals("wrong eIDAS response", eidasResp, + httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + + Assert.assertNotNull("missing error", protAuthService.getException()); + Assert.assertEquals("Wrong errorId", "PendingRequest object is not of type 'RequestImpl.class'", + ((EaafException) protAuthService.getException()).getErrorId()); + + } + + @Test + public void withOutRelayStateMissingPendingReq() throws IOException, EaafException, SpecificCommunicationException { + //set-up + String pendingReqId = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setPendingReqId(pendingReqId); + storage.storePendingRequest(pendingReq); + + String inResponseTo = "_".concat(Random.nextHexRandom16()); + + Builder iLightResponse = new AuthenticationResponse.Builder(); + iLightResponse.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(Constants.SUCCESS_URI) + .inResponseTo(inResponseTo) + .subjectNameIdFormat("afaf"); + + AuthenticationResponse eidasResp = iLightResponse.build(); + BinaryLightToken token = connector.putResponse(eidasResp); + httpReq.setParameter(EidasParameterKeys.TOKEN.toString(), + Base64.getEncoder().encodeToString(token.getTokenBytes())); + + + //execute test + controller.restoreEidasAuthProcess(httpReq, httpResp); + + + //validate state + Assert.assertNull("eIDAS response", httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertNotNull("missing error", protAuthService.getException()); + Assert.assertEquals("Wrong errorId", "auth.26", + ((EaafException) protAuthService.getException()).getErrorId()); + + } + + @Test + public void withInResponseToElement() throws IOException, EaafException, SpecificCommunicationException { + //set-up + String pendingReqId = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setPendingReqId(pendingReqId); + storage.storePendingRequest(pendingReq); + + String inResponseTo = "_".concat(Random.nextHexRandom16()); + transStore.put(inResponseTo, pendingReqId, -1); + + Builder iLightResponse = new AuthenticationResponse.Builder(); + iLightResponse.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(Constants.SUCCESS_URI) + .inResponseTo(inResponseTo) + .subjectNameIdFormat("afaf"); + + AuthenticationResponse eidasResp = iLightResponse.build(); + BinaryLightToken token = connector.putResponse(eidasResp); + httpReq.setParameter(EidasParameterKeys.TOKEN.toString(), + Base64.getEncoder().encodeToString(token.getTokenBytes())); + + + //execute test + controller.restoreEidasAuthProcess(httpReq, httpResp); + + + //validate state + Assert.assertNotNull("eIDAS response", httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertEquals("wrong eIDAS response", eidasResp, + httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + + Assert.assertNotNull("missing error", protAuthService.getException()); + Assert.assertEquals("Wrong errorId", "PendingRequest object is not of type 'RequestImpl.class'", + ((EaafException) protAuthService.getException()).getErrorId()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ErnpRestClientProductionTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ErnpRestClientProductionTest.java new file mode 100644 index 00000000..66a426a1 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ErnpRestClientProductionTest.java @@ -0,0 +1,460 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients; + +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 org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.IfProfileValue; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.ErnpRestClient.ErnpRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.IErnpClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.DeSpecificDetailSearchProcessor; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest; +import lombok.SneakyThrows; + +@IfProfileValue(name = "spring.profiles.active", value = "devEnvironment") +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_realConfig.xml"}) +@TestPropertySource(locations = { + //"classpath:/application.properties", + "file:/home/tlenz/Projekte/config/ms_connector/default_config.properties", + }) +public class ErnpRestClientProductionTest { + + //private static final String TEST_PREFIX = "XXX_"; + private static final String TEST_PREFIX = ""; + + @Autowired IErnpClient client; + + @Test + @SneakyThrows + public void searchWithPersonalIdentifierServerError() { + String personalIdentifierFirst = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + personalIdentifierFirst = ""; + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-00") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchWithPersonIdentifier( + eidasDataFirst.getPseudonym(), eidasDataFirst.getCitizenCountryCode())); + + assertEquals("wrong errorCode", "module.eidasauth.matching.11", error.getErrorId()); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdentifierSuccess() { + final String personalIdentifierFirst = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("DOPISNÍ") + .givenName("DANA") + .dateOfBirth("1996-01-01") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + // execute operation + ErnpRegisterResult resp = client.searchWithPersonIdentifier( + eidasDataFirst.getPseudonym(), eidasDataFirst.getCitizenCountryCode()); + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + checkErnpResult(resp.getPersonResult().get(0), eidasDataFirst, 1); + assertEquals("wrong bpk", "vypyCkyczK7i+cgPWlJasuJphIA=", + resp.getPersonResult().get(0).getBpk()); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdentifierNoResult() { + final String personalIdentifierFirst = RandomStringUtils.randomAlphanumeric(10); + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("DOPISNÍ") + .givenName("DANA") + .dateOfBirth("1996-01-01") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + // execute operation + ErnpRegisterResult resp = client.searchWithPersonIdentifier( + eidasDataFirst.getPseudonym(), eidasDataFirst.getCitizenCountryCode()); + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 0, resp.getPersonResult().size()); + + } + + + @Test + @SneakyThrows + public void searchWithMdsSuccess() { + final String personalIdentifierFirst = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("DOPISNÍ") + .givenName("DANA") + .dateOfBirth("1996-01-01") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + // execute operation + ErnpRegisterResult resp = client.searchWithMds(eidasDataFirst.getGivenName(), eidasDataFirst.getFamilyName(), + eidasDataFirst.getDateOfBirth(), eidasDataFirst.getCitizenCountryCode()); + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + checkErnpResult(resp.getPersonResult().get(0), eidasDataFirst, 1); + assertEquals("wrong bpk", "vypyCkyczK7i+cgPWlJasuJphIA=", + resp.getPersonResult().get(0).getBpk()); + + } + + @Test + @SneakyThrows + public void searchWithMdsNoResult() { + final String personalIdentifierFirst = RandomStringUtils.randomAlphanumeric(10); + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName(RandomStringUtils.randomAlphanumeric(10)) + .givenName(RandomStringUtils.randomAlphanumeric(10)) + .dateOfBirth("1996-10-15") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + // execute operation + ErnpRegisterResult resp = client.searchWithMds(eidasDataFirst.getGivenName(), eidasDataFirst.getFamilyName(), + eidasDataFirst.getDateOfBirth(), eidasDataFirst.getCitizenCountryCode()); + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 0, resp.getPersonResult().size()); + + } + + @Test + @SneakyThrows + public void addTwiceSameMdsAndMdsSearch() { + // *** add new random first person *** + final String addFirstPersonPersonalIdentifier = RandomStringUtils.randomAlphanumeric(10); + final String cc = "XZ"; + final SimpleEidasData addFirstPersonData = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName(TEST_PREFIX + RandomStringUtils.randomAlphabetic(8)) + .givenName(TEST_PREFIX + RandomStringUtils.randomAlphabetic(8)) + .dateOfBirth("1996-01-01") + .personalIdentifier(cc + "/AT/" + addFirstPersonPersonalIdentifier) + .pseudonym(addFirstPersonPersonalIdentifier) + .build(); + + // add entry + ErnpRegisterResult addFirstPersonResponse = client.add(addFirstPersonData); + + // verify added entry + assertNotNull("no ERnP response", addFirstPersonResponse); + assertEquals("wrong resp size", 1, addFirstPersonResponse.getPersonResult().size()); + checkErnpResult(addFirstPersonResponse.getPersonResult().get(0), addFirstPersonData, 1); + + + // *** add new random second person with same MDS *** + final String addSecondPersonPersonalIdentifier = RandomStringUtils.randomAlphanumeric(10); + final SimpleEidasData addSecondPersonData = addFirstPersonData.toBuilder() + .personalIdentifier(cc + "/AT/" + addSecondPersonPersonalIdentifier) + .pseudonym(addSecondPersonPersonalIdentifier) + .build(); + + // add entry + ErnpRegisterResult addSecondPersonResponse = client.add(addSecondPersonData); + + // verify added entry + assertNotNull("no ERnP response", addSecondPersonResponse); + assertEquals("wrong resp size", 1, addSecondPersonResponse.getPersonResult().size()); + checkErnpResult(addSecondPersonResponse.getPersonResult().get(0), addSecondPersonData, 1); + + + + // search with MDS + ErnpRegisterResult resp = client.searchWithMds(addFirstPersonData.getGivenName(), addFirstPersonData.getFamilyName(), + addFirstPersonData.getDateOfBirth(), cc); + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 2, resp.getPersonResult().size()); + + } + + + + @Test + @SneakyThrows + public void addSearchAndPersonalIdUpdate() { + // *** add new random entry *** + + final String addPersonPersonalIdentifier = RandomStringUtils.randomAlphanumeric(10); + final String cc = "DE"; + final SimpleEidasData addPersonData = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName(TEST_PREFIX + RandomStringUtils.randomAlphabetic(8)) + .givenName(TEST_PREFIX + RandomStringUtils.randomAlphabetic(8)) + .dateOfBirth("1996-01-01") + .personalIdentifier(cc + "/AT/" + addPersonPersonalIdentifier) + .pseudonym(addPersonPersonalIdentifier) + .birthName(RandomStringUtils.randomAlphabetic(8)) + .placeOfBirth(RandomStringUtils.randomAlphabetic(8)) + .build(); + + // add entry + ErnpRegisterResult addPersonResponse = client.add(addPersonData); + + // verify added entry + assertNotNull("no ERnP response", addPersonResponse); + assertEquals("wrong resp size", 1, addPersonResponse.getPersonResult().size()); + checkErnpResult(addPersonResponse.getPersonResult().get(0), addPersonData, 1); + + + // *** search entry by countrySpecifics *** + final String ccPersonPersonalIdentifier = RandomStringUtils.randomAlphanumeric(10); + SimpleEidasData ccSpecificData = addPersonData.toBuilder() + .personalIdentifier(cc + "/AT/" + ccPersonPersonalIdentifier) + .pseudonym(ccPersonPersonalIdentifier) + .build(); + PersonSuchenRequest ccSearchReq = + new DeSpecificDetailSearchProcessor().generateSearchRequest(ccSpecificData); + + // search CC specific + ErnpRegisterResult ccSearchResponse = client.searchCountrySpecific(ccSearchReq, cc); + + // verify cc specific result + assertNotNull("no ERnP response", ccSearchResponse); + assertEquals("wrong resp size", 1, ccSearchResponse.getPersonResult().size()); + RegisterResult ccSearchPersResult = ccSearchResponse.getPersonResult().get(0); + checkErnpResult(ccSearchResponse.getPersonResult().get(0), addPersonData, 1); + assertEquals("wrong bPK", addPersonResponse.getPersonResult().get(0).getBpk(), + ccSearchPersResult.getBpk()); + assertFalse("no PersonalId change detected", ccSpecificData.equalsRegisterData(ccSearchPersResult)); + + + // *** update entry because PersonalId has changed *** + // update ERnP entry + ErnpRegisterResult updateResponse = client.update(ccSearchPersResult, ccSpecificData); + assertNotNull("no ERnP response", updateResponse); + assertEquals("wrong resp size", 1, updateResponse.getPersonResult().size()); + checkErnpResult(updateResponse.getPersonResult().get(0), addPersonData, 2); + assertEquals("wrong bPK", addPersonResponse.getPersonResult().get(0).getBpk(), ccSearchPersResult.getBpk()); + checkPersonalIdentifier(updateResponse.getPersonResult().get(0), addPersonPersonalIdentifier); + checkPersonalIdentifier(updateResponse.getPersonResult().get(0), ccPersonPersonalIdentifier); + + + + // *** search by first personalIdentifier + ErnpRegisterResult persIdSearchFirstResp = client.searchWithPersonIdentifier( + addPersonPersonalIdentifier, cc); + assertNotNull("no ERnP response", persIdSearchFirstResp); + assertEquals("wrong resp size", 1, persIdSearchFirstResp.getPersonResult().size()); + assertEquals("wrong bPK", addPersonResponse.getPersonResult().get(0).getBpk(), ccSearchPersResult.getBpk()); + checkPersonalIdentifier(updateResponse.getPersonResult().get(0), addPersonPersonalIdentifier); + checkPersonalIdentifier(updateResponse.getPersonResult().get(0), ccPersonPersonalIdentifier); + checkErnpResult(updateResponse.getPersonResult().get(0), addPersonData, 2); + + + + // *** search by second personalIdentifier + ErnpRegisterResult persIdSearchSecondResp = client.searchWithPersonIdentifier( + ccPersonPersonalIdentifier, cc); + assertNotNull("no ERnP response", persIdSearchSecondResp); + assertEquals("wrong resp size", 1, persIdSearchSecondResp.getPersonResult().size()); + assertEquals("wrong bPK", addPersonResponse.getPersonResult().get(0).getBpk(), ccSearchPersResult.getBpk()); + checkPersonalIdentifier(updateResponse.getPersonResult().get(0), addPersonPersonalIdentifier); + checkPersonalIdentifier(updateResponse.getPersonResult().get(0), ccPersonPersonalIdentifier); + checkErnpResult(updateResponse.getPersonResult().get(0), addPersonData, 2); + + } + + @Test + @SneakyThrows + public void addSearchAndMdsUpdate() { + // *** add new random entry *** + + final String addPersonPersonalIdentifier = RandomStringUtils.randomAlphanumeric(10); + final String cc = "DE"; + final SimpleEidasData addPersonData = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName(TEST_PREFIX + RandomStringUtils.randomAlphabetic(8)) + .givenName(TEST_PREFIX + RandomStringUtils.randomAlphabetic(8)) + .dateOfBirth("1985-05-05") + .personalIdentifier(cc + "/AT/" + addPersonPersonalIdentifier) + .pseudonym(addPersonPersonalIdentifier) + .birthName(RandomStringUtils.randomAlphabetic(8)) + .placeOfBirth(RandomStringUtils.randomAlphabetic(8)) + .build(); + + // add entry + ErnpRegisterResult addPersonResponse = client.add(addPersonData); + + // verify added entry + assertNotNull("no ERnP response", addPersonResponse); + assertEquals("wrong resp size", 1, addPersonResponse.getPersonResult().size()); + checkErnpResult(addPersonResponse.getPersonResult().get(0), addPersonData, 1); + + + // *** search entry by personalId *** + SimpleEidasData mdsHasChanged = addPersonData.toBuilder() + .givenName(RandomStringUtils.randomAlphanumeric(10)) + .familyName(RandomStringUtils.randomAlphanumeric(10)) + .build(); + + // search by personalId + ErnpRegisterResult personalIdResponse = client.searchWithPersonIdentifier(addPersonPersonalIdentifier, cc); + + // verify personalId result + assertNotNull("no ERnP response", personalIdResponse); + assertEquals("wrong resp size", 1, personalIdResponse.getPersonResult().size()); + RegisterResult persIdSearchResult = personalIdResponse.getPersonResult().get(0); + checkErnpResult(personalIdResponse.getPersonResult().get(0), addPersonData, 1); + assertEquals("wrong bPK", addPersonResponse.getPersonResult().get(0).getBpk(), + persIdSearchResult.getBpk()); + assertFalse("no MDS change detected", mdsHasChanged.equalsRegisterData(persIdSearchResult)); + + + // *** update entry because MDS has changed *** + // update ERnP entry + ErnpRegisterResult updateResponse = client.update(persIdSearchResult, mdsHasChanged); + assertNotNull("no ERnP response", updateResponse); + assertEquals("wrong resp size", 1, updateResponse.getPersonResult().size()); + checkErnpResult(updateResponse.getPersonResult().get(0), mdsHasChanged, 1); + assertEquals("wrong bPK", addPersonResponse.getPersonResult().get(0).getBpk(), persIdSearchResult.getBpk()); + checkPersonalIdentifier(updateResponse.getPersonResult().get(0), addPersonPersonalIdentifier); + + + // *** search by first personalIdentifier + ErnpRegisterResult persIdSearchFirstResp = client.searchWithPersonIdentifier( + addPersonPersonalIdentifier, cc); + assertNotNull("no ERnP response", persIdSearchFirstResp); + assertEquals("wrong resp size", 1, persIdSearchFirstResp.getPersonResult().size()); + assertEquals("wrong bPK", addPersonResponse.getPersonResult().get(0).getBpk(), persIdSearchResult.getBpk()); + checkPersonalIdentifier(updateResponse.getPersonResult().get(0), addPersonPersonalIdentifier); + checkErnpResult(updateResponse.getPersonResult().get(0), mdsHasChanged, 1); + + // *** search by first personalIdentifier + ErnpRegisterResult mdsSearchResp = client.searchWithMds( + mdsHasChanged.getGivenName(), mdsHasChanged.getFamilyName(), mdsHasChanged.getDateOfBirth(), cc); + assertNotNull("no ERnP response", mdsSearchResp); + assertEquals("wrong resp size", 1, mdsSearchResp.getPersonResult().size()); + assertEquals("wrong bPK", addPersonResponse.getPersonResult().get(0).getBpk(), persIdSearchResult.getBpk()); + checkPersonalIdentifier(updateResponse.getPersonResult().get(0), addPersonPersonalIdentifier); + checkErnpResult(updateResponse.getPersonResult().get(0), mdsHasChanged, 1); + + + + } + + + @Ignore + @Test + @SneakyThrows + public void addErnpEntry() { + final String personalIdentifierFirst = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("DOPISNÍ") + .givenName("DANA") + .dateOfBirth("1996-01-01") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + // execute operation + ErnpRegisterResult resp = client.add(eidasDataFirst); + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + checkErnpResult(resp.getPersonResult().get(0), eidasDataFirst, 1); + + } + + @Test + @SneakyThrows + public void addRandomErnpEntry() { + final String addPersonPersonalIdentifier = RandomStringUtils.randomAlphanumeric(10); + final String cc = "XZ"; + final SimpleEidasData addPersonData = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName(TEST_PREFIX + RandomStringUtils.randomAlphabetic(8)) + .givenName(TEST_PREFIX + RandomStringUtils.randomAlphabetic(8)) + .dateOfBirth("1985-05-05") + .personalIdentifier(cc + "/AT/" + addPersonPersonalIdentifier) + .pseudonym(addPersonPersonalIdentifier) + .birthName(RandomStringUtils.randomAlphabetic(8)) + .placeOfBirth(RandomStringUtils.randomAlphabetic(8)) + .build(); + + // add entry + ErnpRegisterResult addPersonResponse = client.add(addPersonData); + + // verify added entry + assertNotNull("no ERnP response", addPersonResponse); + assertEquals("wrong resp size", 1, addPersonResponse.getPersonResult().size()); + checkErnpResult(addPersonResponse.getPersonResult().get(0), addPersonData, 1); + + } + + + private void checkErnpResult(RegisterResult registerResult, final SimpleEidasData eidasData, int numOfPseudonyms) { + assertEquals("wrong familyname", eidasData.getFamilyName(), registerResult.getFamilyName()); + assertEquals("wrong givenname", eidasData.getGivenName(), registerResult.getGivenName()); + assertEquals("wrong birthday", eidasData.getDateOfBirth(), registerResult.getDateOfBirth()); + assertEquals("wrong personalId size", numOfPseudonyms, registerResult.getPseudonym().size()); + assertEquals("wrong placeOfBirth", eidasData.getPlaceOfBirth(), registerResult.getPlaceOfBirth()); + assertEquals("wrong birthName", eidasData.getBirthName(), registerResult.getBirthName()); + assertTrue("no bPK", StringUtils.isNotEmpty(registerResult.getBpk())); + checkPersonalIdentifier(registerResult, eidasData.getPseudonym()); + + } + + private void checkPersonalIdentifier(RegisterResult registerResult, String pseudonym) { + assertTrue("wrong or no personalId", registerResult.getPseudonym().stream() + .filter(el -> pseudonym.equals(el)) + .findFirst() + .isPresent()); + + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ErnpRestClientTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ErnpRestClientTest.java new file mode 100644 index 00000000..a9e10de6 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ErnpRestClientTest.java @@ -0,0 +1,1085 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.net.HttpURLConnection; +import java.util.Arrays; +import java.util.Iterator; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.ErnpRestClient.ErnpRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.IErnpClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.DeSpecificDetailSearchProcessor; +import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; +import lombok.SneakyThrows; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import okhttp3.mockwebserver.SocketPolicy; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" }) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public class ErnpRestClientTest { + + @Autowired MsConnectorDummyConfigMap basicConfig; + @Autowired IErnpClient client; + + private static ObjectMapper mapper = new ObjectMapper(); + private static MockWebServer mockWebServer; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + @SneakyThrows + public static void classInitializer() { + mockWebServer = new MockWebServer(); + mockWebServer.start(1718); + + } + + @AfterClass + @SneakyThrows + public static void resetTestEnviroment() { + mockWebServer.shutdown(); + + } + + /** + * jUnit test initializer. + * + * @throws InterruptedException in case of an error + */ + @Before + public void initialize() throws InterruptedException { + mockWebServer.takeRequest(2, TimeUnit.MILLISECONDS); + TransactionIdUtils.setTransactionId(UUID.randomUUID().toString()); + + } + + + @Test + @SneakyThrows + public void searchWithPersonalIdentifierServerError() { + final String personalIdentifierFirst = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(500) + .setBody("Internal error")); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchWithPersonIdentifier( + eidasDataFirst.getPseudonym(), eidasDataFirst.getCitizenCountryCode())); + + mockWebServer.takeRequest(); + assertEquals("wrong errorCode", "module.eidasauth.matching.11", error.getErrorId()); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdentifierSuccess() { + final String personalIdentifierFirst = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/ernp_handbook_example.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + + // execute operation + ErnpRegisterResult resp = client.searchWithPersonIdentifier( + eidasDataFirst.getPseudonym(), eidasDataFirst.getCitizenCountryCode()); + + // validate request + final RecordedRequest request = mockWebServer.takeRequest(); + String reqBody = request.getBody().readUtf8(); + assertFalse("no request body", reqBody.isEmpty()); + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + + + } + + @Test + @SneakyThrows + public void searchResidence() { + // execute operation + ErnpRegisterResult resp = client.searchWithResidenceData(null, null, null, null, null, null); + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 0, resp.getPersonResult().size()); + + } + + @Test + @SneakyThrows + public void searchWithMdsNoResponse() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + mockWebServer.enqueue(new MockResponse() + .setSocketPolicy(SocketPolicy.NO_RESPONSE) + .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchWithMds(eidasDataFirst.getGivenName(), eidasDataFirst.getFamilyName(), eidasDataFirst.getDateOfBirth(), cc)); + assertEquals("wrong errorCode", "module.eidasauth.matching.11", error.getErrorId()); + mockWebServer.takeRequest(); + + + } + + @Test + @SneakyThrows + public void searchWithMdsErrorResponse() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(400) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/error_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchWithMds(eidasDataFirst.getGivenName(), eidasDataFirst.getFamilyName(), eidasDataFirst.getDateOfBirth(), cc)); + assertEquals("wrong errorCode", "module.eidasauth.matching.11", error.getErrorId()); + mockWebServer.takeRequest(); + + } + + @Test + @SneakyThrows + public void searchWithMdsNoResult() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/ernp_empty_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + ErnpRegisterResult resp = client.searchWithMds(eidasDataFirst.getGivenName(), eidasDataFirst.getFamilyName(), eidasDataFirst.getDateOfBirth(), cc); + + // validate request + final RecordedRequest request = mockWebServer.takeRequest(); + String reqBody = request.getBody().readUtf8(); + assertFalse("no request body", reqBody.isEmpty()); + JsonNode reqJson = mapper.readTree(reqBody); + checkSearchOptions(reqJson, "Searching with MDS only"); + JsonNode person = getJsonObject(reqJson, "suchdaten"); + checkJsonElement(person, "familienname", eidasDataFirst.getFamilyName()); + checkJsonElement(person, "vorname", eidasDataFirst.getGivenName()); + checkPersonDateOfBirth(person, eidasDataFirst.getDateOfBirth()); + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 0, resp.getPersonResult().size()); + + } + + @Test + @SneakyThrows + public void searchWithMdsSingleResult() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/3_search_with_mds_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + ErnpRegisterResult resp = client.searchWithMds(eidasDataFirst.getGivenName(), eidasDataFirst.getFamilyName(), eidasDataFirst.getDateOfBirth(), cc); + + // validate state + mockWebServer.takeRequest(); + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("wrong familyname", "DOPISNÍ", persInfo.getFamilyName()); + assertEquals("wrong givenName", "DANA", persInfo.getGivenName()); + assertEquals("wrong dateOfBirth", "1996-01-01", persInfo.getDateOfBirth()); + assertEquals("wrong bpk", "vypyCkyczK7i+cgPWlJasuJphIA=", persInfo.getBpk()); + assertEquals("wrong pseudonym", "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", persInfo.getPseudonym().get(0)); + assertNull("placeOfBirth", persInfo.getPlaceOfBirth()); + assertNull("birthName", persInfo.getBirthName()); + + } + + @Test + @SneakyThrows + public void searchWithMdsMultiResult() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/4_search_with_mds_multi_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + ErnpRegisterResult resp = client.searchWithMds(eidasDataFirst.getGivenName(), eidasDataFirst.getFamilyName(), eidasDataFirst.getDateOfBirth(), cc); + + // validate state + mockWebServer.takeRequest(); + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 2, resp.getPersonResult().size()); + + } + + + @Test + @SneakyThrows + public void searchWithPersonalIdNoResponse() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + mockWebServer.enqueue(new MockResponse() + .setSocketPolicy(SocketPolicy.NO_RESPONSE) + .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchWithPersonIdentifier(eidasDataFirst.getPseudonym(), cc)); + assertEquals("wrong errorCode", "module.eidasauth.matching.11", error.getErrorId()); + mockWebServer.takeRequest(); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdErrorResponse() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(400) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/error_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchWithPersonIdentifier(eidasDataFirst.getPseudonym(), cc)); + assertEquals("wrong errorCode", "module.eidasauth.matching.11", error.getErrorId()); + mockWebServer.takeRequest(); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdNoResult() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/ernp_empty_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + ErnpRegisterResult resp = client.searchWithPersonIdentifier(eidasDataFirst.getPseudonym(), cc); + + // validate request + final RecordedRequest request = mockWebServer.takeRequest(); + String reqBody = request.getBody().readUtf8(); + assertFalse("no request body", reqBody.isEmpty()); + JsonNode reqJson = mapper.readTree(reqBody); + checkSearchOptions(reqJson, "Searching PersonIdentifier"); + JsonNode person = getJsonObject(reqJson, "suchdaten"); + checkEidasDocument(person, "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", cc, eidasDataFirst.getPseudonym()); + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 0, resp.getPersonResult().size()); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdSingleResult() { + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/1_search_with_personalId_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + ErnpRegisterResult resp = client.searchWithPersonIdentifier(eidasDataFirst.getPseudonym(), cc); + + // validate state + mockWebServer.takeRequest(); + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("wrong familyname", "CtKKrtUe", persInfo.getFamilyName()); + assertEquals("wrong givenName", "dUeYzUFg", persInfo.getGivenName()); + assertEquals("wrong dateOfBirth", "1985-05-05", persInfo.getDateOfBirth()); + assertEquals("wrong bpk", "+OQnljn0Son1W2rkM73nP/VMsvc=", persInfo.getBpk()); + assertEquals("wrong pseudonym", "Y8ADWaeh0h", persInfo.getPseudonym().get(0)); + assertEquals("wrong placeOfBirth", "hrFevCfP", persInfo.getPlaceOfBirth()); + assertEquals("wrong birthName", "sNUEAhEr", persInfo.getBirthName()); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdSingleResultCountryNoMatch() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/1_search_with_personalId_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + ErnpRegisterResult resp = client.searchWithPersonIdentifier(eidasDataFirst.getPseudonym(), cc); + + // validate state + mockWebServer.takeRequest(); + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("wrong familyname", "CtKKrtUe", persInfo.getFamilyName()); + assertEquals("wrong givenName", "dUeYzUFg", persInfo.getGivenName()); + assertEquals("wrong dateOfBirth", "1985-05-05", persInfo.getDateOfBirth()); + assertEquals("wrong bpk", "+OQnljn0Son1W2rkM73nP/VMsvc=", persInfo.getBpk()); + assertTrue("pseudonym", persInfo.getPseudonym().isEmpty()); + assertNull("placeOfBirth", persInfo.getPlaceOfBirth()); + assertNull("birthName", persInfo.getBirthName()); + + } + + + @Test + @SneakyThrows + public void searchWithPersonalIdMultiResult() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/4_search_with_mds_multi_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchWithPersonIdentifier(eidasDataFirst.getPseudonym(), cc)); + assertEquals("wrong errorCode", "module.eidasauth.matching.03", error.getErrorId()); + mockWebServer.takeRequest(); + + } + + + @Test + @SneakyThrows + public void searchWithCcspecificsNoResponse() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + mockWebServer.enqueue(new MockResponse() + .setSocketPolicy(SocketPolicy.NO_RESPONSE) + .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchCountrySpecific(new DeSpecificDetailSearchProcessor().generateSearchRequest(eidasDataFirst), cc)); + assertEquals("wrong errorCode", "module.eidasauth.matching.11", error.getErrorId()); + mockWebServer.takeRequest(); + + } + + @Test + @SneakyThrows + public void searchWithCcspecificsErrorResponse() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(400) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/error_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchCountrySpecific(new DeSpecificDetailSearchProcessor().generateSearchRequest(eidasDataFirst), cc)); + assertEquals("wrong errorCode", "module.eidasauth.matching.11", error.getErrorId()); + mockWebServer.takeRequest(); + + } + + @Test + @SneakyThrows + public void searchWithCcspecificsNoResult() { + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc).toBuilder() + .birthName(RandomStringUtils.randomAlphabetic(5)) + .placeOfBirth(RandomStringUtils.randomAlphabetic(5)) + .build(); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/ernp_empty_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + ErnpRegisterResult resp = client.searchCountrySpecific( + new DeSpecificDetailSearchProcessor().generateSearchRequest(eidasDataFirst), cc); + + // validate request + final RecordedRequest request = mockWebServer.takeRequest(); + String reqBody = request.getBody().readUtf8(); + assertFalse("no request body", reqBody.isEmpty()); + JsonNode reqJson = mapper.readTree(reqBody); + checkSearchOptions(reqJson, "Searching DE specific"); + JsonNode person = getJsonObject(reqJson, "suchdaten"); + checkJsonElement(person, "familienname", eidasDataFirst.getFamilyName()); + checkJsonElement(person, "vorname", eidasDataFirst.getGivenName()); + checkPersonDateOfBirth(person, eidasDataFirst.getDateOfBirth()); + checkEidasDocument(person, "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", cc, eidasDataFirst.getPlaceOfBirth()); + checkEidasDocument(person, "http://eidas.europa.eu/attributes/naturalperson/BirthName", cc, eidasDataFirst.getBirthName()); + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 0, resp.getPersonResult().size()); + + } + + @Test + @SneakyThrows + public void searchWithCcspecificsSingleResult() { + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/1_search_with_personalId_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + ErnpRegisterResult resp = client.searchCountrySpecific( + new DeSpecificDetailSearchProcessor().generateSearchRequest(eidasDataFirst), cc); + + // validate state + mockWebServer.takeRequest(); + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("wrong familyname", "CtKKrtUe", persInfo.getFamilyName()); + assertEquals("wrong givenName", "dUeYzUFg", persInfo.getGivenName()); + assertEquals("wrong dateOfBirth", "1985-05-05", persInfo.getDateOfBirth()); + assertEquals("wrong bpk", "+OQnljn0Son1W2rkM73nP/VMsvc=", persInfo.getBpk()); + assertEquals("wrong pseudonym", "Y8ADWaeh0h", persInfo.getPseudonym().get(0)); + assertEquals("wrong placeOfBirth", "hrFevCfP", persInfo.getPlaceOfBirth()); + assertEquals("wrong birthName", "sNUEAhEr", persInfo.getBirthName()); + + } + + @Test + @SneakyThrows + public void searchWithCcspecificsSingleResultCountryNoMatch() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/1_search_with_personalId_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + ErnpRegisterResult resp = client.searchCountrySpecific( + new DeSpecificDetailSearchProcessor().generateSearchRequest(eidasDataFirst), cc); + + // validate state + mockWebServer.takeRequest(); + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("wrong familyname", "CtKKrtUe", persInfo.getFamilyName()); + assertEquals("wrong givenName", "dUeYzUFg", persInfo.getGivenName()); + assertEquals("wrong dateOfBirth", "1985-05-05", persInfo.getDateOfBirth()); + assertEquals("wrong bpk", "+OQnljn0Son1W2rkM73nP/VMsvc=", persInfo.getBpk()); + assertTrue("pseudonym", persInfo.getPseudonym().isEmpty()); + assertNull("placeOfBirth", persInfo.getPlaceOfBirth()); + assertNull("birthName", persInfo.getBirthName()); + + } + + + @Test + @SneakyThrows + public void searchWithCcspecificsMultiResult() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/4_search_with_mds_multi_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchCountrySpecific(new DeSpecificDetailSearchProcessor().generateSearchRequest(eidasDataFirst), cc)); + assertEquals("wrong errorCode", "module.eidasauth.matching.03", error.getErrorId()); + mockWebServer.takeRequest(); + + } + + + @Test + @SneakyThrows + public void addPersonNoResponse() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + mockWebServer.enqueue(new MockResponse() + .setSocketPolicy(SocketPolicy.NO_RESPONSE) + .setResponseCode(HttpURLConnection.HTTP_NO_CONTENT)); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.add(eidasDataFirst)); + assertEquals("wrong errorCode", "module.eidasauth.matching.11", error.getErrorId()); + mockWebServer.takeRequest(); + + } + + @Test + @SneakyThrows + public void addPersonSimpleSuccess() { + final String cc = "CZ"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/2_add_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + // execute operation + ErnpRegisterResult resp = client.add(eidasDataFirst); + + // validate request + final RecordedRequest request = mockWebServer.takeRequest(); + String reqBody = request.getBody().readUtf8(); + assertFalse("no request body", reqBody.isEmpty()); + JsonNode reqJson = mapper.readTree(reqBody); + checkJsonElement(reqJson, "begruendung", "Add new person"); + JsonNode person = getJsonObject(reqJson, "personendaten"); + checkJsonElement(person, "familienname", eidasDataFirst.getFamilyName()); + checkJsonElement(person, "vorname", eidasDataFirst.getGivenName()); + checkPersonDateOfBirth(person, eidasDataFirst.getDateOfBirth()); + checkEidasDocument(reqJson, "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", cc, eidasDataFirst.getPseudonym()); + checkEidasDocument(reqJson, "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", cc); + checkEidasDocument(reqJson, "http://eidas.europa.eu/attributes/naturalperson/BirthName", cc); + + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("wrong familyname", "mRjMKAQc", persInfo.getFamilyName()); + assertEquals("wrong givenName", "vdqZZIaA", persInfo.getGivenName()); + assertEquals("wrong dateOfBirth", "1996-01-01", persInfo.getDateOfBirth()); + assertEquals("wrong bpk", "TBGoMlirU881e2jMGETa9WLx1+A=", persInfo.getBpk()); + + } + + @Test + @SneakyThrows + public void addPersonSimpleComplexe() { + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc).toBuilder() + .birthName(RandomStringUtils.randomAlphabetic(5)) + .placeOfBirth(RandomStringUtils.randomAlphabetic(5)) + .build(); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/2_add_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute operation + // execute operation + ErnpRegisterResult resp = client.add(eidasDataFirst); + + // validate request + final RecordedRequest request = mockWebServer.takeRequest(); + String reqBody = request.getBody().readUtf8(); + assertFalse("no request body", reqBody.isEmpty()); + JsonNode reqJson = mapper.readTree(reqBody); + checkJsonElement(reqJson, "begruendung", "Add new person"); + JsonNode person = getJsonObject(reqJson, "personendaten"); + checkJsonElement(person, "familienname", eidasDataFirst.getFamilyName()); + checkJsonElement(person, "vorname", eidasDataFirst.getGivenName()); + checkPersonDateOfBirth(person, eidasDataFirst.getDateOfBirth()); + checkEidasDocument(reqJson, "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", cc, eidasDataFirst.getPseudonym()); + checkEidasDocument(reqJson, "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", cc, eidasDataFirst.getPlaceOfBirth()); + checkEidasDocument(reqJson, "http://eidas.europa.eu/attributes/naturalperson/BirthName", cc, eidasDataFirst.getBirthName()); + + // validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("wrong familyname", "mRjMKAQc", persInfo.getFamilyName()); + assertEquals("wrong givenName", "vdqZZIaA", persInfo.getGivenName()); + assertEquals("wrong dateOfBirth", "1996-01-01", persInfo.getDateOfBirth()); + assertEquals("wrong bpk", "TBGoMlirU881e2jMGETa9WLx1+A=", persInfo.getBpk()); + assertEquals("wrong pseudonym", "88hvWzUaIX", persInfo.getPseudonym().get(0)); + assertEquals("wrong placeOfBirth", "VRNCAylF", persInfo.getPlaceOfBirth()); + assertEquals("wrong birthName", "miEklFHC", persInfo.getBirthName()); + + } + + @Test + @SneakyThrows + public void updateNoLatestVersion() { + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = generateRandomEidasData(cc).toBuilder() + .birthName(RandomStringUtils.randomAlphabetic(5)) + .placeOfBirth(RandomStringUtils.randomAlphabetic(5)) + .build(); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/ernp_empty_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + RegisterResult ernpResult = RegisterResult.builder() + .familyName(eidasDataFirst.getFamilyName()) + .givenName(eidasDataFirst.getGivenName()) + .dateOfBirth(eidasDataFirst.getDateOfBirth()) + .bpk("") + .pseudonym(Arrays.asList(eidasDataFirst.getPseudonym())) + .build(); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.update(ernpResult, eidasDataFirst)); + assertEquals("wrong errorCode", "module.eidasauth.matching.03", error.getErrorId()); + mockWebServer.takeRequest(); + + + } + + + @Test + @SneakyThrows + public void updateNoUpdateRequired() { + final String cc = "DE"; + final String personalIdentifierFirst = "Y8ADWaeh0h"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("CtKKrtUe") + .givenName("dUeYzUFg") + .dateOfBirth("1985-05-05") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/1_kitt_search_latest_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + RegisterResult ernpResult = RegisterResult.builder() + .familyName(eidasDataFirst.getFamilyName()) + .givenName(eidasDataFirst.getGivenName()) + .dateOfBirth(eidasDataFirst.getDateOfBirth()) + .bpk("+OQnljn0Son1W2rkM73nP/VMsvc=") + .pseudonym(Arrays.asList(eidasDataFirst.getPseudonym())) + .birthName("sNUEAhEr") + .placeOfBirth("hrFevCfP") + .build(); + + // execute operation + ErnpRegisterResult resp = client.update(ernpResult, eidasDataFirst); + + // validate request + final RecordedRequest request = mockWebServer.takeRequest(); + String reqBody = request.getBody().readUtf8(); + assertFalse("no request body", reqBody.isEmpty()); + JsonNode reqJson = mapper.readTree(reqBody); + checkSearchOptions(reqJson, "KITT get-latest-version"); + JsonNode person = getJsonObject(reqJson, "suchdaten"); + checkJsonElement(person, "familienname", ernpResult.getFamilyName()); + checkJsonElement(person, "vorname", ernpResult.getGivenName()); + checkJsonElement(person, "bpkZp", ernpResult.getBpk()); + checkPersonDateOfBirth(person, ernpResult.getDateOfBirth()); + + //validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("wrong familyname", ernpResult.getFamilyName(), persInfo.getFamilyName()); + assertEquals("wrong givenName", ernpResult.getGivenName(), persInfo.getGivenName()); + assertEquals("wrong dateOfBirth", ernpResult.getDateOfBirth(), persInfo.getDateOfBirth()); + assertEquals("wrong bpk", ernpResult.getBpk(), persInfo.getBpk()); + assertEquals("wrong pseudonym", ernpResult.getPseudonym().get(0), persInfo.getPseudonym().get(0)); + assertEquals("wrong placeOfBirth", "hrFevCfP", persInfo.getPlaceOfBirth()); + assertEquals("wrong birthName", "sNUEAhEr", persInfo.getBirthName()); + + } + + @Test + @SneakyThrows + public void updateUpdateRequiredMds() { + final String cc = "DE"; + final String personalIdentifierFirst = "Y8ADWaeh0h"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("mVzTMpig6r") + .givenName("Jb2vj1Xpql") + .dateOfBirth("1985-05-05") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .placeOfBirth("hrFevCfP") + .birthName("sNUEAhEr") + .build(); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/1_kitt_search_latest_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/1_kitt_update_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + RegisterResult ernpResult = RegisterResult.builder() + .familyName("CtKKrtUe") + .givenName("dUeYzUFg") + .dateOfBirth("1985-05-05") + .bpk("+OQnljn0Son1W2rkM73nP/VMsvc=") + .pseudonym(Arrays.asList("Y8ADWaeh0h")) + .birthName("sNUEAhEr") + .placeOfBirth("hrFevCfP") + .build(); + + // execute operation + ErnpRegisterResult resp = client.update(ernpResult, eidasDataFirst); + + // validate request + // check get-latest-version request + final RecordedRequest request = mockWebServer.takeRequest(); + String reqBody = request.getBody().readUtf8(); + assertFalse("no request body", reqBody.isEmpty()); + JsonNode reqJson = mapper.readTree(reqBody); + checkSearchOptions(reqJson, "KITT get-latest-version"); + JsonNode person = getJsonObject(reqJson, "suchdaten"); + checkJsonElement(person, "familienname", ernpResult.getFamilyName()); + checkJsonElement(person, "vorname", ernpResult.getGivenName()); + checkJsonElement(person, "bpkZp", ernpResult.getBpk()); + checkPersonDateOfBirth(person, ernpResult.getDateOfBirth()); + + // check update request + final RecordedRequest requestKitt = mockWebServer.takeRequest(); + String reqBodyKitt = requestKitt.getBody().readUtf8(); + assertFalse("no request body", reqBodyKitt.isEmpty()); + JsonNode reqJsonKitt = mapper.readTree(reqBodyKitt); + checkJsonElement(reqJsonKitt, "begruendung", "KITT update dataset"); + checkJsonElement(reqJsonKitt, "entityId", "1933000000000475"); + checkJsonElement(reqJsonKitt, "version", "2022-03-03T10:07:28.885Z"); + JsonNode personChange = getJsonObject(reqJsonKitt, "aendern"); + JsonNode personKitt = getJsonObject(personChange, "personendaten"); + checkJsonElement(personKitt, "familienname", eidasDataFirst.getFamilyName()); + checkJsonElement(personKitt, "vorname", eidasDataFirst.getGivenName()); + checkPersonDateOfBirth(personKitt, eidasDataFirst.getDateOfBirth()); + + assertFalse("find 'aendern' element", reqJsonKitt.has("anlegen")); + assertFalse("find 'aendern' element", personChange.has("eidas")); + + + //validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("wrong familyname", eidasDataFirst.getFamilyName(), persInfo.getFamilyName()); + assertEquals("wrong givenName", eidasDataFirst.getGivenName(), persInfo.getGivenName()); + assertEquals("wrong dateOfBirth", ernpResult.getDateOfBirth(), persInfo.getDateOfBirth()); + assertEquals("wrong bpk", ernpResult.getBpk(), persInfo.getBpk()); + assertEquals("wrong pseudonym", ernpResult.getPseudonym().get(0), persInfo.getPseudonym().get(0)); + assertEquals("wrong placeOfBirth", "hrFevCfP", persInfo.getPlaceOfBirth()); + assertEquals("wrong birthName", "sNUEAhEr", persInfo.getBirthName()); + + } + + @Test + @SneakyThrows + public void updateUpdateRequiredEidasDocs() { + final String cc = "DE"; + final String personalIdentifierFirst = "nj1m79jm9z"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("mRjMKAQc") + .givenName("vdqZZIaA") + .dateOfBirth("1996-01-01") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .birthName(RandomStringUtils.randomAlphabetic(10)) + .build(); + + // set ERnP response + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/2_kitt_search_latest_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/2_kitt_update_resp.json"), + "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + RegisterResult ernpResult = RegisterResult.builder() + .familyName("mRjMKAQc") + .givenName("vdqZZIaA") + .dateOfBirth("1996-01-01") + .bpk("TBGoMlirU881e2jMGETa9WLx1+A=") + .pseudonym(Arrays.asList("88hvWzUaIX")) + .birthName("VRNCAylF") + .placeOfBirth("miEklFHC") + .build(); + + // execute operation + ErnpRegisterResult resp = client.update(ernpResult, eidasDataFirst); + + // validate request + // check get-latest-version request + final RecordedRequest request = mockWebServer.takeRequest(); + String reqBody = request.getBody().readUtf8(); + assertFalse("no request body", reqBody.isEmpty()); + JsonNode reqJson = mapper.readTree(reqBody); + checkSearchOptions(reqJson, "KITT get-latest-version"); + JsonNode person = getJsonObject(reqJson, "suchdaten"); + checkJsonElement(person, "familienname", ernpResult.getFamilyName()); + checkJsonElement(person, "vorname", ernpResult.getGivenName()); + checkJsonElement(person, "bpkZp", ernpResult.getBpk()); + checkPersonDateOfBirth(person, ernpResult.getDateOfBirth()); + + // check update request + final RecordedRequest requestKitt = mockWebServer.takeRequest(); + String reqBodyKitt = requestKitt.getBody().readUtf8(); + assertFalse("no request body", reqBodyKitt.isEmpty()); + JsonNode reqJsonKitt = mapper.readTree(reqBodyKitt); + checkJsonElement(reqJsonKitt, "begruendung", "KITT update dataset"); + checkJsonElement(reqJsonKitt, "entityId", "1933000000000498"); + checkJsonElement(reqJsonKitt, "version", "2022-03-03T10:14:59.712Z"); + JsonNode personChange = getJsonObject(reqJsonKitt, "anlegen"); + checkEidasDocument(personChange, "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", cc, eidasDataFirst.getPseudonym()); + assertFalse("find 'aendern' element", reqJsonKitt.has("aendern")); + + //validate state + assertNotNull("no ERnP response", resp); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("wrong familyname", eidasDataFirst.getFamilyName(), persInfo.getFamilyName()); + assertEquals("wrong givenName", eidasDataFirst.getGivenName(), persInfo.getGivenName()); + assertEquals("wrong dateOfBirth", ernpResult.getDateOfBirth(), persInfo.getDateOfBirth()); + assertEquals("wrong bpk", ernpResult.getBpk(), persInfo.getBpk()); + assertEquals("wrong pseudonym", ernpResult.getPseudonym().get(0), persInfo.getPseudonym().get(0)); + assertEquals("wrong pseudonym", eidasDataFirst.getPseudonym(), persInfo.getPseudonym().get(1)); + assertEquals("wrong placeOfBirth", "VRNCAylF", persInfo.getPlaceOfBirth()); + assertEquals("wrong birthName", "miEklFHC", persInfo.getBirthName()); + + } + + + private SimpleEidasData generateRandomEidasData(String cc) { + final String personalIdentifierFirst = RandomStringUtils.randomAlphanumeric(10); + return SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName(RandomStringUtils.randomAlphanumeric(10)) + .givenName(RandomStringUtils.randomAlphanumeric(10)) + .dateOfBirth("1996-10-15") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + } + + private void checkEidasDocument(JsonNode person, String art, String cc, String expected) { + assertTrue("no element: eidas", person.has("eidas")); + assertTrue("wrong type element: eidas", person.get("eidas").isArray()); + + boolean found = false; + Iterator<JsonNode> docs = person.get("eidas").elements(); + while (docs.hasNext() && !found) { + JsonNode el = docs.next(); + assertTrue("art", el.has("art")); + assertTrue("wert", el.has("wert")); + assertTrue("cc", el.has("staatscode2")); + found = art.equals(el.get("art").asText()) && cc.equals(el.get("staatscode2").asText()) + && expected.equals(el.get("wert").asText()); + + } + assertTrue("Missing eidas document", found); + + } + + private void checkEidasDocument(JsonNode person, String art, String cc) { + assertTrue("no element: eidas", person.has("eidas")); + assertTrue("wrong type element: eidas", person.get("eidas").isArray()); + + boolean found = false; + Iterator<JsonNode> docs = person.get("eidas").elements(); + while (docs.hasNext() && !found) { + JsonNode el = docs.next(); + assertTrue("art", el.has("art")); + assertTrue("wert", el.has("wert")); + assertTrue("cc", el.has("staatscode2")); + found = art.equals(el.get("art").asText()) && cc.equals(el.get("staatscode2").asText()); + + } + assertFalse("Missing eidas document", found); + + } + + private void checkPersonDateOfBirth(JsonNode person, String dateOfBirth) { + JsonNode birthDay = getJsonObject(person, "geburtsdatum"); + String[] el = dateOfBirth.split("-"); + checkJsonElement(birthDay, "jahr", Integer.parseInt(el[0])); + checkJsonElement(birthDay, "monat", Integer.parseInt(el[1])); + checkJsonElement(birthDay, "tag", Integer.parseInt(el[2])); + + } + + private void checkSearchOptions(JsonNode json, String reason) { + checkJsonElement(json, "begruendung", reason); + JsonNode options = getJsonObject(json, "suchoptionen"); + checkJsonElement(options, "historisch", "AktuellUndHistorisch"); + checkJsonElement(options, "sucheMitNamensteilen", false); + checkJsonElement(options, "suchwizard", false); + checkJsonElement(options, "zmr", false); + + } + + private JsonNode getJsonObject(JsonNode json, String key) { + assertTrue("no element: " + key, json.has(key)); + assertTrue("wrong type element: " + key, json.get(key).isObject()); + return json.get(key); + + } + + private void checkJsonElement(JsonNode json, String key, int expected) { + assertTrue("no element: " + key, json.has(key)); + assertTrue("wong element-type: " + key, json.get(key).isInt()); + assertEquals("wong element-value: " + key, expected, json.get(key).asInt()); + + } + + private void checkJsonElement(JsonNode json, String key, String expected) { + assertTrue("no element: " + key, json.has(key)); + assertTrue("wong element-type: " + key, json.get(key).isTextual()); + assertEquals("wong element-value: " + key, expected, json.get(key).asText()); + + } + + private void checkJsonElement(JsonNode json, String key, boolean expected) { + assertTrue("no element: " + key, json.has(key)); + assertTrue("wong element-type: " + key, json.get(key).isBoolean()); + assertEquals("wong element-value: " + key, expected, json.get(key).asBoolean()); + + } + + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/SzrClientProductionTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/SzrClientProductionTest.java new file mode 100644 index 00000000..fb52a729 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/SzrClientProductionTest.java @@ -0,0 +1,116 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients; + +import java.util.List; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Base64; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.IfProfileValue; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.szr.SzrClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; + + +@IfProfileValue(name = "spring.profiles.active", value = "devEnvironment") +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_realConfig.xml"}) +@TestPropertySource(locations = { + //"classpath:/application.properties", + "file:/home/tlenz/Projekte/config/ms_connector/default_config.properties", + }) +public class SzrClientProductionTest { + private static final Logger log = LoggerFactory.getLogger(SzrClientProductionTest.class); + + @Autowired + SzrClient szrClient; + @Autowired + IConfiguration basicConfig; + + private static final String DUMMY_TARGET = EaafConstants.URN_PREFIX_CDID + "ZP"; + + @Test + public void dummyTest() { + + } + + @Test + public void getEidasBind() throws EidasSAuthenticationException { + String vsz = RandomStringUtils.randomAlphanumeric(10); + String bindingPubKey = Base64.toBase64String(RandomStringUtils.random(20).getBytes()); + String eidStatus = "urn:eidgvat:eid.status.eidas"; + + String eidasBind = szrClient.getEidasBind(vsz, bindingPubKey, eidStatus, getEidData()); + + Assert.assertNotNull("eidasBind", eidasBind); + + } + + @Ignore + @Test + public void getBpkTest() throws EidasSAuthenticationException { + String vkz = basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ, "no VKZ defined"); + final List<String> bPK = szrClient.getBpk(getEidData(), DUMMY_TARGET, vkz); + + if (bPK.isEmpty()) { + throw new SzrCommunicationException("ernb.01", new Object[]{"bPK list is empty"}); + } + for (String b : bPK) { + if (StringUtils.isEmpty(b)) { + throw new SzrCommunicationException("ernb.01", new Object[]{"bPK is null or empty"}); + } + } + + } + + private SimpleEidasData getEidData() { + return SimpleEidasData.builder() + .familyName("Mustermann") + .givenName("Franz") + .dateOfBirth("1989-05-04") + .citizenCountryCode("IS") + .pseudonym("1234ffgsdfg56789ABCDEF") + .build(); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/SzrClientTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/SzrClientTest.java new file mode 100644 index 00000000..e61532a3 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/SzrClientTest.java @@ -0,0 +1,284 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.util.List; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.cxf.binding.soap.SoapFault; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import com.github.skjolber.mockito.soap.SoapServiceRule; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.szr.SzrClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import lombok.extern.slf4j.Slf4j; +import szrservices.GetIdentityLinkEidasResponse; +import szrservices.PersonInfoType; +import szrservices.SZR; +import szrservices.SZRException_Exception; +import szrservices.SignContentEntry; +import szrservices.SignContentResponse; +import szrservices.SignContentResponseType; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +@Slf4j +public class SzrClientTest { + + @Autowired SzrClient szrClient; + @Autowired MsConnectorDummyConfigMap basicConfig; + + private static final String DUMMY_TARGET = EaafConstants.URN_PREFIX_CDID + "ZP"; + + private SZR szrMock = null; + + @Rule + public SoapServiceRule soap = SoapServiceRule.newInstance(); + + /** + * Initialize jUnit test. + */ + @Before + public void initializer() { + if (szrMock == null) { + szrMock = soap.mock(SZR.class, "http://localhost:1234/demoszr"); + } + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.eidasbind.mds.inject", "false"); + + } + + @Test + public void getEidasBindRealSzrResponse() throws SZRException_Exception, SzrCommunicationException, IOException { + final SignContentResponse szrResponse = new SignContentResponse(); + final SignContentEntry result1 = new SignContentEntry(); + final SignContentResponseType content = new SignContentResponseType(); + content.getOut().add(result1); + szrResponse.setSignContentResponse(content); + + result1.setKey("bcBindReq"); + result1.setValue(IOUtils.toString(SzrClient.class.getResourceAsStream("/data/szr/signed_eidasBind.jws"))); + + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content); + + final String bcBind = szrClient + .getEidasBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), getEidData()); + + Assert.assertNotNull("bcBind is null", bcBind); + Assert.assertEquals("bcBind not match", result1.getValue(), bcBind); + + } + + @Test + public void eidasBindNull() throws SZRException_Exception { + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(null); + + try { + szrClient + .getEidasBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), getEidData()); + } catch (SzrCommunicationException e) { + Assert.assertTrue("Not correct error", e.getMessage().contains("ernb.01")); + + } + } + + @Test + public void eidasBindInvalidResponse() throws SZRException_Exception { + final SignContentEntry result2 = new SignContentEntry(); + final SignContentResponseType content1 = new SignContentResponseType(); + content1.getOut().add(result2); + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content1); + + try { + szrClient + .getEidasBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), getEidData()); + } catch (SzrCommunicationException e) { + Assert.assertTrue("Not correct error", e.getMessage().contains("ernb.01")); + + } + } + + public void eidasBindEmptyResponse() throws SZRException_Exception { + final SignContentEntry result2 = new SignContentEntry(); + final SignContentResponseType content1 = new SignContentResponseType(); + content1.getOut().add(result2); + result2.setKey("bcBindReq"); + result2.setValue(""); + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content1); + + try { + szrClient + .getEidasBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), getEidData()); + } catch (SzrCommunicationException e) { + Assert.assertTrue("Not correct error", e.getMessage().contains("ernb.01")); + + } + } + + @Test + public void eidasBindValid() throws SZRException_Exception, SzrCommunicationException { + final SignContentResponse szrResponse = new SignContentResponse(); + final SignContentEntry result1 = new SignContentEntry(); + final SignContentResponseType content = new SignContentResponseType(); + content.getOut().add(result1); + szrResponse.setSignContentResponse(content); + + result1.setKey("bcBindReq"); + result1.setValue(RandomStringUtils.randomAlphanumeric(100)); + + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content); + + final String bcBind = szrClient + .getEidasBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), getEidData()); + + Assert.assertNotNull("bcBind is null", bcBind); + Assert.assertEquals("bcBind not match", result1.getValue(), bcBind); + + } + + @Test + public void eidasBindValidWithMds() throws SZRException_Exception, SzrCommunicationException { + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.eidasbind.mds.inject", "true"); + + final SignContentResponse szrResponse = new SignContentResponse(); + final SignContentEntry result1 = new SignContentEntry(); + final SignContentResponseType content = new SignContentResponseType(); + content.getOut().add(result1); + szrResponse.setSignContentResponse(content); + + result1.setKey("bcBindReq"); + result1.setValue(RandomStringUtils.randomAlphanumeric(100)); + + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content); + + final String bcBind = szrClient + .getEidasBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), getEidData()); + + Assert.assertNotNull("bcBind is null", bcBind); + Assert.assertEquals("bcBind not match", result1.getValue(), bcBind); + + } + + @Ignore + @Test + public void getBpkTest() throws EidasSAuthenticationException { + final List<String> bPK = szrClient.getBpk(getEidData(), DUMMY_TARGET, basicConfig + .getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ, "no VKZ defined")); + + if (bPK.isEmpty()) { + throw new SzrCommunicationException("ernb.01", new Object[]{"bPK list is empty"}); + } + for (final String b : bPK) { + if (StringUtils.isEmpty(b)) { + throw new SzrCommunicationException("ernb.01", new Object[]{"bPK is null or empty"}); + } + } + + } + + private void checkElement(String expected, String value) { + Assert.assertNotNull(value); + Assert.assertEquals(expected, value); + + } + + @SuppressWarnings("SameParameterValue") + private void setSzrResponseIdentityLink(String responseXmlPath) throws JAXBException, SZRException_Exception { + final JAXBContext jaxbContext = JAXBContext + .newInstance(szrservices.ObjectFactory.class, org.w3._2001._04.xmldsig_more.ObjectFactory.class, + org.w3._2000._09.xmldsig.ObjectFactory.class, + at.gv.e_government.reference.namespace.persondata._20020228.ObjectFactory.class); + final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); + final GetIdentityLinkEidasResponse szrResponse = (GetIdentityLinkEidasResponse) jaxbUnmarshaller + .unmarshal(this.getClass().getResourceAsStream(responseXmlPath)); + when(szrMock.getIdentityLinkEidas(any(PersonInfoType.class))).thenReturn(szrResponse.getGetIdentityLinkReturn()); + + } + + @SuppressWarnings("SameParameterValue") + private void setSzrExceptionIdentityLink(String responseXmlPath) + throws ParserConfigurationException, SAXException, IOException, SZRException_Exception { + final Element detailerror = DomUtils.parseXmlNonValidating(this.getClass().getResourceAsStream(responseXmlPath)); + final javax.xml.namespace.QName qName = new javax.xml.namespace.QName("urn:SZRServices", "F455", "p344"); + final SoapFault fault = new SoapFault( + "The travel document you sent to insert a person already exists for another person. " + "Either check the document or have the person altered accordingly", + qName); + fault.setRole("urn:SZRServices"); + fault.setDetail(detailerror); + when(szrMock.getIdentityLinkEidas(any(PersonInfoType.class))).thenThrow(fault); + + } + + private SimpleEidasData getEidData() { + return SimpleEidasData.builder() + .familyName("Mustermann") + .givenName("Franz") + .dateOfBirth("1989-05-05") + .citizenCountryCode("IS") + .pseudonym("1234sdgsdfg56789ABCDEF") + .build(); + } + + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ZmrAddressSearchClientProductionTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ZmrAddressSearchClientProductionTest.java new file mode 100644 index 00000000..a6ff234b --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ZmrAddressSearchClientProductionTest.java @@ -0,0 +1,169 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.IfProfileValue; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrAddressSoapClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrAddressSoapClient.AddressInfo; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrAddressSoapClient.DetailLevel; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.LoggingHandler; +import at.gv.bmi.namespace.zmr_su.zrm._20040201_.address.Adressdaten; +import at.gv.e_government.reference.namespace.persondata.de._20040201.PostAdresseTyp; +import at.gv.e_government.reference.namespace.persondata.de._20040201.ZustelladresseTyp; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; + +@IfProfileValue(name = "spring.profiles.active", value = "devEnvironment") +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_realConfig.xml" }) +@TestPropertySource(locations = { + // "classpath:/application.properties", + "file:/home/tlenz/Projekte/config/ms_connector/default_config.properties", +}) +public class ZmrAddressSearchClientProductionTest { + + + @Autowired ZmrAddressSoapClient client; + @Autowired IConfiguration basicConfig; + + @BeforeClass + public static void classInitializer() { + final Logger logger1 = (Logger) LoggerFactory.getLogger(LoggingHandler.class); + logger1.setLevel(Level.TRACE); + + final Logger logger2 = (Logger) LoggerFactory.getLogger(ZmrAddressSoapClient.class); + logger2.setLevel(Level.TRACE); + + final Logger rootLogger = (Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); + rootLogger.setLevel(Level.INFO); + + } + + @Test + public void gemeinde() throws EidasSAuthenticationException { + // build dummy request + Adressdaten req = new Adressdaten(); + PostAdresseTyp address = new PostAdresseTyp(); + address.setGemeinde("Frohnl*"); + req.setPostAdresse(address); + + // execute test + AddressInfo resp = client.searchAddress(req); + + // validate state + assertFalse("no results", resp.getPersonResult().isEmpty()); + assertEquals("wrong detail level", DetailLevel.CITY, resp.getLevel()); + + + } + + @Test + public void ortschaftAndGemeinde() throws EidasSAuthenticationException { + // build dummy request + Adressdaten req = new Adressdaten(); + PostAdresseTyp address = new PostAdresseTyp(); + address.setGemeinde("Frohnleiten"); + address.setOrtschaft("Wannersdorf"); + req.setPostAdresse(address); + + // execute test + AddressInfo resp = client.searchAddress(req); + + // validate state + assertFalse("no results", resp.getPersonResult().isEmpty()); + assertEquals("wrong detail level", DetailLevel.STREET, resp.getLevel()); + + } + + @Test + public void ortschaftAndGemeindeAndStreet() throws EidasSAuthenticationException { + // build dummy request + Adressdaten req = new Adressdaten(); + PostAdresseTyp address = new PostAdresseTyp(); + address.setGemeinde("Frohnleiten"); + address.setOrtschaft("Wannersdorf"); + req.setPostAdresse(address); + + ZustelladresseTyp addressDetail = new ZustelladresseTyp(); + addressDetail.setStrassenname("Wannersdorf"); + address.setZustelladresse(addressDetail); + + // execute test + AddressInfo resp = client.searchAddress(req); + + // validate state + assertFalse("no results", resp.getPersonResult().isEmpty()); + assertEquals("wrong detail level", DetailLevel.NUMBER, resp.getLevel()); + + } + + + @Test + public void ortschaftAndGemeinde2() throws EidasSAuthenticationException { + // build dummy request + Adressdaten req = new Adressdaten(); + PostAdresseTyp address = new PostAdresseTyp(); + address.setGemeinde("Fro*"); + address.setOrtschaft("Wannersdorf"); + req.setPostAdresse(address); + + // execute test + AddressInfo resp = client.searchAddress(req); + + // validate state + assertFalse("no results", resp.getPersonResult().isEmpty()); + assertEquals("wrong detail level", DetailLevel.CITY, resp.getLevel()); + + } + + @Test + public void ortschaftAndGemeinde3() throws EidasSAuthenticationException { + // build dummy request + Adressdaten req = new Adressdaten(); + PostAdresseTyp address = new PostAdresseTyp(); + address.setGemeinde("Eggelsberg"); + address.setOrtschaft("Wannersdorf"); + req.setPostAdresse(address); + + // execute test + AddressInfo resp = client.searchAddress(req); + + // validate state + assertFalse("no results", resp.getPersonResult().isEmpty()); + assertEquals("wrong detail level", DetailLevel.STREET, resp.getLevel()); + + } + + + @Test + public void ortschaft() throws EidasSAuthenticationException { + // build dummy request + Adressdaten req = new Adressdaten(); + PostAdresseTyp address = new PostAdresseTyp(); + address.setOrtschaft("Wannersdorf"); + req.setPostAdresse(address); + + // execute test + AddressInfo resp = client.searchAddress(req); + + // validate state + assertFalse("no results", resp.getPersonResult().isEmpty()); + assertEquals("wrong detail level", DetailLevel.CITY, resp.getLevel()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ZmrClientProductionTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ZmrClientProductionTest.java new file mode 100644 index 00000000..97ea5bfa --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ZmrClientProductionTest.java @@ -0,0 +1,478 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.List; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.IfProfileValue; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient.ZmrRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.LoggingHandler; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.EidasSuchdatenType; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest; +import at.gv.e_government.reference.namespace.persondata.de._20040201.NatuerlichePersonTyp; +import at.gv.e_government.reference.namespace.persondata.de._20040201.PersonenNameTyp; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; + +@IfProfileValue(name = "spring.profiles.active", value = "devEnvironment") +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_realConfig.xml" }) +@TestPropertySource(locations = { + // "classpath:/application.properties", + "file:/home/tlenz/Projekte/config/ms_connector/default_config.properties", +}) +public class ZmrClientProductionTest { + + @Autowired + ZmrSoapClient client; + @Autowired + IConfiguration basicConfig; + + @BeforeClass + public static void classInitializer() { + final Logger logger1 = (Logger) LoggerFactory.getLogger(LoggingHandler.class); + logger1.setLevel(Level.TRACE); + + final Logger logger2 = (Logger) LoggerFactory.getLogger(ZmrSoapClient.class); + logger2.setLevel(Level.TRACE); + + final Logger rootLogger = (Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); + rootLogger.setLevel(Level.INFO); + + } + + @Ignore + @Test + public void searchWithMdsOnly() throws EidasSAuthenticationException { + + final ZmrRegisterResult result = client.searchWithMds(null, + "Thomas", "Lenz", "1982-09-06", + "AT"); + + assertNotNull("ZMR response", result); + assertNotNull("ZMR processId", result.getProcessId()); + assertNotNull("ZMR personResult", result.getPersonResult()); + assertEquals("personResult size", 1, result.getPersonResult().size()); + + } + + @Test + public void searchWithMdsOnlyTestIdentity() throws EidasSAuthenticationException { + + final ZmrRegisterResult result = client.searchWithMds(null, + "XXXHildegard", "XXXÖhlinger", "1971-02-18", + "AT"); + + assertNotNull("ZMR response", result); + assertNotNull("ZMR processId", result.getProcessId()); + assertNotNull("ZMR personResult", result.getPersonResult()); + assertEquals("personResult size", 1, result.getPersonResult().size()); + + } + + /* + * Ignore this test because "javier", "Garcia", "1964-12-31", "EE" is used as test-identity + * in test-country on vidp.gv.at. vidp.gv.at uses Test-SZR, but Test-SZR is connected to + * Q-ZMR and Q-ERnP. There is a staging problem because this test uses T-ZMR and T-ERnP. + */ + @Ignore + @Test + public void searchWithMdsOnlyEidasIdentity() throws EidasSAuthenticationException { + + final ZmrRegisterResult result = client.searchWithMds(null, + "javier", "Garcia", "1964-12-31", + "EE"); + + assertNotNull("ZMR response", result); + assertNotNull("ZMR processId", result.getProcessId()); + assertNotNull("ZMR personResult", result.getPersonResult()); + assertEquals("personResult size", 1, result.getPersonResult().size()); + + } + + @Test + public void searchWithCountrySpecificsNoExits() throws EidasSAuthenticationException { + final ZmrRegisterResult result = client.searchCountrySpecific(null, + generateCustomRequest("AT", "Lenz", "Thomas", "1982-09-06", + null, + RandomStringUtils.randomAlphabetic(5), + RandomStringUtils.randomAlphabetic(5)), + "AT"); + + assertNotNull("ZMR response", result); + assertNotNull("ZMR processId", result.getProcessId()); + assertNotNull("ZMR personResult", result.getPersonResult()); + assertEquals("personResult size", 0, result.getPersonResult().size()); + + } + + @Test + public void searchWithCountrySpecificsWithPersonalId() throws EidasSAuthenticationException { + final ZmrRegisterResult result = client.searchCountrySpecific(null, + generateCustomRequest("EE", "Lenz", "Thomas", "1982-09-06", + "7cEYSvKZvon+V4CDVzNT4E7cjkU4Vq", + null, + null), + "EE"); + + assertNotNull("ZMR response", result); + assertNotNull("ZMR processId", result.getProcessId()); + assertNotNull("ZMR personResult", result.getPersonResult()); + assertEquals("personResult size", 1, result.getPersonResult().size()); + + } + + @Test + public void searchWithPersonalIdOnlyNoExisting() throws EidasSAuthenticationException { + + final ZmrRegisterResult result = client.searchWithPersonIdentifier(null, + RandomStringUtils.randomAlphanumeric(25), + "AT"); + + assertNotNull("ZMR response", result); + assertNotNull("ZMR processId", result.getProcessId()); + assertNotNull("ZMR personResult", result.getPersonResult()); + assertEquals("personResult size", 0, result.getPersonResult().size()); + + } + + @Test + public void updateZmrEntry() throws EidasSAuthenticationException { + final String personalIdentifier = "7cEYSvKZvon+V4CDVzNT4E7cjkU4Vq"; + final String cc = "EE"; + + final SimpleEidasData eidasData = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("Lenz") + .givenName("Thomas") + .dateOfBirth("1982-09-06") + .personalIdentifier(cc + "/AT/" + personalIdentifier) + .pseudonym(personalIdentifier) + .build(); + + // get initial result + final ZmrRegisterResult result = client.searchWithMds(null, + eidasData.getGivenName(), + eidasData.getFamilyName(), + eidasData.getDateOfBirth(), + eidasData.getCitizenCountryCode()); + assertNotNull("ZMR response", result); + assertEquals("personResult size", 1, result.getPersonResult().size()); + + // update ZMR entry + final ZmrRegisterResult updateResult = + client.update(result.getProcessId(), + result.getPersonResult().get(0), + eidasData); + + assertNotNull("ZMR response", updateResult); + assertEquals("personResult size", 1, updateResult.getPersonResult().size()); + + final ZmrRegisterResult afterUpdateResult = client.searchWithPersonIdentifier(null, + personalIdentifier, cc); + + assertNotNull("ZMR response", afterUpdateResult); + assertEquals("personResult size", 1, afterUpdateResult.getPersonResult().size()); + + } + + @Ignore + @Test + public void updateZmrEntryTestIdentity() throws EidasSAuthenticationException { + final String personalIdentifier = "7cEYSvKZasdfsafsaf4CDVzNT4E7cjkU4Vq"; + final String cc = "EE"; + + final SimpleEidasData eidasData = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXÖhlinger") + .givenName("XXXHildegard") + .dateOfBirth("1971-02-18") + .personalIdentifier(cc + "/AT/" + personalIdentifier) + .pseudonym(personalIdentifier) + .build(); + + // get initial result + final ZmrRegisterResult result = client.searchWithMds(null, + eidasData.getGivenName(), + eidasData.getFamilyName(), + eidasData.getDateOfBirth(), + eidasData.getCitizenCountryCode()); + assertNotNull("ZMR response", result); + assertEquals("personResult size", 1, result.getPersonResult().size()); + + // update ZMR entry + final ZmrRegisterResult updateResult = + client.update(result.getProcessId(), + result.getPersonResult().get(0), + eidasData); + + assertNotNull("ZMR response", updateResult); + assertEquals("personResult size", 1, updateResult.getPersonResult().size()); + + + final ZmrRegisterResult afterUpdateResultMds = client.searchCountrySpecific(null, + generateCustomRequest("EE", "XXXHildegard", "XXXÖhlinger", "1971-02-18", + "7cEYSvKZasdfsafsaf4CDVzNT4E7cjkU4Vq", + null, + null), + cc); + + assertNotNull("ZMR response", afterUpdateResultMds); + assertNotNull("ZMR processId", afterUpdateResultMds.getProcessId()); + assertNotNull("ZMR personResult", afterUpdateResultMds.getPersonResult()); + assertEquals("personResult size", 1, afterUpdateResultMds.getPersonResult().size()); + + + // check if ZMR entry can be found by PersonalId + final ZmrRegisterResult afterUpdateResult = client.searchWithPersonIdentifier(null, + personalIdentifier, cc); + + assertNotNull("ZMR response", afterUpdateResult); + assertEquals("personResult size", 1, afterUpdateResult.getPersonResult().size()); + + } + + @Test + public void updateZmrEntryDeSpecific() throws EidasSAuthenticationException { + final String personalIdentifierFirst = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .placeOfBirth("Hintergigritzpotschn") + .birthName("XXXvon Heuburg") + .build(); + + // first login with update + // get initial result + final ZmrRegisterResult result = client.searchWithMds(null, + eidasDataFirst.getGivenName(), + eidasDataFirst.getFamilyName(), + eidasDataFirst.getDateOfBirth(), + eidasDataFirst.getCitizenCountryCode()); + assertNotNull("ZMR response", result); + assertEquals("personResult size", 1, result.getPersonResult().size()); + + // update ZMR entry + final ZmrRegisterResult updateResult = + client.update(result.getProcessId(), + result.getPersonResult().get(0), + eidasDataFirst); + + assertNotNull("ZMR response", updateResult); + assertEquals("personResult size", 1, updateResult.getPersonResult().size()); + + // check if ZMR entry can be found by first PersonalId + final ZmrRegisterResult firstPersonalIdResult = client.searchWithPersonIdentifier(null, + personalIdentifierFirst, cc); + assertNotNull("ZMR response", firstPersonalIdResult); + assertEquals("first personResult size", 1, firstPersonalIdResult.getPersonResult().size()); + + + // check if ZMR entry is not found by valid pseudonym but wrong country + final ZmrRegisterResult wrongPersonalIdResult = client.searchWithPersonIdentifier(null, + personalIdentifierFirst, "ES"); + assertNotNull("ZMR response", wrongPersonalIdResult); + assertEquals("first personResult size", 0, wrongPersonalIdResult.getPersonResult().size()); + + + // search CC-specific with MDS + placeOfBirth + birthName + final ZmrRegisterResult ccSpecificFirstEntry = client.searchCountrySpecific(null, + generateCustomRequest( + eidasDataFirst.getCitizenCountryCode(), + eidasDataFirst.getFamilyName(), + eidasDataFirst.getGivenName(), + eidasDataFirst.getDateOfBirth(), + null, + eidasDataFirst.getPlaceOfBirth(), + eidasDataFirst.getBirthName()), + cc); + + assertNotNull("ZMR response", ccSpecificFirstEntry); + assertNotNull("ZMR processId", ccSpecificFirstEntry.getProcessId()); + assertNotNull("ZMR personResult", ccSpecificFirstEntry.getPersonResult()); + assertEquals("personResult size", 1, ccSpecificFirstEntry.getPersonResult().size()); + + } + + @Test + public void updateZmrEntryTestIdentity2() throws EidasSAuthenticationException { + final String personalIdentifierFirst = "7cEYSvKZasdfsafsaf4CDVzNT4E7cjkU4Vq_first"; + final String personalIdentifierSecond = "7cEYSvKZasdfsafsaf4CDVzNT4E7cjkU4Vq_second"; + final String cc = "EE"; + + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXTüzekçi") + .givenName("XXXŐzgür") + .dateOfBirth("1983-06-04") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + final SimpleEidasData eidasDataSecond = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXTüzekçi") + .givenName("XXXŐzgür") + .dateOfBirth("1983-06-04") + .personalIdentifier(cc + "/AT/" + personalIdentifierSecond) + .pseudonym(personalIdentifierSecond) + .build(); + + + // first login with update + // get initial result + final ZmrRegisterResult result = client.searchWithMds(null, + eidasDataFirst.getGivenName(), + eidasDataFirst.getFamilyName(), + eidasDataFirst.getDateOfBirth(), + eidasDataFirst.getCitizenCountryCode()); + assertNotNull("ZMR response", result); + assertEquals("personResult size", 1, result.getPersonResult().size()); + + // update ZMR entry + final ZmrRegisterResult updateResult = + client.update(result.getProcessId(), + result.getPersonResult().get(0), + eidasDataFirst); + + assertNotNull("ZMR response", updateResult); + assertEquals("personResult size", 1, updateResult.getPersonResult().size()); + + + // second login with update + // get initial result + final ZmrRegisterResult resultSecond = client.searchWithMds(null, + eidasDataSecond.getGivenName(), + eidasDataSecond.getFamilyName(), + eidasDataSecond.getDateOfBirth(), + eidasDataSecond.getCitizenCountryCode()); + assertNotNull("ZMR response", resultSecond); + assertEquals("personResult size", 1, resultSecond.getPersonResult().size()); + + // update ZMR entry + final ZmrRegisterResult updateResultSecond = + client.update(resultSecond.getProcessId(), + resultSecond.getPersonResult().get(0), + eidasDataSecond); + + assertNotNull("ZMR response", updateResultSecond); + assertEquals("personResult size", 1, updateResultSecond.getPersonResult().size()); + + + // check if ZMR entry can be found by first PersonalId + final ZmrRegisterResult firstPersonalIdResult = client.searchWithPersonIdentifier(null, + personalIdentifierFirst, cc); + assertNotNull("ZMR response", firstPersonalIdResult); + assertEquals("first personResult size", 1, firstPersonalIdResult.getPersonResult().size()); + + // check if ZMR entry can be found by second PersonalId + final ZmrRegisterResult secondPersonalIdResult = client.searchWithPersonIdentifier(null, + personalIdentifierFirst, cc); + assertNotNull("ZMR response", secondPersonalIdResult); + assertEquals("second personResult size", 1, secondPersonalIdResult.getPersonResult().size()); + + + // search CC-specific with first MDS + final ZmrRegisterResult ccSpecificFirstEntry = client.searchCountrySpecific(null, + generateCustomRequest( + eidasDataFirst.getCitizenCountryCode(), + eidasDataFirst.getFamilyName(), + eidasDataFirst.getGivenName(), + eidasDataFirst.getDateOfBirth(), + eidasDataFirst.getPseudonym(), + null, + null), + cc); + + assertNotNull("ZMR response", ccSpecificFirstEntry); + assertNotNull("ZMR processId", ccSpecificFirstEntry.getProcessId()); + assertNotNull("ZMR personResult", ccSpecificFirstEntry.getPersonResult()); + assertEquals("personResult size", 1, ccSpecificFirstEntry.getPersonResult().size()); + + + // search CC-specific with second MDS + final ZmrRegisterResult ccSpecificSecondEntry = client.searchCountrySpecific(null, + generateCustomRequest( + eidasDataSecond.getCitizenCountryCode(), + eidasDataSecond.getFamilyName(), + eidasDataSecond.getGivenName(), + eidasDataSecond.getDateOfBirth(), + eidasDataSecond.getPseudonym(), + null, + null), + cc); + + assertNotNull("ZMR response", ccSpecificSecondEntry); + assertNotNull("ZMR processId", ccSpecificSecondEntry.getProcessId()); + assertNotNull("ZMR personResult", ccSpecificSecondEntry.getPersonResult()); + assertEquals("personResult size", 1, ccSpecificSecondEntry.getPersonResult().size()); + + + } + + + private PersonSuchenRequest generateCustomRequest(String cc, String familyName, String givenName, + String dateOfBirth, String personalId, String placeOfBirth, String birthName) { + final PersonSuchenRequest req = new PersonSuchenRequest(); + + // set basic MDS information + final NatuerlichePersonTyp searchNatPerson = new NatuerlichePersonTyp(); + req.setNatuerlichePerson(searchNatPerson); + final PersonenNameTyp searchNatPersonName = new PersonenNameTyp(); + searchNatPerson.setPersonenName(searchNatPersonName); + searchNatPersonName.setFamilienname(familyName); + searchNatPersonName.setVorname(givenName); + searchNatPerson.setGeburtsdatum(dateOfBirth); + + // add addtional eIDAS attributes if available + addIfAvailable(req.getEidasSuchdaten(), cc, Constants.eIDAS_ATTRURN_PLACEOFBIRTH, placeOfBirth); + addIfAvailable(req.getEidasSuchdaten(), cc, Constants.eIDAS_ATTRURN_BIRTHNAME, birthName); + addIfAvailable(req.getEidasSuchdaten(), cc, Constants.eIDAS_ATTRURN_PERSONALIDENTIFIER, personalId); + + return req; + + } + + private void addIfAvailable(List<EidasSuchdatenType> eidasSuchdaten, + String cc, String attrName, String attrValue) { + if (StringUtils.isNotEmpty(attrValue)) { + eidasSuchdaten.add(buildEidasSuchData(cc, attrName, attrValue)); + + } + } + + private EidasSuchdatenType buildEidasSuchData(String cc, String attrName, String attrValue) { + final EidasSuchdatenType eidasInfos = new EidasSuchdatenType(); + eidasInfos.setStaatscode2(cc); + eidasInfos.setEidasArt(attrName); + eidasInfos.setEidasWert(attrValue); + return eidasInfos; + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ZmrClientTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ZmrClientTest.java new file mode 100644 index 00000000..4e0a1f28 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/clients/ZmrClientTest.java @@ -0,0 +1,1242 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.cxf.binding.soap.SoapFault; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.github.skjolber.mockito.soap.SoapServiceRule; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient.ZmrRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController.AdresssucheOutput; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException; +import at.gv.bmi.namespace.zmr_su.base._20040201.RequestType; +import at.gv.bmi.namespace.zmr_su.base._20040201.ResponseType; +import at.gv.bmi.namespace.zmr_su.base._20040201_.ServicePort; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.EidasIdentitaetAnlageType; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.EidasSuchdatenType; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonAendernRequest; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonensucheInfoType; +import at.gv.e_government.reference.namespace.persondata.de._20040201.NatuerlichePersonTyp; +import at.gv.e_government.reference.namespace.persondata.de._20040201.PersonenNameTyp; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import lombok.SneakyThrows; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" }) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public class ZmrClientTest { + + public static final String PROCESS_GENERAL = "GP_EIDAS"; + public static final String PROCESS_TASK_SEARCH = "ZPR_VO_Person_suchen_Meldevorgang"; + public static final String PROCESS_TASK_UPDATE = "ZPR_VO_Person_aendern"; + + @Autowired + MsConnectorDummyConfigMap basicConfig; + @Autowired + ZmrSoapClient client; + + @Rule + public SoapServiceRule soap = SoapServiceRule.newInstance(); + + private ServicePort zmrMock = null; + + private static JAXBContext jaxbContext; + + /** + * Initialize jUnit class. + */ + @BeforeClass + @SneakyThrows + public static void classInitializer() { + jaxbContext = JAXBContext.newInstance( + at.gv.bmi.namespace.zmr_su.zmr._20040201.ObjectFactory.class, + at.gv.bmi.namespace.zmr_su.gis._20070725.ObjectFactory.class, + at.gv.bmi.namespace.zmr_su.base._20040201.ObjectFactory.class); + } + + /** + * Initialize jUnit test. + */ + @Before + public void initializer() { + if (zmrMock == null) { + zmrMock = soap.mock(ServicePort.class, "http://localhost:1234/demozmr"); + } + } + + @Test + @SneakyThrows + public void searchWithMdsEmpty() { + String familyName = RandomStringUtils.randomAlphabetic(10); + String givenName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = RandomStringUtils.randomAlphabetic(10); + final String cc = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/empty_zmr_result.xml")); + + // execute operation + ZmrRegisterResult resp = client.searchWithMds(processId, + givenName, familyName, dateOfBirth, cc); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "367100000000079", resp.getProcessId().toString()); + assertEquals("wrong resp size", 0, resp.getPersonResult().size()); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + + checkBasicRequestParameters(zmrReq.getValue(), PROCESS_TASK_SEARCH, processId, "jUnit123456"); + PersonSuchenRequest pSuche = zmrReq.getValue().getPersonSuchenRequest(); + checkSearchParameters(pSuche.getPersonensucheInfo()); + + assertEquals("eidas Docs. size", 0, pSuche.getEidasSuchdaten().size()); + assertNotNull("mds", pSuche.getNatuerlichePerson()); + + assertEquals("req. givenName", givenName, pSuche.getNatuerlichePerson().getPersonenName().getVorname()); + assertEquals("req. familyName", familyName, pSuche.getNatuerlichePerson().getPersonenName().getFamilienname()); + assertEquals("req. dateOfBirth", dateOfBirth, pSuche.getNatuerlichePerson().getGeburtsdatum()); + + } + + @Test + @SneakyThrows + public void searchWithMdsGetHistoricInfos() { + String familyName = RandomStringUtils.randomAlphabetic(10); + String givenName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = RandomStringUtils.randomAlphabetic(10); + final String cc = "EE"; + + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/search_with_personalId_only_resp_historicIncluded.xml")); + + // execute operation + ZmrRegisterResult resp = client.searchWithMds(processId, + givenName, familyName, dateOfBirth, cc); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "367100000000080", resp.getProcessId().toString()); + assertEquals("wrong resp size", 0, resp.getPersonResult().size()); + + } + + @Test + @SneakyThrows + public void searchWithMdsSuccess() { + String familyName = RandomStringUtils.randomAlphabetic(10); + String givenName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = RandomStringUtils.randomAlphabetic(10); + final String cc = "EE"; + + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/search_with_personalId_only_resp_moreThanOne_2.xml")); + + // execute operation + ZmrRegisterResult resp = client.searchWithMds(processId, + givenName, familyName, dateOfBirth, cc); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "367100000000080", resp.getProcessId().toString()); + assertEquals("wrong resp size", 2, resp.getPersonResult().size()); + + // check first person + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("bPK", "9/MtsPZgBHQMBpQOD6aOY2TUqcY=", persInfo.getBpk()); + assertEquals("dateOfBirth", "1983-06-04", persInfo.getDateOfBirth()); + assertEquals("familyName", "XXXTüzekçi", persInfo.getFamilyName()); + assertEquals("givenName", "XXXŐzgür", persInfo.getGivenName()); + assertNull("placeOfBirth", persInfo.getPlaceOfBirth()); + assertNull("birthName", persInfo.getBirthName()); + assertEquals("num. stored eIDAS identifiers", 1, persInfo.getPseudonym().size()); + assertEquals("stored eIDAS identifiers", + "aabbcc_should_not_be_included_for_DE", persInfo.getPseudonym().get(0)); + + // check second person + RegisterResult persInfo2 = resp.getPersonResult().get(1); + assertEquals("bPK", "UgeknNsc26lVuB7U/uYGVmWtnnA=", persInfo2.getBpk()); + assertEquals("dateOfBirth", "1983-06-04", persInfo2.getDateOfBirth()); + assertEquals("familyName", "XXXTüzekçi", persInfo2.getFamilyName()); + assertEquals("givenName", "XXXŐzgür", persInfo2.getGivenName()); + assertEquals("num. stored eIDAS identifiers", 1, persInfo2.getPseudonym().size()); + assertEquals("stored eIDAS identifiers", + "7cEYSvKZasdfsafsaf4CDVzNT4E7cjkU4Vq_first", persInfo2.getPseudonym().get(0)); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getValue(), PROCESS_TASK_SEARCH, processId, "jUnit123456"); + PersonSuchenRequest pSuche = zmrReq.getValue().getPersonSuchenRequest(); + checkSearchParameters(pSuche.getPersonensucheInfo()); + + assertEquals("eidas Docs. size", 0, pSuche.getEidasSuchdaten().size()); + assertNotNull("mds", pSuche.getNatuerlichePerson()); + + assertEquals("req. givenName", givenName, pSuche.getNatuerlichePerson().getPersonenName().getVorname()); + assertEquals("req. familyName", familyName, pSuche.getNatuerlichePerson().getPersonenName().getFamilienname()); + assertEquals("req. dateOfBirth", dateOfBirth, pSuche.getNatuerlichePerson().getGeburtsdatum()); + + } + + //TODO: test does not throw the valid exception to catch the error that we like to test. + @Ignore + @Test + @SneakyThrows + public void searchWithPersonalIdentifierZmrError() { + final String personalIdentifierFirst = RandomStringUtils.randomAlphanumeric(10); + final String cc = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + + // inject response + when(zmrMock.service(any(), any())).thenThrow(injectError(false)); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchWithPersonIdentifier(null, personalIdentifierFirst, cc)); + + assertEquals("wrong errorCode", "module.eidasauth.matching.01", error.getErrorId()); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdentifierZmrGenericError() { + final String personalIdentifierFirst = RandomStringUtils.randomAlphanumeric(10); + final String cc = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + + // inject response + when(zmrMock.service(any(), any())).thenThrow(injectError(true)); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchWithPersonIdentifier(null, personalIdentifierFirst, cc)); + + assertEquals("wrong errorCode", "module.eidasauth.matching.99", error.getErrorId()); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdentifierGetHistoricInfos() { + final String personalIdentifierFirst = RandomStringUtils.randomAlphanumeric(10); + final String cc = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/search_with_personalId_only_resp_historicIncluded.xml")); + + // execute operation + EidasSAuthenticationException error = assertThrows("wrong Exception", EidasSAuthenticationException.class, + () -> client.searchWithPersonIdentifier(null, personalIdentifierFirst, cc)); + + assertEquals("wrong errorCode", "module.eidasauth.matching.99", error.getErrorId()); + assertEquals("wrong errorCode", "module.eidasauth.matching.02", ((EaafException) error.getCause()).getErrorId()); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdentifierEmptyResult() { + final String personalIdentifierFirst = RandomStringUtils.randomAlphanumeric(10); + final String cc = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/empty_zmr_result.xml")); + + // execute operation + ZmrRegisterResult resp = client.searchWithPersonIdentifier(null, personalIdentifierFirst, cc); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "367100000000079", resp.getProcessId().toString()); + assertEquals("wrong resp size", 0, resp.getPersonResult().size()); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + + checkBasicRequestParameters(zmrReq.getValue(), PROCESS_TASK_SEARCH, null, "jUnit123456"); + PersonSuchenRequest pSuche = zmrReq.getValue().getPersonSuchenRequest(); + checkSearchParameters(pSuche.getPersonensucheInfo()); + + assertEquals("eidas Docs. size", 1, pSuche.getEidasSuchdaten().size()); + checkEidasDocumentResult(pSuche.getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", cc, personalIdentifierFirst); + assertNull("mds", pSuche.getNatuerlichePerson()); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdentifierMoreThanOneResult() { + final String personalIdentifierFirst = RandomStringUtils.randomAlphanumeric(10); + final String cc = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + + // inject response + when(zmrMock.service(any(), any())).thenReturn( + loadResponseFromFile("/data/zmr/search_with_personalId_only_resp_moreThanOne.xml")); + + // execute operation + WorkflowException error = assertThrows("wrong Exception", WorkflowException.class, + () -> client.searchWithPersonIdentifier(null, personalIdentifierFirst, cc)); + + assertEquals("wrong errorCode", "module.eidasauth.matching.03", error.getErrorId()); + assertEquals("wrong param 1", "Searching PersonIdentifier", error.getParams()[0]); + assertEquals("wrong param 2", "Find more-than-one ZMR entry with search criteria that has to be unique", + error.getParams()[1]); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdentifierSuccess() { + final String personalIdentifierFirst = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/search_with_personalId_only_resp.xml")); + + // execute operation + ZmrRegisterResult resp = client.searchWithPersonIdentifier(processId, + eidasDataFirst.getPseudonym(), eidasDataFirst.getCitizenCountryCode()); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "367100000000079", resp.getProcessId().toString()); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("bPK", "UgeknNsc26lVuB7U/uYGVmWtnnA=", persInfo.getBpk()); + assertEquals("dateOfBirth", eidasDataFirst.getDateOfBirth(), persInfo.getDateOfBirth()); + assertEquals("familyName", eidasDataFirst.getFamilyName(), persInfo.getFamilyName()); + assertEquals("givenName", eidasDataFirst.getGivenName(), persInfo.getGivenName()); + assertEquals("placeOfBirth", "Hintergigritzpotschn", persInfo.getPlaceOfBirth()); + assertEquals("birthName", "XXXvon Heuburg", persInfo.getBirthName()); + assertEquals("num. stored eIDAS identifiers", 2, persInfo.getPseudonym().size()); + assertEquals("stored eIDAS identifiers", "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", + persInfo.getPseudonym().get(0)); + assertEquals("stored eIDAS identifiers", + "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit_second_one", + persInfo.getPseudonym().get(1)); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getValue(), PROCESS_TASK_SEARCH, processId, "jUnit123456"); + PersonSuchenRequest pSuche = zmrReq.getValue().getPersonSuchenRequest(); + checkSearchParameters(pSuche.getPersonensucheInfo()); + + assertEquals("eidas Docs. size", 1, pSuche.getEidasSuchdaten().size()); + checkEidasDocumentResult(pSuche.getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", cc, personalIdentifierFirst); + assertNull("mds", pSuche.getNatuerlichePerson()); + + } + + @Test + @SneakyThrows + public void searchWithPersonalIdentifierNoBpkZP() { + final String personalIdentifierFirst = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/no_bpk_zp.xml")); + + // execute operation + ZmrRegisterResult resp = client.searchWithPersonIdentifier(processId, + eidasDataFirst.getPseudonym(), eidasDataFirst.getCitizenCountryCode()); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "367100000000079", resp.getProcessId().toString()); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + + RegisterResult persInfo = resp.getPersonResult().get(0); + assertNull("bPK", persInfo.getBpk()); + assertEquals("dateOfBirth", eidasDataFirst.getDateOfBirth(), persInfo.getDateOfBirth()); + assertEquals("familyName", eidasDataFirst.getFamilyName(), persInfo.getFamilyName()); + assertEquals("givenName", eidasDataFirst.getGivenName(), persInfo.getGivenName()); + assertEquals("placeOfBirth", "Hintergigritzpotschn", persInfo.getPlaceOfBirth()); + assertEquals("birthName", "XXXvon Heuburg", persInfo.getBirthName()); + assertEquals("num. stored eIDAS identifiers", 2, persInfo.getPseudonym().size()); + assertEquals("stored eIDAS identifiers", "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", + persInfo.getPseudonym().get(0)); + assertEquals("stored eIDAS identifiers", + "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit_second_one", + persInfo.getPseudonym().get(1)); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getValue(), PROCESS_TASK_SEARCH, processId, "jUnit123456"); + PersonSuchenRequest pSuche = zmrReq.getValue().getPersonSuchenRequest(); + checkSearchParameters(pSuche.getPersonensucheInfo()); + + assertEquals("eidas Docs. size", 1, pSuche.getEidasSuchdaten().size()); + checkEidasDocumentResult(pSuche.getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", cc, personalIdentifierFirst); + assertNull("mds", pSuche.getNatuerlichePerson()); + + } + + @Test + @SneakyThrows + public void searchCcSpecificEmpty() { + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final String cc = "DE"; + String familyName = RandomStringUtils.randomAlphabetic(10); + String givenName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = RandomStringUtils.randomAlphabetic(10); + String personalIdentifier = RandomStringUtils.randomAlphabetic(10); + String placeOfBirth = RandomStringUtils.randomAlphabetic(10); + String birthName = RandomStringUtils.randomAlphabetic(10); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/empty_zmr_result.xml")); + + // execute operation + ZmrRegisterResult resp = client.searchCountrySpecific(processId, + generateCustomRequest(cc, familyName, givenName, dateOfBirth, personalIdentifier, placeOfBirth, birthName), + cc); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "367100000000079", resp.getProcessId().toString()); + assertEquals("wrong resp size", 0, resp.getPersonResult().size()); + + } + + @Test + @SneakyThrows + public void searchCcSpecificMoreThanOneResult() { + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final String cc = "DE"; + String familyName = RandomStringUtils.randomAlphabetic(10); + String givenName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = RandomStringUtils.randomAlphabetic(10); + String personalIdentifier = RandomStringUtils.randomAlphabetic(10); + String placeOfBirth = RandomStringUtils.randomAlphabetic(10); + String birthName = RandomStringUtils.randomAlphabetic(10); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/search_with_personalId_only_resp_moreThanOne.xml")); + + // execute operation + WorkflowException error = assertThrows("wrong Exception", WorkflowException.class, + () -> client.searchCountrySpecific(processId, + generateCustomRequest(cc, familyName, givenName, dateOfBirth, personalIdentifier, placeOfBirth, birthName), + cc)); + + assertEquals("wrong errorCode", "module.eidasauth.matching.03", error.getErrorId()); + assertEquals("wrong param 1", "Searching DE specific", error.getParams()[0]); + assertEquals("wrong param 2", "Find more-than-one ZMR entry with search criteria that has to be unique", + error.getParams()[1]); + + } + + @Test + @SneakyThrows + public void searchCcSpecificSuccess() { + final String personalIdentifierFirst = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + String familyName = RandomStringUtils.randomAlphabetic(10); + String givenName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = RandomStringUtils.randomAlphabetic(10); + String personalIdentifier = RandomStringUtils.randomAlphabetic(10); + String placeOfBirth = RandomStringUtils.randomAlphabetic(10); + String birthName = RandomStringUtils.randomAlphabetic(10); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/search_with_personalId_only_resp.xml")); + + // execute operation + ZmrRegisterResult resp = client.searchCountrySpecific(processId, + generateCustomRequest(cc, familyName, givenName, dateOfBirth, personalIdentifier, placeOfBirth, birthName), + cc); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "367100000000079", resp.getProcessId().toString()); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("bPK", "UgeknNsc26lVuB7U/uYGVmWtnnA=", persInfo.getBpk()); + assertEquals("dateOfBirth", eidasDataFirst.getDateOfBirth(), persInfo.getDateOfBirth()); + assertEquals("familyName", eidasDataFirst.getFamilyName(), persInfo.getFamilyName()); + assertEquals("givenName", eidasDataFirst.getGivenName(), persInfo.getGivenName()); + assertEquals("placeOfBirth", "Hintergigritzpotschn", persInfo.getPlaceOfBirth()); + assertEquals("birthName", "XXXvon Heuburg", persInfo.getBirthName()); + assertEquals("num. stored eIDAS identifiers", 2, persInfo.getPseudonym().size()); + assertEquals("stored eIDAS identifiers", "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", + persInfo.getPseudonym().get(0)); + assertEquals("stored eIDAS identifiers", + "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit_second_one", + persInfo.getPseudonym().get(1)); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getValue(), PROCESS_TASK_SEARCH, processId, "jUnit123456"); + PersonSuchenRequest pSuche = zmrReq.getValue().getPersonSuchenRequest(); + checkSearchParameters(pSuche.getPersonensucheInfo()); + + assertEquals("eidas Docs. size", 3, pSuche.getEidasSuchdaten().size()); + checkEidasDocumentResult(pSuche.getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", cc, placeOfBirth); + checkEidasDocumentResult(pSuche.getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/BirthName", cc, birthName); + checkEidasDocumentResult(pSuche.getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", cc, personalIdentifier); + + assertNotNull("mds", pSuche.getNatuerlichePerson()); + assertEquals("req. givenName", givenName, pSuche.getNatuerlichePerson().getPersonenName().getVorname()); + assertEquals("req. familyName", familyName, pSuche.getNatuerlichePerson().getPersonenName().getFamilienname()); + assertEquals("req. dateOfBirth", dateOfBirth, pSuche.getNatuerlichePerson().getGeburtsdatum()); + + } + + @Test + @SneakyThrows + public void searchResidenceEmpty() { + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final String cc = "DE"; + String familyName = RandomStringUtils.randomAlphabetic(10); + String givenName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = RandomStringUtils.randomAlphabetic(10); + AdresssucheOutput addressInfo = AdresssucheOutput.builder() + .municipality(RandomStringUtils.randomAlphabetic(10)) + .number(RandomStringUtils.randomAlphabetic(10)) + .postleitzahl(RandomStringUtils.randomAlphabetic(10)) + .street(RandomStringUtils.randomAlphabetic(10)) + .village(RandomStringUtils.randomAlphabetic(10)) + .build(); + + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/empty_zmr_result.xml")); + + // execute operation + ZmrRegisterResult resp = client.searchWithResidenceData(processId, + givenName, familyName, dateOfBirth, cc, addressInfo); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "367100000000079", resp.getProcessId().toString()); + assertEquals("wrong resp size", 0, resp.getPersonResult().size()); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getValue(), PROCESS_TASK_SEARCH, processId, "jUnit123456"); + PersonSuchenRequest pSuche = zmrReq.getValue().getPersonSuchenRequest(); + checkSearchParameters(pSuche.getPersonensucheInfo()); + + assertNotNull("mds", pSuche.getNatuerlichePerson()); + assertEquals("req. givenName", givenName, pSuche.getNatuerlichePerson().getPersonenName().getVorname()); + assertEquals("req. familyName", familyName, pSuche.getNatuerlichePerson().getPersonenName().getFamilienname()); + assertEquals("req. dateOfBirth", dateOfBirth, pSuche.getNatuerlichePerson().getGeburtsdatum()); + + assertEquals("req. Municipality", addressInfo.getMunicipality(), pSuche.getPostAdresse().getGemeinde()); + assertEquals("req. Postleitzahl", addressInfo.getPostleitzahl(), pSuche.getPostAdresse().getPostleitzahl()); + assertEquals("req. Village", addressInfo.getVillage(), pSuche.getPostAdresse().getOrtschaft()); + assertEquals("req. Street", addressInfo.getStreet(), pSuche.getPostAdresse().getZustelladresse().getStrassenname()); + assertEquals("req. Number", addressInfo.getNumber(), pSuche.getPostAdresse().getZustelladresse().getOrientierungsnummer()); + + } + + @Test + @SneakyThrows + public void searchResidenceMoreThanOneResult() { + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final String cc = "DE"; + String familyName = RandomStringUtils.randomAlphabetic(10); + String givenName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = RandomStringUtils.randomAlphabetic(10); + AdresssucheOutput addressInfo = AdresssucheOutput.builder() + .municipality(RandomStringUtils.randomAlphabetic(10)) + .postleitzahl(RandomStringUtils.randomAlphabetic(10)) + .street(RandomStringUtils.randomAlphabetic(10)) + .build(); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/search_with_personalId_only_resp_moreThanOne.xml")); + + // execute operation + ZmrRegisterResult resp = client.searchWithResidenceData(processId, + givenName, familyName, dateOfBirth, cc, addressInfo); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "367100000000079", resp.getProcessId().toString()); + assertEquals("wrong resp size", 2, resp.getPersonResult().size()); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getValue(), PROCESS_TASK_SEARCH, processId, "jUnit123456"); + PersonSuchenRequest pSuche = zmrReq.getValue().getPersonSuchenRequest(); + assertEquals("req. Municipality", addressInfo.getMunicipality(), pSuche.getPostAdresse().getGemeinde()); + assertEquals("req. Postleitzahl", addressInfo.getPostleitzahl(), pSuche.getPostAdresse().getPostleitzahl()); + assertNull("req. Village", pSuche.getPostAdresse().getOrtschaft()); + assertEquals("req. Street", addressInfo.getStreet(), pSuche.getPostAdresse().getZustelladresse().getStrassenname()); + assertNull("req. Number", pSuche.getPostAdresse().getZustelladresse().getOrientierungsnummer()); + + } + + @Test + @SneakyThrows + public void searchResidenceSuccess() { + final String personalIdentifierFirst = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "DE"; + final SimpleEidasData eidasDataFirst = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifierFirst) + .pseudonym(personalIdentifierFirst) + .build(); + + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + String familyName = RandomStringUtils.randomAlphabetic(10); + String givenName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = RandomStringUtils.randomAlphabetic(10); + AdresssucheOutput addressInfo = AdresssucheOutput.builder() + .municipality(RandomStringUtils.randomAlphabetic(10)) + .postleitzahl(RandomStringUtils.randomAlphabetic(10)) + .build(); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())).thenReturn( + loadResponseFromFile("/data/zmr/search_with_personalId_only_resp.xml")); + + // execute operation + ZmrRegisterResult resp = client.searchWithResidenceData(processId, + givenName, familyName, dateOfBirth, cc, addressInfo); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "367100000000079", resp.getProcessId().toString()); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + + RegisterResult persInfo = resp.getPersonResult().get(0); + assertEquals("bPK", "UgeknNsc26lVuB7U/uYGVmWtnnA=", persInfo.getBpk()); + assertEquals("dateOfBirth", eidasDataFirst.getDateOfBirth(), persInfo.getDateOfBirth()); + assertEquals("familyName", eidasDataFirst.getFamilyName(), persInfo.getFamilyName()); + assertEquals("givenName", eidasDataFirst.getGivenName(), persInfo.getGivenName()); + assertEquals("placeOfBirth", "Hintergigritzpotschn", persInfo.getPlaceOfBirth()); + assertEquals("birthName", "XXXvon Heuburg", persInfo.getBirthName()); + assertEquals("num. stored eIDAS identifiers", 2, persInfo.getPseudonym().size()); + assertEquals("stored eIDAS identifiers", "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", + persInfo.getPseudonym().get(0)); + assertEquals("stored eIDAS identifiers", + "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit_second_one", + persInfo.getPseudonym().get(1)); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getValue(), PROCESS_TASK_SEARCH, processId, "jUnit123456"); + PersonSuchenRequest pSuche = zmrReq.getValue().getPersonSuchenRequest(); + assertEquals("req. Municipality", addressInfo.getMunicipality(), pSuche.getPostAdresse().getGemeinde()); + assertEquals("req. Postleitzahl", addressInfo.getPostleitzahl(), pSuche.getPostAdresse().getPostleitzahl()); + assertNull("req. Village", pSuche.getPostAdresse().getOrtschaft()); + assertNull("req. Number", pSuche.getPostAdresse().getZustelladresse()); + + } + + + @Test + @SneakyThrows + public void updateProcessNoLatestVersionResult() { + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final String personalIdentifier = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "DE"; + final SimpleEidasData eidasData = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifier) + .pseudonym(personalIdentifier) + .birthName("XXXvon Heuburg") + .placeOfBirth("Hintergigritzpotschn") + .build(); + + RegisterResult toUpdate = RegisterResult.builder() + .bpk("UgeknNsc26lVuB7U/uYGVmWtnnA=") + .dateOfBirth("1994-12-31") + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + //.birthName("") + //.placeOfBirth("") + //.pseudonym(Arrays.asList("")) + .build(); + + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) + .thenThrow(new RuntimeException("Request not needed any more")); + + + // execute operation + WorkflowException error = assertThrows("wrong Exception", WorkflowException.class, + () -> client.update(processId, toUpdate, eidasData)); + + assertEquals("wrong errorCode", "module.eidasauth.matching.03", error.getErrorId()); + assertEquals("wrong param 1", "KITT get-latest-version", error.getParams()[0]); + assertEquals("wrong param 2", "Find NO data-set with already matchted eID during ZMR KITT process", + error.getParams()[1]); + + } + + @Test + @SneakyThrows + public void updateProcessMultiLatestVersionResult() { + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final String personalIdentifier = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "DE"; + final SimpleEidasData eidasData = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifier) + .pseudonym(personalIdentifier) + .birthName("XXXvon Heuburg") + .placeOfBirth("Hintergigritzpotschn") + .build(); + + RegisterResult toUpdate = RegisterResult.builder() + .bpk("UgeknNsc26lVuB7U/uYGVmWtnnA=") + .dateOfBirth("1994-12-31") + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + //.birthName("") + //.placeOfBirth("") + //.pseudonym(Arrays.asList("")) + .build(); + + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/search_with_personalId_only_resp_moreThanOne.xml")) + .thenThrow(new RuntimeException("Request not needed any more")); + + + // execute operation + WorkflowException error = assertThrows("wrong Exception", WorkflowException.class, + () -> client.update(processId, toUpdate, eidasData)); + + assertEquals("wrong errorCode", "module.eidasauth.matching.03", error.getErrorId()); + assertEquals("wrong param 1", "KITT get-latest-version", error.getParams()[0]); + assertEquals("wrong param 2", "Find MORE-THAN-ONE data-sets with already matchted eID during ZMR KITT process", + error.getParams()[1]); + + } + + @Test + @SneakyThrows + public void updateProcessRequired() { + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final String personalIdentifier = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "DE"; + final SimpleEidasData eidasData = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifier) + .pseudonym(personalIdentifier) + .birthName("XXXvon Heuburg") + .placeOfBirth("Hintergigritzpotschn") + .build(); + + RegisterResult toUpdate = RegisterResult.builder() + .bpk("UgeknNsc26lVuB7U/uYGVmWtnnA=") + .dateOfBirth("1994-12-31") + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + //.birthName("") + //.placeOfBirth("") + //.pseudonym(Arrays.asList("")) + .build(); + + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-4_kitt_get_latest_version_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-6_kitt_update_resp.xml")) + .thenThrow(new RuntimeException("Request not needed any more")); + + + // execute operation + ZmrRegisterResult resp = client.update(processId, toUpdate, eidasData); + + // validate request + assertEquals("wrong number of req.", 2, zmrReq.getAllValues().size()); + + // check get laterst version request + RequestType firstReq = zmrReq.getAllValues().get(0); + assertNotNull("1 req.", firstReq.getPersonSuchenRequest()); + checkBasicRequestParameters(firstReq , PROCESS_TASK_SEARCH, processId, "jUnit123456"); + PersonSuchenRequest pSuche = firstReq .getPersonSuchenRequest(); + checkSearchParameters(pSuche.getPersonensucheInfo()); + assertNull("1 req. ZMR Zahl", pSuche.getZMRZahl()); + assertEquals("1 req. identifier size", 1, + pSuche.getNatuerlichePerson().getIdentification().size()); + assertEquals("1 req. givenName", toUpdate.getBpk(), + pSuche.getNatuerlichePerson().getIdentification().get(0).getValue()); + assertEquals("1 req. givenName", "urn:publicid:gv.at:cdid+ZP", + pSuche.getNatuerlichePerson().getIdentification().get(0).getType()); + assertNotNull("1 mds", pSuche.getNatuerlichePerson()); + assertEquals("1 req. givenName", toUpdate.getGivenName(), + pSuche.getNatuerlichePerson().getPersonenName().getVorname()); + assertEquals("1 req. familyName", toUpdate.getFamilyName(), + pSuche.getNatuerlichePerson().getPersonenName().getFamilienname()); + assertEquals("1 req. dateOfBirth", toUpdate.getDateOfBirth(), + pSuche.getNatuerlichePerson().getGeburtsdatum()); + + + // check update request + RequestType secondReq = zmrReq.getAllValues().get(1); + assertNotNull("2 req.", secondReq.getPersonAendernRequest()); + checkBasicRequestParameters(secondReq , PROCESS_TASK_UPDATE, processId, "jUnit123456"); + PersonAendernRequest secondpSuche = secondReq.getPersonAendernRequest(); + + assertEquals("2 req. ZMR Zahl", "000430320173", secondpSuche.getPersonReferenz().getZMRZahl()); + assertEquals("2 req. tech. Ref. value", "44453600000000697", + secondpSuche.getPersonReferenz().getTechnisch().getEntityID()); + assertEquals("2 req. tech. Ref. date", "2020-02-05T13:07:06.311", + secondpSuche.getPersonReferenz().getTechnisch().getLetzteAenderung().toString()); + + assertEquals("eidas Docs. size", 6, secondpSuche.getEidasIdentitaetAnlage().size()); + checkEidasDocumentAdd(secondpSuche.getEidasIdentitaetAnlage(), + "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", cc, eidasData.getPlaceOfBirth()); + checkEidasDocumentAdd(secondpSuche.getEidasIdentitaetAnlage(), + "http://eidas.europa.eu/attributes/naturalperson/BirthName", cc, eidasData.getBirthName()); + checkEidasDocumentAdd(secondpSuche.getEidasIdentitaetAnlage(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", cc, eidasData.getPseudonym()); + checkEidasDocumentAdd(secondpSuche.getEidasIdentitaetAnlage(), + "http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName", cc, eidasData.getGivenName()); + checkEidasDocumentAdd(secondpSuche.getEidasIdentitaetAnlage(), + "http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName", cc, eidasData.getFamilyName()); + checkEidasDocumentAdd(secondpSuche.getEidasIdentitaetAnlage(), + "http://eidas.europa.eu/attributes/naturalperson/DateOfBirth", cc, eidasData.getDateOfBirth()); + + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "366200000000082", resp.getProcessId().toString()); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + + } + + @Test + @SneakyThrows + public void updateProcessNoUpdateRequired() { + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final String personalIdentifier = "7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"; + final String cc = "DE"; + final SimpleEidasData eidasData = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifier) + .pseudonym(personalIdentifier) + .birthName("XXXvon Heuburg") + .placeOfBirth("Hintergigritzpotschn") + .build(); + + RegisterResult toUpdate = RegisterResult.builder() + .bpk("UgeknNsc26lVuB7U/uYGVmWtnnA=") + .dateOfBirth("1994-12-31") + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .birthName("XXXvon Heuburg") + .placeOfBirth("Hintergigritzpotschn") + .pseudonym(Arrays.asList(personalIdentifier)) + .build(); + + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-8_search_with_personalId_only_resp.xml")) + .thenThrow(new RuntimeException("Request not needed any more")); + + + // execute operation + ZmrRegisterResult resp = client.update(processId, toUpdate, eidasData); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + + // check get laterst version request + RequestType firstReq = zmrReq.getAllValues().get(0); + assertNotNull("1 req.", firstReq.getPersonSuchenRequest()); + checkBasicRequestParameters(firstReq , PROCESS_TASK_SEARCH, processId, "jUnit123456"); + PersonSuchenRequest pSuche = firstReq .getPersonSuchenRequest(); + checkSearchParameters(pSuche.getPersonensucheInfo()); + assertNull("1 req. ZMR Zahl", pSuche.getZMRZahl()); + assertEquals("1 req. identifier size", 1, + pSuche.getNatuerlichePerson().getIdentification().size()); + assertEquals("1 req. givenName", toUpdate.getBpk(), + pSuche.getNatuerlichePerson().getIdentification().get(0).getValue()); + assertEquals("1 req. givenName", "urn:publicid:gv.at:cdid+ZP", + pSuche.getNatuerlichePerson().getIdentification().get(0).getType()); + assertNotNull("1 mds", pSuche.getNatuerlichePerson()); + assertEquals("1 req. givenName", toUpdate.getGivenName(), + pSuche.getNatuerlichePerson().getPersonenName().getVorname()); + assertEquals("1 req. familyName", toUpdate.getFamilyName(), + pSuche.getNatuerlichePerson().getPersonenName().getFamilienname()); + assertEquals("1 req. dateOfBirth", toUpdate.getDateOfBirth(), + pSuche.getNatuerlichePerson().getGeburtsdatum()); + + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", processId.toString(), resp.getProcessId().toString()); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + + } + + @Test + @SneakyThrows + public void updateProcessSomeSpecialCases() { + BigInteger processId = new BigInteger(RandomStringUtils.randomNumeric(6)); + + final String personalIdentifier = RandomStringUtils.randomAlphanumeric(10); + final String cc = "DE"; + final SimpleEidasData eidasData = SimpleEidasData.builder() + .citizenCountryCode(cc) + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .dateOfBirth("1994-12-31") + .personalIdentifier(cc + "/AT/" + personalIdentifier) + .pseudonym(personalIdentifier) + .birthName("") //empty addr. values should be ignored + .placeOfBirth(RandomStringUtils.randomAlphabetic(10)) //should be ignored because it was already set for DE + .build(); + + RegisterResult toUpdate = RegisterResult.builder() + .bpk("UgeknNsc26lVuB7U/uYGVmWtnnA=") + .dateOfBirth("1994-12-31") + .familyName("XXXvon Brandenburg") + .givenName("XXXClaus - Maria") + .birthName("XXXvon Heuburg") + .placeOfBirth("Hintergigritzpotschn") + .pseudonym(Arrays.asList("7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit")) + .build(); + + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-8_search_with_personalId_only_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-6_kitt_update_resp.xml")) + .thenThrow(new RuntimeException("Request not needed any more")); + + + // execute operation + ZmrRegisterResult resp = client.update(processId, toUpdate, eidasData); + + // validate request + assertEquals("wrong number of req.", 2, zmrReq.getAllValues().size()); + + // check get latest version request + RequestType firstReq = zmrReq.getAllValues().get(0); + assertNotNull("1 req.", firstReq.getPersonSuchenRequest()); + checkBasicRequestParameters(firstReq , PROCESS_TASK_SEARCH, processId, "jUnit123456"); + PersonSuchenRequest pSuche = firstReq .getPersonSuchenRequest(); + checkSearchParameters(pSuche.getPersonensucheInfo()); + assertNull("1 req. ZMR Zahl", pSuche.getZMRZahl()); + assertEquals("1 req. identifier size", 1, + pSuche.getNatuerlichePerson().getIdentification().size()); + assertEquals("1 req. givenName", toUpdate.getBpk(), + pSuche.getNatuerlichePerson().getIdentification().get(0).getValue()); + assertEquals("1 req. givenName", "urn:publicid:gv.at:cdid+ZP", + pSuche.getNatuerlichePerson().getIdentification().get(0).getType()); + assertNotNull("1 mds", pSuche.getNatuerlichePerson()); + assertEquals("1 req. givenName", toUpdate.getGivenName(), + pSuche.getNatuerlichePerson().getPersonenName().getVorname()); + assertEquals("1 req. familyName", toUpdate.getFamilyName(), + pSuche.getNatuerlichePerson().getPersonenName().getFamilienname()); + assertEquals("1 req. dateOfBirth", toUpdate.getDateOfBirth(), + pSuche.getNatuerlichePerson().getGeburtsdatum()); + + // check update request + RequestType secondReq = zmrReq.getAllValues().get(1); + assertNotNull("2 req.", secondReq.getPersonAendernRequest()); + checkBasicRequestParameters(secondReq , PROCESS_TASK_UPDATE, processId, "jUnit123456"); + PersonAendernRequest secondpSuche = secondReq.getPersonAendernRequest(); + + assertEquals("2 req. ZMR Zahl", "000430320173", secondpSuche.getPersonReferenz().getZMRZahl()); + assertEquals("2 req. tech. Ref. value", "44453600000000697", + secondpSuche.getPersonReferenz().getTechnisch().getEntityID()); + assertEquals("2 req. tech. Ref. date", "2020-02-05T13:07:06.311", + secondpSuche.getPersonReferenz().getTechnisch().getLetzteAenderung().toString()); + + + // only one attribute for update because birthname is empty and placeOfBirth was already set for DE + assertEquals("eidas Docs. size", 1, secondpSuche.getEidasIdentitaetAnlage().size()); + checkEidasDocumentAdd(secondpSuche.getEidasIdentitaetAnlage(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", cc, eidasData.getPseudonym()); + + // validate state + assertNotNull("no ZMR response", resp); + assertEquals("wrong processId", "366200000000082", resp.getProcessId().toString()); + assertEquals("wrong resp size", 1, resp.getPersonResult().size()); + + } + + + private PersonSuchenRequest generateCustomRequest(String cc, String familyName, String givenName, + String dateOfBirth, String personalId, String placeOfBirth, String birthName) { + final PersonSuchenRequest req = new PersonSuchenRequest(); + + // set basic MDS information + final NatuerlichePersonTyp searchNatPerson = new NatuerlichePersonTyp(); + req.setNatuerlichePerson(searchNatPerson); + final PersonenNameTyp searchNatPersonName = new PersonenNameTyp(); + searchNatPerson.setPersonenName(searchNatPersonName); + searchNatPersonName.setFamilienname(familyName); + searchNatPersonName.setVorname(givenName); + searchNatPerson.setGeburtsdatum(dateOfBirth); + + // add addtional eIDAS attributes if available + addIfAvailable(req.getEidasSuchdaten(), cc, Constants.eIDAS_ATTRURN_PLACEOFBIRTH, placeOfBirth); + addIfAvailable(req.getEidasSuchdaten(), cc, Constants.eIDAS_ATTRURN_BIRTHNAME, birthName); + addIfAvailable(req.getEidasSuchdaten(), cc, Constants.eIDAS_ATTRURN_PERSONALIDENTIFIER, personalId); + + return req; + + } + + private void addIfAvailable(List<EidasSuchdatenType> eidasSuchdaten, + String cc, String attrName, String attrValue) { + if (StringUtils.isNotEmpty(attrValue)) { + eidasSuchdaten.add(buildEidasSuchData(cc, attrName, attrValue)); + + } + } + + private EidasSuchdatenType buildEidasSuchData(String cc, String attrName, String attrValue) { + final EidasSuchdatenType eidasInfos = new EidasSuchdatenType(); + eidasInfos.setStaatscode2(cc); + eidasInfos.setEidasArt(attrName); + eidasInfos.setEidasWert(attrValue); + return eidasInfos; + + } + + private void checkSearchParameters(PersonensucheInfoType toCheck) { + assertTrue("searchWithHistory flag", toCheck.getSuchkriterien().isInclusivHistorie()); + assertFalse("withERsB flag", toCheck.getSuchkriterien().isInclusivERnP()); + assertFalse("formalisiert flag", toCheck.getSuchkriterien().isFormalisiert()); + assertFalse("resultWithHistory flag", toCheck.getErgebniskriterien().isInclusivHistorie()); + + } + + private void checkEidasDocumentResult(List<EidasSuchdatenType> list, String type, String cc, String value) { + Optional<EidasSuchdatenType> eidasDoc = list.stream() + .filter(el -> type.equals(el.getEidasArt())) + .findFirst(); + + assertTrue("eidas doc: " + type, eidasDoc.isPresent()); + assertEquals("eIDAS docType", type, eidasDoc.get().getEidasArt()); + assertEquals("eIDAS docValue", value, eidasDoc.get().getEidasWert()); + assertEquals("eIDAS docCC", cc, eidasDoc.get().getStaatscode2()); + + } + + private void checkEidasDocumentAdd(List<EidasIdentitaetAnlageType> list, String type, String cc, + String value) { + Optional<EidasIdentitaetAnlageType> eidasDoc = list.stream() + .filter(el -> type.equals(el.getEidasArt())) + .findFirst(); + + assertTrue("eidas doc: " + type, eidasDoc.isPresent()); + assertEquals("eIDAS docType", type, eidasDoc.get().getEidasArt()); + assertEquals("eIDAS docValue", value, eidasDoc.get().getEidasWert()); + assertEquals("eIDAS docCC", cc, eidasDoc.get().getStaatscode2()); + + } + + private void checkBasicRequestParameters(RequestType requestType, String vorgangName, BigInteger processId, + String behoerdennummer) { + assertNotNull("no workflow infos", requestType.getWorkflowInfoClient()); + assertEquals("processName", PROCESS_GENERAL, requestType.getWorkflowInfoClient().getProzessName()); + assertEquals("vorgangsName", vorgangName, requestType.getWorkflowInfoClient().getVorgangName()); + + if (processId != null) { + assertEquals("processId", processId, requestType.getWorkflowInfoClient().getProzessInstanzID()); + } else { + assertNull("processId", requestType.getWorkflowInfoClient().getProzessInstanzID()); + } + + assertNotNull("no client infos", requestType.getClientInfo()); + assertEquals("behoerdennummer", behoerdennummer, requestType.getClientInfo().getOrganisation() + .getBehoerdenNr()); + } + + private ResponseType loadResponseFromFile(String filepath) throws JAXBException { + final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + JAXBElement<?> resp = (JAXBElement<?>) unmarshaller.unmarshal(ZmrClientTest.class.getResourceAsStream( + filepath)); + return (ResponseType) resp.getValue(); + + } + + private Throwable injectError(boolean isGeneric) { + javax.xml.namespace.QName qName; + if (isGeneric) { + qName = new javax.xml.namespace.QName("urn:SZRServices", "F455", "p344"); + + } else { + qName = new javax.xml.namespace.QName("http://bmi.gv.at/namespace/zmr-su/base/20040201#", "ServiceFault", "zmr"); + + } + final SoapFault fault = new SoapFault( + "The travel document you sent to insert a person already exists for another person. " + "Either check the document or have the person altered accordingly", + qName); + fault.setRole("zmr:ServiceFault"); + return fault; + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/config/EidasConnectorMessageSourceTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/config/EidasConnectorMessageSourceTest.java new file mode 100644 index 00000000..1f96b25c --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/config/EidasConnectorMessageSourceTest.java @@ -0,0 +1,43 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.config; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext +public class EidasConnectorMessageSourceTest { + + @Autowired + private ResourceLoader loader; + @Autowired(required = false) + private List<IMessageSourceLocation> messageSources; + + @Test + public void checkMessageSources() { + Assert.assertNotNull("No messageSource", messageSources); + + for (final IMessageSourceLocation messageSource : messageSources) { + Assert.assertNotNull("No sourcePath", messageSource.getMessageSourceLocation()); + + for (final String el : messageSource.getMessageSourceLocation()) { + final Resource messages = loader.getResource(el + ".properties"); + Assert.assertTrue("Source not exist", messages.exists()); + + } + } + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummyAuthConfigMap.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummyAuthConfigMap.java new file mode 100644 index 00000000..ba531029 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummyAuthConfigMap.java @@ -0,0 +1,144 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; + +import org.apache.commons.lang3.StringUtils; + +/** + * Dummy Application-configuration implementation for jUnit tests. + * + * @author tlenz + * + */ +public class DummyAuthConfigMap implements IConfigurationWithSP { + + private Map<String, String> config = new HashMap<>(); + + /** + * Empty Dummy Application-configuration. + * + */ + public DummyAuthConfigMap() { + + } + + /** + * Dummy Application-configuration. + * + * @param configIs Property based configuration + * @throws IOException In case of an configuration read error + */ + public DummyAuthConfigMap(final InputStream configIs) throws IOException { + + final Properties props = new Properties(); + props.load(configIs); + + config = KeyValueUtils.convertPropertiesToMap(props); + + } + + /** + * Dummy Application-configuration. + * + * @param path Path to property based configuration + * @throws IOException In case of an configuration read error + */ + public DummyAuthConfigMap(final String path) throws IOException { + + final Properties props = new Properties(); + props.load(this.getClass().getResourceAsStream(path)); + + config = KeyValueUtils.convertPropertiesToMap(props); + + } + + + @Override + public String getBasicConfiguration(final String key) { + return config.get(key); + + } + + @Override + public String getBasicConfiguration(final String key, final String defaultValue) { + final String value = getBasicConfiguration(key); + if (StringUtils.isEmpty(value)) { + return defaultValue; + } else { + return value; + } + + } + + @Override + public boolean getBasicConfigurationBoolean(final String key) { + final String value = getBasicConfiguration(key); + if (StringUtils.isEmpty(value)) { + return false; + } else { + return Boolean.valueOf(value); + } + } + + @Override + public boolean getBasicConfigurationBoolean(final String key, final boolean defaultValue) { + return Boolean.parseBoolean(getBasicConfiguration(key, String.valueOf(defaultValue))); + + } + + @Override + public Map<String, String> getBasicConfigurationWithPrefix(final String prefix) { + return KeyValueUtils.getSubSetWithPrefix(config, prefix); + + } + + @Override + public ISpConfiguration getServiceProviderConfiguration(final String uniqueID) + throws EaafConfigurationException { + return null; + } + + @Override + public <T> T getServiceProviderConfiguration(final String spIdentifier, final Class<T> decorator) + throws EaafConfigurationException { + return null; + } + + @Override + public URI getConfigurationRootDirectory() { + return new java.io.File(".").toURI(); + + } + + @Override + public String validateIdpUrl(final URL authReqUrl) throws EaafException { + return authReqUrl.toString(); + } + + public void putConfigValue(final String key, final String value) { + config.put(key, value); + } + + public void removeConfigValue(final String key) { + config.remove(key); + + } + + public void removeAll() { + config.clear(); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummyOA.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummyOA.java new file mode 100644 index 00000000..074dd0bb --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummyOA.java @@ -0,0 +1,304 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; + +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.utils.KeyValueUtils; +import lombok.Getter; +import lombok.Setter; + +public class DummyOA implements IAhSpConfiguration { + + private static final long serialVersionUID = 1L; + private String uniqueAppId = null; + private String targetIdentifier = null; + private String friendlyName = null; + private String cc = "AT"; + private final Map<String, String> config = new HashMap<>(); + private final List<Pair<String, String>> reqAttributes = new ArrayList<>(); + + private boolean mandateEnabled = false; + private boolean onlyMandateEnabled = false; + private String mandateProfilesCsv; + + private boolean eidasEnabled = false; + + private boolean testCredentialEnabled = true; + private String additionalBpkTargetCsv; + private List<Pair<String, String>> additionalEncBpkTargets; + + @Setter + private boolean restricted = true; + + @Setter + private long latestVdaAuthentication = 60 * 365 * 5; + + @Getter + @Setter + private boolean publicServiceProvider; + + @Getter + @Setter + private boolean multiMandateEnabled; + + @Setter + private String bmiUniqueIdentifier; + + @Override + public Map<String, String> getFullConfiguration() { + return this.config; + } + + @Override + public String getConfigurationValue(final String key) { + return this.config.get(key); + } + + @Override + public String getConfigurationValue(final String key, final String defaultValue) { + if (StringUtils.isNotEmpty(getConfigurationValue(key))) { + return getConfigurationValue(key); + } else { + return defaultValue; + } + } + + @Override + public boolean isConfigurationValue(final String key) { + if (StringUtils.isNotEmpty(getConfigurationValue(key))) { + return Boolean.parseBoolean(getConfigurationValue(key)); + } else { + return false; + } + + } + + @Override + public boolean isConfigurationValue(final String key, final boolean defaultValue) { + return Boolean.parseBoolean(getConfigurationValue(key, String.valueOf(defaultValue))); + + } + + @Override + public boolean containsConfigurationKey(final String key) { + return this.config.containsKey(key); + } + + @Override + public String getUniqueIdentifier() { + return this.uniqueAppId; + } + + @Override + public String getUniqueApplicationRegisterIdentifier() { + return this.bmiUniqueIdentifier; + + } + + @Override + public String getFriendlyName() { + return this.friendlyName; + } + + @Override + public boolean hasBaseIdInternalProcessingRestriction() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean hasBaseIdTransferRestriction() { + // TODO Auto-generated method stub + return false; + } + + @Override + public Set<String> getTargetsWithNoBaseIdInternalProcessingRestriction() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Set<String> getTargetsWithNoBaseIdTransferRestriction() { + // TODO Auto-generated method stub + return null; + } + + @Override + public List<String> getRequiredLoA() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getLoAMatchingMode() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getAreaSpecificTargetIdentifier() { + return this.targetIdentifier; + } + + @Override + public boolean isTestCredentialEnabled() { + return this.testCredentialEnabled; + } + + @Override + public List<String> getTestCredentialOids() { + // TODO Auto-generated method stub + return null; + } + + @Override + public List<Pair<String, String>> getRequiredAttributes() { + return this.reqAttributes; + + } + + public void setUniqueAppId(final String uniqueAppId) { + this.uniqueAppId = uniqueAppId; + } + + @Override + public String getCountryCode() { + return cc; + } + + @Override + public void setCountryCode(final String cc) { + this.cc = cc; + + } + + public void setTargetIdentifier(final String targetIdentifier) { + this.targetIdentifier = BpkBuilder.normalizeBpkTargetIdentifierToCommonFormat(targetIdentifier); + + } + + public void setFriendlyName(final String friendlyName) { + this.friendlyName = friendlyName; + } + + public void putGenericConfigurationKey(final String key, final String value) { + this.config.put(key, value); + + } + + public void addRequiredAttribute(final String attrUri) { + this.reqAttributes.add(Pair.newInstance(attrUri, null)); + + } + + public void removeRequiredAttribute(final String attrUri) { + for (final Pair<String, String> el : reqAttributes) { + if (el.getFirst().equals(attrUri)) { + reqAttributes.remove(el); + break; + + } + + + } + } + + public void addRequiredAttribute(final String attrUri, String param) { + this.reqAttributes.add(Pair.newInstance(attrUri, param)); + + } + + @Override + public boolean isMandateEnabled() { + return this.mandateEnabled; + } + + @Override + public boolean isOnlyMandateEnabled() { + return this.onlyMandateEnabled; + + } + + @Override + public List<String> getMandateProfiles() { + return KeyValueUtils.getListOfCsvValues(mandateProfilesCsv); + } + + @Override + public List<String> getAdditionalBpkTargets() { + return KeyValueUtils.getListOfCsvValues(additionalBpkTargetCsv); + + } + + @Override + public List<Pair<String, String>> getAdditionalForeignBpkTargets() { + if (additionalEncBpkTargets == null) { + return Collections.emptyList(); + + } else { + return additionalEncBpkTargets; + + } + } + + @Override + public long lastVdaAuthenticationDelay() { + return latestVdaAuthentication; + + } + + @Override + public boolean isRestrictedServiceProvider() { + return this.restricted; + } + + + public void setMandateEnabled(final boolean mandateEnabled) { + this.mandateEnabled = mandateEnabled; + } + + public void setOnlyMandateEnabled(final boolean onlyMandateEnabled) { + this.onlyMandateEnabled = onlyMandateEnabled; + } + + public void setMandateProfilesCsv(final String mandateProfilesCsv) { + this.mandateProfilesCsv = mandateProfilesCsv; + } + + public void setTestCredentialEnabled(final boolean testCredentialEnabled) { + this.testCredentialEnabled = testCredentialEnabled; + } + + public void setAdditionalBpkTargetCsv(String additionalBpkTargetCsv) { + this.additionalBpkTargetCsv = additionalBpkTargetCsv; + } + + public void setAdditionalEncBpkTargets(List<Pair<String, String>> additionalEncBpkTargets) { + this.additionalEncBpkTargets = additionalEncBpkTargets; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public boolean isEidasEnabled() { + return this.eidasEnabled; + + } + + public void setEidasEnabled(boolean eidasEnabled) { + this.eidasEnabled = eidasEnabled; + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummyPendingRequest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummyPendingRequest.java new file mode 100644 index 00000000..9a91ecbd --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummyPendingRequest.java @@ -0,0 +1,8 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy; + +import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; + +public class DummyPendingRequest extends RequestImpl { + private static final long serialVersionUID = 8136280395622411505L; +} + diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummySpecificCommunicationService.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummySpecificCommunicationService.java new file mode 100644 index 00000000..d2b0c1ae --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummySpecificCommunicationService.java @@ -0,0 +1,58 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy; + +import java.util.Collection; + +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.light.ILightRequest; +import eu.eidas.auth.commons.light.ILightResponse; +import eu.eidas.auth.commons.tx.BinaryLightToken; +import eu.eidas.specificcommunication.BinaryLightTokenHelper; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; +import eu.eidas.specificcommunication.protocol.SpecificCommunicationService; + +public class DummySpecificCommunicationService implements SpecificCommunicationService { + + private ILightRequest lightRequest; + private ILightResponse lightResponse; + + @Override + public BinaryLightToken putRequest(ILightRequest lightRequest) throws SpecificCommunicationException { + this.lightRequest = lightRequest; + return BinaryLightTokenHelper.createBinaryLightToken("Test", "TestSecret", "SHA-256"); + } + + @Override + public ILightRequest getAndRemoveRequest(String tokenBase64, Collection<AttributeDefinition<?>> registry) + throws SpecificCommunicationException { + return lightRequest; + } + + @Override + public BinaryLightToken putResponse(ILightResponse lightResponse) throws SpecificCommunicationException { + this.lightResponse = lightResponse; + return BinaryLightTokenHelper.createBinaryLightToken("Test", "TestSecret", "SHA-256"); + } + + @Override + public ILightResponse getAndRemoveResponse(String tokenBase64, Collection<AttributeDefinition<?>> registry) + throws SpecificCommunicationException { + return lightResponse; + } + + public ILightRequest getiLightRequest() { + return lightRequest; + } + + public void setiLightRequest(ILightRequest lightReques) { + this.lightRequest = lightReques; + } + + public ILightResponse getiLightResponse() { + return lightResponse; + } + + public void setiLightResponse(ILightResponse lightResponse) { + this.lightResponse = lightResponse; + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/IAhSpConfiguration.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/IAhSpConfiguration.java new file mode 100644 index 00000000..13d61f15 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/IAhSpConfiguration.java @@ -0,0 +1,152 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy; + +import java.util.List; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.impl.data.Pair; + +public interface IAhSpConfiguration extends ISpConfiguration { + + + /** + * Flag if this Service Provider is enabled. + * + * @return true if the SP is enabled, otherwise false + */ + boolean isEnabled(); + + /** + * Get unique identifier that is used in Application-Register from BM.I. + * + * <p>If no BM.I specific identifier is available then this method returns + * the same identifier as <code>getUniqueIdentifier()</code></p> + * + * @return unique identifier from BM.I AppReg, or generic uniqueId of no specific exists + */ + String getUniqueApplicationRegisterIdentifier(); + + /** + * Flag that marks this Service-Provider as <i>public</i> or <i>private</i>. + * + * <p><b>Default:</b> If it is not set or has an unknown value, its <i>private</i> by default</p> + * + * @return <code>true</code> if it is from <i>public</i>, otherwise <code>false</code> + */ + boolean isPublicServiceProvider(); + + /** + * Enable test identities for this Service Provider. + * + * @return true if test identities are allowed, otherwise false + */ + boolean isTestCredentialEnabled(); + + /** + * Get a List of OID's that refine the set of allowed test identities. + * + * @return @link {@link List} of test-identity OID's + */ + @Nullable + List<String> getTestCredentialOids(); + + + /** + * Get a List of unique attribute URI's that are required by this SP. + * + * @return {@link List} of attribute URI's / parameter {@link Pair}s + */ + List<Pair<String, String>> getRequiredAttributes(); + + + /** + * Get the CountryCode for this service. <br> + * <br> + * <b>Default:</b> AT + * + * @return + */ + String getCountryCode(); + + /** + * Set the CountryCode for this service. If not countryCode is set, AT is used as default. + * + * @param cc Service-Provider country-code + */ + void setCountryCode(String cc); + + /** + * Enable mandates for this service provider. + * + * @return <code>true</code> if mandates are enabled, otherwise <code>false</code> + */ + boolean isMandateEnabled(); + + /** + * Enables multi-mandates for this service-provider. + * + * @return <code>true</code> if multi-mandates are enabled, otherwise <code>false</code> + */ + boolean isMultiMandateEnabled(); + + /** + * Only mandates are allowed for this service provider. + * + * @return <code>true</code> if only mandates are allowed, otherwise <code>false</code> + */ + boolean isOnlyMandateEnabled(); + + /** + * Get a {@link List} of mandate profiles that are supported by this Service provider. + * + * @return + */ + @Nonnull List<String> getMandateProfiles(); + + + /** + * eIDAS authentication allowed flag. + * + * @return <code>true</code> if eIDAS authentication is enabled, otherwise <code>false</code> + */ + boolean isEidasEnabled(); + + /** + * Get a List of targets for additional bPKs that are required by this service provider. + * + * @return List of prefixed bPK targets + */ + @Nonnull List<String> getAdditionalBpkTargets(); + + /** + * Get a list of foreign bPK targets that are required by this service provider. + * + * @return List of pairs with prefixed bPK targets as first element and VKZ as second element + */ + @Nonnull List<Pair<String, String>> getAdditionalForeignBpkTargets(); + + /** + * Flag that indicates that service-provider as restricted or unrestricted. + * + * <p>A restricted service-provider can only used by test-identities that contains a + * valid application-restriction in User-Certificate Pinning</p> + * + * <p><b>Default:</b> true</p> + * + * @return <code>true</code> if it is restricted, otherwise <code>false</code> + */ + boolean isRestrictedServiceProvider(); + + +/** + * Defines the time in minutes how long the last VDA registration h@Override + ave passed as maximum. + * + * @return time in minutes + */ +long lastVdaAuthenticationDelay(); + +} + diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/handler/DeSpecificDetailSearchProcessorTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/handler/DeSpecificDetailSearchProcessorTest.java new file mode 100644 index 00000000..21c9fd80 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/handler/DeSpecificDetailSearchProcessorTest.java @@ -0,0 +1,105 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.handler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.DeSpecificDetailSearchProcessor; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest; + +@RunWith(BlockJUnit4ClassRunner.class) +public class DeSpecificDetailSearchProcessorTest { + + private DeSpecificDetailSearchProcessor handler = new DeSpecificDetailSearchProcessor(); + + @Test + public void checkName() { + assertEquals("wrong handler name", "DeSpecificDetailSearchProcessor", handler.getName()); + + } + + @Test + public void canHandlerCheck_1() { + SimpleEidasData eidData = SimpleEidasData.builder() + .birthName(RandomStringUtils.randomAlphabetic(5)) + .placeOfBirth(RandomStringUtils.randomAlphabetic(5)) + .build(); + assertFalse("wrong 'canHandle' flag", handler.canHandle("XX", eidData)); + + } + + @Test + public void canHandlerCheck_2() { + SimpleEidasData eidData = SimpleEidasData.builder() + .birthName(RandomStringUtils.randomAlphabetic(5)) + .placeOfBirth(RandomStringUtils.randomAlphabetic(5)) + .build(); + assertTrue("wrong 'canHandle' flag", handler.canHandle("DE", eidData)); + + } + + @Test + public void canHandlerCheck_3() { + SimpleEidasData eidData = SimpleEidasData.builder() + .birthName(RandomStringUtils.randomAlphabetic(5)) + .placeOfBirth(RandomStringUtils.randomAlphabetic(5)) + .build(); + assertTrue("wrong 'canHandle' flag", handler.canHandle("de", eidData)); + + } + + @Test + public void canHandlerCheck_4() { + SimpleEidasData eidData = SimpleEidasData.builder() + .birthName(null) + .placeOfBirth(RandomStringUtils.randomAlphabetic(5)) + .build(); + assertFalse("wrong 'canHandle' flag", handler.canHandle("DE", eidData)); + + } + + @Test + public void canHandlerCheck_5() { + SimpleEidasData eidData = SimpleEidasData.builder() + .birthName(RandomStringUtils.randomAlphabetic(5)) + .placeOfBirth(null) + .build(); + assertFalse("wrong 'canHandle' flag", handler.canHandle("DE", eidData)); + + } + + @Test + public void generateZmrSearchRequest() { + SimpleEidasData eidData = SimpleEidasData.builder() + .citizenCountryCode("DE") + .givenName(RandomStringUtils.randomAlphabetic(5)) + .familyName(RandomStringUtils.randomAlphabetic(5)) + .dateOfBirth(RandomStringUtils.randomAlphabetic(5)) + .birthName(RandomStringUtils.randomAlphabetic(5)) + .placeOfBirth(RandomStringUtils.randomAlphabetic(5)) + .build(); + + // perform operation + PersonSuchenRequest req = handler.generateSearchRequest(eidData); + + //validate response + assertNotNull("no search request", req); + assertNotNull("no MDS", req.getNatuerlichePerson()); + assertNotNull("no MDS PersonName", req.getNatuerlichePerson().getPersonenName()); + assertEquals("familyName", eidData.getFamilyName(), req.getNatuerlichePerson().getPersonenName().getFamilienname()); + assertEquals("givenName", eidData.getGivenName(), req.getNatuerlichePerson().getPersonenName().getVorname()); + assertEquals("birthday", eidData.getDateOfBirth(), req.getNatuerlichePerson().getGeburtsdatum()); + + assertNotNull("no eIDAS documenst", req.getEidasSuchdaten()); + //TODO: add validation if we can add more than one eIDAS document + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/handler/ItSpecificDetailSearchProcessorTes.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/handler/ItSpecificDetailSearchProcessorTes.java new file mode 100644 index 00000000..9b638ee5 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/handler/ItSpecificDetailSearchProcessorTes.java @@ -0,0 +1,84 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.handler; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.ItSpecificDetailSearchProcessor; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest; + +@RunWith(BlockJUnit4ClassRunner.class) +public class ItSpecificDetailSearchProcessorTes { + + private ItSpecificDetailSearchProcessor handler = new ItSpecificDetailSearchProcessor(); + + @Test + public void checkName() { + assertEquals("wrong handler name", "ItSpecificDetailSearchProcessor", handler.getName()); + + } + + @Test + public void canHandlerCheck_1() { + SimpleEidasData eidData = SimpleEidasData.builder() + .taxNumber(RandomStringUtils.randomAlphabetic(5)) + .build(); + assertFalse("wrong 'canHandle' flag", handler.canHandle("XX", eidData)); + + } + + @Test + public void canHandlerCheck_2() { + SimpleEidasData eidData = SimpleEidasData.builder() + .taxNumber(RandomStringUtils.randomAlphabetic(5)) + .build(); + assertTrue("wrong 'canHandle' flag", handler.canHandle("IT", eidData)); + + } + + @Test + public void canHandlerCheck_3() { + SimpleEidasData eidData = SimpleEidasData.builder() + .taxNumber(RandomStringUtils.randomAlphabetic(5)) + .build(); + assertTrue("wrong 'canHandle' flag", handler.canHandle("it", eidData)); + + } + + @Test + public void canHandlerCheck_4() { + SimpleEidasData eidData = SimpleEidasData.builder() + .taxNumber("") + .build(); + assertFalse("wrong 'canHandle' flag", handler.canHandle("IT", eidData)); + + } + + @Test + public void generateZmrSearchRequest() { + SimpleEidasData eidData = SimpleEidasData.builder() + .citizenCountryCode("IT") + .givenName(RandomStringUtils.randomAlphabetic(5)) + .familyName(RandomStringUtils.randomAlphabetic(5)) + .dateOfBirth(RandomStringUtils.randomAlphabetic(5)) + .taxNumber(RandomStringUtils.randomAlphabetic(5)) + .build(); + + // perform operation + PersonSuchenRequest req = handler.generateSearchRequest(eidData); + + //validate response + assertNotNull("no search request", req); + + //TODO: add validation if we can add more information about taxNumber from Italy + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaAuthSignalControllerTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaAuthSignalControllerTest.java new file mode 100644 index 00000000..cddcd11c --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaAuthSignalControllerTest.java @@ -0,0 +1,197 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.idaustriaclient; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.SerializationUtils; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.controller.IdAustriaClientAuthSignalController; +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.ExceptionContainer; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; +import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyProtocolAuthService; +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.spring.test.DummyTransactionStorage.DummyDbEntry; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +public class IdAustriaAuthSignalControllerTest { + + @Autowired(required = true) + private IdAustriaClientAuthSignalController controller; + @Autowired(required = true) + private ITransactionStorage cache; + @Autowired(required = true) + private IPendingRequestIdGenerationStrategy pendingReqGeneration; + @Autowired(required = true) + private IRequestStorage reqStorage; + @Autowired(required = true) + private IConfiguration basicConfig; + @Autowired private ITransactionStorage transactionStorage; + + @Autowired private DummyProtocolAuthService protAuthService; + + @Test + public void noRelayState() throws IOException, EaafException { + final MockHttpServletRequest httpReq = + new MockHttpServletRequest("POST", "https://localhost/authhandler"); + final MockHttpServletResponse httpResp = new MockHttpServletResponse(); + + controller.performAuthentication(httpReq, httpResp); + Assert.assertEquals("httpStausCode", 200, httpResp.getStatus()); + + final String errorId = protAuthService.getErrorKey(); + final Object error = cache.get(errorId); + Assert.assertNotNull("Error is null", error); + org.springframework.util.Assert.isInstanceOf(byte[].class, + ((DummyDbEntry) error).getObj()); + final Object errorObj = SerializationUtils.deserialize((byte[]) ((DummyDbEntry) error).getObj()); + org.springframework.util.Assert.isInstanceOf(ExceptionContainer.class, errorObj); + org.springframework.util.Assert.isInstanceOf(EaafException.class, + ((ExceptionContainer) errorObj).getExceptionThrown()); + + } + + @Test + public void validRelayStateNoPendingReqId() throws EaafException, IOException { + final String pendingReqId = pendingReqGeneration.generateExternalPendingRequestId(); + final MockHttpServletRequest httpReq = + new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpReq.addParameter(IdAustriaClientAuthSignalController.HTTP_PARAM_RELAYSTATE, pendingReqId); + final MockHttpServletResponse httpResp = new MockHttpServletResponse(); + + controller.performAuthentication(httpReq, httpResp); + Assert.assertEquals("httpStausCode", 200, httpResp.getStatus()); + + final String errorId = protAuthService.getErrorKey(); + final Object error = cache.get(errorId); + Assert.assertNotNull("Error is null", error); + org.springframework.util.Assert.isInstanceOf(byte[].class, + ((DummyDbEntry) error).getObj()); + final Object errorObj = SerializationUtils.deserialize((byte[]) ((DummyDbEntry) error).getObj()); + org.springframework.util.Assert.isInstanceOf(ExceptionContainer.class, errorObj); + org.springframework.util.Assert.isInstanceOf(EaafException.class, + ((ExceptionContainer) errorObj).getExceptionThrown()); + //TODO: + Assert.assertEquals("ErrorCode not match", "auth.26", + ((EaafException) ((ExceptionContainer) errorObj).getExceptionThrown()).getErrorId()); + + } + + @Test + public void validRelayStateSuspectPendingReqId() throws EaafException, IOException { + String relayState = RandomStringUtils.randomAlphanumeric(10); + transactionStorage.put(relayState, false, -1); + + final MockHttpServletRequest httpReq = + new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpReq.addParameter(IdAustriaClientAuthSignalController.HTTP_PARAM_RELAYSTATE, relayState); + final MockHttpServletResponse httpResp = new MockHttpServletResponse(); + + controller.performAuthentication(httpReq, httpResp); + Assert.assertEquals("httpStausCode", 200, httpResp.getStatus()); + + final String errorId = protAuthService.getErrorKey(); + final Object error = cache.get(errorId); + Assert.assertNotNull("Error is null", error); + org.springframework.util.Assert.isInstanceOf(byte[].class, + ((DummyDbEntry) error).getObj()); + final Object errorObj = SerializationUtils.deserialize((byte[]) ((DummyDbEntry) error).getObj()); + org.springframework.util.Assert.isInstanceOf(ExceptionContainer.class, errorObj); + org.springframework.util.Assert.isInstanceOf(EaafException.class, + ((ExceptionContainer) errorObj).getExceptionThrown()); + //TODO: + Assert.assertEquals("ErrorCode not match", "auth.26", + ((EaafException) ((ExceptionContainer) errorObj).getExceptionThrown()).getErrorId()); + + Assert.assertNull("RelayState was not removed", transactionStorage.get(relayState)); + + } + + @Test + public void validRelayStateNoPendingReq() throws EaafException, IOException { + final String pendingReqId = pendingReqGeneration.generateExternalPendingRequestId(); + String relayState = RandomStringUtils.randomAlphanumeric(10); + transactionStorage.put(relayState, pendingReqId, -1); + + final MockHttpServletRequest httpReq = + new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpReq.addParameter(IdAustriaClientAuthSignalController.HTTP_PARAM_RELAYSTATE, relayState); + final MockHttpServletResponse httpResp = new MockHttpServletResponse(); + + controller.performAuthentication(httpReq, httpResp); + Assert.assertEquals("httpStausCode", 200, httpResp.getStatus()); + + final String errorId = protAuthService.getErrorKey(); + final Object error = cache.get(errorId); + Assert.assertNotNull("Error is null", error); + org.springframework.util.Assert.isInstanceOf(byte[].class, + ((DummyDbEntry) error).getObj()); + final Object errorObj = SerializationUtils.deserialize((byte[]) ((DummyDbEntry) error).getObj()); + org.springframework.util.Assert.isInstanceOf(ExceptionContainer.class, errorObj); + org.springframework.util.Assert.isInstanceOf(EaafException.class, + ((ExceptionContainer) errorObj).getExceptionThrown()); + Assert.assertEquals("ErrorCode not match", "auth.28", + ((EaafException) ((ExceptionContainer) errorObj).getExceptionThrown()).getErrorId()); + + Assert.assertNull("RelayState was not removed", transactionStorage.get(relayState)); + + } + + @Test + public void validRelayStateWithPendingReq() throws EaafException, IOException { + final String pendingReqId = pendingReqGeneration.generateExternalPendingRequestId(); + + String relayState = RandomStringUtils.randomAlphanumeric(10); + transactionStorage.put(relayState, pendingReqId, -1); + + final TestRequestImpl pendingReq = new TestRequestImpl(); + pendingReq.setPendingReqId(pendingReqId); + pendingReq.setAuthUrl("http://localhost/idp"); + final Map<String, String> spConfigMap = new HashMap<>(); + spConfigMap.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "http://test.sp"); + final DummySpConfiguration spConfig = new DummySpConfiguration(spConfigMap, basicConfig); + pendingReq.setSpConfig(spConfig); + reqStorage.storePendingRequest(pendingReq); + + final MockHttpServletRequest httpReq = + new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpReq.addParameter(IdAustriaClientAuthSignalController.HTTP_PARAM_RELAYSTATE, relayState); + final MockHttpServletResponse httpResp = new MockHttpServletResponse(); + + controller.performAuthentication(httpReq, httpResp); + + Assert.assertEquals("httpStausCode", 200, httpResp.getStatus()); + + final String errorId = protAuthService.getErrorKey(); + final Object error = cache.get(errorId); + Assert.assertNotNull("Error is null", error); + org.springframework.util.Assert.isInstanceOf(byte[].class, + ((DummyDbEntry) error).getObj()); + final Object errorObj = SerializationUtils.deserialize((byte[]) ((DummyDbEntry) error).getObj()); + org.springframework.util.Assert.isInstanceOf(ExceptionContainer.class, errorObj); + org.springframework.util.Assert.isInstanceOf(EaafException.class, + ((ExceptionContainer) errorObj).getExceptionThrown()); + Assert.assertEquals("ErrorCode not match", + "PendingRequest object is not of type 'RequestImpl.class'", + ((EaafException) ((ExceptionContainer) errorObj).getExceptionThrown()).getErrorId()); + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthHealthCheckTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthHealthCheckTest.java new file mode 100644 index 00000000..a912f344 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthHealthCheckTest.java @@ -0,0 +1,130 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.idaustriaclient; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.w3c.dom.Element; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthConstants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.provider.IdAustriaClientAuthHealthCheck; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.provider.IdAustriaClientAuthMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.utils.IPvp2CredentialProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import net.shibboleth.utilities.java.support.resolver.ResolverException; +import net.shibboleth.utilities.java.support.xml.SerializeSupport; +import net.shibboleth.utilities.java.support.xml.XMLParserException; +import okhttp3.HttpUrl; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +public class IdAustriaClientAuthHealthCheckTest { + + @Autowired private IdAustriaClientAuthHealthCheck toCheck; + @Autowired protected MsConnectorDummyConfigMap config; + @Autowired private IPvp2CredentialProvider credentialProvider; + @Autowired IdAustriaClientAuthMetadataProvider provider; + + private static MockWebServer mockWebServer; + private static HttpUrl mockServerUrl; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void classInitializer() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + mockWebServer = new MockWebServer(); + mockServerUrl = mockWebServer.url("/sp/metadata"); + + } + + @Test + public void notActive() { + //set-up test + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID, + null); + + //perform check + Health status = toCheck.health(); + + //evaluate status + Assert.assertEquals("wrong status", Health.unknown().build().getStatus(), status.getStatus()); + + } + + @Test + public void success() throws SamlSigningException, CredentialsNotAvailableException, + XMLParserException, UnmarshallingException, MarshallingException { + + //set-up test + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID, + mockServerUrl.url().toString()); + injectValidHttpMetadata(mockServerUrl.url().toString()); + + //perform check + Health status = toCheck.health(); + + //evaluate status + Assert.assertEquals("wrong status", Health.up().build().getStatus(), status.getStatus()); + + } + + @Test + public void invalid() throws SamlSigningException, CredentialsNotAvailableException, + XMLParserException, UnmarshallingException, MarshallingException, ResolverException { + //set-up test + provider.clear(); + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID, + "http://localhost:1234/junit/metadata"); + + //perform check + Health status = toCheck.health(); + + //evaluate status + Assert.assertEquals("wrong status", Health.outOfService().build().getStatus(), status.getStatus()); + + } + + private String injectValidHttpMetadata(String dynEntityId) throws XMLParserException, + UnmarshallingException, MarshallingException, SamlSigningException, CredentialsNotAvailableException { + final EntityDescriptor metadata = (EntityDescriptor) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + IdAustriaClientAuthHealthCheckTest.class.getResourceAsStream("/data/idp_metadata_no_sig.xml")); + metadata.setValidUntil(Instant.now().plus(1, ChronoUnit.DAYS)); + metadata.setSignature(null); + metadata.setEntityID(dynEntityId); + Saml2Utils.signSamlObject(metadata, credentialProvider.getMetaDataSigningCredential(), true); + final Element metadataElement = XMLObjectSupport.marshall(metadata); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(SerializeSupport.nodeToString(metadataElement)) + .setHeader("Content-Type", "text/html;charset=utf-8")); + return dynEntityId; + +} + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthMetadataControllerTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthMetadataControllerTest.java new file mode 100644 index 00000000..095a020a --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthMetadataControllerTest.java @@ -0,0 +1,136 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.idaustriaclient; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.metadata.resolver.filter.FilterException; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilterContext; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthConstants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.controller.IdAustriaClientAuthMetadataController; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.provider.IdAustriaClientAuthCredentialProvider; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.SchemaValidationFilter; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.SimpleMetadataSignatureVerificationFilter; +import net.shibboleth.utilities.java.support.xml.XMLParserException; + + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) +public class IdAustriaClientAuthMetadataControllerTest { + + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + + @Autowired private IdAustriaClientAuthMetadataController controller; + @Autowired private IdAustriaClientAuthCredentialProvider credProvider; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void initialize() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + } + + /** + * Single jUnit-test set-up. + */ + @Before + public void testSetup() { + httpReq = new MockHttpServletRequest("GET", "http://localhost/authhandler"); + httpReq.setContextPath("/authhandler"); + httpResp = new MockHttpServletResponse(); + + } + + @Test + public void buildMetadataValidInEidMode() throws IOException, EaafException, + XMLParserException, UnmarshallingException, FilterException { + + //build metdata + controller.getSpMetadata(httpReq, httpResp); + + //check result + validateResponse(7); + + } + + private void validateResponse(int numberOfRequestedAttributes) throws UnsupportedEncodingException, + XMLParserException, UnmarshallingException, FilterException, CredentialsNotAvailableException { + Assert.assertEquals("HTTP Statuscode", 200, httpResp.getStatus()); + Assert.assertEquals("ContentType", "text/xml; charset=utf-8", httpResp.getContentType()); + Assert.assertEquals("ContentEncoding", "UTF-8", httpResp.getCharacterEncoding()); + + final String metadataXml = httpResp.getContentAsString(); + Assert.assertNotNull("XML Metadata", metadataXml); + + final EntityDescriptor metadata = (EntityDescriptor) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), new ByteArrayInputStream(metadataXml.getBytes("UTF-8"))); + + Assert.assertEquals("EntityId", + "http://localhost/authhandler" + IdAustriaClientAuthConstants.ENDPOINT_METADATA, + metadata.getEntityID()); + + MetadataFilterContext filterContext = new MetadataFilterContext(); + + //check XML scheme + final SchemaValidationFilter schemaFilter = new SchemaValidationFilter(); + schemaFilter.filter(metadata, filterContext); + + //check signature + final SimpleMetadataSignatureVerificationFilter sigFilter = + new SimpleMetadataSignatureVerificationFilter(credProvider.getKeyStore().getFirst(), + metadata.getEntityID()); + sigFilter.filter(metadata, filterContext); + + //check content + final SPSSODescriptor spSsoDesc = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS); + Assert.assertNotNull("SPSSODescr.", spSsoDesc); + + Assert.assertFalse("AssertionConsumerServices", + spSsoDesc.getAssertionConsumerServices().isEmpty()); + + Assert.assertFalse("KeyDescriptors", + spSsoDesc.getKeyDescriptors().isEmpty()); + Assert.assertEquals("#KeyDescriptors", 2, spSsoDesc.getKeyDescriptors().size()); + + Assert.assertFalse("NameIDFormats", + spSsoDesc.getNameIDFormats().isEmpty()); + Assert.assertEquals("wrong NameIDFormats", "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", + spSsoDesc.getNameIDFormats().get(0).getURI()); + + Assert.assertFalse("AttributeConsumingServices", + spSsoDesc.getAttributeConsumingServices().isEmpty()); + Assert.assertEquals("#RequestAttributes", numberOfRequestedAttributes, + spSsoDesc.getAttributeConsumingServices().get(0).getRequestedAttributes().size()); + + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthMetadataProviderFirstTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthMetadataProviderFirstTest.java new file mode 100644 index 00000000..c4dd5d2e --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthMetadataProviderFirstTest.java @@ -0,0 +1,239 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.idaustriaclient; + +import java.io.IOException; +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.criterion.EntityIdCriterion; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.w3c.dom.Element; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.provider.IdAustriaClientAuthMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.utils.IPvp2CredentialProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.test.metadata.MetadataResolverTest; +import net.shibboleth.utilities.java.support.resolver.CriteriaSet; +import net.shibboleth.utilities.java.support.resolver.ResolverException; +import net.shibboleth.utilities.java.support.xml.SerializeSupport; +import net.shibboleth.utilities.java.support.xml.XMLParserException; +import okhttp3.HttpUrl; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +public class IdAustriaClientAuthMetadataProviderFirstTest { + + @Autowired + IPvp2CredentialProvider credentialProvider; + @Autowired + IdAustriaClientAuthMetadataProvider provider; + @Autowired + PvpMetadataResolverFactory resolverFactory; + + private static MockWebServer mockWebServer; + private static HttpUrl mockServerUrl; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void classInitializer() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + mockWebServer = new MockWebServer(); + mockServerUrl = mockWebServer.url("/sp/metadata"); + + } + + /** + * jUnit test set-up. + * + * @throws ResolverException + * + */ + @Before + public void testSetup() { + provider.fullyDestroy(); + + } + + @Test + public void simpleManuelAddingTest() throws Pvp2MetadataException, ResolverException { + final IPvp2MetadataProvider resolver1 = resolverFactory.createMetadataProvider( + "classpath:/data/idp_metadata_sig_notvalid.xml", + null, "junit", null); + Assert.assertNotNull("Resolver 1 is null", resolver1); + provider.addMetadataResolverIntoChain(resolver1); + + final IPvp2MetadataProvider resolver2 = resolverFactory.createMetadataProvider( + "classpath:/data/idp_metadata_sig_valid_wrong_alg.xml", + null, "junit", null); + Assert.assertNotNull("Resolver 2 is null", resolver2); + provider.addMetadataResolverIntoChain(resolver2); + + final EntityDescriptor entity1 = provider.getEntityDescriptor("https://localEntity"); + Assert.assertNotNull("Entity 1 not found", entity1); + + final EntityDescriptor entity2 = provider.getEntityDescriptor( + "https://vidp.gv.at/ms_connector/pvp/metadata"); + Assert.assertNotNull("Entity 2 not found", entity2); + + final EntityDescriptor entity3 = provider.getEntityDescriptor("https://egiz.gv.at/abababa"); + Assert.assertNull("Entity 3 found", entity3); + + } + + @Test + public void dynamicLoadingNoValidSignature() throws ResolverException { + final EntityDescriptor entity = provider.getEntityDescriptor("classpath:/data/idp_metadata_no_sig2.xml"); + Assert.assertNull("Entity found", entity); + + } + + @Test + public void dynamicLoadingValidSignature() throws XMLParserException, UnmarshallingException, + SamlSigningException, CredentialsNotAvailableException, MarshallingException, ResolverException { + + final String entityId = injectValidHttpMetadata(); + final EntityDescriptor entity = provider.getEntityDescriptor(entityId); + Assert.assertNotNull("Entity not found", entity); + + } + + @Test + public void reloadNotPossible() throws XMLParserException, UnmarshallingException, + SamlSigningException, CredentialsNotAvailableException, MarshallingException, ResolverException { + + final String entityId = injectValidHttpMetadata(); + final EntityDescriptor entity = provider.getEntityDescriptor(entityId); + Assert.assertNotNull("Entity not found", entity); + Assert.assertNotNull("Entity not found", + provider.resolveSingle(generateEntityIdCreteria(entityId))); + + Assert.assertFalse("Refresh should not be possible", + provider.refreshMetadataProvider(entityId)); + + final EntityDescriptor entity2 = provider.getEntityDescriptor(entityId); + Assert.assertNull("Entity not found", entity2); + Assert.assertNull("Entity not found", + provider.resolveSingle(generateEntityIdCreteria(entityId))); + + Assert.assertFalse("Last refresh", provider.wasLastRefreshSuccess()); + + } + + @Test + public void refeshTest() throws Pvp2MetadataException, ResolverException { + Assert.assertFalse("Last refresh", provider.wasLastRefreshSuccess()); + Assert.assertNull("LastRefresh", provider.getLastRefresh()); + Assert.assertNull("LastSuccessfulRefresh", provider.getLastSuccessfulRefresh()); + Assert.assertNull("LastUpdate", provider.getLastUpdate()); + + final IPvp2MetadataProvider resolver1 = resolverFactory.createMetadataProvider( + "classpath:/data/idp_metadata_sig_notvalid.xml", + null, "junit", null); + Assert.assertNotNull("Resolver 1 is null", resolver1); + provider.addMetadataResolverIntoChain(resolver1); + + final IPvp2MetadataProvider resolver2 = resolverFactory.createMetadataProvider( + "classpath:/data/idp_metadata_sig_valid_wrong_alg.xml", + null, "junit", null); + Assert.assertNotNull("Resolver 2 is null", resolver2); + provider.addMetadataResolverIntoChain(resolver2); + + provider.refresh(); + + Assert.assertTrue("Last refresh", provider.wasLastRefreshSuccess()); + Assert.assertNotNull("LastRefresh", provider.getLastRefresh()); + Assert.assertNotNull("LastSuccessfulRefresh", provider.getLastSuccessfulRefresh()); + Assert.assertNotNull("LastUpdate", provider.getLastUpdate()); + + } + + @Test + public void reloadPossible() throws XMLParserException, UnmarshallingException, + SamlSigningException, CredentialsNotAvailableException, MarshallingException, ResolverException, + IOException { + + mockWebServer.shutdown(); + mockWebServer = new MockWebServer(); + mockServerUrl = mockWebServer.url("/sp/metadata"); + + final String entityId = injectValidHttpMetadata(); + final EntityDescriptor entity = provider.getEntityDescriptor(entityId); + Assert.assertNotNull("Entity not found", entity); + Assert.assertNotNull("Entity not found", + provider.resolveSingle(generateEntityIdCreteria(entityId))); + + Assert.assertFalse("Last refresh", provider.wasLastRefreshSuccess()); + + injectValidHttpMetadata(entityId); + Assert.assertTrue("Refresh should not be possible", + provider.refreshMetadataProvider(entityId)); + + final EntityDescriptor entity2 = provider.getEntityDescriptor(entityId); + Assert.assertNotNull("Entity not found", entity2); + Assert.assertNotNull("Entity not found", + provider.resolveSingle(generateEntityIdCreteria(entityId))); + + Assert.assertFalse("Last refresh", provider.wasLastRefreshSuccess()); + + } + + private String injectValidHttpMetadata() throws SamlSigningException, CredentialsNotAvailableException, + XMLParserException, UnmarshallingException, MarshallingException { + return injectValidHttpMetadata(mockServerUrl.url().toString() + + "/" + RandomStringUtils.randomAlphabetic(5)); + } + + private String injectValidHttpMetadata(String dynEntityId) throws XMLParserException, + UnmarshallingException, + MarshallingException, SamlSigningException, CredentialsNotAvailableException { + final EntityDescriptor metadata = (EntityDescriptor) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + MetadataResolverTest.class.getResourceAsStream("/data/idp_metadata_no_sig.xml")); + metadata.setValidUntil(Instant.now().plus(1, ChronoUnit.DAYS)); + metadata.setSignature(null); + metadata.setEntityID(dynEntityId); + Saml2Utils.signSamlObject(metadata, credentialProvider.getMetaDataSigningCredential(), true); + final Element metadataElement = XMLObjectSupport.marshall(metadata); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(SerializeSupport.nodeToString(metadataElement)) + .setHeader("Content-Type", "text/html;charset=utf-8")); + + return dynEntityId; + + } + + private CriteriaSet generateEntityIdCreteria(String entityId) { + final CriteriaSet result = new CriteriaSet(); + result.add(new EntityIdCriterion(entityId)); + return result; + + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthMetadataProviderSecondTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthMetadataProviderSecondTest.java new file mode 100644 index 00000000..3ee6ddcd --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientAuthMetadataProviderSecondTest.java @@ -0,0 +1,66 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.idaustriaclient; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.provider.IdAustriaClientAuthMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import net.shibboleth.utilities.java.support.resolver.ResolverException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +public class IdAustriaClientAuthMetadataProviderSecondTest { + + @Autowired + IdAustriaClientAuthMetadataProvider provider; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void classInitializer() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + } + + /** + * jUnit test set-up. + * + * @throws ResolverException + * + */ + @Before + public void testSetup() { + provider.fullyDestroy(); + + } + + @Test + public void notTrustedX509CertsInTrustStore() throws ResolverException { + final EntityDescriptor entity = provider.getEntityDescriptor("classpath:/data/idp_metadata_no_sig2.xml"); + Assert.assertNull("Entity found", entity); + + } + + @Test + public void readStaticInfos() { + Assert.assertEquals("wrong providerId", + IdAustriaClientAuthMetadataProvider.PROVIDER_ID, provider.getId()); + + provider.runGarbageCollector(); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientCredentialProviderTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientCredentialProviderTest.java new file mode 100644 index 00000000..bdc0df15 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/idaustriaclient/IdAustriaClientCredentialProviderTest.java @@ -0,0 +1,414 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.idaustriaclient; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.common.base.Optional; +import com.google.common.base.Predicates; +import com.google.common.base.Throwables; +import com.google.common.collect.FluentIterable; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthConstants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.provider.IdAustriaClientAuthCredentialProvider; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafFactoryException; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_basic_lazy.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +@DirtiesContext +public class IdAustriaClientCredentialProviderTest { + + private static final String PATH_JKS = "../keystore/junit_test.jks"; + private static final String ALIAS_METADATA = "meta"; + private static final String ALIAS_SIGN = "sig"; + private static final String ALIAS_ENC = "enc"; + private static final String PASSWORD = "password"; + + @Autowired + private ApplicationContext context; + @Autowired(required = true) + protected MsConnectorDummyConfigMap config; + + /** + * jUnit test initializer. + */ + @Before + public void initialize() { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_KEYSTORE_PATH, PATH_JKS); + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_KEYSTORE_PASSWORD, PASSWORD); + + config.removeConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_METADATA_ALIAS); + config.removeConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD); + + config.removeConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS); + config.removeConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD); + + config.removeConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ENCRYPTION_ALIAS); + config.removeConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD); + + } + + @Test + @DirtiesContext + public void noKeyStoreUrl() { + config.removeConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_KEYSTORE_PATH); + try { + context.getBean(IdAustriaClientAuthCredentialProvider.class); + Assert.fail("No KeyStore not detected"); + + } catch (final BeansException e) { + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, + e.getCause(), "Wrong exception"); + } + + } + + @Test + @DirtiesContext + public void noKeyStore() { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_KEYSTORE_PATH, + "src/test/resources/config/notExist.p12"); + try { + context.getBean(IdAustriaClientAuthCredentialProvider.class); + Assert.fail("No KeyStore not detected"); + + } catch (final BeansException e) { + final Optional<Throwable> eaafException = FluentIterable.from( + Throwables.getCausalChain(e)).filter( + Predicates.instanceOf(EaafConfigurationException.class)).first(); + Assert.assertTrue("Wrong exception", eaafException.isPresent()); + Assert.assertEquals("Wrong errorId", "internal.keystore.06", + ((EaafException) eaafException.get()).getErrorId()); + + } + + } + + @Test + @DirtiesContext + public void noWrongKeyStorePassword() { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_KEYSTORE_PASSWORD, "test"); + try { + context.getBean(IdAustriaClientAuthCredentialProvider.class); + Assert.fail("No KeyStore not detected"); + + } catch (final BeansException e) { + final Optional<Throwable> eaafException = FluentIterable.from( + Throwables.getCausalChain(e)).filter( + Predicates.instanceOf(EaafFactoryException.class)).first(); + Assert.assertTrue("Wrong exception", eaafException.isPresent()); + Assert.assertEquals("Wrong errorId", "internal.keystore.06", + ((EaafException) eaafException.get()).getErrorId()); + + } + + } + + @Test + @DirtiesContext + public void notKeyConfigurationWrongAlias() { + final IdAustriaClientAuthCredentialProvider credential = context.getBean( + IdAustriaClientAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_METADATA_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + credential.getMessageSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ENCRYPTION_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + credential.getMessageEncryptionCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + } + + @Test + @DirtiesContext + public void notKeyConfigurationWrongPassword() { + final IdAustriaClientAuthCredentialProvider credential = context.getBean( + IdAustriaClientAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + credential.getMessageSigningCredential(); + Assert.fail("No message signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + final EaafX509Credential encCred = credential.getMessageEncryptionCredential(); + Assert.assertNull("No encryption signing credentials not detected", encCred); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + } + + @Test + @DirtiesContext + public void notKeyConfigurationValidAliasWrongPassword() { + final IdAustriaClientAuthCredentialProvider credential = context.getBean( + IdAustriaClientAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_METADATA_ALIAS, + ALIAS_METADATA); + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS, + ALIAS_SIGN); + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + credential.getMessageSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ENCRYPTION_ALIAS, + ALIAS_ENC); + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + credential.getMessageEncryptionCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + } + + @Test + @DirtiesContext + public void notKeyConfigurationWrongAliasValidPassword() { + final IdAustriaClientAuthCredentialProvider credential = context.getBean( + IdAustriaClientAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_METADATA_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD, + PASSWORD); + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD, + PASSWORD); + credential.getMessageSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ENCRYPTION_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD, + PASSWORD); + credential.getMessageEncryptionCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + } + + @Test + @DirtiesContext + public void validonfiguration() throws CredentialsNotAvailableException { + final IdAustriaClientAuthCredentialProvider credential = context.getBean( + IdAustriaClientAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_METADATA_ALIAS, + ALIAS_METADATA); + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD, + PASSWORD); + credential.getMetaDataSigningCredential(); + + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS, + ALIAS_SIGN); + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD, + PASSWORD); + credential.getMessageSigningCredential(); + + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ENCRYPTION_ALIAS, + ALIAS_ENC); + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD, + PASSWORD); + credential.getMessageEncryptionCredential(); + + } + + @Test + @DirtiesContext + public void notKeyConfiguration() { + final IdAustriaClientAuthCredentialProvider credential = context.getBean( + IdAustriaClientAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + credential.getMessageSigningCredential(); + Assert.fail("No message signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + final EaafX509Credential encCred = credential.getMessageEncryptionCredential(); + Assert.assertNull("No encryption signing credentials not detected", encCred); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + } + + @Test + @DirtiesContext + public void notKeyConfigurationPkcs12() { + config.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_KEYSTORE_PATH, + "../keystore/pvp.p12"); + final IdAustriaClientAuthCredentialProvider credential = context.getBean( + IdAustriaClientAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + credential.getMessageSigningCredential(); + Assert.fail("No message signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + final EaafX509Credential encCred = credential.getMessageEncryptionCredential(); + Assert.assertNull("No encryption signing credentials not detected", encCred); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/AlternativeSearchTaskWithRegisterTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/AlternativeSearchTaskWithRegisterTest.java new file mode 100644 index 00000000..3814c632 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/AlternativeSearchTaskWithRegisterTest.java @@ -0,0 +1,1042 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.RandomStringUtils; +import org.jetbrains.annotations.NotNull; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.github.skjolber.mockito.soap.SoapServiceRule; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.ErnpRestClient.ErnpRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.IErnpClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.IZmrClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient.ZmrRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MatchedPersonResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.CountrySpecificDetailSearchProcessor; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.GenericEidProcessor; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterOperationStatus; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterStatusResults; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.AlternativeSearchTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients.ZmrClientTest; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; +import at.gv.bmi.namespace.zmr_su.base._20040201.RequestType; +import at.gv.bmi.namespace.zmr_su.base._20040201.ResponseType; +import at.gv.bmi.namespace.zmr_su.base._20040201_.ServicePort; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.EidasIdentitaetAnlageType; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.EidasSuchdatenType; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +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.light.impl.LightRequest; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import lombok.SneakyThrows; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml", + "/SpringTest-context_ccSearchProcessor_test.xml" +}) +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class AlternativeSearchTaskWithRegisterTest { + + @Rule + public SoapServiceRule soap = SoapServiceRule.newInstance(); + + @Mock private IErnpClient ernpClient; + + @Autowired private IZmrClient zmrClient; + @Autowired private List<CountrySpecificDetailSearchProcessor> handlers; + private RegisterSearchService registerSearchService; + + private ServicePort zmrMock = null; + + private final ICcSpecificEidProcessingService eidPostProcessor = createEidPostProcessor(); + private AlternativeSearchTask task; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private TestRequestImpl pendingReq; + private static JAXBContext jaxbContext; + + + /** + * Initialize jUnit class. + */ + @BeforeClass + @SneakyThrows + public static void classInitializer() { + jaxbContext = JAXBContext.newInstance( + at.gv.bmi.namespace.zmr_su.zmr._20040201.ObjectFactory.class, + at.gv.bmi.namespace.zmr_su.gis._20070725.ObjectFactory.class, + at.gv.bmi.namespace.zmr_su.base._20040201.ObjectFactory.class); + } + + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws URISyntaxException, EaafStorageException { + if (zmrMock == null) { + zmrMock = soap.mock(ServicePort.class, "http://localhost:1234/demozmr"); + + } + + registerSearchService = new RegisterSearchService(handlers, zmrClient, ernpClient); + task = new AlternativeSearchTask(registerSearchService, eidPostProcessor); + + MockHttpServletRequest httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + MockHttpServletResponse httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + pendingReq = new TestRequestImpl(); + + } + + + @Test + @SneakyThrows + public void missingStateInfoFirstEidasData() { + // inject matching intermediate state + RegisterStatusResults matchingState = new RegisterStatusResults(null, + Arrays.asList(RegisterResult.builder() + .bpk("") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .pseudonym(Arrays.asList("7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit")) + .build()), + Collections.emptyList()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, matchingState ); + + //inject alternative eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31")); + + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertEquals("wrong errorparam 1", "step11", ((EaafException) exception.getOriginalException()).getParams()[0]); + assertTrue("Wrong flag 'step11'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + assertEquals("wrong errorparam 1", "No initial eIDAS authn data", + ((EaafException) exception.getOriginalException()).getParams()[1]); + + + } + + @Test + @SneakyThrows + public void missingStateInfoIntermediateMatchingState() { + //inject initial eIDAS data + MatchingTaskUtils.storeInitialEidasData(pendingReq, SimpleEidasData.builder() + .personalIdentifier("DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .pseudonym("cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .build()); + + //inject alternative eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31")); + + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertEquals("wrong errorparam 1", "step11", ((EaafException) exception.getOriginalException()).getParams()[0]); + assertTrue("Wrong flag 'step11'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + assertEquals("wrong errorparam 1", "No intermediate matching-state", + ((EaafException) exception.getOriginalException()).getParams()[1]); + + } + + @Test + @SneakyThrows + public void countryCodeNotMatch() { + //inject initial eIDAS data + MatchingTaskUtils.storeInitialEidasData(pendingReq, SimpleEidasData.builder() + .personalIdentifier("DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .pseudonym("cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .citizenCountryCode("DE") + .build()); + + // inject matching intermediate state + RegisterStatusResults matchingState = new RegisterStatusResults(null, + Arrays.asList(RegisterResult.builder() + .bpk("") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .pseudonym(Arrays.asList("7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit")) + .build()), + Collections.emptyList()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, matchingState ); + + //inject alternative eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "EE/AT/7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31")); + + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertEquals("wrong errorparam 1", "step11", ((EaafException) exception.getOriginalException()).getParams()[0]); + assertTrue("Wrong flag 'step11'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + assertEquals("wrong errorparam 1", "Country Code of alternative eIDAS authn not matching", + ((EaafException) exception.getOriginalException()).getParams()[1]); + + } + + @Test + @SneakyThrows + public void mdsNoMatch() { + //inject initial eIDAS data + MatchingTaskUtils.storeInitialEidasData(pendingReq, SimpleEidasData.builder() + .personalIdentifier("DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .pseudonym("cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .citizenCountryCode("DE") + .build()); + + // inject matching intermediate state + RegisterStatusResults matchingState = new RegisterStatusResults(null, + Arrays.asList(RegisterResult.builder() + .bpk("") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .pseudonym(Arrays.asList("7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit")) + .build()), + Collections.emptyList()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, matchingState ); + + //inject alternative eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, + buildDummyAuthResponse("XXXClaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1995-12-31")); + + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertEquals("wrong errorparam 1", "step11", ((EaafException) exception.getOriginalException()).getParams()[0]); + assertTrue("Wrong flag 'step11'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + assertEquals("wrong errorparam 1", "MDS of alternative eIDAS authn does not match initial authn", + ((EaafException) exception.getOriginalException()).getParams()[1]); + + } + + @Test + @SneakyThrows + public void seachPersonalIdMoreThanOneResult() { + //inject initial eIDAS data + MatchingTaskUtils.storeInitialEidasData(pendingReq, SimpleEidasData.builder() + .personalIdentifier("DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .pseudonym("cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .citizenCountryCode("DE") + .build()); + + // inject matching intermediate state + RegisterStatusResults matchingState = new RegisterStatusResults( + new RegisterOperationStatus(new BigInteger(RandomStringUtils.randomNumeric(5))), + Arrays.asList(RegisterResult.builder() + .bpk("") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .pseudonym(Arrays.asList("7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit")) + .build()), + Collections.emptyList()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, matchingState); + + //inject alternative eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31")); + + // inject response + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/search_with_personalId_only_resp_moreThanOne.xml")) + .thenThrow(new RuntimeException("This request is not needed any more")); + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertEquals("wrong errorparam 1", "searchWithPersonalIdentifier", ((EaafException) exception.getOriginalException()).getParams()[0]); + assertTrue("Wrong flag 'step11'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + checkBasicRequestParameters(zmrReq.getValue(), ZmrClientTest.PROCESS_TASK_SEARCH, + matchingState.getOperationStatus().getZmrProcessId(), "jUnit123456"); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + checkEidasDocumentResult(zmrReq.getValue().getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", + "DE", "7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"); + + } + + @Test + @SneakyThrows + public void seachPersonalIdNoBpkMatchWithIntermediateResults() { + //inject initial eIDAS data + MatchingTaskUtils.storeInitialEidasData(pendingReq, SimpleEidasData.builder() + .personalIdentifier("DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .pseudonym("cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .citizenCountryCode("DE") + .build()); + + // inject matching intermediate state + RegisterStatusResults matchingState = new RegisterStatusResults(null, + Arrays.asList(RegisterResult.builder() + .bpk("notExists") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .pseudonym(Arrays.asList("7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit")) + .build()), + Collections.emptyList()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, matchingState ); + + //inject alternative eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31")); + + // inject response + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-8_search_with_personalId_only_resp.xml")) + .thenThrow(new RuntimeException("This request is not needed any more")); + + Mockito.when(ernpClient.searchWithPersonIdentifier(any(), any())) + .thenReturn(emptyErnpRegisterResult()); + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertEquals("wrong errorparam 1", "step7bKittProcess", ((EaafException) exception.getOriginalException()).getParams()[0]); + assertFalse("Wrong flag 'step11'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + assertEquals("wrong errorparam 1", "Register result from alternativ authentication does not fit into intermediate state", + ((EaafException) exception.getOriginalException()).getParams()[1]); + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + checkEidasDocumentResult(zmrReq.getValue().getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", + "DE", "7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"); + + } + + @Test + @SneakyThrows + public void seachPersonalIdSuccess() { + //inject initial eIDAS data + MatchingTaskUtils.storeInitialEidasData(pendingReq, SimpleEidasData.builder() + .personalIdentifier("DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .pseudonym("cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .citizenCountryCode("DE") + .build()); + + // inject matching intermediate state + RegisterStatusResults matchingState = new RegisterStatusResults( + new RegisterOperationStatus(new BigInteger(RandomStringUtils.randomNumeric(5))), + Arrays.asList(RegisterResult.builder() + .bpk("UgeknNsc26lVuB7U/uYGVmWtnnA=") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .pseudonym(Arrays.asList("7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit")) + .build()), + Collections.emptyList()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, matchingState ); + + //inject alternative eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31")); + + // inject response + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-8_search_with_personalId_only_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_3-4_kitt_get_latest_version_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_3-6_kitt_update_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_3-8_kitt_get_latest_version_resp.xml")) + .thenThrow(new RuntimeException("This request is not needed any more")); + + Mockito.when(ernpClient.searchWithPersonIdentifier(any(), any())) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchWithMds(any(), any(), any(), any())) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + // execute task + task.execute(pendingReq, executionContext); + + // validate state + //INFO: has to be the old givenName because ZMR allows no update of MDS information + checkMatchingSuccessState(pendingReq, "UgeknNsc26lVuB7U/uYGVmWtnnA=", "XXXvon Brandenburg", + "XXXClaus - Maria", "1994-12-31", "DE"); + assertNull("wrong executionContextFlag 'alternative eIDAS result'", + executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + + + // validate request + assertEquals("wrong number of req.", 4, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getAllValues().get(0).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(0), ZmrClientTest.PROCESS_TASK_SEARCH, + matchingState.getOperationStatus().getZmrProcessId(), "jUnit123456"); + checkEidasDocumentResult(zmrReq.getAllValues().get(0).getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", + "DE", "7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"); + + + assertNotNull("Personensuche KITT req.", zmrReq.getAllValues().get(1).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(1), ZmrClientTest.PROCESS_TASK_SEARCH, + new BigInteger("367100000000079"), "jUnit123456"); + + assertNotNull("PersonAender KITT req.", zmrReq.getAllValues().get(2).getPersonAendernRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(2), ZmrClientTest.PROCESS_TASK_UPDATE, + new BigInteger("367100000000079"), "jUnit123456"); + + assertEquals("wrong number of eIDAS Docs to Add", 4, + zmrReq.getAllValues().get(2).getPersonAendernRequest().getEidasIdentitaetAnlage().size()); + checkEidasDocumentAdd(zmrReq.getAllValues().get(2).getPersonAendernRequest().getEidasIdentitaetAnlage(), + "http://eidas.europa.eu/attributes/naturalperson/DateOfBirth", "DE", "1994-12-31"); + checkEidasDocumentAdd(zmrReq.getAllValues().get(2).getPersonAendernRequest().getEidasIdentitaetAnlage(), + "http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName", "DE", "XXXKlaus - Maria"); + checkEidasDocumentAdd(zmrReq.getAllValues().get(2).getPersonAendernRequest().getEidasIdentitaetAnlage(), + "http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName", "DE", "XXXvon Brandenburg"); + + assertNotNull("Personensuche KITT req.", zmrReq.getAllValues().get(3).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(3), ZmrClientTest.PROCESS_TASK_SEARCH, + new BigInteger("367100000000079"), "jUnit123456"); + + } + + @Test + @SneakyThrows + public void seachCcSpecificSuccess() { + //inject initial eIDAS data + MatchingTaskUtils.storeInitialEidasData(pendingReq, SimpleEidasData.builder() + .personalIdentifier("DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .pseudonym("cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .citizenCountryCode("DE") + .build()); + + // inject matching intermediate state + RegisterStatusResults matchingState = new RegisterStatusResults( + new RegisterOperationStatus(new BigInteger(RandomStringUtils.randomNumeric(5))), + Arrays.asList(RegisterResult.builder() + .bpk("UgeknNsc26lVuB7U/uYGVmWtnnA=") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .pseudonym(Arrays.asList("7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit")) + .build()), + Collections.emptyList()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, matchingState ); + + //inject alternative eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31", + null, "Hintergigritzpotschn", "XXXvon Heuburg")); + + // inject response + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-8_search_with_personalId_only_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_3-4_kitt_get_latest_version_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_3-6_kitt_update_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_3-8_kitt_get_latest_version_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_3-10_kitt_update_resp.xml")) + .thenThrow(new RuntimeException("This request is not needed any more")); + + Mockito.when(ernpClient.searchWithPersonIdentifier(any(), any())) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchCountrySpecific(any(), any())) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchWithMds(any(), any(), any(), any())) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + // execute task + task.execute(pendingReq, executionContext); + + // validate state + //INFO: has to be the old givenName because ZMR allows no update of MDS information + checkMatchingSuccessState(pendingReq, "UgeknNsc26lVuB7U/uYGVmWtnnA=", "XXXvon Brandenburg", + "XXXClaus - Maria", "1994-12-31", "DE"); + assertNull("wrong executionContextFlag 'alternative eIDAS result'", + executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + + + // validate request + assertEquals("wrong number of req.", 6, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getAllValues().get(0).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(0), ZmrClientTest.PROCESS_TASK_SEARCH, + matchingState.getOperationStatus().getZmrProcessId(), "jUnit123456"); + checkEidasDocumentResult(zmrReq.getAllValues().get(0).getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", + "DE", "7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"); + + assertNotNull("Personensuche CC-specific req.", zmrReq.getAllValues().get(0).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(1), ZmrClientTest.PROCESS_TASK_SEARCH, + new BigInteger("367100000000079"), "jUnit123456"); + checkEidasDocumentResult(zmrReq.getAllValues().get(1).getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", + "DE", "Hintergigritzpotschn"); + checkEidasDocumentResult(zmrReq.getAllValues().get(1).getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/BirthName", + "DE", "XXXvon Heuburg"); + + + assertNotNull("Personensuche KITT req.", zmrReq.getAllValues().get(2).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(2), ZmrClientTest.PROCESS_TASK_SEARCH, + new BigInteger("367100000000079"), "jUnit123456"); + + assertNotNull("PersonAender KITT req.", zmrReq.getAllValues().get(3).getPersonAendernRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(3), ZmrClientTest.PROCESS_TASK_UPDATE, + new BigInteger("367100000000079"), "jUnit123456"); + + assertNotNull("Personensuche KITT req.", zmrReq.getAllValues().get(4).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(4), ZmrClientTest.PROCESS_TASK_SEARCH, + new BigInteger("367100000000079"), "jUnit123456"); + + assertNotNull("PersonAender KITT req.", zmrReq.getAllValues().get(5).getPersonAendernRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(5), ZmrClientTest.PROCESS_TASK_UPDATE, + new BigInteger("367100000000079"), "jUnit123456"); + } + + @Test + @SneakyThrows + public void seachCcSpecificNotPossible() { + //inject initial eIDAS data + MatchingTaskUtils.storeInitialEidasData(pendingReq, SimpleEidasData.builder() + .personalIdentifier("DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .pseudonym("cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .citizenCountryCode("EE") + .build()); + + // inject matching intermediate state + RegisterStatusResults matchingState = new RegisterStatusResults( + new RegisterOperationStatus(new BigInteger(RandomStringUtils.randomNumeric(5))), + Arrays.asList(RegisterResult.builder() + .bpk("UgeknNsc26lVuB7U/uYGVmWtnnA=") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .pseudonym(Arrays.asList("7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit")) + .build()), + Collections.emptyList()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, matchingState ); + + //inject alternative eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "EE/AT/7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31", + null, "Hintergigritzpotschn", "XXXvon Heuburg")); + + // inject response + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) + .thenThrow(new RuntimeException("This request is not needed any more")); + + Mockito.when(ernpClient.searchWithPersonIdentifier(any(), any())) + .thenReturn(emptyErnpRegisterResult()); + + // execute task + task.execute(pendingReq, executionContext); + + // validate state + assertNotNull("find no eIDAS inbut data", MatchingTaskUtils.getInitialEidasData(pendingReq)); + assertNull("final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + assertEquals("wrong executionContextFlag 'alternative eIDAS result'", true, + executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + + + // validate request + assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getAllValues().get(0).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(0), ZmrClientTest.PROCESS_TASK_SEARCH, + matchingState.getOperationStatus().getZmrProcessId(), "jUnit123456"); + checkEidasDocumentResult(zmrReq.getAllValues().get(0).getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", + "EE", "7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"); + + } + + @Test + @SneakyThrows + public void seachCcSpecificMoreThanOneResult() { + //inject initial eIDAS data + MatchingTaskUtils.storeInitialEidasData(pendingReq, SimpleEidasData.builder() + .personalIdentifier("DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .pseudonym("cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .citizenCountryCode("DE") + .build()); + + // inject matching intermediate state + RegisterStatusResults matchingState = new RegisterStatusResults( + new RegisterOperationStatus(new BigInteger(RandomStringUtils.randomNumeric(5))), + Arrays.asList(RegisterResult.builder() + .bpk("UgeknNsc26lVuB7U/uYGVmWtnnA=") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .pseudonym(Arrays.asList("7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit")) + .build()), + Collections.emptyList()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, matchingState ); + + //inject alternative eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31", + null, "Hintergigritzpotschn", "XXXvon Heuburg")); + + // inject response + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/search_with_personalId_only_resp_moreThanOne.xml")) + .thenThrow(new RuntimeException("This request is not needed any more")); + + Mockito.when(ernpClient.searchWithPersonIdentifier(any(), any())) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchWithMds(any(), any(), any(), any())) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertEquals("wrong errorparam 1", "searchWithCountrySpecifics", ((EaafException) exception.getOriginalException()).getParams()[0]); + assertTrue("Wrong flag 'step11'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + + + // validate request + assertEquals("wrong number of req.", 2, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getAllValues().get(0).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(0), ZmrClientTest.PROCESS_TASK_SEARCH, + matchingState.getOperationStatus().getZmrProcessId(), "jUnit123456"); + checkEidasDocumentResult(zmrReq.getAllValues().get(0).getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", + "DE", "7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"); + + assertNotNull("Personensuche CC-specific req.", zmrReq.getAllValues().get(0).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(1), ZmrClientTest.PROCESS_TASK_SEARCH, + new BigInteger("367100000000079"), "jUnit123456"); + checkEidasDocumentResult(zmrReq.getAllValues().get(1).getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", + "DE", "Hintergigritzpotschn"); + checkEidasDocumentResult(zmrReq.getAllValues().get(1).getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/BirthName", + "DE", "XXXvon Heuburg"); + + } + + @Test + @SneakyThrows + public void seachCcSpecificEmptyResult() { + //inject initial eIDAS data + MatchingTaskUtils.storeInitialEidasData(pendingReq, SimpleEidasData.builder() + .personalIdentifier("DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .pseudonym("cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .citizenCountryCode("DE") + .build()); + + // inject matching intermediate state + RegisterStatusResults matchingState = new RegisterStatusResults( + new RegisterOperationStatus(new BigInteger(RandomStringUtils.randomNumeric(5))), + Arrays.asList(RegisterResult.builder() + .bpk("UgeknNsc26lVuB7U/uYGVmWtnnA=") + .givenName("XXXKlaus - Maria") + .familyName("XXXvon Brandenburg") + .dateOfBirth("1994-12-31") + .pseudonym(Arrays.asList("7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit")) + .build()), + Collections.emptyList()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, matchingState ); + + //inject alternative eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31", + null, "Hintergigritzpotschn", "XXXvon Heuburg")); + + // inject response + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) + .thenThrow(new RuntimeException("This request is not needed any more")); + + Mockito.when(ernpClient.searchWithPersonIdentifier("7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "DE")) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchCountrySpecific(any(), any())) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + + // execute task + task.execute(pendingReq, executionContext); + + // validate state + assertNotNull("find no eIDAS inbut data", MatchingTaskUtils.getInitialEidasData(pendingReq)); + assertNull("final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + assertEquals("wrong executionContextFlag 'alternative eIDAS result'", true, + executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + assertEquals("failed reason", "module.eidasauth.matching.25", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON)); + + + + // validate request + assertEquals("wrong number of req.", 2, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getAllValues().get(0).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(0), ZmrClientTest.PROCESS_TASK_SEARCH, + matchingState.getOperationStatus().getZmrProcessId(), "jUnit123456"); + checkEidasDocumentResult(zmrReq.getAllValues().get(0).getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", + "DE", "7cEYasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit"); + + assertNotNull("Personensuche CC-specific req.", zmrReq.getAllValues().get(0).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(1), ZmrClientTest.PROCESS_TASK_SEARCH, + new BigInteger("367100000000079"), "jUnit123456"); + checkEidasDocumentResult(zmrReq.getAllValues().get(1).getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", + "DE", "Hintergigritzpotschn"); + checkEidasDocumentResult(zmrReq.getAllValues().get(1).getPersonSuchenRequest().getEidasSuchdaten(), + "http://eidas.europa.eu/attributes/naturalperson/BirthName", + "DE", "XXXvon Heuburg"); + + } + + @NotNull + private ICcSpecificEidProcessingService createEidPostProcessor() { + return new ICcSpecificEidProcessingService() { + + private final GenericEidProcessor genericEidProcessor = new GenericEidProcessor(); + + @Override + public SimpleEidasData postProcess(Map<String, Object> eidasAttrMap) throws EidPostProcessingException, EidasAttributeException { + return genericEidProcessor.postProcess(eidasAttrMap); + } + + @Override + public void preProcess(String selectedCC, IRequest pendingReq, LightRequest.Builder authnRequestBuilder) { + genericEidProcessor.preProcess(pendingReq, authnRequestBuilder); + } + }; + } + + @NotNull + private ZmrRegisterResult zmrRegisterResult(RegisterResult registerResult, BigInteger processId) { + return new ZmrRegisterResult(Collections.singletonList(registerResult), processId); + } + + @NotNull + private ZmrRegisterResult zmrRegisterResult(RegisterResult registerResult) { + return zmrRegisterResult(registerResult, generateRandomProcessId()); + } + + + private BigInteger generateRandomProcessId() { + return new BigInteger(RandomStringUtils.randomNumeric(10)); + + } + + private void checkMatchingSuccessState(IRequest pendingReq, String bpk, String familyName, String givenName, + String birhday, String countryCode) { + assertNull("Find intermediate matching data but matching should be finished", + MatchingTaskUtils.getIntermediateMatchingResult(pendingReq)); + assertNotNull("find no eIDAS inbut data", MatchingTaskUtils.getInitialEidasData(pendingReq)); + + MatchedPersonResult personInfo = MatchingTaskUtils.getFinalMatchingResult(pendingReq); + assertNotNull("no final matching result", personInfo); + assertEquals("wrong bpk", bpk, personInfo.getBpk()); + assertEquals("wrong givenName", givenName, personInfo.getGivenName()); + assertEquals("wrong familyName", familyName, personInfo.getFamilyName()); + assertEquals("wrong dateOfBirth", birhday, personInfo.getDateOfBirth()); + assertEquals("wrong countryCode", countryCode, personInfo.getCountryCode()); + + } + + private void checkIntermediateResult(int resultSize) { + Boolean transitionGUI = (Boolean) executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK); + Assert.assertTrue("Wrong transition", transitionGUI); + Boolean transitionErnb = (Boolean) executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK); + Assert.assertNull("Wrong transition", transitionErnb); + + assertNotNull("find no eIDAS inbut data", MatchingTaskUtils.getInitialEidasData(pendingReq)); + assertNull("Find final matching data but no match sould be found", + MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + RegisterStatusResults result = MatchingTaskUtils.getIntermediateMatchingResult(pendingReq); + assertNotNull("Find no intermediate matching data", result); + assertEquals("wrong intermediate result size", resultSize, result.getResultCount()); + + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponse(String givenName, String familyName, String identifier, + String dateOfBirth) throws URISyntaxException { + return buildDummyAuthResponse(givenName, familyName, identifier, dateOfBirth, null, null, null); + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponseDE(String givenName, String familyName, String identifier, + String dateOfBirth, String placeOfBirth, + String birthName) throws URISyntaxException { + return buildDummyAuthResponse(givenName, familyName, identifier, dateOfBirth, null, placeOfBirth, birthName); + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponse(String givenName, String familyName, String identifier, + String dateOfBirth, String taxNumber, String placeOfBirth, + String birthName) throws URISyntaxException { + ImmutableAttributeMap.Builder builder = ImmutableAttributeMap.builder() + .put(generateStringAttribute(Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + randomAlphabetic(2), randomAlphabetic(2)), identifier) + .put(generateStringAttribute(Constants.eIDAS_ATTR_CURRENTFAMILYNAME, + randomAlphabetic(3), randomAlphabetic(3)), familyName) + .put(generateStringAttribute(Constants.eIDAS_ATTR_CURRENTGIVENNAME, + randomAlphabetic(4), randomAlphabetic(4)), givenName) + .put(generateDateTimeAttribute(Constants.eIDAS_ATTR_DATEOFBIRTH, + randomAlphabetic(5), randomAlphabetic(5)), dateOfBirth); + if (taxNumber != null) { + builder.put(generateStringAttribute(Constants.eIDAS_ATTR_TAXREFERENCE, + randomAlphabetic(6), randomAlphabetic(6)), taxNumber); + } + if (birthName != null) { + builder.put(generateStringAttribute(Constants.eIDAS_ATTR_BIRTHNAME, + randomAlphabetic(7), randomAlphabetic(7)), birthName); + } + if (placeOfBirth != null) { + builder.put(generateStringAttribute(Constants.eIDAS_ATTR_PLACEOFBIRTH, + randomAlphabetic(8), randomAlphabetic(8)), placeOfBirth); + } + final ImmutableAttributeMap attributeMap = builder.build(); + + return new AuthenticationResponse.Builder().id(randomAlphabetic(5)) + .issuer(randomAlphabetic(5)).subject(randomAlphabetic(5)).statusCode("200") + .inResponseTo(randomAlphabetic(5)).subjectNameIdFormat(randomAlphabetic(5)) + .attributes(attributeMap).build(); + } + + private AttributeDefinition<Object> generateStringAttribute(String friendlyName, String fragment, String prefix) + throws URISyntaxException { + return generateAttribute(friendlyName, fragment, prefix, "eu.eidas.auth.commons.attribute.impl" + + ".LiteralStringAttributeValueMarshaller"); + } + + @SuppressWarnings("SameParameterValue") + private AttributeDefinition<Object> generateDateTimeAttribute(String friendlyName, String fragment, String prefix) + throws URISyntaxException { + return generateAttribute(friendlyName, fragment, prefix, "eu.eidas.auth.commons.attribute.impl" + + ".DateTimeAttributeValueMarshaller"); + } + + private AttributeDefinition<Object> generateAttribute(String friendlyName, String fragment, String prefix, + String marshaller) throws URISyntaxException { + return AttributeDefinition.builder() + .friendlyName(friendlyName).nameUri(new URI("ad", "sd", fragment)) + .personType(PersonType.LEGAL_PERSON).xmlType(new QName("http://saf", "as", prefix)) + .attributeValueMarshaller(marshaller).build(); + } + + private ResponseType loadResponseFromFile(String filepath) throws JAXBException { + final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + JAXBElement<?> resp = (JAXBElement<?>) unmarshaller.unmarshal(ZmrClientTest.class.getResourceAsStream( + filepath)); + return (ResponseType) resp.getValue(); + + } + + private void checkBasicRequestParameters(RequestType requestType, String vorgangName, BigInteger processId, + String behoerdennummer) { + assertNotNull("no workflow infos", requestType.getWorkflowInfoClient()); + assertEquals("processName", ZmrClientTest.PROCESS_GENERAL, requestType.getWorkflowInfoClient().getProzessName()); + assertEquals("vorgangsName", vorgangName, requestType.getWorkflowInfoClient().getVorgangName()); + + if (processId != null) { + assertEquals("processId", processId, requestType.getWorkflowInfoClient().getProzessInstanzID()); + } else { + assertNull("processId", requestType.getWorkflowInfoClient().getProzessInstanzID()); + } + + assertNotNull("no client infos", requestType.getClientInfo()); + assertEquals("behoerdennummer", behoerdennummer, requestType.getClientInfo().getOrganisation() + .getBehoerdenNr()); + } + + private void checkEidasDocumentResult(List<EidasSuchdatenType> list, String type, String cc, String value) { + Optional<EidasSuchdatenType> eidasDoc = list.stream() + .filter(el -> type.equals(el.getEidasArt())) + .findFirst(); + + assertTrue("eidas doc: " + type, eidasDoc.isPresent()); + assertEquals("eIDAS docType", type, eidasDoc.get().getEidasArt()); + assertEquals("eIDAS docValue", value, eidasDoc.get().getEidasWert()); + assertEquals("eIDAS docCC", cc, eidasDoc.get().getStaatscode2()); + + } + + + private void checkEidasDocumentAdd(List<EidasIdentitaetAnlageType> list, String type, String cc, String value) { + Optional<EidasIdentitaetAnlageType> eidasDoc = list.stream() + .filter(el -> type.equals(el.getEidasArt())) + .findFirst(); + + assertTrue("eidas doc: " + type, eidasDoc.isPresent()); + assertEquals("eIDAS docType", type, eidasDoc.get().getEidasArt()); + assertEquals("eIDAS docValue", value, eidasDoc.get().getEidasWert()); + assertEquals("eIDAS docCC", cc, eidasDoc.get().getStaatscode2()); + } + + @NotNull + private ErnpRegisterResult emptyErnpRegisterResult() { + return new ErnpRegisterResult(Collections.emptyList()); + } + + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java new file mode 100644 index 00000000..44c2624e --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java @@ -0,0 +1,624 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static at.asitplus.eidas.specific.core.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.mockito.Mockito.when; + +import java.net.URISyntaxException; +import java.security.KeyStore; +import java.security.Provider; +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; + +import javax.annotation.Nonnull; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.jose4j.jwa.AlgorithmConstraints; +import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; +import org.jose4j.jws.AlgorithmIdentifiers; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +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.github.skjolber.mockito.soap.SoapServiceRule; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MatchedPersonResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils; +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.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; +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.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +import at.gv.egiz.eaaf.core.impl.data.Pair; +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.AttributeValue; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap.Builder; +import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress; +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; + +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class CreateIdentityLinkTaskEidNewTest { + + @Autowired(required = true) + private CreateIdentityLinkTask task; + + @Autowired(required = true) + private MsConnectorDummyConfigMap basicConfig; + @Autowired + protected EidasAttributeRegistry attrRegistry; + + @Autowired + EaafKeyStoreFactory keyStoreFactory; + + @Autowired + ICcSpecificEidProcessingService eidPostProcessor; + + @Autowired + private IRequestStorage requestStorage; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private DummySpConfiguration oaParam; + private SZR szrMock; + + private static final String PW = "f/+saJBc3a}*/T^s"; + private static final String ALIAS = "connectorkeypair"; + + private static final List<String> BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING = Collections.unmodifiableList(Arrays + .asList(AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256, + 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; + private MatchedPersonResult matchingInfos; + + @Rule + public final SoapServiceRule soap = SoapServiceRule.newInstance(); + + /** + * jUnit test set-up. + * @throws EidasAttributeException + * @throws EidPostProcessingException + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException, EidPostProcessingException, EidasAttributeException { + + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + + final Map<String, String> spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); + oaParam = new DummySpConfiguration(spConfig, basicConfig); + pendingReq = new TestRequestImpl(); + + response = buildDummyAuthResponse(false); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + + final Map<String, Object> eidasAttributes = convertEidasAttrToSimpleMap( + response.getAttributes().getAttributeMap()); + final SimpleEidasData eidData = eidPostProcessor.postProcess(eidasAttributes); + MatchingTaskUtils.storeInitialEidasData(pendingReq, eidData); + + matchingInfos = MatchedPersonResult.builder() + .bpk(RandomStringUtils.randomAlphabetic(5)) + .givenName(eidData.getGivenName()) + .familyName(eidData.getFamilyName()) + .dateOfBirth(eidData.getDateOfBirth()) + .countryCode(eidData.getCitizenCountryCode()) + .build(); + MatchingTaskUtils.storeFinalMatchingResult(pendingReq, matchingInfos); + + pendingReq.setSpConfig(oaParam); + 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); + + szrMock = soap.mock(SZR.class, "http://localhost:1234/demoszr"); + } + + @Test + public void successfulProcessWithDeInfos() throws Exception { + //initialize test + response = buildDummyAuthResponse(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + SimpleEidasData eidData = eidPostProcessor.postProcess( + convertEidasAttrToSimpleMap(response.getAttributes().getAttributeMap())); + MatchingTaskUtils.storeInitialEidasData(pendingReq, eidData); + + matchingInfos = MatchedPersonResult.builder() + .bpk(RandomStringUtils.randomAlphabetic(5)) + .givenName(eidData.getGivenName()) + .familyName(eidData.getFamilyName()) + .dateOfBirth(eidData.getDateOfBirth()) + .countryCode(eidData.getCitizenCountryCode()) + .build(); + MatchingTaskUtils.storeFinalMatchingResult(pendingReq, matchingInfos); + + String vsz = RandomStringUtils.randomNumeric(10); + when(szrMock.getStammzahlEncrypted(any(), any())).thenReturn(vsz); + SignContentResponseType 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 + // 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(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNotNull("AuthBlock", authBlock); + + 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)); + + // 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()); + 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()); + Assert.assertFalse("binding pubKey", authBlockJson.has("bindingPublicKey")); + + + + // 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.assertFalse("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.assertNull("PlaceOfBirth", person.getPerson().getPlaceOfBirth()); + Assert.assertNull("BirthName", person.getPerson().getAlternativeName()); + Assert.assertNull("TravelDocument", person.getTravelDocument()); + + // 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()); + + } + + @Test + public void successfulProcessWithDataFromMatching() throws Exception { + //initialize test + String vsz = RandomStringUtils.randomNumeric(10); + when(szrMock.getStammzahlEncrypted(any(), any())).thenReturn(vsz); + SignContentResponseType 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); + String bindingPubKey = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME, bindingPubKey); + + + //perform test + task.execute(pendingReq, executionContext); + + + //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(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + // check authblock signature + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNotNull("AuthBlock", authBlock); + + 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()); + 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()); + Assert.assertTrue("binding pubKey", authBlockJson.has("bindingPublicKey")); + Assert.assertEquals("binding PubKey", bindingPubKey, authBlockJson.get("bindingPublicKey").asText()); + + 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)); + + // 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.assertFalse("insertERnP flag", param5); + PersonInfoType person = argument4.getValue(); + Assert.assertEquals("FamilyName", + matchingInfos.getFamilyName(), + person.getPerson().getName().getFamilyName()); + Assert.assertEquals("GivenName", + matchingInfos.getGivenName(), + person.getPerson().getName().getGivenName()); + Assert.assertEquals("DateOfBirth", + matchingInfos.getDateOfBirth(), + person.getPerson().getDateOfBirth()); + Assert.assertEquals("bPK", + matchingInfos.getBpk(), + person.getPerson().getIdentification().getValue()); + Assert.assertEquals("bPKType", + EaafConstants.URN_PREFIX_CDID + "ZP", + person.getPerson().getIdentification().getType()); + + + Assert.assertNull("PlaceOfBirth", person.getPerson().getPlaceOfBirth()); + Assert.assertNull("BirthName", person.getPerson().getAlternativeName()); + + } + + @Test + public void successfulProcessWithStandardInfos() throws Exception { + //initialize test + 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 + // 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(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNotNull("AuthBlock", authBlock); + + 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)); + + // 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.assertFalse("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.assertNull("PlaceOfBirth", person.getPerson().getPlaceOfBirth()); + Assert.assertNull("BirthName", person.getPerson().getAlternativeName()); + Assert.assertNull("TravelDocument", person.getTravelDocument()); + + + } + + @Test + public void getStammzahlEncryptedExceptionTest() throws Exception { + try { + when(szrMock.getStammzahlEncrypted(any(), any())).thenReturn(null); + task.execute(pendingReq, executionContext); + } catch (TaskExecutionException e) { + Assert.assertEquals("Incorrect exception thrown", e.getMessage(), + "IdentityLink generation for foreign person " + "FAILED."); + Assert.assertEquals("Incorrect exception thrown", ((SzrCommunicationException) e.getCause()).getErrorId(), + "ernb.01"); + Assert.assertTrue("Incorrect exception thrown", e.getCause().getMessage().contains("Stammzahl response empty")); + } + } + + @Test + public void signContentExceptionTest() throws Exception { + try { + when(szrMock.getStammzahlEncrypted(any(), any())).thenReturn(RandomStringUtils.randomNumeric(10)); + when(szrMock.signContent(any(), any(), any())).thenReturn(null); + task.execute(pendingReq, executionContext); + } catch (TaskExecutionException e) { + Assert.assertEquals("Incorrect exception thrown", e.getMessage(), + "IdentityLink generation for foreign person " + "FAILED."); + Assert.assertEquals("Incorrect exception thrown", ((SzrCommunicationException) e.getCause()).getErrorId(), + "ernb.01"); + Assert.assertTrue("Incorrect exception thrown", e.getCause().getMessage().contains("BcBind response empty")); + } + } + + private Pair<KeyStore, Provider> getKeyStore() throws EaafException { + // read Connector wide config data TODO connector wide! + String keyStoreName = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_NAME); + String keyStorePw = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PASSWORD); + String keyStorePath = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PATH); + String keyStoreType = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_TYPE); + + + //build new KeyStore configuration + KeyStoreConfiguration keyStoreConfiguration = new KeyStoreConfiguration(); + keyStoreConfiguration.setFriendlyName("jUnit test"); + + keyStoreConfiguration.setSoftKeyStoreFilePath(keyStorePath); + keyStoreConfiguration.setSoftKeyStorePassword(keyStorePw); + keyStoreConfiguration.setKeyStoreType(KeyStoreConfiguration.KeyStoreType.fromString(keyStoreType)); + keyStoreConfiguration.setKeyStoreName(keyStoreName); + + //build new KeyStore based on configuration + return keyStoreFactory.buildNewKeyStore(keyStoreConfiguration); + + } + + @Nonnull + private AuthenticationResponse buildDummyAuthResponse(boolean withAll) throws URISyntaxException { + final AttributeDefinition attributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition attributeDef2 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition attributeDef3 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition attributeDef4 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + final AttributeDefinition attributeDef5 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PLACEOFBIRTH).first(); + final AttributeDefinition attributeDef6 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_BIRTHNAME).first(); + + final Builder attributeMap = ImmutableAttributeMap.builder(); + attributeMap.put(attributeDef, "LU/AT/" + RandomStringUtils.randomNumeric(64)); + attributeMap.put(attributeDef2, RandomStringUtils.randomAlphabetic(10)); + attributeMap.put(attributeDef3, RandomStringUtils.randomAlphabetic(10)); + attributeMap.put(attributeDef4, "2001-01-01"); + if (withAll) { + attributeMap.put(attributeDef5, RandomStringUtils.randomAlphabetic(10)); + attributeMap.put(attributeDef6, RandomStringUtils.randomAlphabetic(10)); + + } + + val b = new AuthenticationResponse.Builder(); + return b.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(Constants.SUCCESS_URI) + .inResponseTo("_".concat(Random.nextHexRandom16())) + .subjectNameIdFormat("afaf") + .levelOfAssurance(EaafConstants.EIDAS_LOA_PREFIX + RandomStringUtils.randomAlphabetic(5)) + .attributes(attributeMap.build()) + .build(); + } + + private Map<String, Object> convertEidasAttrToSimpleMap( + ImmutableMap<AttributeDefinition<?>, ImmutableSet<? extends AttributeValue<?>>> attributeMap) { + final Map<String, Object> result = new HashMap<>(); + for (final AttributeDefinition<?> el : attributeMap.keySet()) { + final Class<?> parameterizedType = el.getParameterizedType(); + if (DateTime.class.equals(parameterizedType)) { + convertDateTime(attributeMap, result, el); + } else if (PostalAddress.class.equals(parameterizedType)) { + convertPostalAddress(attributeMap, result, el); + } else { + convertString(attributeMap, result, el); + } + } + return result; + } + + private void convertString(ImmutableMap<AttributeDefinition<?>, + ImmutableSet<? extends AttributeValue<?>>> attributeMap, + Map<String, Object> result, AttributeDefinition<?> el) { + final List<String> natPersonIdObj = EidasResponseUtils + .translateStringListAttribute(el, attributeMap.get(el)); + final String stringAttr = natPersonIdObj.get(0); + if (StringUtils.isNotEmpty(stringAttr)) { + result.put(el.getFriendlyName(), stringAttr); + + } + } + + private void convertPostalAddress(ImmutableMap<AttributeDefinition<?>, + ImmutableSet<? extends AttributeValue<?>>> attributeMap, + Map<String, Object> result, AttributeDefinition<?> el) { + final PostalAddress addressAttribute = EidasResponseUtils + .translateAddressAttribute(el, attributeMap.get(el).asList()); + if (addressAttribute != null) { + result.put(el.getFriendlyName(), addressAttribute); + + } + } + + private void convertDateTime(ImmutableMap<AttributeDefinition<?>, + ImmutableSet<? extends AttributeValue<?>>> attributeMap, + Map<String, Object> result, AttributeDefinition<?> el) { + final DateTime attribute = EidasResponseUtils.translateDateAttribute(el, attributeMap.get(el).asList()); + if (attribute != null) { + result.put(el.getFriendlyName(), attribute); + + } + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskTest.java new file mode 100644 index 00000000..5c528532 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskTest.java @@ -0,0 +1,552 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; +import static org.mockito.ArgumentMatchers.any; + +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.joda.time.DateTime; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.github.skjolber.mockito.soap.SoapServiceRule; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MatchedPersonResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; +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.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +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.AttributeValue; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import lombok.val; +import szrservices.GetBPK; +import szrservices.GetBPKResponse; +import szrservices.GetIdentityLinkEidasResponse; +import szrservices.PersonInfoType; +import szrservices.SZR; +import szrservices.SZRException_Exception; + +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class CreateIdentityLinkTaskTest { + + @Autowired(required = true) + private CreateIdentityLinkTask task; + + @Autowired(required = true) + private MsConnectorDummyConfigMap basicConfig; + @Autowired + protected EidasAttributeRegistry attrRegistry; + + @Autowired + EaafKeyStoreFactory keyStoreFactory; + + @Autowired + ICcSpecificEidProcessingService eidPostProcessor; + + @Autowired + IRequestStorage requestStorage; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private DummySpConfiguration oaParam; + private SZR szrMock; + + private MatchedPersonResult matchingInfos; + private AuthenticationResponse response; + private Map<String, String> spConfig; + + @Rule + public final SoapServiceRule soap = SoapServiceRule.newInstance(); + + /** + * jUnit test set-up. + * @throws EidasAttributeException + * @throws EidPostProcessingException + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException, EidPostProcessingException, EidasAttributeException { + + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation", "false"); + + spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "false"); + oaParam = new DummySpConfiguration(spConfig, basicConfig); + pendingReq = new TestRequestImpl(); + + response = buildDummyAuthResponse(); + final Map<String, Object> eidasAttributes = convertEidasAttrToSimpleMap( + response.getAttributes().getAttributeMap()); + final SimpleEidasData eidData = eidPostProcessor.postProcess(eidasAttributes); + MatchingTaskUtils.storeInitialEidasData(pendingReq, eidData); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + + matchingInfos = MatchedPersonResult.builder() + .bpk(RandomStringUtils.randomAlphabetic(5)) + .givenName(eidData.getGivenName()) + .familyName(eidData.getFamilyName()) + .dateOfBirth(eidData.getDateOfBirth()) + .countryCode(eidData.getCitizenCountryCode()) + .build(); + MatchingTaskUtils.storeFinalMatchingResult(pendingReq, matchingInfos); + + pendingReq.setSpConfig(oaParam); + 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); + + szrMock = soap.mock(SZR.class, "http://localhost:1234/demoszr"); + } + + + @Test + public void buildIdentityLink() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + + + //perform test + task.execute(pendingReq, executionContext); + + + //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.assertNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNull("AuthBlock", authBlock); + + Assert.assertFalse("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("IDL", authProcessData.getIdentityLink()); + checkElement("Mustermann", authProcessData.getIdentityLink().getFamilyName()); + checkElement("Hans", authProcessData.getIdentityLink().getGivenName()); + checkElement("1989-05-05", authProcessData.getIdentityLink().getDateOfBirth()); + checkElement("urn:publicid:gv.at:baseid", authProcessData.getIdentityLink().getIdentificationType()); + checkElement("k+zDM1BVpN1WJO4x7ZQ3ng==", authProcessData.getIdentityLink().getIdentificationValue()); + Assert.assertNotNull(authProcessData.getIdentityLink().getSerializedSamlAssertion()); + Assert.assertNotNull(authProcessData.getIdentityLink().getSamlAssertion()); + + Assert.assertNotNull("no bPK", authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + Assert.assertEquals("wrong bPK", "XX:FkXtOaSSeR3elyL9KLLvijIYDMU=", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + + } + + @Test + public void successfulProcessWithDataFromMatching() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + + MatchedPersonResult matchingInfos = MatchedPersonResult.builder() + .bpk(RandomStringUtils.randomAlphabetic(5)) + .givenName(RandomStringUtils.randomAlphabetic(5)) + .familyName(RandomStringUtils.randomAlphabetic(5)) + .dateOfBirth(RandomStringUtils.randomAlphabetic(5)) + .countryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .build(); + + MatchingTaskUtils.storeFinalMatchingResult(pendingReq, matchingInfos); + + //perform test + task.execute(pendingReq, executionContext); + + + //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.assertNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNull("AuthBlock", authBlock); + + Assert.assertFalse("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("IDL", authProcessData.getIdentityLink()); + checkElement("Mustermann", authProcessData.getIdentityLink().getFamilyName()); + checkElement("Hans", authProcessData.getIdentityLink().getGivenName()); + checkElement("1989-05-05", authProcessData.getIdentityLink().getDateOfBirth()); + checkElement("urn:publicid:gv.at:baseid", authProcessData.getIdentityLink().getIdentificationType()); + checkElement("k+zDM1BVpN1WJO4x7ZQ3ng==", authProcessData.getIdentityLink().getIdentificationValue()); + Assert.assertNotNull(authProcessData.getIdentityLink().getSerializedSamlAssertion()); + Assert.assertNotNull(authProcessData.getIdentityLink().getSamlAssertion()); + + Assert.assertNotNull("no bPK", authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + Assert.assertEquals("wrong bPK", "XX:FkXtOaSSeR3elyL9KLLvijIYDMU=", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + + } + + @Test + public void buildIdentityLinkWithWbpk() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + spConfig.put("target", EaafConstants.URN_PREFIX_WBPK + "FN+123456i"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "true"); + + //perform test + task.execute(pendingReq, executionContext); + + + //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.assertNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNull("AuthBlock", authBlock); + + Assert.assertFalse("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("no bPK", authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + Assert.assertEquals("wrong bPK", "FN+123456i:D26vJncPS2W790RH/LP04V+vNOQ=", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + + } + + @Test + public void buildIdentityLinkWithEidasBpk() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_2.xml"); + spConfig.put("target", EaafConstants.URN_PREFIX_EIDAS + "AT+EU"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "true"); + + //perform test + task.execute(pendingReq, executionContext); + + + //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.assertNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNull("AuthBlock", authBlock); + + Assert.assertFalse("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("IDL", authProcessData.getIdentityLink()); + checkElement("Musterfrau", authProcessData.getIdentityLink().getFamilyName()); + checkElement("Martina", authProcessData.getIdentityLink().getGivenName()); + checkElement("1991-04-15", authProcessData.getIdentityLink().getDateOfBirth()); + checkElement("urn:publicid:gv.at:baseid", authProcessData.getIdentityLink().getIdentificationType()); + checkElement("k+zDM1BV1312312332x7ZQ3ng==", authProcessData.getIdentityLink().getIdentificationValue()); + + Assert.assertNotNull("no bPK", authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + Assert.assertEquals("wrong bPK", "AT+EU:AT/EU/1+wqDl059/02Ptny0g+LyuLDJV0=", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + + } + + @Test + public void buildIdentityLinkWithUnknownBpk() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + spConfig.put("target", "urn:notextis:1234"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "true"); + + try { + task.execute(pendingReq, executionContext); + Assert.fail("unknown bPKType not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorId", "builder.33", + ((EaafException) e.getOriginalException()).getErrorId()); + Assert.assertEquals("wrong parameter size", 1, ((EaafException) e.getOriginalException()) + .getParams().length); + + } + } + + @Test + public void noBpkResult() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + GetBPKResponse getBpkResp = new GetBPKResponse(); + org.mockito.Mockito.when(szrMock.getBPK(any(GetBPK.class))).thenReturn(getBpkResp ); + + spConfig.put("target", "urn:notextis:1234"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "true"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation", "true"); + + try { + task.execute(pendingReq, executionContext); + Assert.fail("unknown bPKType not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorId", "ernb.01", + ((EaafException) e.getOriginalException()).getErrorId()); + + } + } + + @Test + public void bPKFromSzr() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + String bpk = RandomStringUtils.randomAlphanumeric(10); + GetBPKResponse getBpkResp = new GetBPKResponse(); + getBpkResp.getGetBPKReturn().add(bpk); + org.mockito.Mockito.when(szrMock.getBPK(any(GetBPK.class))).thenReturn(getBpkResp ); + + spConfig.put("target", "urn:notextis:1234"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "true"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation", "true"); + + //execute test + task.execute(pendingReq, executionContext); + + + //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.assertNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNull("AuthBlock", authBlock); + + Assert.assertFalse("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("no bPK", authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + Assert.assertEquals("wrong bPK", bpk, + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + } + + private void setSzrResponseIdentityLink(String responseXmlPath) throws JAXBException, SZRException_Exception { + final JAXBContext jaxbContext = JAXBContext + .newInstance(szrservices.ObjectFactory.class, org.w3._2001._04.xmldsig_more.ObjectFactory.class, + org.w3._2000._09.xmldsig.ObjectFactory.class, + at.gv.e_government.reference.namespace.persondata._20020228.ObjectFactory.class); + final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); + final GetIdentityLinkEidasResponse szrResponse = (GetIdentityLinkEidasResponse) jaxbUnmarshaller + .unmarshal(this.getClass().getResourceAsStream(responseXmlPath)); + org.mockito.Mockito.when(szrMock.getIdentityLinkEidas(any(PersonInfoType.class))).thenReturn(szrResponse.getGetIdentityLinkReturn()); + + } + private void checkElement(String expected, String value) { + Assert.assertNotNull(value); + Assert.assertEquals(expected, value); + + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponse() throws URISyntaxException { + final AttributeDefinition attributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition attributeDef2 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition attributeDef3 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition attributeDef4 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + + final ImmutableAttributeMap attributeMap = ImmutableAttributeMap.builder() + .put(attributeDef, "LU/AT/" + 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("_".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(); + } + + private Map<String, Object> convertEidasAttrToSimpleMap( + ImmutableMap<AttributeDefinition<?>, ImmutableSet<? extends AttributeValue<?>>> attributeMap) { + final Map<String, Object> result = new HashMap<>(); + for (final AttributeDefinition<?> el : attributeMap.keySet()) { + final Class<?> parameterizedType = el.getParameterizedType(); + if (DateTime.class.equals(parameterizedType)) { + convertDateTime(attributeMap, result, el); + } else if (PostalAddress.class.equals(parameterizedType)) { + convertPostalAddress(attributeMap, result, el); + } else { + convertString(attributeMap, result, el); + } + } + return result; + } + + private void convertString(ImmutableMap<AttributeDefinition<?>, + ImmutableSet<? extends AttributeValue<?>>> attributeMap, + Map<String, Object> result, AttributeDefinition<?> el) { + final List<String> natPersonIdObj = EidasResponseUtils + .translateStringListAttribute(el, attributeMap.get(el)); + final String stringAttr = natPersonIdObj.get(0); + if (StringUtils.isNotEmpty(stringAttr)) { + result.put(el.getFriendlyName(), stringAttr); + + } + } + + private void convertPostalAddress(ImmutableMap<AttributeDefinition<?>, + ImmutableSet<? extends AttributeValue<?>>> attributeMap, + Map<String, Object> result, AttributeDefinition<?> el) { + final PostalAddress addressAttribute = EidasResponseUtils + .translateAddressAttribute(el, attributeMap.get(el).asList()); + if (addressAttribute != null) { + result.put(el.getFriendlyName(), addressAttribute); + + } + } + + private void convertDateTime(ImmutableMap<AttributeDefinition<?>, + ImmutableSet<? extends AttributeValue<?>>> attributeMap, + Map<String, Object> result, AttributeDefinition<?> el) { + final DateTime attribute = EidasResponseUtils.translateDateAttribute(el, attributeMap.get(el).asList()); + if (attribute != null) { + result.put(el.getFriendlyName(), attribute); + + } + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateNewErnpEntryTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateNewErnpEntryTaskTest.java new file mode 100644 index 00000000..985a5e14 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateNewErnpEntryTaskTest.java @@ -0,0 +1,198 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; + +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.RandomStringUtils; +import org.jetbrains.annotations.NotNull; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.ErnpRestClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.ErnpRestClient.ErnpRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MatchedPersonResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateNewErnpEntryTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import lombok.SneakyThrows; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class CreateNewErnpEntryTaskTest { + + CreateNewErnpEntryTask task; + + @Mock ErnpRestClient ernpClient; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private TestRequestImpl pendingReq; + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws URISyntaxException, EaafStorageException { + task = new CreateNewErnpEntryTask(ernpClient); + + MockHttpServletRequest httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + MockHttpServletResponse httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + pendingReq = new TestRequestImpl(); + pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); + + } + + + @Test + @SneakyThrows + public void missingEidasData() { + Mockito.when(ernpClient.add(any())) + .thenThrow(new IllegalStateException("add ERnP entry should not be neccessary")); + + TaskExecutionException error = assertThrows("wrong exception", TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals("wrong pendingRequestId", pendingReq.getPendingRequestId(), error.getPendingRequestID()); + assertTrue("Wrong exception", (error.getOriginalException() instanceof WorkflowException)); + assertTrue("Wrong flag 'manualFixNeeded'", + ((WorkflowException) error.getOriginalException()).isRequiresManualFix()); + + } + + @Test + @SneakyThrows + public void noErnpResponse() { + SimpleEidasData input = buildInputData(); + Mockito.when(ernpClient.add(input)) + .thenReturn(ernpRegisterResult(Arrays.asList())); + + TaskExecutionException error = assertThrows("wrong exception", TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals("wrong pendingRequestId", pendingReq.getPendingRequestId(), error.getPendingRequestID()); + assertTrue("Wrong exception", (error.getOriginalException() instanceof WorkflowException)); + assertTrue("Wrong flag 'manualFixNeeded'", + ((WorkflowException) error.getOriginalException()).isRequiresManualFix()); + + } + + @Test + @SneakyThrows + public void moreThanOneErnpResponse() { + String bpk = RandomStringUtils.randomAlphabetic(5); + SimpleEidasData input = buildInputData(); + Mockito.when(ernpClient.add(input)) + .thenReturn(ernpRegisterResult(Arrays.asList(buildErnpResultEntry(input, bpk), buildRandomResultEntry()))); + + TaskExecutionException error = assertThrows("wrong exception", TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals("wrong pendingRequestId", pendingReq.getPendingRequestId(), error.getPendingRequestID()); + assertTrue("Wrong exception", (error.getOriginalException() instanceof WorkflowException)); + assertTrue("Wrong flag 'manualFixNeeded'", + ((WorkflowException) error.getOriginalException()).isRequiresManualFix()); + + } + + @Test + @SneakyThrows + public void insertErnpSuccess() { + String bpk = RandomStringUtils.randomAlphabetic(5); + SimpleEidasData input = buildInputData(); + Mockito.when(ernpClient.add(input)) + .thenReturn(ernpRegisterResult(Arrays.asList(buildErnpResultEntry(input, bpk)))); + + // perform test + task.execute(pendingReq, executionContext); + + // validate state + MatchedPersonResult result = MatchingTaskUtils.getFinalMatchingResult(pendingReq); + assertNotNull("no matching result", result); + assertEquals("familyname", input.getFamilyName(), result.getFamilyName()); + assertEquals("givenyname", input.getGivenName(), result.getGivenName()); + assertEquals("dateOfBirth", input.getDateOfBirth(), result.getDateOfBirth()); + assertEquals("bpk", bpk, result.getBpk()); + assertEquals("countryCode", input.getCitizenCountryCode(), result.getCountryCode()); + + } + + + @NotNull + private ErnpRegisterResult ernpRegisterResult(List<RegisterResult> registerResult) { + return new ErnpRegisterResult(registerResult); + + } + + private RegisterResult buildErnpResultEntry(SimpleEidasData input, String bpk) { + return buildErnpResultEntry(input.getFamilyName(), input.getGivenName(), input.getDateOfBirth(), bpk); + + } + + private RegisterResult buildRandomResultEntry() { + return buildErnpResultEntry(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5), + RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + + } + + private RegisterResult buildErnpResultEntry(String familyName, String givenName, String birthday, String bpk) { + return RegisterResult.builder() + .bpk(bpk) + .dateOfBirth(birthday) + .givenName(givenName) + .familyName(familyName) + .build(); + + } + + private SimpleEidasData buildInputData() throws EaafStorageException { + String cc = RandomStringUtils.randomAlphabetic(5).toUpperCase(); + String pseudonym = RandomStringUtils.randomAlphabetic(5); + String familyName = RandomStringUtils.randomAlphabetic(5); + String givenName = RandomStringUtils.randomAlphabetic(5); + String birthday = RandomStringUtils.randomNumeric(4) + "-" + + RandomStringUtils.randomNumeric(2) + "-" + RandomStringUtils.randomNumeric(2); + + SimpleEidasData input = SimpleEidasData.builder() + .familyName(familyName) + .givenName(givenName) + .dateOfBirth(birthday) + .personalIdentifier(cc + "/AT/" + pseudonym) + .pseudonym(pseudonym) + .citizenCountryCode(cc) + .build(); + MatchingTaskUtils.storeInitialEidasData(pendingReq, input); + return input; + + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateAuthnRequestTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateAuthnRequestTaskTest.java new file mode 100644 index 00000000..763d7d39 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateAuthnRequestTaskTest.java @@ -0,0 +1,670 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.junit.Assert.assertNull; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.GenerateAuthnRequestTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy.DummySpecificCommunicationService; +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.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.GuiBuildException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +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 eu.eidas.auth.commons.light.ILightRequest; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class GenerateAuthnRequestTaskTest { + + @Autowired(required = true) + private GenerateAuthnRequestTask task; + @Autowired(required = true) + private DummySpecificCommunicationService commService; + @Autowired(required = true) + private MsConnectorDummyConfigMap basicConfig; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private DummySpConfiguration oaParam; + private Map<String, String> spConfig; + + + /** + * jUnit test set-up. + * + */ + @Before + public void setUp() { + + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + oaParam = new DummySpConfiguration(spConfig, basicConfig); + + pendingReq = new TestRequestImpl(); + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.node_v2.requesterId.useHashedForm", "true"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.node_v2.entityId", + RandomStringUtils.randomAlphabetic(10)); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", + "http://test/" + RandomStringUtils.randomAlphabetic(5)); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.requested.nameIdFormat"); + basicConfig.removeConfigValue(Constants.CONIG_PROPS_EIDAS_WORKAROUND_STAGING_MS_CONNECTOR); + + } + + @Test + public void missingIssuer() { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.entityId"); + + //execute test + try { + task.execute(pendingReq, executionContext); + Assert.fail("Missing Issuer not detected"); + + } catch (final TaskExecutionException e) { + // forward URL is not set in example config + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e.getOriginalException(), + "Wrong exception"); + Assert.assertEquals("wrong errorCode", "config.27", ((EaafException) e.getOriginalException()) + .getErrorId()); + Assert.assertEquals("wrong parameter size", 1, ((EaafException) e.getOriginalException()) + .getParams().length); + + } + } + + @Test + public void missingForwardUrl() { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.forward.endpoint"); + + //execute test + try { + task.execute(pendingReq, executionContext); + Assert.fail("Missing Forward-URL not detected"); + + } catch (final TaskExecutionException e) { + // forward URL is not set in example config + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e.getOriginalException(), + "Wrong exception"); + Assert.assertEquals("wrong errorCode", "config.08", ((EaafException) e.getOriginalException()) + .getErrorId()); + Assert.assertEquals("wrong parameter size", 1, ((EaafException) e.getOriginalException()) + .getParams().length); + Assert.assertEquals("wrong errorMsg", Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL, ((EaafException) e + .getOriginalException()).getParams()[0]); + + } + } + + @Test + public void selectUnknownStage() { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + String stage = RandomStringUtils.randomAlphabetic(5); + executionContext.put("selectedEnvironment", stage); + + //execute test + try { + task.execute(pendingReq, executionContext); + Assert.fail("Missing Forward-URL not detected"); + + } catch (final TaskExecutionException e) { + // forward URL is not set in example config + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e.getOriginalException(), + "Wrong exception"); + Assert.assertEquals("wrong errorCode", "config.08", ((EaafException) e.getOriginalException()) + .getErrorId()); + Assert.assertEquals("wrong parameter size", 1, ((EaafException) e.getOriginalException()) + .getParams().length); + Assert.assertEquals("wrong errorMsg", Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL + "." + stage, ((EaafException) e + .getOriginalException()).getParams()[0]); + + } + } + + @Test + public void selectQsEndpoint() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + executionContext.put("selectedEnvironment", "qs"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint.qs", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + } + + @Test + public void selectTestEndpoint() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + executionContext.put("selectedEnvironment", "test"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint.test", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + } + + @Test + public void selectDevEndpoint() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + executionContext.put("selectedEnvironment", "dev"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint.dev", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + } + + @Test + public void noCountryCode() { + try { + task.execute(pendingReq, executionContext); + Assert.fail("No countryCode not detected"); + + } catch (final TaskExecutionException e) { + Assert.assertEquals("wrong pendingReqId", pendingReq.getPendingRequestId(), e.getPendingRequestID()); + org.springframework.util.Assert.isInstanceOf(EidasSAuthenticationException.class, e + .getOriginalException(), "Wrong exception"); + Assert.assertEquals("wrong errorCode", "eidas.03", ((EaafException) e.getOriginalException()) + .getErrorId()); + + } + } + + @Test + public void withStaticProviderNameForPublicSPs() throws TaskExecutionException, + SpecificCommunicationException { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.publicSectorTargets", ".*"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "true"); + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.staticProviderNameForPublicSPs"); + + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("ProviderName is not Static", + Constants.DEFAULT_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP, eidasReq.getProviderName()); + Assert.assertEquals("no PublicSP", "public", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", "http://eidas.europa.eu/LoA/high", eidasReq.getLevelOfAssurance()); + Assert.assertNull("msConnector Staging", + pendingReq.getRawData(MsEidasNodeConstants.EXECCONTEXT_PARAM_MSCONNECTOR_STAGING, String.class)); + + } + + @Test + public void withMsConnectorStaging() throws TaskExecutionException, + SpecificCommunicationException { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.publicSectorTargets", ".*"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "true"); + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.staticProviderNameForPublicSPs"); + + String msConnectorStage = RandomStringUtils.randomAlphanumeric(10); + basicConfig.putConfigValue(Constants.CONIG_PROPS_EIDAS_WORKAROUND_STAGING_MS_CONNECTOR, msConnectorStage); + + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("msConnector Staging", msConnectorStage, + pendingReq.getRawData(MsEidasNodeConstants.EXECCONTEXT_PARAM_MSCONNECTOR_STAGING, String.class)); + + + + } + + @Test + public void withCustomStaticProviderNameForPublicSPs() throws TaskExecutionException, + SpecificCommunicationException { + String cc = RandomStringUtils.randomAlphabetic(2); + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, cc); + + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.publicSectorTargets", ".*"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderNames", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.staticProviderNameForPublicSPs", "myNode"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("wrong issuer", + basicConfig.getBasicConfiguration("eidas.ms.auth.eIDAS.node_v2.entityId"), eidasReq.getIssuer()); + Assert.assertEquals("ProviderName is not Static", "myNode", eidasReq.getProviderName()); + Assert.assertEquals("no PublicSP", "public", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", "http://eidas.europa.eu/LoA/high", eidasReq.getLevelOfAssurance()); + Assert.assertEquals("wrong CC", cc, eidasReq.getCitizenCountryCode()); + assertNull("NameIdPolicy not null", eidasReq.getNameIdFormat()); + + } + + @Test + public void withDynamicProviderNameForPublicSPs() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException, UnsupportedEncodingException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + executionContext.put("selectedEnvironment", "prod"); + + String providerName = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "false"); + + String nameIdFormat = RandomStringUtils.randomAlphabetic(10); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.requested.nameIdFormat", nameIdFormat); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertNotNull("ProviderName found", eidasReq.getProviderName()); + Assert.assertEquals("PrividerName", providerName, eidasReq.getProviderName()); + Assert.assertNull("RequesterId found", eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", EaafConstants.EIDAS_LOA_HIGH, + eidasReq.getLevelOfAssurance()); + + Assert.assertEquals("Wrong req. attr. size", 4, eidasReq.getRequestedAttributes().size()); + Assert.assertEquals("NameIdFormat", nameIdFormat, eidasReq.getNameIdFormat()); + + } + + @Test + public void publicSpWithCountryLu() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException, UnsupportedEncodingException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "LU"); + executionContext.put("selectedEnvironment", "prod"); + + String providerName = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("PrividerName", "myNode", eidasReq.getProviderName()); + Assert.assertEquals("RequesterId found", "myNode", eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", EaafConstants.EIDAS_LOA_HIGH, + eidasReq.getLevelOfAssurance()); + + Assert.assertEquals("Wrong req. attr. size", 4, eidasReq.getRequestedAttributes().size()); + + } + + @Test + public void privateSpWithCountryLu() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException, UnsupportedEncodingException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "LU"); + executionContext.put("selectedEnvironment", "prod"); + + String providerName = RandomStringUtils.randomAlphanumeric(10); + String requesterId = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + pendingReq.setRawDataToTransaction(Constants.DATA_REQUESTERID, requesterId); + + spConfig.put("target", + EaafConstants.URN_PREFIX_WBPK_TARGET_WITH_X + "FN+" + RandomStringUtils.randomNumeric(6)); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "true"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("PrividerName", "Austria", eidasReq.getProviderName()); + Assert.assertEquals("RequesterId", "Austria", eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "private", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", EaafConstants.EIDAS_LOA_HIGH, + eidasReq.getLevelOfAssurance()); + + Assert.assertEquals("Wrong req. attr. size", 4, eidasReq.getRequestedAttributes().size()); + + } + + @Test + public void withEidasNodePostReqNotValidTemplate() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException, UnsupportedEncodingException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + String providerName = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "false"); + + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "POST"); + + //execute test + try { + task.execute(pendingReq, executionContext); + Assert.fail("Missing template not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorCode", "Could not resolve view with name 'eidas_node_forward.html' ", + ((GuiBuildException) e.getOriginalException()).getMessage()); + + } + } + + @Test + public void withDynamicProviderNameForPrivateSPs() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + spConfig.put("target", + EaafConstants.URN_PREFIX_WBPK_TARGET_WITH_X + "FN+" + RandomStringUtils.randomNumeric(6)); + String providerName = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + pendingReq.setRawDataToTransaction(Constants.DATA_REQUESTERID, "http://junit.sp"); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "false"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("PrividerName", providerName, eidasReq.getProviderName()); + Assert.assertEquals("RequesterId", "Wr8LrrVf5SYneblOlZdZNaLQQCCgzklfKQvyeZjBx10=", eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "private", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", "http://eidas.europa.eu/LoA/high", eidasReq.getLevelOfAssurance()); + + } + + @Test + public void privateSPWithoutRequestIdHashing() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + spConfig.put("target", + EaafConstants.URN_PREFIX_WBPK_TARGET_WITH_X + "FN+" + RandomStringUtils.randomNumeric(6)); + String providerName = RandomStringUtils.randomAlphanumeric(10); + String requesterId = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + pendingReq.setRawDataToTransaction(Constants.DATA_REQUESTERID, requesterId); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.node_v2.requesterId.useHashedForm", "false"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("PrividerName", providerName, eidasReq.getProviderName()); + Assert.assertEquals("RequesterId", requesterId, eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "private", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", "http://eidas.europa.eu/LoA/high", eidasReq.getLevelOfAssurance()); + + } + + @Test + public void withoutProviderNameForPublicSPs() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + String providerName = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "false"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "false"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "false"); + + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertNull("ProviderName found", eidasReq.getProviderName()); + Assert.assertNull("RequesterId found", eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", "http://eidas.europa.eu/LoA/high", eidasReq.getLevelOfAssurance()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateMobilePhoneSignatureRequestTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateMobilePhoneSignatureRequestTaskTest.java new file mode 100644 index 00000000..e82d4122 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateMobilePhoneSignatureRequestTaskTest.java @@ -0,0 +1,286 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.springframework.util.Assert.isInstanceOf; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Base64; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthConstants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.provider.IdAustriaClientAuthMetadataProvider; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.GenerateMobilePhoneSignatureRequestTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy.DummyOA; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiBuilderConfiguration; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; +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.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.SamlVerificationEngine; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml", + "classpath:/eaaf_pvp_sp.beans.xml" +}) + +public class GenerateMobilePhoneSignatureRequestTaskTest { + + private static final String METADATA_PATH = "classpath:/data/idp_metadata_classpath_entity.xml"; + private static final String METADATA_SP_PATH = "classpath:/data/sp_metadata_junit.xml"; + + @Autowired(required = true) + private ApplicationContext context; + @Autowired(required = true) + protected MsConnectorDummyConfigMap authConfig; + @Autowired + private IdAustriaClientAuthMetadataProvider metadataProvider; + @Autowired + private PvpMetadataResolverFactory metadataFactory; + @Autowired + private DummyGuiBuilderConfigurationFactory guiBuilderConfigFactory; + @Autowired + private SamlVerificationEngine samlVerifyEngine; + @Autowired + private ITransactionStorage transactionStorage; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private DummyOA oaParam; + + private GenerateMobilePhoneSignatureRequestTask task; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void initialize() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + } + + /** + * jUnit test set-up. + * + * @throws Exception In case of an set-up error + */ + @Before + public void setUp() throws Exception { + task = (GenerateMobilePhoneSignatureRequestTask) context.getBean( + "GenerateMobilePhoneSignatureRequestTask"); + + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + authConfig.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID, + METADATA_PATH); + authConfig.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS, + "sig"); + + oaParam = new DummyOA(); + oaParam.setUniqueAppId("http://test.com/test"); + oaParam.setBmiUniqueIdentifier(oaParam.getUniqueIdentifier() + "#" + RandomStringUtils.randomAlphanumeric( + 5)); + oaParam.setTargetIdentifier( + EaafConstants.URN_PREFIX_CDID + RandomStringUtils.randomAlphabetic(2)); + oaParam.setEidasEnabled(true); + + pendingReq = new TestRequestImpl(); + pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); + pendingReq.setSpConfig(oaParam); + pendingReq.setAuthUrl("https://localhost/authhandler"); + + metadataProvider.fullyDestroy(); + guiBuilderConfigFactory.setVelocityBuilderConfig(createDummyGuiConfig()); + + } + + @Test + public void noMetadataAvailableOnGlobalConfig() { + authConfig.removeConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + assertNotNull(e.getOriginalException()); + isInstanceOf(EaafConfigurationException.class, e.getOriginalException()); + assertEquals("module.eidasauth.00", ((EaafConfigurationException) e.getOriginalException()).getErrorId()); + } + + @Test + public void wrongMetadataAvailableOnGlobalConfig() { + authConfig.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID, + "http://wrong.path/" + RandomStringUtils.randomAlphabetic(5)); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + assertNotNull(e.getPendingRequestID()); + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + assertNotNull(e.getOriginalException()); + isInstanceOf(EaafConfigurationException.class, e.getOriginalException()); + assertEquals("module.eidasauth.idaustria.02", + ((EaafConfigurationException) e.getOriginalException()).getErrorId()); + } + + @Test + public void noMetadataSigningKeyStore() throws Pvp2MetadataException { + authConfig.removeConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS); + + metadataProvider.addMetadataResolverIntoChain( + metadataFactory.createMetadataProvider(METADATA_PATH, null, "jUnitTest", null)); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + assertNotNull(e.getPendingRequestID()); + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + assertNotNull(e.getOriginalException()); + isInstanceOf(CredentialsNotAvailableException.class, e.getOriginalException()); + assertEquals("internal.pvp.01", + ((CredentialsNotAvailableException) e.getOriginalException()).getErrorId()); + } + + @Test + public void success() throws Exception { + metadataProvider.addMetadataResolverIntoChain( + metadataFactory.createMetadataProvider(METADATA_PATH, null, "jUnitTest", null)); + pendingReq.setTransactionId(RandomStringUtils.randomAlphanumeric(10)); + + task.execute(pendingReq, executionContext); + + validate(); + + } + + private void validate() throws Exception { + assertEquals("HTTP Statuscode", 200, httpResp.getStatus()); + assertEquals("ContentType", "text/html;charset=UTF-8", httpResp.getContentType()); + assertEquals("ContentEncoding", "UTF-8", httpResp.getCharacterEncoding()); + + final String html = httpResp.getContentAsString(); + assertNotNull("XML Metadata", html); + + final int startIndex = html.indexOf("SAMLRequest="); + assertTrue("No SAMLRequest in html", startIndex >= 0); + final String authnXml = html.substring(startIndex + "SAMLRequest=".length()); + + // check if relaystate was stored + final int startIndexRelayState = html.indexOf("RelayState="); + assertTrue("wrong RelayState in HTML", + startIndexRelayState >= 0); + final String relayState = html.substring(startIndexRelayState + "RelayState=".length(), startIndex); + final String storedPendingReqId = transactionStorage.get(relayState, String.class); + assertEquals("relayStore not map to pendingRequestId", + pendingReq.getPendingRequestId(), storedPendingReqId); + + final AuthnRequest authnRequest = (AuthnRequest) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), new ByteArrayInputStream( + Base64.getDecoder().decode(authnXml))); + + assertNotNull("AuthnReq", authnRequest); + assertNotNull("Issuer", authnRequest.getIssuer()); + assertEquals("EntityId", + "https://localhost/authhandler" + IdAustriaClientAuthConstants.ENDPOINT_METADATA, + authnRequest.getIssuer().getValue()); + + // check XML scheme + Saml2Utils.schemeValidation(authnRequest); + + // check signature + final PvpSProfileRequest msg = new PvpSProfileRequest( + authnRequest, + SAMLConstants.SAML2_POST_BINDING_URI); + msg.setEntityID(authnRequest.getIssuer().getValue()); + metadataProvider.addMetadataResolverIntoChain( + metadataFactory.createMetadataProvider(METADATA_SP_PATH, null, "jUnit SP", null)); + samlVerifyEngine.verify(msg, TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); + + assertNotNull("RequestedAuthnContext", authnRequest.getRequestedAuthnContext()); + assertNotNull("AuthnContextClassRef", authnRequest.getRequestedAuthnContext().getAuthnContextClassRefs()); + assertEquals("#AuthnContextClassRef", 1, + authnRequest.getRequestedAuthnContext().getAuthnContextClassRefs().size()); + assertEquals("LoA", "http://eidas.europa.eu/LoA/high", + authnRequest.getRequestedAuthnContext().getAuthnContextClassRefs().get(0).getAuthnContextClassRef()); + + } + + private IVelocityGuiBuilderConfiguration createDummyGuiConfig() { + return new IVelocityGuiBuilderConfiguration() { + + @Override + public Map<String, Object> getViewParameters() { + return null; + } + + @Override + public String getViewName() { + return "SAML2 Post-Binding"; + } + + @Override + public String getDefaultContentType() { + return null; + } + + @Override + public InputStream getTemplate(String viewName) { + return GenerateMobilePhoneSignatureRequestTaskTest.class.getResourceAsStream( + "/data/pvp_postbinding_template.html"); + } + + @Override + public String getClasspathTemplateDir() { + return null; + + } + + @Override + public boolean isWriteAsynch() { + return false; + + } + }; + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateOtherLoginMethodGuiTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateOtherLoginMethodGuiTaskTest.java new file mode 100644 index 00000000..ff994061 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateOtherLoginMethodGuiTaskTest.java @@ -0,0 +1,207 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.UnsupportedEncodingException; +import java.text.MessageFormat; +import java.util.Locale; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +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.fasterxml.jackson.databind.json.JsonMapper; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SelectedLoginMethod; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.GenerateOtherLoginMethodGuiTask; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import lombok.SneakyThrows; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml", + "/common_gui.beans.xml" +}) +@WebAppConfiguration +public class GenerateOtherLoginMethodGuiTaskTest { + + private static final String TEST_PATTER_REQ_PARAM = + "<input type=\"hidden\" name=\"loginSelection\" value=\"{0}\">"; + + private static ObjectMapper mapper = new ObjectMapper(); + + @Autowired + GenerateOtherLoginMethodGuiTask task; + + private ExecutionContextImpl executionContext = new ExecutionContextImpl(); + private TestRequestImpl pendingReq; + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + + @BeforeClass + public static void classInitializer() { + Locale.setDefault(Locale.ENGLISH); + + } + + /** + * jUnit test set-up. + */ + @Before + public void initialize() { + httpReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + pendingReq = new TestRequestImpl(); + pendingReq.setAuthUrl("https://localhost/ms_connector"); + pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); + + LocaleContextHolder.resetLocaleContext(); + } + + + @Test + @SneakyThrows + public void jsonResponse() throws TaskExecutionException, UnsupportedEncodingException { + String reason = RandomStringUtils.randomAlphabetic(5); + executionContext.put(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED, true); + executionContext.put(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON, reason); + httpReq.addHeader("Accept", "application/json"); + + task.execute(pendingReq, executionContext); + + //result validation + Assert.assertEquals("httpStausCode", 200, httpResp.getStatus()); + Assert.assertEquals("http ContentType", "application/json;charset=UTF-8", httpResp.getContentType()); + final String content = httpResp.getContentAsString(); + assertNotNull("response body is null", content); + Assert.assertFalse("response body is empty", content.isEmpty()); + final JsonNode json = new JsonMapper().readTree(content); + assertNotNull("response body is null", json); + assertNotNull("advancedMatchFailed", json.get(Constants.HTML_FORM_ADVANCED_MATCHING_FAILED)); + assertTrue("advancedMatchFailed", json.get(Constants.HTML_FORM_ADVANCED_MATCHING_FAILED).asBoolean()); + assertNotNull("advancedMatchingFailedReason", json.get(Constants.HTML_FORM_ADVANCED_MATCHING_FAILED_REASON)); + assertEquals("advancedMatchingFailedReason", reason, + json.get(Constants.HTML_FORM_ADVANCED_MATCHING_FAILED_REASON).asText()); + + } + + @Test + public void advancedMatchingFailedMsg() throws TaskExecutionException, UnsupportedEncodingException { + executionContext.put(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED, true); + + task.execute(pendingReq, executionContext); + + String html = doBasicValidation(); + Assert.assertTrue("Missing eIDAS infos", + html.contains(MessageFormat.format(TEST_PATTER_REQ_PARAM, SelectedLoginMethod.ADD_ME_AS_NEW))); + Assert.assertTrue("missing errorfield", + html.contains("<div id=\"matchingError\"")); + + } + + @Test + public void advancedMatchingFailedMsgWithDetails() throws TaskExecutionException, UnsupportedEncodingException { + String reason = RandomStringUtils.randomAlphabetic(5); + executionContext.put(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED, true); + executionContext.put(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON, reason); + + task.execute(pendingReq, executionContext); + + String html = doBasicValidation(); + Assert.assertTrue("Missing eIDAS infos", + html.contains(MessageFormat.format(TEST_PATTER_REQ_PARAM, SelectedLoginMethod.ADD_ME_AS_NEW))); + Assert.assertTrue("missing errorfield", + html.contains("<div id=\"matchingError\"")); + Assert.assertTrue("missing errorfield", + html.contains(reason)); + + } + + @Test + public void validHtmlResponseWithOutLocale() throws TaskExecutionException, UnsupportedEncodingException { + + task.execute(pendingReq, executionContext); + + doBasicValidation(); + + } + + @Test + public void validHtmlResponseWithDE() throws TaskExecutionException, UnsupportedEncodingException { + LocaleContextHolder.setLocale(Locale.GERMAN); + httpReq.addHeader("Accept-Language", "de"); + + task.execute(pendingReq, executionContext); + + doBasicValidation(); + + } + + @Test + public void validHtmlResponseWithEN() throws TaskExecutionException, UnsupportedEncodingException { + LocaleContextHolder.setLocale(Locale.ENGLISH); + + task.execute(pendingReq, executionContext); + + doBasicValidation(); + + } + + @Test + public void validHtmlResponseWithFR() throws TaskExecutionException, UnsupportedEncodingException { + LocaleContextHolder.setLocale(Locale.FRANCE); + httpReq.addHeader("Accept-Language", "fr"); + + task.execute(pendingReq, executionContext); + + doBasicValidation(); + + } + + private String doBasicValidation() throws UnsupportedEncodingException { + Assert.assertEquals("Wrong http StatusCode", 200, httpResp.getStatus()); + Assert.assertEquals("Wrong http ContentType", "text/html;charset=UTF-8", httpResp.getContentType()); + + String html = httpResp.getContentAsString(); + Assert.assertNotNull("html result is null", html); + Assert.assertFalse("html result is empty", html.isEmpty()); + + Assert.assertTrue("Missing IDA Login", + html.contains(MessageFormat.format(TEST_PATTER_REQ_PARAM, SelectedLoginMethod.MOBILE_PHONE_SIGNATURE_LOGIN))); + Assert.assertTrue("Missing residence infos", + html.contains(MessageFormat.format(TEST_PATTER_REQ_PARAM, SelectedLoginMethod.NO_OTHER_LOGIN))); + Assert.assertTrue("Missing eIDAS infos", + html.contains(MessageFormat.format(TEST_PATTER_REQ_PARAM, SelectedLoginMethod.EIDAS_LOGIN))); + + Assert.assertTrue("No language selector with pendingRequestId", + html.contains("/otherLoginMethod?pendingid=" + pendingReq.getPendingRequestId())); + Assert.assertTrue("No country-selection form", + html.contains("<form method=\"post\" action=\"/otherLoginMethod\">")); + + return html; + + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskTest.java new file mode 100644 index 00000000..74ac065e --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskTest.java @@ -0,0 +1,939 @@ +/* + * Copyright 2020 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; + +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.xml.namespace.QName; + +import org.apache.commons.lang3.RandomStringUtils; +import org.jetbrains.annotations.NotNull; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.ErnpRestClient.ErnpRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.IErnpClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.IZmrClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient.ZmrRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MatchedPersonResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.ZmrCommunicationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.CountrySpecificDetailSearchProcessor; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.GenericEidProcessor; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterStatusResults; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.InitialSearchTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; +import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +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.light.impl.LightRequest; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class InitialSearchTaskTest { + + + private static final String EE = "EE"; + private static final String DE = "DE"; + + private static final String EE_ST = EE + "/ST/"; + private static final String DE_ST = DE + "/ST/"; + + @Mock + private IZmrClient zmrClient; + @Mock + private IErnpClient ernpClient; + + @Autowired + private List<CountrySpecificDetailSearchProcessor> handlers; + private RegisterSearchService registerSearchService; + + private final ICcSpecificEidProcessingService eidPostProcessor = createEidPostProcessor(); + private InitialSearchTask task; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private TestRequestImpl pendingReq; + private final String randomBpk = RandomStringUtils.randomNumeric(6); + private final String randomPseudonym = RandomStringUtils.randomNumeric(10); + private final String randomPersonalIdentifier_DE = DE_ST + randomPseudonym; + private final String randomPersonalIdentifier_EE = EE_ST + randomPseudonym; + private final String randomFamilyName = randomAlphabetic(10); + private final String randomGivenName = randomAlphabetic(10); + private final String randomPlaceOfBirth = randomAlphabetic(10); + private final String randomBirthName = randomAlphabetic(10); + private final String randomBirthDate = "2011-01-" + (10 + new Random().nextInt(18)); + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws URISyntaxException, EaafStorageException { + registerSearchService = new RegisterSearchService(handlers, zmrClient, ernpClient); + task = new InitialSearchTask(registerSearchService, eidPostProcessor); + + MockHttpServletRequest httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + MockHttpServletResponse httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + final AuthenticationResponse response = buildDummyAuthResponseRandomPerson(); + pendingReq = new TestRequestImpl(); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + } + + @NotNull + private ICcSpecificEidProcessingService createEidPostProcessor() { + return new ICcSpecificEidProcessingService() { + + private final GenericEidProcessor genericEidProcessor = new GenericEidProcessor(); + + @Override + public SimpleEidasData postProcess(Map<String, Object> eidasAttrMap) throws EidPostProcessingException, EidasAttributeException { + return genericEidProcessor.postProcess(eidasAttrMap); + } + + @Override + public void preProcess(String selectedCC, IRequest pendingReq, LightRequest.Builder authnRequestBuilder) { + genericEidProcessor.preProcess(pendingReq, authnRequestBuilder); + } + }; + } + + /** + * One match, but register update needed + */ + @Test + @DirtiesContext + public void singlePersonalIdMatchUpdateNecessary_Zmr() throws Exception { + String oldGivenName = randomAlphabetic(10); + String placeOfBirth = randomAlphabetic(10); + RegisterResult firstZmrResult = randomRegisterResult(oldGivenName, randomBpk, placeOfBirth); + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(zmrRegisterResult(firstZmrResult)); + + Mockito.when(zmrClient.searchCountrySpecific(any(), any(), any())) + .thenThrow(new IllegalStateException("CountrySpecific search search should not be neccessary")); + Mockito.when(zmrClient.searchWithMds(any(), any(), any(), any(), any())) + .thenThrow(new IllegalStateException("MDS search should not be neccessary")); + Mockito.when(zmrClient.update(any(), any(), any())) + .thenReturn(zmrRegisterResult(firstZmrResult)); + + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchWithMds(any(), any(), any(), any())) + .thenThrow(new IllegalStateException("MDS search should not be neccessary")); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + //INFO: has to be the old givenName because ZMR allows no update of MDS information + checkMatchingSuccessState(pendingReq, randomBpk, randomFamilyName, oldGivenName, randomBirthDate, DE); + + } + + /** + * + * One match, but register update needed. + * + * @throws EidasSAuthenticationException + */ + @Test + @DirtiesContext + public void singlePersonalIdMatchUpdateNecessary_Ernp() throws TaskExecutionException, EidasSAuthenticationException { + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(emptyZmrRegisterResult()); + Mockito.when(zmrClient.searchCountrySpecific(any(), any(), any())) + .thenThrow(new IllegalStateException("CountrySpecific search search should not be neccessary")); + Mockito.when(zmrClient.searchWithMds(any(), any(), any(), any(), any())) + .thenThrow(new IllegalStateException("MDS search should not be neccessary")); + Mockito.when(zmrClient.update(any(), any(), any())) + .thenThrow(new IllegalStateException("ZMR update should not be neccessary")); + + String oldRandomGivenName = randomAlphabetic(10); + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(ernpRegisterResult(randomRegisterResult(oldRandomGivenName, randomBpk))); + Mockito.when(ernpClient.searchCountrySpecific(any(), any())) + .thenThrow(new IllegalStateException("CountrySpecific search search should not be neccessary")); + Mockito.when(ernpClient.searchWithMds(any(), any(), any(), any())) + .thenThrow(new IllegalStateException("MDS search should not be neccessary")); + Mockito.when(ernpClient.update(any(), any())) + .thenReturn(ernpRegisterResult(RegisterResult.builder() + .bpk(randomBpk) + .dateOfBirth(randomBirthDate) + .givenName(randomGivenName) + .familyName(randomFamilyName) + .build())); + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + checkMatchingSuccessState(pendingReq, randomBpk, randomFamilyName, randomGivenName, randomBirthDate, DE); + } + + + + /** + * Two matches by PersonalId found in ZMR + * + * @throws EidasSAuthenticationException + */ + @Test + @DirtiesContext + public void multiPersonalIdMatch_Zmr() throws EidasSAuthenticationException { + String newRandomGivenName = randomAlphabetic(10); + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(new ZmrRegisterResult(Arrays.asList(randomRegisterResult(), randomRegisterResult(newRandomGivenName, randomBpk)), generateRandomProcessId())); + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(emptyErnpRegisterResult()); + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertTrue("Wrong flag 'manualFixNeeded'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + + } + + /** + * Two matches by PersonalId found in ZMR + * + * @throws EidasSAuthenticationException + */ + @Test + @DirtiesContext + public void withErrorFromZmr() throws EidasSAuthenticationException { + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenThrow(new ZmrCommunicationException("jUnit ZMR error", null)); + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(emptyErnpRegisterResult()); + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertFalse("Wrong flag 'manualFixNeeded'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + + } + + /** + * Two matches by PersonalId found in ErnP + * + * @throws EidasSAuthenticationException + */ + @Test + @DirtiesContext + public void multiPersonalIdMatch_Ernp() throws EidasSAuthenticationException { + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(emptyZmrRegisterResult()); + String newRandomGivenName = randomAlphabetic(10); + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(ernpRegisterResult( + Arrays.asList(randomRegisterResult(), randomRegisterResult(newRandomGivenName, randomBpk)))); + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertTrue("Wrong flag 'manualFixNeeded'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + + } + + /** + * Two matches by PersonalId + * + * @throws EidasSAuthenticationException + */ + @Test + @DirtiesContext + public void multiPersonalIdMatch_ErnpAndZmr() throws EidasSAuthenticationException { + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(zmrRegisterResult(randomRegisterResult())); + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(ernpRegisterResult(randomRegisterResult())); + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertTrue("Wrong flag 'manualFixNeeded'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + + } + + /** + * One match by PersonalId, no register update needed + */ + @Test + @DirtiesContext + public void singlePersonalIdMatchNoUpdate_Ernp() throws Exception { + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(emptyZmrRegisterResult()); + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(ernpRegisterResult(randomRegisterResult())); + + Mockito.when(zmrClient.update(any(), any(), any())) + .thenThrow(new IllegalStateException("ZMR update should not be neccessary")); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + checkMatchingSuccessState(pendingReq, randomBpk, randomFamilyName, randomGivenName, randomBirthDate, DE); + } + + /** + * One match by PersonalId, no register update needed + */ + @Test + @DirtiesContext + public void singlePersonalIdMatchNoUpdate_Zmr() throws Exception { + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(zmrRegisterResult(randomRegisterResult())); + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(emptyErnpRegisterResult()); + + Mockito.when(zmrClient.update(any(), any(), any())) + .thenThrow(new IllegalStateException("ZMR update should not be neccessary")); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + checkMatchingSuccessState(pendingReq, randomBpk, randomFamilyName, randomGivenName, randomBirthDate, DE); + } + + /** + * Find single person in ZMR by country specifics. + */ + @Test + @DirtiesContext + public void singlePersonFindWithCountySpecifics_Zmr() throws Exception { + final AuthenticationResponse response = buildDummyAuthResponseDE(randomGivenName, randomFamilyName, + randomPersonalIdentifier_DE, randomBirthDate, randomPlaceOfBirth, randomBirthName); + TestRequestImpl pendingReq1 = new TestRequestImpl(); + pendingReq1.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + + BigInteger zmrProcessId = generateRandomProcessId(); + RegisterResult zmrResult = RegisterResult.builder() + .bpk(randomBpk) + .pseudonym(Collections.singletonList(randomPseudonym)) + .givenName(randomGivenName) + .familyName(randomFamilyName) + .dateOfBirth(randomBirthDate) + .placeOfBirth(randomPlaceOfBirth) + .birthName(randomBirthName) + .build(); + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + Mockito.when(zmrClient.searchCountrySpecific(eq(zmrProcessId), any(PersonSuchenRequest.class), eq(DE))) + .thenReturn(zmrRegisterResult(zmrResult, zmrProcessId)); + RegisterResult randomRegisterResult = RegisterResult.builder() + .bpk(randomBpk) + .pseudonym(Arrays.asList(randomPseudonym, RandomStringUtils.randomAlphanumeric(10))) + .givenName(randomGivenName) + .familyName(randomFamilyName) + .dateOfBirth(randomBirthDate) + .placeOfBirth(randomPlaceOfBirth) + .birthName(randomBirthName) + .build(); + Mockito.when(zmrClient.update(eq(zmrProcessId), eq(zmrResult), any())) + .thenReturn(zmrRegisterResult(randomRegisterResult, zmrProcessId)); + Mockito.when(zmrClient.searchWithMds(any(), any(), any(), any(), any())) + .thenThrow(new IllegalStateException("MDS search should not be neccessary")); + + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchCountrySpecific(any(), eq(DE))) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchWithMds(any(), any(), any(), eq(DE))) + .thenThrow(new IllegalStateException("ERnP MDS search should not be neccessary")); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + Mockito.when(ernpClient.add(any())) + .thenThrow(new IllegalStateException("ERnP add-entity should not be neccessary")); + + // execute test + task.execute(pendingReq1, executionContext); + + // validate state + checkMatchingSuccessState(pendingReq1, randomBpk, randomFamilyName, randomGivenName, randomBirthDate, DE); + + } + + /** + * Multiple matches found in ZMR by country specifics. + */ + @Test + @DirtiesContext + public void multiplePersonFindWithCountySpecifics_Zmr() throws Exception { + String newRandomPseudonym = randomPersonalIdentifier_DE + RandomStringUtils.randomNumeric(2); + String newRandomBpk = randomBpk + RandomStringUtils.randomNumeric(6); + final AuthenticationResponse response = buildDummyAuthResponseDE(randomGivenName, randomFamilyName, + randomPersonalIdentifier_DE, + randomBirthDate, randomPlaceOfBirth, randomBirthName); + TestRequestImpl pendingReq1 = new TestRequestImpl(); + pendingReq1.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + + BigInteger zmrProcessId = generateRandomProcessId(); + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + RegisterResult randomResult1 = RegisterResult.builder() + .bpk(randomBpk) + .pseudonym(Collections.singletonList(randomPseudonym)) + .givenName(randomGivenName) + .familyName(randomFamilyName) + .dateOfBirth(randomBirthDate) + .placeOfBirth(randomPlaceOfBirth) + .birthName(randomBirthName) + .build(); + RegisterResult randomResult2 = RegisterResult.builder() + .bpk(newRandomBpk) + .pseudonym(Collections.singletonList(newRandomPseudonym)) + .givenName(randomGivenName) + .familyName(randomFamilyName) + .dateOfBirth(randomBirthDate) + .placeOfBirth(randomPlaceOfBirth) + .birthName(randomBirthName) + .build(); + Mockito.when(zmrClient.searchCountrySpecific(eq(zmrProcessId), any(PersonSuchenRequest.class), eq(DE))) + .thenReturn(new ZmrRegisterResult(Arrays.asList(randomResult1, randomResult2), zmrProcessId)); + + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchCountrySpecific(any(), eq(DE))) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq1, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertTrue("Wrong flag 'manualFixNeeded'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + + } + + /** + * Multiple matches found in ZMR and ERnP by country specifics. + */ + @Test + @DirtiesContext + public void multiplePersonFindWithCountySpecifics_ZmrAndErnp() throws Exception { + final AuthenticationResponse response = buildDummyAuthResponseDE(randomGivenName, randomFamilyName, + randomPersonalIdentifier_DE, + randomBirthDate, randomPlaceOfBirth, randomBirthName); + TestRequestImpl pendingReq1 = new TestRequestImpl(); + pendingReq1.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + + BigInteger zmrProcessId = generateRandomProcessId(); + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + RegisterResult randomResult1 = RegisterResult.builder() + .bpk(randomBpk) + .pseudonym(Collections.singletonList(randomPseudonym)) + .givenName(randomGivenName) + .familyName(randomFamilyName) + .dateOfBirth(randomBirthDate) + .placeOfBirth(randomPlaceOfBirth) + .birthName(randomBirthName) + .build(); + Mockito.when(zmrClient.searchCountrySpecific(eq(zmrProcessId), any(PersonSuchenRequest.class), eq(DE))) + .thenReturn(new ZmrRegisterResult(Arrays.asList(randomResult1), zmrProcessId)); + + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchCountrySpecific(any(), eq(DE))) + .thenReturn(ernpRegisterResult(randomRegisterResult())); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq1, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertTrue("Wrong flag 'manualFixNeeded'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + + } + + /** + * Multiple matches found in ERnP by country specifics. + */ + @Test + @DirtiesContext + public void multiplePersonFindWithCountySpecifics_Ernp() throws Exception { + final AuthenticationResponse response = buildDummyAuthResponseDE(randomGivenName, randomFamilyName, + randomPersonalIdentifier_DE, + randomBirthDate, randomPlaceOfBirth, randomBirthName); + TestRequestImpl pendingReq1 = new TestRequestImpl(); + pendingReq1.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + + BigInteger zmrProcessId = generateRandomProcessId(); + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + Mockito.when(zmrClient.searchCountrySpecific(eq(zmrProcessId), any(PersonSuchenRequest.class), eq(DE))) + .thenReturn(new ZmrRegisterResult(Arrays.asList(), zmrProcessId)); + + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchCountrySpecific(any(), eq(DE))) + .thenReturn(ernpRegisterResult(Arrays.asList(randomRegisterResult(), randomRegisterResult()))); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq1, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertTrue("Wrong flag 'manualFixNeeded'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + + } + + /** + * NO match found in ZMR and ErnP with Initial and MDS search + * + * @throws EidasSAuthenticationException + * @throws URISyntaxException + * @throws EaafStorageException + */ + @Test + @DirtiesContext + public void noResultByAnySearch() throws TaskExecutionException, EidasSAuthenticationException, URISyntaxException, EaafStorageException { + BigInteger zmrProcessId = generateRandomProcessId(); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse(randomGivenName, randomFamilyName, randomPersonalIdentifier_EE, randomBirthDate)); + + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, EE)) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + Mockito.when(zmrClient.searchWithMds(zmrProcessId, randomGivenName, randomFamilyName, randomBirthDate, EE)) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + Mockito.when(zmrClient.update(any(), any(), any())) + .thenThrow(new IllegalStateException("ZMR update should not be neccessary")); + + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, EE)) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchWithMds(randomGivenName, randomFamilyName, randomBirthDate, EE)) + .thenReturn(new ErnpRegisterResult(Collections.emptyList())); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ZMR update should not be neccessary")); + + // execute task + task.execute(pendingReq, executionContext); + + + // validate state + assertNotNull("find no eIDAS inbut data", MatchingTaskUtils.getInitialEidasData(pendingReq)); + + assertNull("Find intermediate matching data but matching should be finished", + MatchingTaskUtils.getIntermediateMatchingResult(pendingReq)); + assertNull("Find final matching data but no match sould be found", + MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + Boolean transitionGUI = (Boolean) executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK); + Assert.assertNull("Wrong transition", transitionGUI); + Boolean transitionErnb = (Boolean) executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK); + Assert.assertTrue("Wrong transition", transitionErnb); + + } + + /** + * Find one match with MDS search in ERnP. + */ + @Test + @DirtiesContext + public void resultByMdsSearch_Ernb() throws TaskExecutionException, EidasSAuthenticationException, URISyntaxException, EaafStorageException { + BigInteger zmrProcessId = generateRandomProcessId(); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse(randomGivenName, randomFamilyName, randomPersonalIdentifier_EE, randomBirthDate)); + + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, EE)) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + Mockito.when(zmrClient.searchWithMds(zmrProcessId, randomGivenName, randomFamilyName, randomBirthDate, EE)) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, EE)) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchWithMds(randomGivenName, randomFamilyName, randomBirthDate, EE)) + .thenReturn(ernpRegisterResult(randomRegisterResult())); + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + checkIntermediateResult(1); + + } + + /** + * Find one match with MDS search in ZMR. + */ + @Test + @DirtiesContext + public void resultByMdsSearch_Zmr() throws TaskExecutionException, EidasSAuthenticationException { + BigInteger zmrProcessId = generateRandomProcessId(); + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + Mockito.when(zmrClient.searchWithMds(zmrProcessId, randomGivenName, randomFamilyName, randomBirthDate, DE)) + .thenReturn(zmrRegisterResult(randomRegisterResult(), zmrProcessId)); + Mockito.when(zmrClient.update(any(), any(), any())) + .thenThrow(new IllegalStateException("ZMR update should not be neccessary")); + + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)).thenReturn( + emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchWithMds(randomGivenName, randomFamilyName, randomBirthDate, DE)) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + checkIntermediateResult(1); + + } + + /** + * Find matches with MDS search in ZMR and ERnP. + */ + @Test + @DirtiesContext + public void resultByMdsSearch_ZmrAndErnp() throws TaskExecutionException, EidasSAuthenticationException { + BigInteger zmrProcessId = generateRandomProcessId(); + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + Mockito.when(zmrClient.searchWithMds(zmrProcessId, randomGivenName, randomFamilyName, randomBirthDate, DE)) + .thenReturn(zmrRegisterResult(randomRegisterResult(), zmrProcessId)); + Mockito.when(zmrClient.update(any(), any(), any())) + .thenThrow(new IllegalStateException("ZMR update should not be neccessary")); + + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)).thenReturn( + emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchWithMds(randomGivenName, randomFamilyName, randomBirthDate, DE)) + .thenReturn(ernpRegisterResult(randomRegisterResult())); + Mockito.when(ernpClient.update(any(), any())) + .thenThrow(new IllegalStateException("ERnP update should not be neccessary")); + + + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + checkIntermediateResult(2); + + } + + /** + * resultByMdsSearch + */ + @Test + @DirtiesContext + public void multipleResultsByMdsSearch() throws TaskExecutionException, EidasSAuthenticationException { + BigInteger zmrProcessId = generateRandomProcessId(); + Mockito.when(zmrClient.searchWithPersonIdentifier(null, randomPseudonym, DE)) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + Mockito.when(zmrClient.searchCountrySpecific(eq(zmrProcessId), any(PersonSuchenRequest.class), any(String.class))) + .thenReturn(new ZmrRegisterResult(Collections.emptyList(), zmrProcessId)); + Mockito.when(zmrClient.searchWithMds(zmrProcessId, randomGivenName, randomFamilyName, randomBirthDate, DE)) + .thenReturn(zmrRegisterResult(randomRegisterResult(randomBpk + "2"), zmrProcessId)); + Mockito.when(zmrClient.update(any(), any(), any())) + .thenThrow(new IllegalStateException("ZMR update should not be neccessary")); + + Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) + .thenReturn(emptyErnpRegisterResult()); + Mockito.when(ernpClient.searchWithMds(randomGivenName, randomFamilyName, randomBirthDate, DE)) + .thenReturn(ernpRegisterResult(Arrays.asList(randomRegisterResult(), randomRegisterResult(randomBpk + "1")))); + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + checkIntermediateResult(3); + + } + + @NotNull + private ZmrSoapClient.ZmrRegisterResult emptyZmrRegisterResult() { + return new ZmrRegisterResult(Collections.emptyList(), generateRandomProcessId()); + } + + @NotNull + private ErnpRegisterResult emptyErnpRegisterResult() { + return new ErnpRegisterResult(Collections.emptyList()); + } + + @NotNull + private ZmrRegisterResult zmrRegisterResult(RegisterResult registerResult, BigInteger processId) { + return new ZmrRegisterResult(Collections.singletonList(registerResult), processId); + } + + @NotNull + private ZmrRegisterResult zmrRegisterResult(RegisterResult registerResult) { + return zmrRegisterResult(registerResult, generateRandomProcessId()); + } + + @NotNull + private ErnpRegisterResult ernpRegisterResult(RegisterResult registerResult) { + return new ErnpRegisterResult(Collections.singletonList(registerResult)); + } + + @NotNull + private ErnpRegisterResult ernpRegisterResult(List<RegisterResult> registerResult) { + return new ErnpRegisterResult(registerResult); + } + + @NotNull + private RegisterResult randomRegisterResult() { + return randomRegisterResult(randomGivenName, randomBpk); + } + + @NotNull + private RegisterResult randomRegisterResult(String randomBpk) { + return randomRegisterResult(randomGivenName, randomBpk); + } + + @NotNull + private RegisterResult randomRegisterResult(String randomGivenName, String randomBpk) { + return RegisterResult.builder() + .bpk(randomBpk) + .pseudonym(Collections.singletonList(randomPseudonym)) + .givenName(randomGivenName) + .familyName(randomFamilyName) + .dateOfBirth(randomBirthDate) + .build(); + } + + @NotNull + private RegisterResult randomRegisterResult(String randomGivenName, String randomBpk, String placeOfBirth) { + return RegisterResult.builder() + .bpk(randomBpk) + .pseudonym(Collections.singletonList(randomPseudonym)) + .givenName(randomGivenName) + .familyName(randomFamilyName) + .dateOfBirth(randomBirthDate) + .placeOfBirth(placeOfBirth) + .build(); + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponseRandomPerson() throws URISyntaxException { + return buildDummyAuthResponse(randomGivenName, randomFamilyName, DE_ST + randomPseudonym, randomBirthDate); + } + + private BigInteger generateRandomProcessId() { + return new BigInteger(RandomStringUtils.randomNumeric(10)); + + } + + private void checkMatchingSuccessState(IRequest pendingReq, String bpk, String familyName, String givenName, + String birhday, String countryCode) { + assertNull("Find intermediate matching data but matching should be finished", + MatchingTaskUtils.getIntermediateMatchingResult(pendingReq)); + assertNotNull("find no eIDAS inbut data", MatchingTaskUtils.getInitialEidasData(pendingReq)); + + MatchedPersonResult personInfo = MatchingTaskUtils.getFinalMatchingResult(pendingReq); + assertNotNull("no final matching result", personInfo); + assertEquals("wrong bpk", bpk, personInfo.getBpk()); + assertEquals("wrong givenName", givenName, personInfo.getGivenName()); + assertEquals("wrong familyName", familyName, personInfo.getFamilyName()); + assertEquals("wrong dateOfBirth", birhday, personInfo.getDateOfBirth()); + assertEquals("wrong countryCode", countryCode, personInfo.getCountryCode()); + + } + + private void checkIntermediateResult(int resultSize) { + Boolean transitionGUI = (Boolean) executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK); + Assert.assertTrue("Wrong transition", transitionGUI); + Boolean transitionErnb = (Boolean) executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK); + Assert.assertNull("Wrong transition", transitionErnb); + + assertNotNull("find no eIDAS inbut data", MatchingTaskUtils.getInitialEidasData(pendingReq)); + assertNull("Find final matching data but no match sould be found", + MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + RegisterStatusResults result = MatchingTaskUtils.getIntermediateMatchingResult(pendingReq); + assertNotNull("Find no intermediate matching data", result); + assertEquals("wrong intermediate result size", resultSize, result.getResultCount()); + + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponse(String givenName, String familyName, String identifier, + String dateOfBirth) throws URISyntaxException { + return buildDummyAuthResponse(givenName, familyName, identifier, dateOfBirth, null, null, null); + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponseDE(String givenName, String familyName, String identifier, + String dateOfBirth, String placeOfBirth, + String birthName) throws URISyntaxException { + return buildDummyAuthResponse(givenName, familyName, identifier, dateOfBirth, null, placeOfBirth, birthName); + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponse(String givenName, String familyName, String identifier, + String dateOfBirth, String taxNumber, String placeOfBirth, + String birthName) throws URISyntaxException { + ImmutableAttributeMap.Builder builder = ImmutableAttributeMap.builder() + .put(generateStringAttribute(Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + randomAlphabetic(2), randomAlphabetic(2)), identifier) + .put(generateStringAttribute(Constants.eIDAS_ATTR_CURRENTFAMILYNAME, + randomAlphabetic(3), randomAlphabetic(3)), familyName) + .put(generateStringAttribute(Constants.eIDAS_ATTR_CURRENTGIVENNAME, + randomAlphabetic(4), randomAlphabetic(4)), givenName) + .put(generateDateTimeAttribute(Constants.eIDAS_ATTR_DATEOFBIRTH, + randomAlphabetic(5), randomAlphabetic(5)), dateOfBirth); + if (taxNumber != null) { + builder.put(generateStringAttribute(Constants.eIDAS_ATTR_TAXREFERENCE, + randomAlphabetic(6), randomAlphabetic(6)), taxNumber); + } + if (birthName != null) { + builder.put(generateStringAttribute(Constants.eIDAS_ATTR_BIRTHNAME, + randomAlphabetic(7), randomAlphabetic(7)), birthName); + } + if (placeOfBirth != null) { + builder.put(generateStringAttribute(Constants.eIDAS_ATTR_PLACEOFBIRTH, + randomAlphabetic(8), randomAlphabetic(8)), placeOfBirth); + } + final ImmutableAttributeMap attributeMap = builder.build(); + + return new AuthenticationResponse.Builder().id(randomAlphabetic(5)) + .issuer(randomAlphabetic(5)).subject(randomAlphabetic(5)).statusCode("200") + .inResponseTo(randomAlphabetic(5)).subjectNameIdFormat(randomAlphabetic(5)) + .attributes(attributeMap).build(); + } + + private AttributeDefinition<Object> generateStringAttribute(String friendlyName, String fragment, String prefix) + throws URISyntaxException { + return generateAttribute(friendlyName, fragment, prefix, "eu.eidas.auth.commons.attribute.impl" + + ".LiteralStringAttributeValueMarshaller"); + } + + @SuppressWarnings("SameParameterValue") + private AttributeDefinition<Object> generateDateTimeAttribute(String friendlyName, String fragment, String prefix) + throws URISyntaxException { + return generateAttribute(friendlyName, fragment, prefix, "eu.eidas.auth.commons.attribute.impl" + + ".DateTimeAttributeValueMarshaller"); + } + + private AttributeDefinition<Object> generateAttribute(String friendlyName, String fragment, String prefix, + String marshaller) throws URISyntaxException { + return AttributeDefinition.builder() + .friendlyName(friendlyName).nameUri(new URI("ad", "sd", fragment)) + .personType(PersonType.LEGAL_PERSON).xmlType(new QName("http://saf", "as", prefix)) + .attributeValueMarshaller(marshaller).build(); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskWithRegistersTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskWithRegistersTest.java new file mode 100644 index 00000000..6d0e7c31 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskWithRegistersTest.java @@ -0,0 +1,683 @@ +/* + * Copyright 2020 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.namespace.QName; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.jetbrains.annotations.NotNull; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.github.skjolber.mockito.soap.SoapServiceRule; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.ernp.IErnpClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.IZmrClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient.ZmrRegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MatchedPersonResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.CountrySpecificDetailSearchProcessor; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.GenericEidProcessor; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterStatusResults; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.InitialSearchTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients.ErnpRestClientTest; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients.ZmrClientTest; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; +import at.gv.bmi.namespace.zmr_su.base._20040201.RequestType; +import at.gv.bmi.namespace.zmr_su.base._20040201.ResponseType; +import at.gv.bmi.namespace.zmr_su.base._20040201_.ServicePort; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +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.light.impl.LightRequest; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import lombok.SneakyThrows; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml", + "/SpringTest-context_ccSearchProcessor_test.xml" +}) +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class InitialSearchTaskWithRegistersTest { + + private static final String EE = "EE"; + private static final String DE = "DE"; + + @Rule + public SoapServiceRule soap = SoapServiceRule.newInstance(); + + @Autowired IErnpClient ernpClient; + @Autowired IZmrClient zmrClient; + @Autowired List<CountrySpecificDetailSearchProcessor> handlers; + + private RegisterSearchService registerSearchService; + + private ServicePort zmrMock = null; + + private static MockWebServer mockWebServer; + + private final ICcSpecificEidProcessingService eidPostProcessor = createEidPostProcessor(); + private InitialSearchTask task; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private TestRequestImpl pendingReq; + private static JAXBContext jaxbContext; + + /** + * Initialize jUnit class. + */ + @BeforeClass + @SneakyThrows + public static void classInitializer() { + jaxbContext = JAXBContext.newInstance( + at.gv.bmi.namespace.zmr_su.zmr._20040201.ObjectFactory.class, + at.gv.bmi.namespace.zmr_su.gis._20070725.ObjectFactory.class, + at.gv.bmi.namespace.zmr_su.base._20040201.ObjectFactory.class); + + mockWebServer = new MockWebServer(); + mockWebServer.start(1718); + + } + + @AfterClass + @SneakyThrows + public static void resetTestEnviroment() { + mockWebServer.shutdown(); + + } + + /** + * jUnit test set-up. + */ + @Before + @SneakyThrows + public void setUp() throws URISyntaxException, EaafStorageException { + if (zmrMock == null) { + zmrMock = soap.mock(ServicePort.class, "http://localhost:1234/demozmr"); + + } + + registerSearchService = new RegisterSearchService(handlers, zmrClient, ernpClient); + task = new InitialSearchTask(registerSearchService, eidPostProcessor); + + MockHttpServletRequest httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + MockHttpServletResponse httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + pendingReq = new TestRequestImpl(); + + } + + /** + * One match, but register update needed + * <p> + * <b>Check if ZMR update request is NOT executed in case of MDS change!</b> + * </p> + */ + @Test + @DirtiesContext + public void singlePersonalIdMatchUpdateNecessary_ZmrNotDone() throws Exception { + + String oldGivenName = "XXXClaus - Maria"; + + //inject eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31")); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-8_search_with_personalId_only_resp.xml")) + + //perform prepair-update request + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-8_search_with_personalId_only_resp.xml")) + + //do not make an update because, MDS update is not allowed and no other data has been changed + .thenThrow(new RuntimeException("This request is not needed any more")); + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody("{}") + .setHeader("Content-Type", "application/json;charset=utf-8")); + + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + //INFO: has to be the old givenName because ZMR allows no update of MDS information + checkMatchingSuccessState(pendingReq, "UgeknNsc26lVuB7U/uYGVmWtnnA=", "XXXvon Brandenburg", + oldGivenName, "1994-12-31", DE); + + // validate request + assertEquals("wrong number of req.", 2, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getValue(), ZmrClientTest.PROCESS_TASK_SEARCH, + new BigInteger("367100000000079"), "jUnit123456"); + + } + + /** + * One match, but register update needed + * <p> + * <b>Check if ZMR update request is executed in case of other data than MDS change!</b> + * </p> + */ + @Test + @DirtiesContext + public void singlePersonalIdMatchUpdateNecessary_ZmrDone() throws Exception { + + String oldGivenName = "XXXClaus - Maria"; + String placeOfBirth = RandomStringUtils.randomAlphabetic(5); + + //inject eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse(oldGivenName, "XXXvon Brandenburg", + "DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31", null, placeOfBirth, null)); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-8_search_with_personalId_only_resp_no_additional_attributes.xml")) + + //perform prepair-update request + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-8_search_with_personalId_only_resp_no_additional_attributes.xml")) + + //do make an update because, MDS DOES NOT change, but additional attribute was available + .thenReturn(loadResponseFromFile("/data/zmr/seq_3-6_kitt_update_resp.xml")); + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody("{}") + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + //INFO: has to be the old givenName because ZMR allows no update of MDS information + checkMatchingSuccessState(pendingReq, "UgeknNsc26lVuB7U/uYGVmWtnnA=", "XXXvon Brandenburg", + oldGivenName, "1994-12-31", DE); + + // validate request + assertEquals("wrong number of req.", 3, zmrReq.getAllValues().size()); + assertNotNull("Personensuche req.", zmrReq.getAllValues().get(0).getPersonSuchenRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(0), ZmrClientTest.PROCESS_TASK_SEARCH, null, "jUnit123456"); + + assertNotNull("Personenupdate req.", zmrReq.getAllValues().get(2).getPersonAendernRequest()); + checkBasicRequestParameters(zmrReq.getAllValues().get(2), ZmrClientTest.PROCESS_TASK_UPDATE, + new BigInteger("367100000000079"), "jUnit123456"); + assertEquals("eIDAS attribute to add", 4, + zmrReq.getAllValues().get(2).getPersonAendernRequest().getEidasIdentitaetAnlage().size()); + assertNull("ZMR update MDS", zmrReq.getAllValues().get(2).getPersonAendernRequest().getPersonAenderung()); + + } + + + /** + * Two matches by PersonalId found in ZMR + * + * @throws EidasSAuthenticationException + */ + @Test + @DirtiesContext + @SneakyThrows + public void multiPersonalIdMatch_Zmr() throws EidasSAuthenticationException { + //inject eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse("XXXKlaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit", "1994-12-31")); + + // inject response + when(zmrMock.service(any(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/search_with_personalId_only_resp_moreThanOne.xml")) + .thenThrow(new RuntimeException("This request is not needed any more")); + + // execute task + TaskExecutionException exception = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + // validate state + assertTrue("Wrong exception", (exception.getOriginalException() instanceof WorkflowException)); + assertTrue("Wrong flag 'manualFixNeeded'", + ((WorkflowException) exception.getOriginalException()).isRequiresManualFix()); + + } + + /** + * Find single person in ZMR by country specifics. + */ + @Test + @DirtiesContext + public void singlePersonFindWithCountySpecifics_Ernp() throws Exception { + //inject eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse("vdqZZIaA", "mRjMKAQc", + "DE/AT/nj1m79jm9z", "1996-01-01", + null, "VRNCAylF", "miEklFHC")); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + BigInteger processId = new BigInteger("367100000000079"); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) //personalId search + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) //CC specific search + .thenThrow(new RuntimeException("This request is not needed any more")); + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) //personalId search + .setBody("{}") + .setHeader("Content-Type", "application/json;charset=utf-8")); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) //CC specific search + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/2_search_with_cc_specific_resp.json"), "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) //KITT search + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/2_kitt_search_latest_resp.json"), "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) //KITT update + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/2_kitt_update_resp.json"), "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + checkMatchingSuccessState(pendingReq, "TBGoMlirU881e2jMGETa9WLx1+A=", "mRjMKAQc", + "vdqZZIaA", "1996-01-01", DE); + + // validate request + assertEquals("wrong number of req.", 2, zmrReq.getAllValues().size()); + checkBasicRequestParameters(zmrReq.getAllValues().get(0), ZmrClientTest.PROCESS_TASK_SEARCH, null, "jUnit123456"); + checkBasicRequestParameters(zmrReq.getAllValues().get(1), ZmrClientTest.PROCESS_TASK_SEARCH, processId, "jUnit123456"); + + } + + + /** + * Find single person in ZMR by country specifics. + */ + @Test + @DirtiesContext + public void singlePersonFindWithCountySpecifics_Zmr() throws Exception { + //inject eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse("XXXClaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit_with_New_ID", "1994-12-31", + null, "Hintergigritzpotschn", "XXXvon Heuburg")); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + BigInteger processId = new BigInteger("367100000000079"); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) //personalId search + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-8_search_with_personalId_only_resp.xml")) //CC specific search + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-4_kitt_get_latest_version_resp.xml")) //KITT latest version + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-6_kitt_update_resp.xml")) //KITT update + .thenThrow(new RuntimeException("This request is not needed any more")); + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody("{}") + .setHeader("Content-Type", "application/json;charset=utf-8")); + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) //CC specific search + .setBody("{}") + .setHeader("Content-Type", "application/json;charset=utf-8")); + + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + checkMatchingSuccessState(pendingReq, "UgeknNsc26lVuB7U/uYGVmWtnnA=", "XXXvon Brandenburg", + "XXXClaus - Maria", "1994-12-31", DE); + + // validate request + assertEquals("wrong number of req.", 4, zmrReq.getAllValues().size()); + checkBasicRequestParameters(zmrReq.getAllValues().get(0), ZmrClientTest.PROCESS_TASK_SEARCH, null, "jUnit123456"); + checkBasicRequestParameters(zmrReq.getAllValues().get(1), ZmrClientTest.PROCESS_TASK_SEARCH, processId, "jUnit123456"); + checkBasicRequestParameters(zmrReq.getAllValues().get(2), ZmrClientTest.PROCESS_TASK_SEARCH, processId, "jUnit123456"); + checkBasicRequestParameters(zmrReq.getAllValues().get(3), ZmrClientTest.PROCESS_TASK_UPDATE, processId, "jUnit123456"); + + } + + /** + * Find one match with MDS search in ZMR. + */ + @Test + @DirtiesContext + @SneakyThrows + public void resultByMdsSearch_Zmr() throws TaskExecutionException, EidasSAuthenticationException { + //inject eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse("XXXClaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit_with_New_ID", "1994-12-31")); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + BigInteger processId = new BigInteger("367100000000079"); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) //personalId search + //CC-specific will be ignored because CC is DE but BirthName and PlaceOfBirth is 'null' + .thenReturn(loadResponseFromFile("/data/zmr/seq_1-2_search_with_mds_resp.xml")) //MDS specific search + .thenThrow(new RuntimeException("This request is not needed any more")); + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody("{}") + .setHeader("Content-Type", "application/json;charset=utf-8")); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) //MDS specific search + .setBody("{}") + .setHeader("Content-Type", "application/json;charset=utf-8")); + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + checkIntermediateResult(1); + + // validate request + assertEquals("wrong number of req.", 2, zmrReq.getAllValues().size()); + checkBasicRequestParameters(zmrReq.getAllValues().get(0), ZmrClientTest.PROCESS_TASK_SEARCH, null, "jUnit123456"); + checkBasicRequestParameters(zmrReq.getAllValues().get(1), ZmrClientTest.PROCESS_TASK_SEARCH, processId, "jUnit123456"); + + } + + /** + * Find one match with MDS search in ZMR. + */ + @Test + @DirtiesContext + @SneakyThrows + public void resultByMdsSearch_Zmr_Second() throws TaskExecutionException, EidasSAuthenticationException { + //inject eIDAS data + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse("XXXClaus - Maria", "XXXvon Brandenburg", + "DE/AT/7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit_with_New_ID", "1994-12-31", + null, "Hintergigritzpotschn", "XXXvon Heuburg")); + + final ArgumentCaptor<RequestType> zmrReq = ArgumentCaptor.forClass(RequestType.class); + BigInteger processId = new BigInteger("367100000000079"); + + // inject response + when(zmrMock.service(zmrReq.capture(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) //personalId search + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")) //CC-specific search + .thenReturn(loadResponseFromFile("/data/zmr/search_with_personalId_only_resp_moreThanOne.xml")) //MDS specific search + .thenThrow(new RuntimeException("This request is not needed any more")); + + + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody("{}") + .setHeader("Content-Type", "application/json;charset=utf-8")); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) //CC specific search + .setBody("{}") + .setHeader("Content-Type", "application/json;charset=utf-8")); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) //MDS specific search + .setBody(IOUtils.toString( + ErnpRestClientTest.class.getResourceAsStream("/data/ernp/3_search_with_mds_resp.json"), "UTF-8")) + .setHeader("Content-Type", "application/json;charset=utf-8")); + + + // execute test + task.execute(pendingReq, executionContext); + + // validate state + checkIntermediateResult(3); + + // validate request + assertEquals("wrong number of req.", 3, zmrReq.getAllValues().size()); + checkBasicRequestParameters(zmrReq.getAllValues().get(0), ZmrClientTest.PROCESS_TASK_SEARCH, null, "jUnit123456"); + checkBasicRequestParameters(zmrReq.getAllValues().get(1), ZmrClientTest.PROCESS_TASK_SEARCH, processId, "jUnit123456"); + checkBasicRequestParameters(zmrReq.getAllValues().get(2), ZmrClientTest.PROCESS_TASK_SEARCH, processId, "jUnit123456"); + + } + + + + @NotNull + private ICcSpecificEidProcessingService createEidPostProcessor() { + return new ICcSpecificEidProcessingService() { + + private final GenericEidProcessor genericEidProcessor = new GenericEidProcessor(); + + @Override + public SimpleEidasData postProcess(Map<String, Object> eidasAttrMap) throws EidPostProcessingException, EidasAttributeException { + return genericEidProcessor.postProcess(eidasAttrMap); + } + + @Override + public void preProcess(String selectedCC, IRequest pendingReq, LightRequest.Builder authnRequestBuilder) { + genericEidProcessor.preProcess(pendingReq, authnRequestBuilder); + } + }; + } + + @NotNull + private ZmrRegisterResult zmrRegisterResult(RegisterResult registerResult, BigInteger processId) { + return new ZmrRegisterResult(Collections.singletonList(registerResult), processId); + } + + @NotNull + private ZmrRegisterResult zmrRegisterResult(RegisterResult registerResult) { + return zmrRegisterResult(registerResult, generateRandomProcessId()); + } + + + private BigInteger generateRandomProcessId() { + return new BigInteger(RandomStringUtils.randomNumeric(10)); + + } + + private void checkMatchingSuccessState(IRequest pendingReq, String bpk, String familyName, String givenName, + String birhday, String countryCode) { + assertNull("Find intermediate matching data but matching should be finished", + MatchingTaskUtils.getIntermediateMatchingResult(pendingReq)); + assertNotNull("find no eIDAS inbut data", MatchingTaskUtils.getInitialEidasData(pendingReq)); + + MatchedPersonResult personInfo = MatchingTaskUtils.getFinalMatchingResult(pendingReq); + assertNotNull("no final matching result", personInfo); + assertEquals("wrong bpk", bpk, personInfo.getBpk()); + assertEquals("wrong givenName", givenName, personInfo.getGivenName()); + assertEquals("wrong familyName", familyName, personInfo.getFamilyName()); + assertEquals("wrong dateOfBirth", birhday, personInfo.getDateOfBirth()); + assertEquals("wrong countryCode", countryCode, personInfo.getCountryCode()); + + } + + private void checkIntermediateResult(int resultSize) { + Boolean transitionGUI = (Boolean) executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK); + Assert.assertTrue("Wrong transition", transitionGUI); + Boolean transitionErnb = (Boolean) executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK); + Assert.assertNull("Wrong transition", transitionErnb); + + assertNotNull("find no eIDAS inbut data", MatchingTaskUtils.getInitialEidasData(pendingReq)); + assertNull("Find final matching data but no match sould be found", + MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + RegisterStatusResults result = MatchingTaskUtils.getIntermediateMatchingResult(pendingReq); + assertNotNull("Find no intermediate matching data", result); + assertEquals("wrong intermediate result size", resultSize, result.getResultCount()); + + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponse(String givenName, String familyName, String identifier, + String dateOfBirth) throws URISyntaxException { + return buildDummyAuthResponse(givenName, familyName, identifier, dateOfBirth, null, null, null); + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponseDE(String givenName, String familyName, String identifier, + String dateOfBirth, String placeOfBirth, + String birthName) throws URISyntaxException { + return buildDummyAuthResponse(givenName, familyName, identifier, dateOfBirth, null, placeOfBirth, birthName); + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponse(String givenName, String familyName, String identifier, + String dateOfBirth, String taxNumber, String placeOfBirth, + String birthName) throws URISyntaxException { + ImmutableAttributeMap.Builder builder = ImmutableAttributeMap.builder() + .put(generateStringAttribute(Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + randomAlphabetic(2), randomAlphabetic(2)), identifier) + .put(generateStringAttribute(Constants.eIDAS_ATTR_CURRENTFAMILYNAME, + randomAlphabetic(3), randomAlphabetic(3)), familyName) + .put(generateStringAttribute(Constants.eIDAS_ATTR_CURRENTGIVENNAME, + randomAlphabetic(4), randomAlphabetic(4)), givenName) + .put(generateDateTimeAttribute(Constants.eIDAS_ATTR_DATEOFBIRTH, + randomAlphabetic(5), randomAlphabetic(5)), dateOfBirth); + if (taxNumber != null) { + builder.put(generateStringAttribute(Constants.eIDAS_ATTR_TAXREFERENCE, + randomAlphabetic(6), randomAlphabetic(6)), taxNumber); + } + if (birthName != null) { + builder.put(generateStringAttribute(Constants.eIDAS_ATTR_BIRTHNAME, + randomAlphabetic(7), randomAlphabetic(7)), birthName); + } + if (placeOfBirth != null) { + builder.put(generateStringAttribute(Constants.eIDAS_ATTR_PLACEOFBIRTH, + randomAlphabetic(8), randomAlphabetic(8)), placeOfBirth); + } + final ImmutableAttributeMap attributeMap = builder.build(); + + return new AuthenticationResponse.Builder().id(randomAlphabetic(5)) + .issuer(randomAlphabetic(5)).subject(randomAlphabetic(5)).statusCode("200") + .inResponseTo(randomAlphabetic(5)).subjectNameIdFormat(randomAlphabetic(5)) + .attributes(attributeMap).build(); + } + + private AttributeDefinition<Object> generateStringAttribute(String friendlyName, String fragment, String prefix) + throws URISyntaxException { + return generateAttribute(friendlyName, fragment, prefix, "eu.eidas.auth.commons.attribute.impl" + + ".LiteralStringAttributeValueMarshaller"); + } + + @SuppressWarnings("SameParameterValue") + private AttributeDefinition<Object> generateDateTimeAttribute(String friendlyName, String fragment, String prefix) + throws URISyntaxException { + return generateAttribute(friendlyName, fragment, prefix, "eu.eidas.auth.commons.attribute.impl" + + ".DateTimeAttributeValueMarshaller"); + } + + private AttributeDefinition<Object> generateAttribute(String friendlyName, String fragment, String prefix, + String marshaller) throws URISyntaxException { + return AttributeDefinition.builder() + .friendlyName(friendlyName).nameUri(new URI("ad", "sd", fragment)) + .personType(PersonType.LEGAL_PERSON).xmlType(new QName("http://saf", "as", prefix)) + .attributeValueMarshaller(marshaller).build(); + } + + private ResponseType loadResponseFromFile(String filepath) throws JAXBException { + final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + JAXBElement<?> resp = (JAXBElement<?>) unmarshaller.unmarshal(ZmrClientTest.class.getResourceAsStream( + filepath)); + return (ResponseType) resp.getValue(); + + } + + private void checkBasicRequestParameters(RequestType requestType, String vorgangName, BigInteger processId, + String behoerdennummer) { + assertNotNull("no workflow infos", requestType.getWorkflowInfoClient()); + assertEquals("processName", ZmrClientTest.PROCESS_GENERAL, requestType.getWorkflowInfoClient().getProzessName()); + assertEquals("vorgangsName", vorgangName, requestType.getWorkflowInfoClient().getVorgangName()); + + if (processId != null) { + assertEquals("processId", processId, requestType.getWorkflowInfoClient().getProzessInstanzID()); + } else { + assertNull("processId", requestType.getWorkflowInfoClient().getProzessInstanzID()); + } + + assertNotNull("no client infos", requestType.getClientInfo()); + assertEquals("behoerdennummer", behoerdennummer, requestType.getClientInfo().getOrganisation() + .getBehoerdenNr()); + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskRegisterTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskRegisterTest.java new file mode 100644 index 00000000..649fa48c --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskRegisterTest.java @@ -0,0 +1,337 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.apache.commons.lang3.RandomStringUtils; +import org.jetbrains.annotations.NotNull; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.github.skjolber.mockito.soap.SoapServiceRule; +import com.google.common.collect.Lists; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController.AdresssucheOutput; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MatchedPersonResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterOperationStatus; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterStatusResults; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAustrianResidenceGuiResponseTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients.ZmrClientTest; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; +import at.gv.bmi.namespace.zmr_su.base._20040201.ResponseType; +import at.gv.bmi.namespace.zmr_su.base._20040201_.ServicePort; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import lombok.SneakyThrows; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +public class ReceiveAustrianResidenceGuiResponseTaskRegisterTest { + + @Autowired + protected MsConnectorDummyConfigMap authConfig; + + @Autowired + private RegisterSearchService registerSearchService; + + @Rule + public SoapServiceRule soap = SoapServiceRule.newInstance(); + private ServicePort zmrMock = null; + private static JAXBContext jaxbContext; + + private ReceiveAustrianResidenceGuiResponseTask task; + private ExecutionContext executionContext; + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + + + /** + * Initialize jUnit class. + */ + @BeforeClass + @SneakyThrows + public static void classInitializer() { + jaxbContext = JAXBContext.newInstance( + at.gv.bmi.namespace.zmr_su.zmr._20040201.ObjectFactory.class, + at.gv.bmi.namespace.zmr_su.gis._20070725.ObjectFactory.class, + at.gv.bmi.namespace.zmr_su.base._20040201.ObjectFactory.class); + + } + + /** + * jUnit test set-up. + * + * @throws Exception In case of an set-up error + */ + @Before + public void setUp() throws Exception { + if (zmrMock == null) { + zmrMock = soap.mock(ServicePort.class, "http://localhost:1234/demozmr"); + + } + + executionContext = new ExecutionContextImpl(); + task = new ReceiveAustrianResidenceGuiResponseTask(registerSearchService); + + httpReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + pendingReq = new TestRequestImpl(); + pendingReq.setAuthUrl("https://localhost/ms_connector"); + pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); + + LocaleContextHolder.resetLocaleContext(); + } + + @Test + public void canceledByUser() throws Exception { + AdresssucheOutput userInput = setupUserInput(); + SimpleEidasData eidasData = setupEidasData(); + RegisterStatusResults registerSearchResult = buildEmptyResult(); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + httpReq.setParameter(ReceiveAustrianResidenceGuiResponseTask.HTTP_PARAM_NO_RESIDENCE, "true"); + + task.execute(pendingReq, executionContext); + + assertEquals("Transition To S9", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + assertEquals("failed reason", "module.eidasauth.matching.20", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON)); + assertNull("no final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + } + + @Test + public void noRegisterResult() throws Exception { + setupUserInput(); + setupEidasData(); + RegisterStatusResults registerSearchResult = buildEmptyResult(); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + + // inject ZMR response + when(zmrMock.service(any(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/empty_zmr_result.xml")); + + // execute task + task.execute(pendingReq, executionContext); + + // validate state + assertEquals("Transition To S9", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + assertEquals("failed reason", "module.eidasauth.matching.22", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON)); + assertNull("no final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + } + + @Test + public void exactlyOneRegisterResult_Update() throws Exception { + setupUserInput(); + SimpleEidasData eidasData = setupEidasData(); + RegisterStatusResults registerSearchResult = buildResultWithOneMatch(buildMatchingRegisterResult(eidasData)); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + + // inject ZMR response + when(zmrMock.service(any(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/search_with_personalId_only_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_3-4_kitt_get_latest_version_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_3-6_kitt_update_resp.xml")); + + task.execute(pendingReq, executionContext); + + // validate state + assertNull("Transition To S9", executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK)); + MatchedPersonResult matchingResult = MatchingTaskUtils.getFinalMatchingResult(pendingReq); + assertNotNull("no final matching result", matchingResult); + + } + + @Test + public void exactlyOneRegisterResult_UpdateFailedByZmrError() throws Exception { + setupUserInput(); + SimpleEidasData eidasData = setupEidasData(); + RegisterStatusResults registerSearchResult = buildResultWithOneMatch(buildMatchingRegisterResult(eidasData)); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + + // inject ZMR response + when(zmrMock.service(any(), any())) + .thenReturn(loadResponseFromFile("/data/zmr/search_with_personalId_only_resp.xml")) + .thenReturn(loadResponseFromFile("/data/zmr/seq_3-4_kitt_get_latest_version_resp.xml")) + .thenThrow(new RuntimeException("ZMR update should fail for that test")); + + TaskExecutionException error = assertThrows("wrong exception", TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals("wrong errorId", "module.eidasauth.matching.04", ((EaafException) error.getOriginalException()).getErrorId()); + + } + + @Test + public void zmrError() throws Exception { + setupUserInput(); + setupEidasData(); + RegisterStatusResults registerSearchResult = buildResultWithTwoMatches(); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + + TaskExecutionException error = assertThrows("wrong exception", TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals("wrong errorId", "module.eidasauth.matching.03", ((EaafException) error.getOriginalException()).getErrorId()); + + } + + @SneakyThrows + private void validateMatchedPerson(MatchedPersonResult current, + RegisterStatusResults registerUpdateResult) { + RegisterResult expected = registerUpdateResult.getResult(); + assertEquals("familyName", expected.getFamilyName(), current.getFamilyName()); + assertEquals("givenName", expected.getGivenName(), current.getGivenName()); + assertEquals("birthday", expected.getDateOfBirth(), current.getDateOfBirth()); + assertEquals("bpk", expected.getBpk(), current.getBpk()); + + } + + @NotNull + private RegisterStatusResults buildEmptyResult() { + return new RegisterStatusResults(new RegisterOperationStatus(generateRandomProcessId()), + Collections.emptyList(), Collections.emptyList()); + + } + + private BigInteger generateRandomProcessId() { + return new BigInteger(RandomStringUtils.randomNumeric(10)); + + } + + @NotNull + private RegisterStatusResults buildResultWithOneMatch(RegisterResult registerResult) { + return new RegisterStatusResults(new RegisterOperationStatus(generateRandomProcessId()), + Collections.singletonList(registerResult), Collections.emptyList()); + + } + + @NotNull + private RegisterStatusResults buildResultWithTwoMatches() { + List<RegisterResult> results = Lists.newArrayList(buildRandomRegisterResult(), buildRandomRegisterResult()); + return new RegisterStatusResults(new RegisterOperationStatus(generateRandomProcessId()), + results, Collections.emptyList()); + + } + + @NotNull + private RegisterResult buildRandomRegisterResult() { + return RegisterResult.builder() + .pseudonym(Arrays.asList(RandomStringUtils.randomAlphabetic(8))) + .givenName(RandomStringUtils.randomAlphabetic(8)) + .familyName(RandomStringUtils.randomAlphabetic(8)) + .dateOfBirth(RandomStringUtils.randomAlphabetic(8)) + .bpk(RandomStringUtils.randomAlphabetic(8)) + .build(); + + } + + private RegisterResult buildMatchingRegisterResult(SimpleEidasData eidData) { + return RegisterResult.builder() + .pseudonym(Arrays.asList(eidData.getPseudonym())) + .givenName(eidData.getGivenName()) + .familyName(eidData.getFamilyName()) + .dateOfBirth(eidData.getDateOfBirth()) + .bpk(RandomStringUtils.randomAlphabetic(8)) + .build(); + + } + + private RegisterResult buildNotMatchingRegisterResult(SimpleEidasData eidData) { + return RegisterResult.builder() + .pseudonym(Arrays.asList(eidData.getPseudonym() + RandomStringUtils.randomAlphabetic(8))) + .givenName(eidData.getGivenName()) + .familyName(eidData.getFamilyName()) + .dateOfBirth(eidData.getDateOfBirth()) + .bpk(RandomStringUtils.randomAlphabetic(8)) + .build(); + + } + + private void setHttpParameters(AdresssucheOutput input) { + httpReq.setParameter(AdresssucheController.PARAM_STREET, input.getStreet()); + httpReq.setParameter(AdresssucheController.PARAM_MUNIPICALITY, input.getMunicipality()); + httpReq.setParameter(AdresssucheController.PARAM_NUMBER, input.getNumber()); + httpReq.setParameter(AdresssucheController.PARAM_VILLAGE, input.getVillage()); + httpReq.setParameter(AdresssucheController.PARAM_POSTLEITZAHL, input.getPostleitzahl()); + + } + + @NotNull + private SimpleEidasData setupEidasData() throws EaafStorageException { + SimpleEidasData result = SimpleEidasData.builder() + .pseudonym(RandomStringUtils.randomAlphabetic(8)) + .familyName(RandomStringUtils.randomAlphabetic(8)) + .givenName(RandomStringUtils.randomAlphabetic(8)) + .dateOfBirth("1970-01-01") + .build(); + AuthProcessDataWrapper authProcessDataWrapper = pendingReq.getSessionData(AuthProcessDataWrapper.class); + authProcessDataWrapper.setGenericDataToSession(Constants.DATA_SIMPLE_EIDAS, result); + return result; + } + + @NotNull + private AdresssucheOutput setupUserInput() { + AdresssucheOutput result = new AdresssucheOutput( + RandomStringUtils.randomAlphabetic(8), + RandomStringUtils.randomAlphabetic(8), + RandomStringUtils.randomAlphabetic(8), + RandomStringUtils.randomAlphabetic(8), + RandomStringUtils.randomAlphabetic(8)); + setHttpParameters(result); + return result; + } + + private ResponseType loadResponseFromFile(String filepath) throws JAXBException { + final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + JAXBElement<?> resp = (JAXBElement<?>) unmarshaller.unmarshal(ZmrClientTest.class.getResourceAsStream( + filepath)); + return (ResponseType) resp.getValue(); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskTest.java new file mode 100644 index 00000000..ece0f16d --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskTest.java @@ -0,0 +1,312 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.eq; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.lang3.RandomStringUtils; +import org.jetbrains.annotations.NotNull; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +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.Lists; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController.AdresssucheOutput; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MatchedPersonResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterOperationStatus; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterStatusResults; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAustrianResidenceGuiResponseTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import lombok.SneakyThrows; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +public class ReceiveAustrianResidenceGuiResponseTaskTest { + + @Autowired + protected MsConnectorDummyConfigMap authConfig; + + @MockBean + private RegisterSearchService registerSearchService; + + private ReceiveAustrianResidenceGuiResponseTask task; + + private ExecutionContext executionContext; + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + + /** + * jUnit test set-up. + * + * @throws Exception In case of an set-up error + */ + @Before + public void setUp() throws Exception { + executionContext = new ExecutionContextImpl(); + task = new ReceiveAustrianResidenceGuiResponseTask(registerSearchService); + + httpReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + pendingReq = new TestRequestImpl(); + pendingReq.setAuthUrl("https://localhost/ms_connector"); + pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); + + LocaleContextHolder.resetLocaleContext(); + } + + @Test + public void canceledByUser() throws Exception { + AdresssucheOutput userInput = setupUserInput(); + SimpleEidasData eidasData = setupEidasData(); + RegisterStatusResults registerSearchResult = buildEmptyResult(); + mockRegisterSearch(userInput, registerSearchResult, eidasData); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + httpReq.setParameter(ReceiveAustrianResidenceGuiResponseTask.HTTP_PARAM_NO_RESIDENCE, "true"); + + task.execute(pendingReq, executionContext); + + assertEquals("Transition To S9", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + assertEquals("failed reason", "module.eidasauth.matching.20", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON)); + assertNull("no final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + } + + @Test + public void noInputData() throws Exception { + RegisterStatusResults registerSearchResult = buildEmptyResult(); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + + task.execute(pendingReq, executionContext); + + assertEquals("Transition To S9", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + assertEquals("failed reason", "module.eidasauth.matching.21", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON)); + assertNull("no final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + } + + @Test + public void noRegisterResult() throws Exception { + AdresssucheOutput userInput = setupUserInput(); + SimpleEidasData eidasData = setupEidasData(); + RegisterStatusResults registerSearchResult = buildEmptyResult(); + mockRegisterSearch(userInput, registerSearchResult, eidasData); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + + task.execute(pendingReq, executionContext); + + assertEquals("Transition To S9", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + assertEquals("failed reason", "module.eidasauth.matching.22", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON)); + assertNull("no final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + } + + @Test + public void exactlyOneRegisterResult_NoUpdate() throws Exception { + AdresssucheOutput userInput = setupUserInput(); + SimpleEidasData eidasData = setupEidasData(); + RegisterStatusResults registerSearchResult = buildResultWithOneMatch(buildMatchingRegisterResult(eidasData)); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + mockRegisterSearch(userInput, registerSearchResult, eidasData); + + task.execute(pendingReq, executionContext); + + // validate state + assertNull("Transition To S9", executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK)); + MatchedPersonResult matchingResult = MatchingTaskUtils.getFinalMatchingResult(pendingReq); + assertNotNull("no final matching result", matchingResult); + validateMatchedPerson(matchingResult, registerSearchResult); + + } + + @Test + public void exactlyOneRegisterResult_UpdateRequired() throws Exception { + AdresssucheOutput userInput = setupUserInput(); + SimpleEidasData eidasData = setupEidasData(); + RegisterStatusResults registerSearchResult = buildResultWithOneMatch(buildNotMatchingRegisterResult(eidasData)); + RegisterStatusResults registerUpdateResult = buildResultWithOneMatch(buildRandomRegisterResult()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + mockRegisterSearch(userInput, registerSearchResult, eidasData); + Mockito.when(registerSearchService.step7aKittProcess(eq(registerSearchResult), eq(eidasData))) + .thenReturn(registerUpdateResult); + + // perform test + task.execute(pendingReq, executionContext); + + // validate state + assertNull("Transition To S9", executionContext.get(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK)); + + MatchedPersonResult matchingResult = MatchingTaskUtils.getFinalMatchingResult(pendingReq); + assertNotNull("no final matching result", matchingResult); + validateMatchedPerson(matchingResult, registerUpdateResult); + + } + + @Test + public void moreThanOneRegisterResult() throws Exception { + AdresssucheOutput userInput = setupUserInput(); + SimpleEidasData eidasData = setupEidasData(); + RegisterStatusResults registerSearchResult = buildResultWithTwoMatches(); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + mockRegisterSearch(userInput, registerSearchResult, eidasData); + + task.execute(pendingReq, executionContext); + + assertEquals("Transition To S9", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + assertEquals("failed reason", "module.eidasauth.matching.22", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON)); + assertNull("no final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + } + + @SneakyThrows + private void validateMatchedPerson(MatchedPersonResult current, + RegisterStatusResults registerUpdateResult) { + RegisterResult expected = registerUpdateResult.getResult(); + assertEquals("familyName", expected.getFamilyName(), current.getFamilyName()); + assertEquals("givenName", expected.getGivenName(), current.getGivenName()); + assertEquals("birthday", expected.getDateOfBirth(), current.getDateOfBirth()); + assertEquals("bpk", expected.getBpk(), current.getBpk()); + + } + + @SneakyThrows + private void mockRegisterSearch(AdresssucheOutput userInput, RegisterStatusResults registerSearchResult, SimpleEidasData eidasData ) { + Mockito.when(registerSearchService.searchWithResidence(eq(registerSearchResult.getOperationStatus()), eq(eidasData), + eq(userInput))).thenReturn(registerSearchResult); + } + + @NotNull + private RegisterStatusResults buildEmptyResult() { + return new RegisterStatusResults(new RegisterOperationStatus(generateRandomProcessId()), + Collections.emptyList(), Collections.emptyList()); + + } + + private BigInteger generateRandomProcessId() { + return new BigInteger(RandomStringUtils.randomNumeric(10)); + + } + + @NotNull + private RegisterStatusResults buildResultWithOneMatch(RegisterResult registerResult) { + return new RegisterStatusResults(new RegisterOperationStatus(generateRandomProcessId()), + Collections.singletonList(registerResult), Collections.emptyList()); + + } + + @NotNull + private RegisterStatusResults buildResultWithTwoMatches() { + List<RegisterResult> results = Lists.newArrayList(buildRandomRegisterResult(), buildRandomRegisterResult()); + return new RegisterStatusResults(new RegisterOperationStatus(generateRandomProcessId()), + results, Collections.emptyList()); + + } + + @NotNull + private RegisterResult buildRandomRegisterResult() { + return RegisterResult.builder() + .pseudonym(Arrays.asList(RandomStringUtils.randomAlphabetic(8))) + .givenName(RandomStringUtils.randomAlphabetic(8)) + .familyName(RandomStringUtils.randomAlphabetic(8)) + .dateOfBirth(RandomStringUtils.randomAlphabetic(8)) + .bpk(RandomStringUtils.randomAlphabetic(8)) + .build(); + + } + + private RegisterResult buildMatchingRegisterResult(SimpleEidasData eidData) { + return RegisterResult.builder() + .pseudonym(Arrays.asList(eidData.getPseudonym())) + .givenName(eidData.getGivenName()) + .familyName(eidData.getFamilyName()) + .dateOfBirth(eidData.getDateOfBirth()) + .bpk(RandomStringUtils.randomAlphabetic(8)) + .build(); + + } + + private RegisterResult buildNotMatchingRegisterResult(SimpleEidasData eidData) { + return RegisterResult.builder() + .pseudonym(Arrays.asList(eidData.getPseudonym() + RandomStringUtils.randomAlphabetic(8))) + .givenName(eidData.getGivenName()) + .familyName(eidData.getFamilyName()) + .dateOfBirth(eidData.getDateOfBirth()) + .bpk(RandomStringUtils.randomAlphabetic(8)) + .build(); + + } + + private void setHttpParameters(AdresssucheOutput input) { + httpReq.setParameter(AdresssucheController.PARAM_STREET, input.getStreet()); + httpReq.setParameter(AdresssucheController.PARAM_MUNIPICALITY, input.getMunicipality()); + httpReq.setParameter(AdresssucheController.PARAM_NUMBER, input.getNumber()); + httpReq.setParameter(AdresssucheController.PARAM_VILLAGE, input.getVillage()); + httpReq.setParameter(AdresssucheController.PARAM_POSTLEITZAHL, input.getPostleitzahl()); + + } + + @NotNull + private SimpleEidasData setupEidasData() throws EaafStorageException { + SimpleEidasData result = SimpleEidasData.builder() + .pseudonym(RandomStringUtils.randomAlphabetic(8)) + .familyName(RandomStringUtils.randomAlphabetic(8)) + .givenName(RandomStringUtils.randomAlphabetic(8)) + .dateOfBirth("1970-01-01") + .build(); + AuthProcessDataWrapper authProcessDataWrapper = pendingReq.getSessionData(AuthProcessDataWrapper.class); + authProcessDataWrapper.setGenericDataToSession(Constants.DATA_SIMPLE_EIDAS, result); + return result; + } + + @NotNull + private AdresssucheOutput setupUserInput() { + AdresssucheOutput result = new AdresssucheOutput( + RandomStringUtils.randomAlphabetic(8), + RandomStringUtils.randomAlphabetic(8), + RandomStringUtils.randomAlphabetic(8), + RandomStringUtils.randomAlphabetic(8), + RandomStringUtils.randomAlphabetic(8)); + setHttpParameters(result); + return result; + } + + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAuthnResponseTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAuthnResponseTaskTest.java new file mode 100644 index 00000000..87681435 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAuthnResponseTaskTest.java @@ -0,0 +1,249 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; + +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Nonnull; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.core.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.ReceiveAuthnResponseTask; +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.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.EidAuthProcessDataWrapper; +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.protocol.impl.AuthenticationResponse; +import lombok.val; + +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class ReceiveAuthnResponseTaskTest { + + @Autowired(required = true) + private ReceiveAuthnResponseTask task; + + @Autowired(required = true) + private MsConnectorDummyConfigMap basicConfig; + @Autowired + protected EidasAttributeRegistry attrRegistry; + + @Autowired private IRequestStorage storage; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private MsConnectorDummySpConfiguration oaParam; + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException { + + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.eid.testidentity.default", "false"); + + final Map<String, String> spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); + oaParam = new MsConnectorDummySpConfiguration(spConfig, basicConfig); + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH)); + pendingReq = new TestRequestImpl(); + + pendingReq.setSpConfig(oaParam); + 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, "LU"); + executionContext.put(EaafConstants.PROCESS_ENGINE_REQUIRES_NO_POSTAUTH_REDIRECT, true); + + } + + @Test + public void missingEidasResponse() { + try { + task.execute(pendingReq, executionContext); + Assert.fail("No eIDAS response not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorId", "eidas.01", + ((EaafException) e.getOriginalException()).getErrorId()); + + } + } + + @Test + public void notSuccessEidasResponse() throws URISyntaxException { + String statusCode = RandomStringUtils.randomAlphabetic(10); + httpReq.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse(statusCode)); + + + try { + task.execute(pendingReq, executionContext); + Assert.fail("No eIDAS response not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorId", "eidas.02", + ((EaafException) e.getOriginalException()).getErrorId()); + Assert.assertEquals("wrong parameter size", 2, ((EaafException) e.getOriginalException()) + .getParams().length); + Assert.assertEquals("wrong errorMsg", statusCode, ((EaafException) e + .getOriginalException()).getParams()[0]); + + } + } + + @Test + public void successAndForward() throws URISyntaxException, TaskExecutionException, + PendingReqIdValidationException, EaafStorageException { + + AuthenticationResponse eidasResponse = buildDummyAuthResponse(Constants.SUCCESS_URI); + httpReq.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, eidasResponse); + + String alternativReturnEndpoint = "http://ms-connector.alternative/" + RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction( + MsEidasNodeConstants.EXECCONTEXT_PARAM_MSCONNECTOR_STAGING, alternativReturnEndpoint); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("msConnectorStage", true, + (Boolean) executionContext.get(MsEidasNodeConstants.EXECCONTEXT_PARAM_MSCONNECTOR_STAGING)); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(alternativReturnEndpoint)); + + + } + + public void success() throws URISyntaxException, TaskExecutionException, PendingReqIdValidationException { + @Nonnull + AuthenticationResponse eidasResponse = buildDummyAuthResponse(Constants.SUCCESS_URI); + httpReq.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, eidasResponse); + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "LU"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + final EidAuthProcessDataWrapper authProcessData = storedReq.getSessionData(EidAuthProcessDataWrapper.class); + Assert.assertEquals("LoA", eidasResponse.getLevelOfAssurance(), authProcessData.getQaaLevel()); + Assert.assertNotNull("eIDAS response", + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertEquals("eIDAS response", eidasResponse, + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE)); + + Assert.assertFalse("testIdentity flag", authProcessData.isTestIdentity()); + + Assert.assertEquals("msConnectorStage", false, + (Boolean) executionContext.get(MsEidasNodeConstants.EXECCONTEXT_PARAM_MSCONNECTOR_STAGING)); + } + + @Test + public void successWithTestIdentity() throws URISyntaxException, TaskExecutionException, PendingReqIdValidationException { + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.eid.testidentity.default", "true"); + + @Nonnull + AuthenticationResponse eidasResponse = buildDummyAuthResponse(Constants.SUCCESS_URI); + httpReq.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, eidasResponse); + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "LU"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + + final EidAuthProcessDataWrapper authProcessData = storedReq.getSessionData(EidAuthProcessDataWrapper.class); + Assert.assertEquals("LoA", eidasResponse.getLevelOfAssurance(), authProcessData.getQaaLevel()); + Assert.assertNotNull("eIDAS response", + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertEquals("eIDAS response", eidasResponse, + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertTrue("testIdentity flag", authProcessData.isTestIdentity()); + + } + + + + @Nonnull + private AuthenticationResponse buildDummyAuthResponse(String statusCode) throws URISyntaxException { + final AttributeDefinition attributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition attributeDef2 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition attributeDef3 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition attributeDef4 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + + final ImmutableAttributeMap attributeMap = ImmutableAttributeMap.builder() + .put(attributeDef, "LU/AT/" + 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("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(statusCode) + .inResponseTo("_".concat(Random.nextHexRandom16())) + .subjectNameIdFormat("afaf") + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .attributes(attributeMap) + .build(); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveEidasResponseTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveEidasResponseTaskTest.java new file mode 100644 index 00000000..72046885 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveEidasResponseTaskTest.java @@ -0,0 +1,246 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; + +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Nonnull; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.core.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.ReceiveAuthnResponseAlternativeTask; +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.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.EidAuthProcessDataWrapper; +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.protocol.impl.AuthenticationResponse; +import lombok.val; + +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class ReceiveEidasResponseTaskTest { + + @Autowired(required = true) + private ReceiveAuthnResponseAlternativeTask task; + + @Autowired(required = true) + private MsConnectorDummyConfigMap basicConfig; + @Autowired + protected EidasAttributeRegistry attrRegistry; + + @Autowired private IRequestStorage storage; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private MsConnectorDummySpConfiguration oaParam; + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException { + + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.eid.testidentity.default", "false"); + + final Map<String, String> spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); + oaParam = new MsConnectorDummySpConfiguration(spConfig, basicConfig); + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH)); + pendingReq = new TestRequestImpl(); + + pendingReq.setSpConfig(oaParam); + 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, "LU"); + executionContext.put(EaafConstants.PROCESS_ENGINE_REQUIRES_NO_POSTAUTH_REDIRECT, true); + + } + + @Test + public void missingEidasResponse() { + try { + task.execute(pendingReq, executionContext); + Assert.fail("No eIDAS response not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorId", "eidas.01", + ((EaafException) e.getOriginalException()).getErrorId()); + + } + } + + @Test + public void notSuccessEidasResponse() throws URISyntaxException { + String statusCode = RandomStringUtils.randomAlphabetic(10); + httpReq.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse(statusCode)); + + + try { + task.execute(pendingReq, executionContext); + Assert.fail("No eIDAS response not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorId", "eidas.02", + ((EaafException) e.getOriginalException()).getErrorId()); + Assert.assertEquals("wrong parameter size", 2, ((EaafException) e.getOriginalException()) + .getParams().length); + Assert.assertEquals("wrong errorMsg", statusCode, ((EaafException) e + .getOriginalException()).getParams()[0]); + + } + } + + @Test + public void successAndForward() throws URISyntaxException, TaskExecutionException, + PendingReqIdValidationException, EaafStorageException { + + AuthenticationResponse eidasResponse = buildDummyAuthResponse(Constants.SUCCESS_URI); + httpReq.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, eidasResponse); + + String alternativReturnEndpoint = "http://ms-connector.alternative/" + RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction( + MsEidasNodeConstants.EXECCONTEXT_PARAM_MSCONNECTOR_STAGING, alternativReturnEndpoint); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("msConnectorStage", true, + (Boolean) executionContext.get(MsEidasNodeConstants.EXECCONTEXT_PARAM_MSCONNECTOR_STAGING)); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(alternativReturnEndpoint)); + + + } + + public void success() throws URISyntaxException, TaskExecutionException, PendingReqIdValidationException { + @Nonnull + AuthenticationResponse eidasResponse = buildDummyAuthResponse(Constants.SUCCESS_URI); + httpReq.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, eidasResponse); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + final EidAuthProcessDataWrapper authProcessData = storedReq.getSessionData(EidAuthProcessDataWrapper.class); + Assert.assertEquals("LoA", eidasResponse.getLevelOfAssurance(), authProcessData.getQaaLevel()); + Assert.assertNotNull("eIDAS response", + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertEquals("eIDAS response", eidasResponse, + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE)); + + Assert.assertFalse("testIdentity flag", authProcessData.isTestIdentity()); + + Assert.assertEquals("msConnectorStage", false, + (Boolean) executionContext.get(MsEidasNodeConstants.EXECCONTEXT_PARAM_MSCONNECTOR_STAGING)); + } + + @Test + public void successWithTestIdentity() throws URISyntaxException, TaskExecutionException, PendingReqIdValidationException { + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.eid.testidentity.default", "true"); + + @Nonnull + AuthenticationResponse eidasResponse = buildDummyAuthResponse(Constants.SUCCESS_URI); + httpReq.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, eidasResponse); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + + final EidAuthProcessDataWrapper authProcessData = storedReq.getSessionData(EidAuthProcessDataWrapper.class); + Assert.assertEquals("LoA", eidasResponse.getLevelOfAssurance(), authProcessData.getQaaLevel()); + Assert.assertNotNull("eIDAS response", + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE)); + Assert.assertEquals("eIDAS response", eidasResponse, + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE)); + Assert.assertTrue("testIdentity flag", authProcessData.isTestIdentity()); + + } + + + + @Nonnull + private AuthenticationResponse buildDummyAuthResponse(String statusCode) throws URISyntaxException { + final AttributeDefinition attributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition attributeDef2 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition attributeDef3 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition attributeDef4 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + + final ImmutableAttributeMap attributeMap = ImmutableAttributeMap.builder() + .put(attributeDef, "LU/AT/" + 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("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(statusCode) + .inResponseTo("_".concat(Random.nextHexRandom16())) + .subjectNameIdFormat("afaf") + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .attributes(attributeMap) + .build(); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveMobilePhoneSignatureResponseTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveMobilePhoneSignatureResponseTaskTest.java new file mode 100644 index 00000000..8fae81b1 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveMobilePhoneSignatureResponseTaskTest.java @@ -0,0 +1,479 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.springframework.util.Assert.isInstanceOf; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import javax.xml.transform.TransformerException; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.jetbrains.annotations.NotNull; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.saml2.core.Issuer; +import org.opensaml.saml.saml2.core.Response; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +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.Lists; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.ManualFixNecessaryException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthConstants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.provider.IdAustriaClientAuthCredentialProvider; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.provider.IdAustriaClientAuthMetadataProvider; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterOperationStatus; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterStatusResults; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveMobilePhoneSignatureResponseTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy.DummyOA; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy.DummyPendingRequest; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AuthnResponseValidationException; +import net.shibboleth.utilities.java.support.xml.ParserPool; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +public class ReceiveMobilePhoneSignatureResponseTaskTest { + + private static final String METADATA_PATH = "classpath:/data/idp_metadata_classpath_entity.xml"; + private static final String BPK_FROM_ID_AUSTRIA = "BF:QVGm48cqcM4UcyhDTNGYmVdrIoY="; + + @Autowired + protected MsConnectorDummyConfigMap authConfig; + @Autowired + private IdAustriaClientAuthMetadataProvider metadataProvider; + @Autowired + private IdAustriaClientAuthCredentialProvider credentialProvider; + @Autowired + private PvpMetadataResolverFactory metadataFactory; + @Autowired + private ReceiveMobilePhoneSignatureResponseTask task; + @MockBean + private RegisterSearchService registerSearchService; + + private final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private DummyPendingRequest pendingReq; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void initialize() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + } + + /** + * jUnit test set-up. + * + * @throws Exception In case of an set-up error + */ + @Before + public void setUp() throws Exception { + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpReq.setScheme("https"); + httpReq.setServerPort(443); + httpReq.setContextPath("/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + authConfig.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID, METADATA_PATH); + + DummyOA oaParam = new DummyOA(); + oaParam.setUniqueAppId("http://test.com/test"); + oaParam.setTargetIdentifier(EaafConstants.URN_PREFIX_CDID + RandomStringUtils.randomAlphabetic(2)); + + pendingReq = new DummyPendingRequest(); + pendingReq.initialize(httpReq, authConfig); + pendingReq.setPendingRequestId(RandomStringUtils.randomAlphanumeric(10)); + pendingReq.setOnlineApplicationConfiguration(oaParam); + + metadataProvider.fullyDestroy(); + } + + @Test + public void unsupportedHttpMethod() { + httpReq = new MockHttpServletRequest("PUT", "https://localhost/authhandler"); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.03", ((AuthnResponseValidationException) e.getOriginalException()).getErrorId()); + } + + @Test + public void httpGetNoMessage() { + httpReq = new MockHttpServletRequest("GET", "https://localhost/authhandler"); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.12", ((AuthnResponseValidationException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostNoMessage() { + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.12", ((AuthnResponseValidationException) e.getOriginalException()).getErrorId()); + } + + @Test + public void httpPostMessageNotSigned() throws IOException { + byte[] bytes = IOUtils.toByteArray(ReceiveMobilePhoneSignatureResponseTask.class + .getResourceAsStream("/data/Response_without_sig_classpath_entityid.xml")); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString(bytes)); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.12", ((AuthnResponseValidationException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostMessageWrongDestinationEndpoint() throws Exception { + initResponse("/data/Response_with_wrong_destination_endpoint.xml", true); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.12", ((AuthnResponseValidationException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostValidSignedNoMetadata() throws Exception { + initResponse("/data/Response_without_sig_classpath_entityid.xml", true); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.11", ((EaafException) e.getOriginalException()).getErrorId()); + } + + @Test + public void httpPostValidSignedAssertionOutDated() throws Exception { + setupMetadataResolver(); + initResponse("/data/Response_without_sig_classpath_entityid.xml", false); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.12", ((EaafException) e.getOriginalException()).getErrorId()); + } + + @Test + public void httpPostValidSignedAssertionFromWrongIdp() throws Exception { + authConfig.putConfigValue(IdAustriaClientAuthConstants.CONFIG_PROPS_ID_AUSTRIA_ENTITYID, + "http://wrong.idp/" + RandomStringUtils.randomAlphabetic(5)); + setupMetadataResolver(); + initResponse("/data/Response_without_sig_classpath_entityid.xml", true); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.08", ((EaafException) e.getOriginalException()).getErrorId()); + } + + @Test + public void httpPostValidSignedAssertionMissingAttributes() throws Exception { + setupMetadataResolver(); + initResponse("/data/Response_without_sig_classpath_entityid.xml", true); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.12", ((EaafException) e.getOriginalException()).getErrorId()); + } + + @Test + public void httpPostValidSignedWithError() throws Exception { + setupMetadataResolver(); + initResponse("/data/Response_without_sig_with_error.xml", true); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.05", ((EaafException) e.getOriginalException()).getErrorId()); + } + + @Test + public void httpPostValidSignedWitUserStopErrorCode() throws Exception { + setupMetadataResolver(); + initResponse("/data/Response_without_sig_with_error_userstop.xml", true); + + task.execute(pendingReq, executionContext); + + assertEquals("Transition To S16", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + assertEquals("failed reason", "module.eidasauth.matching.23", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON)); + assertNull("no final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + } + + @Test + public void httpPostValidSignedWithErrorAndNoSubCode() throws Exception { + setupMetadataResolver(); + initResponse("/data/Response_without_sig_with_error_without_subcode.xml", true); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.05", ((EaafException) e.getOriginalException()).getErrorId()); + } + + @Test + public void httpPostValidSignedWithErrorAndEmptySubCode() throws Exception { + setupMetadataResolver(); + initResponse("/data/Response_without_sig_with_error_empty_subcode.xml", true); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + assertEquals("sp.pvp2.05", ((EaafException) e.getOriginalException()).getErrorId()); + } + + @Test + public void httpPostValidSignedAssertionEidValidButNameMismatch() throws Exception { + setupMetadataResolver(); + initResponse("/data/Response_with_EID.xml", true); + AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class); + SimpleEidasData eidData = createEidasDataMatchingToSamlResponse() + .familyName("notmatching") + .build(); + authProcessData.setGenericDataToSession(Constants.DATA_SIMPLE_EIDAS, eidData); + + + task.execute(pendingReq, executionContext); + + assertEquals("Next task", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("matching failed flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + assertEquals("failed reason", "module.eidasauth.matching.24", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON)); + assertNull("no final matching result", MatchingTaskUtils.getFinalMatchingResult(pendingReq)); + + } + + //TODO: implement new test that this test makes no sense any more + @Ignore + @Test + public void httpPostValidSignedAssertionEidValid_NoRegisterResult() throws Exception { + setupMetadataResolver(); + initResponse("/data/Response_with_EID.xml", true); + AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class); + SimpleEidasData eidData = createEidasDataMatchingToSamlResponse().build(); + authProcessData.setGenericDataToSession(Constants.DATA_SIMPLE_EIDAS, eidData); + RegisterStatusResults registerSearchResult = new RegisterStatusResults(new RegisterOperationStatus(generateRandomProcessId()), + Collections.emptyList(), Collections.emptyList()); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + + task.execute(pendingReq, executionContext); + + AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); + assertEquals("LoA", "http://eidas.europa.eu/LoA/low", session.getQaaLevel()); + assertEquals("IssueInstant", "2014-03-05T06:39:51Z", session.getIssueInstantString()); + assertEquals("Transition To S16", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK)); + } + + @Test + public void httpPostValidSignedAssertionEidValid_ExactlyOneRegisterResult() throws Exception { + setupMetadataResolver(); + initResponse("/data/Response_with_EID.xml", true); + AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class); + SimpleEidasData eidData = createEidasDataMatchingToSamlResponse().build(); + authProcessData.setGenericDataToSession(Constants.DATA_SIMPLE_EIDAS, eidData); + RegisterStatusResults registerSearchResult = buildResultWithOneMatch(); + MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); + + task.execute(pendingReq, executionContext); + + AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); + assertEquals("LoA", "http://eidas.europa.eu/LoA/low", session.getQaaLevel()); + assertEquals("IssueInstant", "2014-03-05T06:39:51Z", session.getIssueInstantString()); + assertNull("Transition To S16", executionContext.get(Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK)); + + //TODO: update this check because this task selects one result from MDS search result before and creates a new element + //Mockito.verify(registerSearchService).step7aKittProcess(eq(registerSearchResult), eq(eidData)); + } + + //TODO: implement new test that this test makes no sense any more + @Ignore + @Test + public void httpPostValidSignedAssertionEidValid_MoreThanOneRegisterResult() throws Exception { + setupMetadataResolver(); + initResponse("/data/Response_with_EID.xml", true); + AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class); + SimpleEidasData eidData = createEidasDataMatchingToSamlResponse().build(); + authProcessData.setGenericDataToSession(Constants.DATA_SIMPLE_EIDAS, eidData); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + + assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + isInstanceOf(AuthnResponseValidationException.class, e.getOriginalException()); + isInstanceOf(ManualFixNecessaryException.class, e.getOriginalException().getCause()); + assertEquals("sp.pvp2.12", ((AuthnResponseValidationException) e.getOriginalException()).getErrorId()); + + + AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); + assertNull("Transition To S16", executionContext.get(Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK)); + } + + @NotNull + private RegisterStatusResults buildResultWithOneMatch() { + return new RegisterStatusResults(new RegisterOperationStatus(generateRandomProcessId()), + Collections.singletonList(RegisterResult.builder() + .bpk(BPK_FROM_ID_AUSTRIA) + .pseudonym(Arrays.asList("bar")) + .givenName("foo") + .familyName("foo") + .dateOfBirth("bar") + .build()), + Collections.emptyList()); + + } + + @NotNull + private RegisterStatusResults buildResultWithTwoMatches() { + List<RegisterResult> results = Lists.newArrayList( + RegisterResult.builder() + .bpk(BPK_FROM_ID_AUSTRIA) + .pseudonym(Arrays.asList("bar")) + .givenName("foo") + .familyName("foo") + .dateOfBirth("bar") + .build(), + RegisterResult.builder() + .bpk("bpk") + .pseudonym(Arrays.asList("pseudonym")) + .givenName("givenName") + .familyName("familyName") + .dateOfBirth("dateOfBirth") + .build()); + + return new RegisterStatusResults(new RegisterOperationStatus(generateRandomProcessId()), + results, Collections.emptyList()); + } + + private BigInteger generateRandomProcessId() { + return new BigInteger(RandomStringUtils.randomNumeric(10)); + + } + + private SimpleEidasData.SimpleEidasDataBuilder createEidasDataMatchingToSamlResponse() { + // data from "/data/Response_with_EID.xml" + return SimpleEidasData.builder() + .familyName("Mustermann") + .givenName("Max") + .dateOfBirth("1940-01-01"); + } + + private void addSamlResponseToHttpReq(Response response) throws TransformerException, IOException, MarshallingException { + String node = DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)); + String base64encoded = Base64.getEncoder().encodeToString(node.getBytes(StandardCharsets.UTF_8)); + httpReq.addParameter("SAMLResponse", base64encoded); + } + + private void initResponse(String responsePath, boolean validConditions) throws Exception { + InputStream inputStream = ReceiveMobilePhoneSignatureResponseTaskTest.class.getResourceAsStream(responsePath); + ParserPool parserPool = Objects.requireNonNull(XMLObjectProviderRegistrySupport.getParserPool()); + Response response = (Response) XMLObjectSupport.unmarshallFromInputStream(parserPool, inputStream); + response.setIssueInstant(Instant.now()); + Issuer issuer = Saml2Utils.createSamlObject(Issuer.class); + issuer.setValue("classpath:/data/idp_metadata_classpath_entity.xml"); + response.setIssuer(issuer); + if (validConditions) { + response.getAssertions().get(0).getConditions().setNotOnOrAfter(Instant.now().plusSeconds(5*60)); + } + Response signedResponse = Saml2Utils.signSamlObject(response, credentialProvider.getMessageSigningCredential(), true); + addSamlResponseToHttpReq(signedResponse); + } + + private void setupMetadataResolver() throws Pvp2MetadataException { + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveOtherLoginMethodGuiResponseTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveOtherLoginMethodGuiResponseTaskTest.java new file mode 100644 index 00000000..da8a7497 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveOtherLoginMethodGuiResponseTaskTest.java @@ -0,0 +1,148 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.springframework.util.Assert.isInstanceOf; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SelectedLoginMethod; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveOtherLoginMethodGuiResponseTask; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml" +}) +@ActiveProfiles(profiles = {"deprecatedConfig"}) +@WebAppConfiguration +public class ReceiveOtherLoginMethodGuiResponseTaskTest { + + @Autowired + private ReceiveOtherLoginMethodGuiResponseTask task; + + private final ExecutionContextImpl executionContext = new ExecutionContextImpl(); + private TestRequestImpl pendingReq; + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + + /** + * jUnit class initializer. + */ + @BeforeClass + public static void classInitializer() { + final String current = new java.io.File(".").toURI().toString(); + System.setProperty("eidas.ms.configuration", current + "src/test/resources/config/junit_config_1.properties"); + } + + /** + * jUnit test set-up. + */ + @Before + public void initialize() { + httpReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + pendingReq = new TestRequestImpl(); + pendingReq.setAuthUrl("https://localhost/ms_connector"); + pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); + + LocaleContextHolder.resetLocaleContext(); + } + + @Test + public void withMobileSignatureSelection() throws TaskExecutionException { + testTransition(SelectedLoginMethod.MOBILE_PHONE_SIGNATURE_LOGIN, Constants.TRANSITION_TO_GENERATE_MOBILE_PHONE_SIGNATURE_REQUEST_TASK); + } + + @Test + public void withEidasSelection() throws TaskExecutionException { + testTransition(SelectedLoginMethod.EIDAS_LOGIN, Constants.TRANSITION_TO_GENERATE_EIDAS_LOGIN); + } + + @Test + public void withNoOtherLoginSelection() throws TaskExecutionException { + testTransition(SelectedLoginMethod.NO_OTHER_LOGIN, Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK); + } + + @Test + public void withAddMeAsNewSelection() throws TaskExecutionException { + testTransition(SelectedLoginMethod.ADD_ME_AS_NEW, Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK); + } + + public void testTransition(SelectedLoginMethod loginMethod, String expectedTransition) throws TaskExecutionException { + httpReq.setParameter(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER, loginMethod.name()); + executionContext.put(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED, true); + + task.execute(pendingReq, executionContext); + + assertFalse("wrong pendingReq auth flag", pendingReq.isAuthenticated()); + assertFalse("wrong process-cancelled flag", executionContext.isProcessCancelled()); + assertNotNull("no login-selection found", executionContext.get(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER)); + assertEquals("Wrong login-selection found", loginMethod, executionContext.get(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER)); + assertEquals("Next task", true, executionContext.get(expectedTransition)); + assertNull("find advancedMatchingError flag", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + + } + + public void withInvalidSelection() throws TaskExecutionException { + httpReq.setParameter(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER, RandomStringUtils.randomAlphabetic(2)); + + task.execute(pendingReq, executionContext); + + assertEquals("Next task", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("advancedMatchingError flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + } + + @Test + public void withNullSelection() throws TaskExecutionException { + httpReq.setParameter(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER, "null"); + + task.execute(pendingReq, executionContext); + + assertEquals("Next task", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("advancedMatchingError flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + } + + @Test + public void withEmptySelection() throws TaskExecutionException { + httpReq.setParameter(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER, ""); + + task.execute(pendingReq, executionContext); + + assertEquals("Next task", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("advancedMatchingError flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + } + + @Test + public void withoutLoginMethodSelection() throws TaskExecutionException { + + task.execute(pendingReq, executionContext); + + assertEquals("Next task", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); + assertEquals("advancedMatchingError flag", true, executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/utils/JoseUtilsTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/utils/JoseUtilsTest.java new file mode 100644 index 00000000..4da03622 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/utils/JoseUtilsTest.java @@ -0,0 +1,136 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.utils; + +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.Provider; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.lang3.RandomStringUtils; +import org.jose4j.jwa.AlgorithmConstraints; +import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; +import org.jose4j.jws.AlgorithmIdentifiers; +import org.jose4j.lang.JoseException; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +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.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; +import at.gv.egiz.eaaf.core.impl.data.Pair; + +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class JoseUtilsTest { + + @Autowired private EaafKeyStoreFactory keyStoreFactory; + + private static final List<String> AUTH_ALGORITHM_WHITELIST_SIGNING = Collections.unmodifiableList( + Arrays.asList( + AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256, + AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512, + AlgorithmIdentifiers.RSA_PSS_USING_SHA256, + AlgorithmIdentifiers.RSA_PSS_USING_SHA512)); + + + @Test + public void missingKey() throws EaafException, JoseException, KeyStoreException, IOException { + + KeyStoreConfiguration config = new KeyStoreConfiguration(); + config.setFriendlyName("jUnittest"); + config.setKeyStoreType(KeyStoreType.JKS); + config.setSoftKeyStoreFilePath("../data/junit.jks"); + config.setSoftKeyStorePassword("password"); + + Pair<KeyStore, Provider> keyStore = keyStoreFactory.buildNewKeyStore(config); + String payLoad = RandomStringUtils.randomAlphanumeric(100); + + //check signing + try { + JoseUtils.createSignature(keyStore, "notExist", "password".toCharArray(), payLoad , true, "jUnitTest"); + Assert.fail("missing Key not detected"); + + } catch (EaafException e) { + Assert.assertEquals("ErrorId", "internal.keystore.09", e.getErrorId()); + + } + } + + @Test + public void createRsaSignature() throws EaafException, JoseException, KeyStoreException, IOException { + + KeyStoreConfiguration config = new KeyStoreConfiguration(); + config.setFriendlyName("jUnittest"); + config.setKeyStoreType(KeyStoreType.JKS); + config.setSoftKeyStoreFilePath("../data/junit.jks"); + config.setSoftKeyStorePassword("password"); + + Pair<KeyStore, Provider> keyStore = keyStoreFactory.buildNewKeyStore(config); + String payLoad = RandomStringUtils.randomAlphanumeric(100); + + //check signing + String result = JoseUtils.createSignature(keyStore, "meta", "password".toCharArray(), payLoad , true, "jUnitTest"); + + Assert.assertNotNull("signed message", result); + Assert.assertFalse("signed msg empty", result.isEmpty()); + + + //validate + List<X509Certificate> trustedCerts = EaafKeyStoreUtils.readCertsFromKeyStore(keyStore.getFirst()); + final AlgorithmConstraints constraints = new AlgorithmConstraints(ConstraintType.PERMIT, + AUTH_ALGORITHM_WHITELIST_SIGNING + .toArray(new String[AUTH_ALGORITHM_WHITELIST_SIGNING.size()])); + JwsResult verify = JoseUtils.validateSignature(result, trustedCerts, constraints); + + Assert.assertTrue("sig. verify", verify.isValid()); + Assert.assertEquals("payload", payLoad, verify.getPayLoad()); + + } + + @Test + public void createEccSignature() throws EaafException, JoseException, KeyStoreException, IOException { + + KeyStoreConfiguration config = new KeyStoreConfiguration(); + config.setFriendlyName("jUnittest"); + config.setKeyStoreType(KeyStoreType.JKS); + config.setSoftKeyStoreFilePath("../data/junit.jks"); + config.setSoftKeyStorePassword("password"); + + Pair<KeyStore, Provider> keyStore = keyStoreFactory.buildNewKeyStore(config); + String payLoad = RandomStringUtils.randomAlphanumeric(100); + + //check signing + String result = JoseUtils.createSignature(keyStore, "sig", "password".toCharArray(), payLoad , true, "jUnitTest"); + + Assert.assertNotNull("signed message", result); + Assert.assertFalse("signed msg empty", result.isEmpty()); + + + //validate + List<X509Certificate> trustedCerts = EaafKeyStoreUtils.readCertsFromKeyStore(keyStore.getFirst()); + final AlgorithmConstraints constraints = new AlgorithmConstraints(ConstraintType.PERMIT, + AUTH_ALGORITHM_WHITELIST_SIGNING + .toArray(new String[AUTH_ALGORITHM_WHITELIST_SIGNING.size()])); + JwsResult verify = JoseUtils.validateSignature(result, trustedCerts, constraints); + + Assert.assertTrue("sig. verify", verify.isValid()); + Assert.assertEquals("payload", payLoad, verify.getPayLoad()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasAttributePostProcessingTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasAttributePostProcessingTest.java new file mode 100644 index 00000000..0a4ab851 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasAttributePostProcessingTest.java @@ -0,0 +1,453 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.validation; + +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.Map; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.CcSpecificEidProcessingService; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public class EidasAttributePostProcessingTest { + + @Autowired + private CcSpecificEidProcessingService postProcessor; + + // lower case + private static final String P1_eIDASID = + "DE/AT/532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25"; + private static final String P1_GIVENNAME = "Max"; + private static final String P1_FAMILYNAME = "Mustermann"; + private static final String P1_DATEOFBIRTH = "2020-01-04"; + private static final String P1_PLACEOFBIRTH = "Nirgendwo"; + private static final String P1_BIRTHNAME = "Musterkind"; + + // mixed + private static final String P3_eIDASID = + "DE/AT/532eaabd9574880dbf76b9b8cc00832c20A6ec113d682299550d7a6e0f345e25"; + private static final String P3_GIVENNAME = "Max"; + private static final String P3_FAMILYNAME = "Mustermann"; + private static final String P3_DATEOFBIRTH = "2020-01-03"; + private static final String P3_PLACEOFBIRTH = "Nirgendwo"; + private static final String P3_BIRTHNAME = "Musterkind"; + + // upper case + private static final String P4_eIDASID = + "DE/AT/532EAABD9574880DBF76B9B8CC00832C20A6EC113D682299550D7A6E0F345E25"; + private static final String P4_GIVENNAME = "Max"; + private static final String P4_FAMILYNAME = "Mustermann"; + private static final String P4_DATEOFBIRTH = "2020-01-05"; + private static final String P4_PLACEOFBIRTH = "Nirgendwo"; + private static final String P4_BIRTHNAME = "Musterkind"; + + // To long identifier + private static final String P5_eIDASID = + "DE/AT/532EAABD9574880DBF76B9B8CC00832C20A6EC113D682299550D7A6E0F345E251"; + private static final String P5_GIVENNAME = "Max"; + private static final String P5_FAMILYNAME = "Mustermann"; + private static final String P5_DATEOFBIRTH = "2020-01-06"; + private static final String P5_PLACEOFBIRTH = "Nirgendwo"; + private static final String P5_BIRTHNAME = "Musterkind"; + + // to short identifier + private static final String P6_eIDASID = "DE/AT/532EAABD9574880DBF76B9B8CC00832C20A6EC113D682299550D7A6E0F"; + private static final String P6_GIVENNAME = "Max"; + private static final String P6_FAMILYNAME = "Mustermann"; + private static final String P6_DATEOFBIRTH = "2020-01-08"; + private static final String P6_PLACEOFBIRTH = "Nirgendwo"; + private static final String P6_BIRTHNAME = "Musterkind"; + + // no hex encoded identifier + private static final String P7_eIDASID = "DE/AT/532EAABD9574880DBF76B9B8CC00832C20A6EC113D682299550D7A6E0F"; + private static final String P7_GIVENNAME = "Max"; + private static final String P7_FAMILYNAME = "Mustermann"; + private static final String P7_DATEOFBIRTH = "2020-01-09"; + private static final String P7_PLACEOFBIRTH = "Nirgendwo"; + private static final String P7_BIRTHNAME = "Musterkind"; + + private static final String P2_eIDASID = + "EE/AT/asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd"; + private static final String P2_GIVENNAME = "Max"; + private static final String P2_FAMILYNAME = "Mustermann"; + private static final String P2_DATEOFBIRTH = "2020-01-10"; + private static final String P2_PLACEOFBIRTH = "Nirgendwo"; + private static final String P2_BIRTHNAME = "Musterkind"; + + /** + * jUnit class initializer. + * + * @throws IOException In case of an error + */ + @BeforeClass + public static void classInitializer() throws IOException { + final String current = new java.io.File(".").toURI().toString(); + System.setProperty("eidas.ms.configuration", current + "../../basicConfig/default_config.properties"); + + } + + @Test + public void deWithHexLowerCase() throws Exception { + try { + final SimpleEidasData result = postProcessor.postProcess( + generateInputData( + P1_eIDASID, + P1_FAMILYNAME, + P1_GIVENNAME, + P1_DATEOFBIRTH, + P1_PLACEOFBIRTH, + P1_BIRTHNAME)); + + validate(result, + "Uy6qvZV0iA2/drm4zACDLCCm7BE9aCKZVQ16bg80XiU=", + P1_FAMILYNAME, + P1_GIVENNAME, + P1_DATEOFBIRTH, + P1_PLACEOFBIRTH, + P1_BIRTHNAME); + + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + + } + } + + @Test + public void deWithHexMixedCase() throws Exception { + try { + final SimpleEidasData result = postProcessor.postProcess( + generateInputData( + P3_eIDASID, + P3_FAMILYNAME, + P3_GIVENNAME, + P3_DATEOFBIRTH, + P3_PLACEOFBIRTH, + P3_BIRTHNAME)); + + validate(result, + "Uy6qvZV0iA2/drm4zACDLCCm7BE9aCKZVQ16bg80XiU=", + P3_FAMILYNAME, + P3_GIVENNAME, + P3_DATEOFBIRTH, + P3_PLACEOFBIRTH, + P3_BIRTHNAME); + + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + + } + } + + @Test + public void deWithHexUpperCase() throws Exception { + try { + final SimpleEidasData result = postProcessor.postProcess( + generateInputData( + P4_eIDASID, + P4_FAMILYNAME, + P4_GIVENNAME, + P4_DATEOFBIRTH, + P4_PLACEOFBIRTH, + P4_BIRTHNAME)); + + validate(result, + "Uy6qvZV0iA2/drm4zACDLCCm7BE9aCKZVQ16bg80XiU=", + P4_FAMILYNAME, + P4_GIVENNAME, + P4_DATEOFBIRTH, + P4_PLACEOFBIRTH, + P4_BIRTHNAME); + + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + + } + } + + @Test + public void deWithHexTooLongCase() throws Exception { + try { + postProcessor.postProcess( + generateInputData( + P5_eIDASID, + P5_FAMILYNAME, + P5_GIVENNAME, + P5_DATEOFBIRTH, + P5_PLACEOFBIRTH, + P5_BIRTHNAME)); + + } catch (final Exception e) { + return; + + } + + fail("Too long input accepted"); + } + + @Test + public void deWithHexTooShortCase() throws Exception { + try { + postProcessor.postProcess( + generateInputData( + P6_eIDASID, + P6_FAMILYNAME, + P6_GIVENNAME, + P6_DATEOFBIRTH, + P6_PLACEOFBIRTH, + P6_BIRTHNAME)); + + } catch (final Exception e) { + return; + + } + + fail("Too short input accepted"); + } + + @Test + public void deWithNoHexCase() throws Exception { + try { + postProcessor.postProcess( + generateInputData( + P7_eIDASID, + P7_FAMILYNAME, + P7_GIVENNAME, + P7_DATEOFBIRTH, + P7_PLACEOFBIRTH, + P7_BIRTHNAME)); + + } catch (final Exception e) { + return; + + } + + fail("Not hex encoded input accepted"); + } + + @Test + public void eeTestCase() throws Exception { + try { + final SimpleEidasData result = postProcessor.postProcess( + generateInputData( + P2_eIDASID, + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME)); + + validate(result, + "asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd", + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME); + + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + + } + } + + @Test + public void eeTestFamilyNameMissingCase() throws Exception { + try { + final SimpleEidasData result = postProcessor.postProcess( + generateInputData( + P2_eIDASID, + null, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME)); + + validate(result, + "asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd", + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME); + + } catch (final Exception e) { + return; + + } + + fail("FamilyName missing input accepted"); + + } + + @Test + public void eeTestGivenNameMissingCase() throws Exception { + try { + final SimpleEidasData result = postProcessor.postProcess( + generateInputData( + P2_eIDASID, + P2_FAMILYNAME, + null, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME)); + + validate(result, + "asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd", + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME); + + } catch (final Exception e) { + return; + + } + + fail("GivenName missing input accepted"); + + } + + @Test + public void eeTestDateOfBirthMissingCase() throws Exception { + try { + final SimpleEidasData result = postProcessor.postProcess( + generateInputData( + P2_eIDASID, + P2_FAMILYNAME, + P2_GIVENNAME, + null, + P2_PLACEOFBIRTH, + P2_BIRTHNAME)); + + validate(result, + "asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd", + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME); + + } catch (final Exception e) { + return; + + } + + fail("DateOfBirth missing input accepted"); + + } + + @Test + public void eeTestIdMissingCase() throws Exception { + try { + final SimpleEidasData result = postProcessor.postProcess( + generateInputData( + null, + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME)); + + validate(result, + "asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd", + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME); + + } catch (final Exception e) { + return; + + } + + fail("eIDAS-Id missing input accepted"); + + } + + private Map<String, Object> generateInputData(String id, String familyName, String givenName, + String dateOfBirth, String placeOfBirth, String birthName) { + final Map<String, Object> result = new HashMap<>(); + result.put(Constants.eIDAS_ATTR_PERSONALIDENTIFIER, id); + result.put(Constants.eIDAS_ATTR_CURRENTGIVENNAME, givenName); + result.put(Constants.eIDAS_ATTR_CURRENTFAMILYNAME, familyName); + result.put(Constants.eIDAS_ATTR_DATEOFBIRTH, dateOfBirth); + result.put(Constants.eIDAS_ATTR_PLACEOFBIRTH, placeOfBirth); + result.put(Constants.eIDAS_ATTR_BIRTHNAME, birthName); + return result; + + } + + private void validate(SimpleEidasData result, String id, String familyName, String givenName, + String dateOfBirth, String placeOfBirth, String birthName) { + if (!result.getPseudonym().equals(id)) { + fail(result.getPseudonym() + "is not equal to " + id); + } + + if (!result.getFamilyName().equals(familyName)) { + fail(result.getFamilyName() + "is not equal to " + familyName); + } + + if (!result.getGivenName().equals(givenName)) { + fail(result.getGivenName() + "is not equal to " + givenName); + } + + if (!result.getDateOfBirth().equals(dateOfBirth)) { + fail(result.getDateOfBirth() + "is not equal to " + dateOfBirth); + } + + if (!result.getPlaceOfBirth().equals(placeOfBirth)) { + fail(result.getPlaceOfBirth() + "is not equal to " + placeOfBirth); + } + + if (!result.getBirthName().equals(birthName)) { + fail(result.getBirthName() + "is not equal to " + birthName); + } + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingFirstTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingFirstTest.java new file mode 100644 index 00000000..84da2344 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingFirstTest.java @@ -0,0 +1,158 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.validation; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.CcSpecificEidProcessingService; +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.idp.IConfigurationWithSP; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummySpConfiguration; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import eu.eidas.auth.commons.light.impl.LightRequest; +import eu.eidas.auth.commons.light.impl.LightRequest.Builder; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_realConfig.xml", + //"/SpringTest-context_basic_mapConfig.xml" + }) +@TestPropertySource(locations = {"classpath:/config/junit_config_de_attributes.properties", "classpath:/config" + + "/junit_config_1_springboot.properties"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public class EidasRequestPreProcessingFirstTest { + + @Autowired + private IConfigurationWithSP basicConfig; + @Autowired + private CcSpecificEidProcessingService preProcessor; + + private TestRequestImpl pendingReq; + private DummySpConfiguration oaParam; + private Builder authnRequestBuilder; + + /** + * jUnit class initializer. + * + * @throws IOException In case of an error + */ + @BeforeClass + public static void classInitializer() throws IOException { +// final String current = new java.io.File(".").toURI().toString(); +// System.setProperty("eidas.ms.configuration", +// current + "src/test/resources/config/junit_config_de_attributes.properties"); + + } + + /** + * jUnit test set-up. + * + */ + @Before + public void setUp() { + + final Map<String, String> spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + oaParam = new DummySpConfiguration(spConfig, basicConfig); + + pendingReq = new TestRequestImpl(); + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + + authnRequestBuilder = LightRequest.builder(); + authnRequestBuilder.id(UUID.randomUUID().toString()); + authnRequestBuilder.issuer("Test"); + authnRequestBuilder.levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH); + + } + + @Test + public void prePreProcessGeneric() throws EidPostProcessingException { + final String testCountry = "XX"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", + Constants.DEFAULT_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP, lightReq.getProviderName()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 4, lightReq.getRequestedAttributes().size()); + + } + + @Test + public void prePreProcessGenericNoCountryCode() throws EidPostProcessingException { + final String testCountry = "XX"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(null, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", + Constants.DEFAULT_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP, lightReq.getProviderName()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 4, lightReq.getRequestedAttributes().size()); + + } + + @Test + public void prePreProcessDE() throws EidPostProcessingException { + + final String testCountry = "DE"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", + Constants.DEFAULT_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP, lightReq.getProviderName()); + Assert.assertNotSame("RequesterId was set", lightReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 8, lightReq.getRequestedAttributes().size()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingSecondTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingSecondTest.java new file mode 100644 index 00000000..9b061b55 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingSecondTest.java @@ -0,0 +1,157 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.validation; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.CcSpecificEidProcessingService; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummySpConfiguration; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import eu.eidas.auth.commons.light.impl.LightRequest; +import eu.eidas.auth.commons.light.impl.LightRequest.Builder; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public class EidasRequestPreProcessingSecondTest { + + @Autowired + private MsConnectorDummyConfigMap basicConfig; + @Autowired + private CcSpecificEidProcessingService preProcessor; + + private TestRequestImpl pendingReq; + private DummySpConfiguration oaParam; + private Builder authnRequestBuilder; + + + /** + * jUnit test set-up. + * + */ + @Before + public void setUp() { + + final Map<String, String> spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + oaParam = new DummySpConfiguration(spConfig, basicConfig); + + pendingReq = new TestRequestImpl(); + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + + authnRequestBuilder = LightRequest.builder(); + authnRequestBuilder.id(UUID.randomUUID().toString()); + authnRequestBuilder.issuer("Test"); + authnRequestBuilder.levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH); + + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.requesterId.lu.useStaticRequesterForAll", "true"); + + } + + @Test + public void prePreProcessDeUnknownAttribute() throws EidPostProcessingException { + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.node_v2.staticProviderNameForPublicSPs", "myNode"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "true"); + + final String testCountry = "DE"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", "myNode", lightReq.getProviderName());//Fixme "myNode" + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 8, lightReq.getRequestedAttributes().size()); + + } + + + /* + * Set ProviderName according to general configuration + */ + @Test + public void prePreProcessLuPublicSpWithoutRequestId() throws EidPostProcessingException { + + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.requesterId.lu.useStaticRequesterForAll", "false"); + + final String testCountry = "LU"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", "myNode", lightReq.getProviderName()); + Assert.assertNull("RequesterId", lightReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 4, lightReq.getRequestedAttributes().size()); + + } + + /* + * Always set requesterId and providername in case of country LU + */ + @Test + public void prePreProcessLuPublicSpWithStaticRequesterId() throws EidPostProcessingException { + + + final String testCountry = "LU"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", + "myNode", lightReq.getProviderName()); + Assert.assertEquals("RequesterId is not Static", + "myNode", lightReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 4, lightReq.getRequestedAttributes().size()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasResponseValidatorTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasResponseValidatorTest.java new file mode 100644 index 00000000..bbba56e2 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasResponseValidatorTest.java @@ -0,0 +1,330 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.validation; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; + +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.common.collect.ImmutableSet; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummySpConfiguration; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasValidationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.validator.EidasResponseValidator; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +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.ImmutableAttributeMap.Builder; +import eu.eidas.auth.commons.attribute.impl.StringAttributeValue; +import eu.eidas.auth.commons.light.ILightResponse; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import lombok.val; + +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class EidasResponseValidatorTest { + + @Autowired private MsConnectorDummyConfigMap basicConfig; + @Autowired protected EidasAttributeRegistry attrRegistry; + + private TestRequestImpl pendingReq; + private MsConnectorDummySpConfiguration oaParam; + + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException { + + final Map<String, String> spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); + oaParam = new MsConnectorDummySpConfiguration(spConfig, basicConfig); + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH)); + pendingReq = new TestRequestImpl(); + + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + pendingReq.setTransactionId("avaasbav"); + pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + + } + + + @Test + public void loaFromResponseToLow() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + "LU/AT/" + RandomStringUtils.randomNumeric(10), + EaafConstants.EIDAS_LOA_LOW, + false); + String spCountry = "AT"; + String citizenCountryCode = "XX"; + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.06", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 1, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "http://eidas.europa.eu/LoA/low", + e.getParams()[0]); + + } + } + + @Test + public void noEidasSpCountry() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + "LU/AT/" + RandomStringUtils.randomNumeric(10), + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + String spCountry = null; + String citizenCountryCode = "LU"; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.07", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 2, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "PersonIdentifier", + e.getParams()[0]); + Assert.assertEquals("wrong errorMsg", + "Destination country does not match to SP country", + e.getParams()[1]); + + } + } + + @Test + public void noEidasResponseCountry() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + "LU/AT/" + RandomStringUtils.randomNumeric(10), + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + String spCountry = "AT"; + String citizenCountryCode = null; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.07", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 2, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "PersonIdentifier", + e.getParams()[0]); + Assert.assertEquals("wrong errorMsg", + "Citizen country does not match to eIDAS-node country that generates the response", + e.getParams()[1]); + + } + } + + @Test + public void wrongEidasResponseCountry() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + "LU/AT/" + RandomStringUtils.randomNumeric(10), + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + String spCountry = "AT"; + String citizenCountryCode = "XX"; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.07", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 2, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "PersonIdentifier", + e.getParams()[0]); + Assert.assertEquals("wrong errorMsg", + "Citizen country does not match to eIDAS-node country that generates the response", + e.getParams()[1]); + + } + } + + @Test + public void missingPersonalIdentifier() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + null, + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + String spCountry = "AT"; + String citizenCountryCode = "LU"; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.05", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 1, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "NO 'PersonalIdentifier' attriubte", + e.getParams()[0]); + + } + } + + @Test + public void moreThanOnePersonalIdentifier() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + null, + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + true); + String spCountry = "AT"; + String citizenCountryCode = "LU"; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.05", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 1, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "NO 'PersonalIdentifier' attriubte", + e.getParams()[0]); + + } + } + + @Test + public void emptyPersonalIdentifier() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + "", + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + String spCountry = "AT"; + String citizenCountryCode = "LU"; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.07", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 2, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "PersonIdentifier", + e.getParams()[0]); + Assert.assertEquals("wrong errorMsg", + "Wrong identifier format", + e.getParams()[1]); + + } + } + + @Test + public void validResponse() throws URISyntaxException, EidasValidationException { + //set-up + + String spCountry = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + String cCountry = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + + ILightResponse eidasResponse = buildDummyAuthResponse( + cCountry + "/" + spCountry + "/" + RandomStringUtils.randomAlphanumeric(20), + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, cCountry, attrRegistry); + + } + + + private AuthenticationResponse buildDummyAuthResponse(String personalId, String loa, boolean moreThanOnePersonalId) + throws URISyntaxException { + + + final AttributeDefinition personIdattributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + + final Builder attributeMap = ImmutableAttributeMap.builder(); + if (personalId != null) { + if (moreThanOnePersonalId) { + ImmutableSet values = ImmutableSet.of(new StringAttributeValue(personalId), + new StringAttributeValue("XX/YY/" + RandomStringUtils.randomAlphanumeric(10))); + attributeMap.put(personIdattributeDef, values); + + } else { + attributeMap.put(personIdattributeDef, personalId); + + } + } + + val b = new AuthenticationResponse.Builder(); + return b.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(Constants.SUCCESS_URI) + .inResponseTo("_".concat(Random.nextHexRandom16())) + .subjectNameIdFormat("afaf") + .levelOfAssurance(loa) + .attributes(attributeMap.build()) + .build(); + } +} + |