aboutsummaryrefslogtreecommitdiff
path: root/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskTest.java')
-rw-r--r--modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskTest.java939
1 files changed, 939 insertions, 0 deletions
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();
+ }
+
+}