From 5b0a9142a0e00fa528f86f8fe432c0e44ed4ae8e Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Mon, 7 Feb 2022 15:19:56 +0100 Subject: refactor(matching): change 'kitt' and 'update' steps in 'InitialSearchTask' - Update MDS in case of changes eIDAS data and already existing ERnP entry - Add additional attributes in case of new eIDAS attributes outside of MDS --- .../modules/auth/eidas/v2/dao/SimpleEidasData.java | 22 +- .../eidas/v2/service/RegisterSearchService.java | 22 +- .../auth/eidas/v2/tasks/InitialSearchTask.java | 42 ++-- .../eidas/v2/test/tasks/InitialSearchTaskTest.java | 41 +++- .../tasks/InitialSearchTaskWithRegistersTest.java | 75 ++++++- ...rsonalId_only_resp_no_additional_attributes.xml | 221 +++++++++++++++++++++ 6 files changed, 386 insertions(+), 37 deletions(-) create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/test/resources/data/zmr/seq_1-8_search_with_personalId_only_resp_no_additional_attributes.xml (limited to 'eidas_modules') diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleEidasData.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleEidasData.java index 5ad92507..e76768b6 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleEidasData.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleEidasData.java @@ -23,10 +23,11 @@ package at.asitplus.eidas.specific.modules.auth.eidas.v2.dao; +import org.apache.commons.lang3.builder.EqualsBuilder; + import at.gv.e_government.reference.namespace.persondata._20020228.PostalAddressType; import lombok.Builder; import lombok.Data; -import org.apache.commons.lang3.builder.EqualsBuilder; @Data @Builder @@ -68,8 +69,11 @@ public class SimpleEidasData { .append(result.getGivenName(), givenName) .append(result.getFamilyName(), familyName) .append(result.getDateOfBirth(), dateOfBirth) - .isEquals() - && result.getPseudonym().stream().anyMatch(el -> el.equals(pseudonym)); + .appendSuper(result.getPseudonym().stream().anyMatch(el -> el.equals(pseudonym))) + .appendSuper(checkOptionalAttributes(result.getPlaceOfBirth(), placeOfBirth)) + .appendSuper(checkOptionalAttributes(result.getBirthName(), birthName)) + .isEquals(); + } /** @@ -84,5 +88,17 @@ public class SimpleEidasData { .isEquals(); } + /** + * Check if eIDAS attribute is available. + * + * @param registerData Attribute value from register + * @param eidasData Attribute value from eIDAS + * @return true if eidasData is null or eidasData does not match to register value, + * otherwise false + */ + private static boolean checkOptionalAttributes(String registerData, String eidasData) { + return eidasData == null || eidasData.equals(registerData); + + } } diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java index 488b571b..85ea942c 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java @@ -7,6 +7,7 @@ import java.util.List; import javax.annotation.Nonnull; import org.jetbrains.annotations.Nullable; +import org.springframework.lang.NonNull; import org.springframework.stereotype.Service; import com.google.common.collect.Streams; @@ -186,34 +187,49 @@ public class RegisterSearchService { * @param initialEidasData Received eidas data from initial authn * @return */ + @NonNull public RegisterStatusResults step7aKittProcess(RegisterStatusResults registerResult, SimpleEidasData initialEidasData) throws WorkflowException { log.trace("Starting step7aKittProcess"); - // TODO verify with which data this method gets called + + // check if only one single result was found if (registerResult.getResultCount() != 1) { throw new WorkflowException("step7aKittProcess", "getResultCount() != 1"); + } + + // perform updated operation in respect to register results try { if (registerResult.getResultsZmr().size() == 1) { RegisterResult entryZmr = registerResult.getResultsZmr().get(0); ZmrRegisterResult updateZmr = zmrClient .update(registerResult.getOperationStatus().getZmrProcessId(), entryZmr, initialEidasData); return RegisterStatusResults.fromZmr(updateZmr); + } else { RegisterResult entryErnp = registerResult.getResultsErnp().get(0); ErnpRegisterResult updateErnp = ernpClient.update(entryErnp, initialEidasData); return RegisterStatusResults.fromErnp(registerResult.operationStatus, updateErnp); + } } catch (final EidasSAuthenticationException e) { throw new WorkflowException("kittMatchedIdentitiess", e.getMessage(), !(e instanceof ZmrCommunicationException), e); + } } - //TODO: check this method, because it's different to 'step7aKittProcess'??? /** * Automatic process to fix the register entries. * Called when the alternative eIDAS authn leads to a match in a register. + * + *

This method perform two additional operations: + *

+ *

* * @param initialSearchResult Register results from initial authentication * @param initialEidasData Received eIDAS data from initial authentication @@ -273,7 +289,7 @@ public class RegisterSearchService { // update ZMR entry by using eIDAS information from alternative authentication ErnpRegisterResult updateAlt = ernpClient.update(entryErnp, altEidasData); - return RegisterStatusResults.fromErnp(altSearchResult.operationStatus, updateAlt); + return RegisterStatusResults.fromErnp(altSearchResult.getOperationStatus(), updateAlt); } } catch (final EidasSAuthenticationException e) { throw new WorkflowException("kittMatchedIdentitiess", e.getMessage(), diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java index c720cb7f..9564a8fc 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java @@ -122,8 +122,9 @@ public class InitialSearchTask extends AbstractAuthServletTask { if (resultCount == 0) { step6CountrySpecificSearch(executionContext, searchResult.getOperationStatus(), eidasData); - } else if (resultCount == 1) { - foundMatchFinalizeTask(searchResult, eidasData); + } else if (resultCount == 1) { + RegisterResult updatedResult = step3CheckRegisterUpdateNecessary(searchResult, eidasData); + foundMatchFinalizeTask(updatedResult, eidasData); } else { throw new WorkflowException("step2RegisterSearchWithPersonIdentifier", @@ -146,10 +147,12 @@ public class InitialSearchTask extends AbstractAuthServletTask { if (searchResult.getResultCount() == 0) { log.trace("'step6CountrySpecificSearch' ends with no result. Forward to next matching step ... "); step8RegisterSearchWithMds(executionContext, searchResult.getOperationStatus(), eidasData); + } else if (searchResult.getResultCount() == 1) { log.trace("'step6CountrySpecificSearch' finds a person. Forward to 'step7aKittProcess' step ... "); - registerSearchService.step7aKittProcess(searchResult, eidasData); - foundMatchFinalizeTask(searchResult, eidasData); + RegisterStatusResults updatedResult = registerSearchService.step7aKittProcess(searchResult, eidasData); + foundMatchFinalizeTask(updatedResult.getResult(), eidasData); + } else { throw new WorkflowException("step6CountrySpecificSearch", "More than one entry with unique country-specific information", true); @@ -172,29 +175,26 @@ public class InitialSearchTask extends AbstractAuthServletTask { } } - private void foundMatchFinalizeTask(RegisterStatusResults searchResult, SimpleEidasData eidasData) - throws WorkflowException, EaafStorageException { - RegisterResult updatedResult = step3CheckRegisterUpdateNecessary(searchResult.getResult(), eidasData); - MatchedPersonResult result = MatchedPersonResult.generateFormMatchingResult( - updatedResult, eidasData.getCitizenCountryCode()); - MatchingTaskUtils.storeFinalMatchingResult(pendingReq, result); - } - - private RegisterResult step3CheckRegisterUpdateNecessary(RegisterResult searchResult, - SimpleEidasData eidasData) { + private RegisterResult step3CheckRegisterUpdateNecessary( + RegisterStatusResults searchResult, SimpleEidasData eidasData) throws WorkflowException { log.trace("Starting step3CheckRegisterUpdateNecessary"); - if (!eidasData.equalsRegisterData(searchResult)) { - log.info("Skipping update-register-information step, because it's not supported yet"); - - //TODO: update of ERnP information are allowed. Add ERnP update-step. Maybe we can use regular KITT steps - + if (!eidasData.equalsRegisterData(searchResult.getResult())) { + log.debug("PersonalIdentifier match but MDS or other information changed. Starting update process ... "); + return registerSearchService.step7aKittProcess(searchResult, eidasData).getResult(); - return searchResult; } else { log.debug("Register information match to eIDAS information. No update required"); - return searchResult; + return searchResult.getResult(); } } + + private void foundMatchFinalizeTask(RegisterResult updatedResult, SimpleEidasData eidasData) + throws WorkflowException, EaafStorageException { + MatchedPersonResult result = + MatchedPersonResult.generateFormMatchingResult(updatedResult, eidasData.getCitizenCountryCode()); + MatchingTaskUtils.storeFinalMatchingResult(pendingReq, result); + + } @NotNull private SimpleEidasData convertEidasAttrToSimpleData() diff --git a/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskTest.java b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskTest.java index b3ba8a9d..74ac065e 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskTest.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskTest.java @@ -48,7 +48,6 @@ import org.apache.commons.lang3.RandomStringUtils; import org.jetbrains.annotations.NotNull; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -181,15 +180,17 @@ public class InitialSearchTaskTest { @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(randomRegisterResult(oldGivenName, randomBpk))); + .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())) - .thenThrow(new IllegalStateException("ZMR update should not be neccessary")); + .thenReturn(zmrRegisterResult(firstZmrResult)); Mockito.when(ernpClient.searchWithPersonIdentifier(randomPseudonym, DE)) .thenReturn(emptyErnpRegisterResult()); @@ -213,17 +214,33 @@ public class InitialSearchTaskTest { * * @throws EidasSAuthenticationException */ - @Ignore @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); @@ -798,6 +815,18 @@ public class InitialSearchTaskTest { .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); diff --git a/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskWithRegistersTest.java b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskWithRegistersTest.java index 0e95f718..7f27a17c 100644 --- a/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskWithRegistersTest.java +++ b/eidas_modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/InitialSearchTaskWithRegistersTest.java @@ -190,10 +190,13 @@ public class InitialSearchTaskWithRegistersTest { /** * One match, but register update needed + *

+ * Check if ZMR update request is NOT executed in case of MDS change! + *

*/ @Test @DirtiesContext - public void singlePersonalIdMatchUpdateNecessary_Zmr() throws Exception { + public void singlePersonalIdMatchUpdateNecessary_ZmrNotDone() throws Exception { String oldGivenName = "XXXClaus - Maria"; @@ -208,7 +211,12 @@ public class InitialSearchTaskWithRegistersTest { // inject response 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")); + + //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")); // execute test @@ -220,13 +228,72 @@ public class InitialSearchTaskWithRegistersTest { oldGivenName, "1994-12-31", DE); // validate request - assertEquals("wrong number of req.", 1, zmrReq.getAllValues().size()); + assertEquals("wrong number of req.", 2, zmrReq.getAllValues().size()); assertNotNull("Personensuche req.", zmrReq.getValue().getPersonSuchenRequest()); - checkBasicRequestParameters(zmrReq.getValue(), ZmrClientTest.PROCESS_TASK_SEARCH, null, "jUnit123456"); + checkBasicRequestParameters(zmrReq.getValue(), ZmrClientTest.PROCESS_TASK_SEARCH, + new BigInteger("367100000000079"), "jUnit123456"); } + /** + * One match, but register update needed + *

+ * Check if ZMR update request is executed in case of other data than MDS change! + *

+ */ + @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 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")); + + + // 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", 1, + zmrReq.getAllValues().get(2).getPersonAendernRequest().getEidasIdentitaetAnlage().size()); + assertEquals("eIDAS attribute to add - Type", "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", + zmrReq.getAllValues().get(2).getPersonAendernRequest().getEidasIdentitaetAnlage().get(0).getEidasArt()); + assertEquals("eIDAS attribute to add - Value", placeOfBirth, + zmrReq.getAllValues().get(2).getPersonAendernRequest().getEidasIdentitaetAnlage().get(0).getEidasWert()); + assertNull("ZMR update MDS", zmrReq.getAllValues().get(2).getPersonAendernRequest().getPersonAenderung()); + + } + + /** * Two matches by PersonalId found in ZMR * diff --git a/eidas_modules/authmodule-eIDAS-v2/src/test/resources/data/zmr/seq_1-8_search_with_personalId_only_resp_no_additional_attributes.xml b/eidas_modules/authmodule-eIDAS-v2/src/test/resources/data/zmr/seq_1-8_search_with_personalId_only_resp_no_additional_attributes.xml new file mode 100644 index 00000000..6551cdd3 --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/test/resources/data/zmr/seq_1-8_search_with_personalId_only_resp_no_additional_attributes.xml @@ -0,0 +1,221 @@ + + + + GP_EIDAS + 367100000000079 + 0 + + + ZMR-Server Version: 5.9.0.0-SNAPSHOT + 2021-11-12T08:24:40.985 + 1877300000000139 + + + + + Searching PersonIdentifier + + true + false + + + false + + 10 + + + + + 5020 + Person gefunden. + + + 1 + 0 + 0 + 1 + + + + + 2021-11-12T08:24:39.695 + + + + 44453600000000697 + 2020-02-05T13:07:06.311 + + 2020-02-05T13:07:06.311 + SONSTIGES + Sonstiges + Testerperson + + + 109091 + + + + 000430320173 + + + UgeknNsc26lVuB7U/uYGVmWtnnA= + urn:publicid:gv.at:cdid+ZP + + + XXXClaus - Maria + XXXvon Brandenburg + + unbekannt + männlich + 1994-12-31 + Wien + Wien + Österreich + + AUT + Österreich + + + 44453600000000727 + 2020-02-05T13:07:06.311 + + 2020-02-05T13:07:06.311 + STAATSANGEH_ANLEGEN + Staatsangehörigkeit anlegen + Testerperson + + + 109091 + + + + + + + + + 1879000000000001 + 2021-11-12T08:24:39.695 + + 2021-11-12T08:24:39.695 + EIDAS_ANLEGEN + KITT for eIDAS Matching + + + 101179 + + eidtapp@bmi.gv.at + + + http://eidas.europa.eu/attributes/naturalperson/BirthName + DE + + XXXvon Heuburg + 9999-12-31 + 9999-12-31 + + + + + 1879000000000005 + 2021-11-12T08:24:39.695 + + 2021-11-12T08:24:39.695 + EIDAS_ANLEGEN + KITT for eIDAS Matching + + + 101179 + + eidtapp@bmi.gv.at + + + http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier + DE + + 7cEYWithDEElementsasdfsafsaf4CDVzNT4E7cjkU4VqForjUnit + 9999-12-31 + 9999-12-31 + + + + + + + 2020-02-05T13:07:06.311 + + + + 44453500000005242 + 2020-02-05T13:07:06.311 + + 2020-02-05T13:07:06.311 + WSANM + Wohnsitz anmelden + + + 109091 + + + + + + 0088 + Testgemeinde + 09988 + Testort A + + Testgasse + 1a-2b + Stg. 3c-4d + 5 + H + false + 0001 + + T800001 + 001 + T800001 + + + + HST111WWW + + T8001 + T80001 + T80000000001 + T80000000002 + + H + Testpostort + + 2020-02-05T13:07:06.311 + WSANM + Wohnsitz anmelden + + + + 44453500000005262 + 2020-02-05T13:07:06.311 + + 2020-02-05T13:07:06.311 + AUSK_SPERRE_SETZ + Auskunftssperre setzen + + + 109091 + + + + 2020-02-05T13:07:06.311 + 9999-12-31T23:59:59.000 + ASMG + Auskunftssperre nach § 18 / 2ff MeldeG + automatische Auskunftssperre + + + + + + + -- cgit v1.2.3