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.IRequestStorage; 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(required = true) protected IRequestStorage requestStoreage; @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.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); task.setRequestStoreage(requestStoreage); 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 { RegisterStatusResults registerSearchResult = buildEmptyResult(); MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, registerSearchResult); httpReq.setParameter(ReceiveAustrianResidenceGuiResponseTask.HTTP_PARAM_NO_RESIDENCE, "true"); task.execute(pendingReq, executionContext); assertEquals("Transition To RequestInserErnp", true, executionContext.get(Constants.TRANSITION_TO_REQUESTING_NEW_ERNP_ENTRY_TASK)); assertEquals("Transition To AddressSearchForm", false, executionContext.get(Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK)); assertNull("matching failed flag", executionContext.get(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED)); 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 RequestInserErnp", false, executionContext.get(Constants.TRANSITION_TO_REQUESTING_NEW_ERNP_ENTRY_TASK)); assertEquals("Transition To AddressSearchForm", true, executionContext.get(Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_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(), true), 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(), true), Collections.singletonList(registerResult), Collections.emptyList()); } @NotNull private RegisterStatusResults buildResultWithTwoMatches() { List results = Lists.newArrayList(buildRandomRegisterResult(), buildRandomRegisterResult()); return new RegisterStatusResults(new RegisterOperationStatus(generateRandomProcessId(), true), 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(); } }