From 2f69fe3154251d4c4e36eca874039b3227d88fcd Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Mon, 17 Oct 2022 12:52:00 +0200 Subject: freat(ernp): update ERnP client to distiguish between active ERnP entries and closed ERnP entries that kitt to ZMR entries --- .../auth/eidas/v2/clients/ernp/ErnpRestClient.java | 149 ++++++++++++++++----- .../eidas/v2/dao/ErnpPersonRegisterResult.java | 30 +++++ 2 files changed, 145 insertions(+), 34 deletions(-) create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/ErnpPersonRegisterResult.java (limited to 'modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific') diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/ernp/ErnpRestClient.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/ernp/ErnpRestClient.java index 4212aae8..5d3f43e6 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/ernp/ErnpRestClient.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/ernp/ErnpRestClient.java @@ -14,12 +14,14 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.PostConstruct; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.apache.http.client.HttpClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; @@ -40,6 +42,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.ErnpPersonRegisterResult; 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.dao.SimpleEidasData.SimpleEidasDataBuilder; @@ -78,7 +81,6 @@ import at.gv.egiz.eaaf.core.impl.http.HttpClientConfiguration; import at.gv.egiz.eaaf.core.impl.http.HttpClientConfiguration.ClientAuthMode; import at.gv.egiz.eaaf.core.impl.http.IHttpClientFactory; import at.gv.egiz.eaaf.core.impl.utils.TransactionIdUtils; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -120,6 +122,9 @@ public class ErnpRestClient implements IErnpClient { // HTTP header-names from ERnP response private static final String ERNP_RESPONSE_HEADER_SERVER_ID = "Server-Request-Id"; + // ERnP person type that indicates mark a person as ZMR entry + private static final String ERNP_RESPONSE_OPERATION_ZMR_FORWARD = "PersonUebernehmen"; + @Autowired IConfiguration basicConfig; @@ -265,7 +270,7 @@ public class ErnpRestClient implements IErnpClient { if (eidasDocumentToAdd.isEmpty() && mdsToUpdate == null) { log.info("Find no eIDAS document or MDS for update during: {}. Nothing todo on ERnP side", PROCESS_KITT_GENERAL); - return new ErnpRegisterResult(Arrays.asList(registerResult)); + return new ErnpRegisterResult(Arrays.asList(new ErnpPersonRegisterResult(registerResult, false))); } else { log.info("Find #{} eIDAS documents for update during: {}", eidasDocumentToAdd.size(), PROCESS_KITT_GENERAL); @@ -386,30 +391,32 @@ public class ErnpRestClient implements IErnpClient { resp.getPerson().size(), processStepFiendlyname); if (forceSinglePersonMatch) { - return new ErnpRegisterResult(processSearchPersonResponseSingleResult( - resp.getPerson(), citizenCountryCode, processStepFiendlyname)); + return processSearchPersonResponseSingleResult( + resp.getPerson(), citizenCountryCode, processStepFiendlyname); } else { - return new ErnpRegisterResult(processSearchPersonResponse( - resp.getPerson(), citizenCountryCode)); + return processSearchPersonResponse( + resp.getPerson(), citizenCountryCode); } } } @Nonnull - private List processSearchPersonResponse( + private ErnpRegisterResult processSearchPersonResponse( @Nonnull List list, @Nonnull String citizenCountryCode) throws EaafAuthenticationException { - return list.stream() + List ernpResult = list.stream() .map(el -> mapErnpResponseToRegisterResult(el, citizenCountryCode)) .filter(Objects::nonNull) .collect(Collectors.toList()); + log.info("Get #{} ERnP results after post-processing", ernpResult.size()); + return new ErnpRegisterResult(ernpResult); } @NonNull - private List processSearchPersonResponseSingleResult( + private ErnpRegisterResult processSearchPersonResponseSingleResult( @Nonnull List persons, @Nonnull String citizenCountryCode, String processStepFiendlyname) throws EaafAuthenticationException { if (persons.size() > 1) { @@ -418,7 +425,8 @@ public class ErnpRestClient implements IErnpClient { "Find more-than-one ERnP entry with search criteria that has to be unique", true); } else { - RegisterResult activeResult = mapErnpResponseToRegisterResult(persons.get(0), citizenCountryCode); + ErnpPersonRegisterResult activeResult = + mapErnpResponseToRegisterResult(persons.get(0), citizenCountryCode); if (activeResult == null) { log.error("ERnP entry, which was selected by matching, looks already closed. " + "Automated operations on closed entries not supported my matching"); @@ -426,40 +434,41 @@ public class ErnpRestClient implements IErnpClient { "ERnP entry, which was selected by matching, is not active any more.", true); } - - return Arrays.asList(activeResult); - + + return new ErnpRegisterResult(Arrays.asList(activeResult)); + } } - - /** * Process a single Person data-set from ERnP. * * @param personEl Person data-set from ERnP * @param citizenCountryCode Country-Code of the citizen - * @return Simplified register result, or null if the person data-set is not active anymore + * @return {@link Pair} of Simplified register result and 'isZMREntry' flag, + * or null if the person data-set is not active anymore * @throws EaafAuthenticationException In case of a validation error */ @Nullable - private RegisterResult mapErnpResponseToRegisterResult(@Nonnull Person person, + private ErnpPersonRegisterResult mapErnpResponseToRegisterResult(@Nonnull Person person, @Nonnull String citizenCountryCode) { if (checkIfPersonIsActive(person)) { // build result - return RegisterResult.builder() - .pseudonym(selectAllEidasDocument(person, citizenCountryCode, - EidasConstants.eIDAS_ATTRURN_PERSONALIDENTIFIER)) - .familyName(person.getPersonendaten().getFamilienname()) - .givenName(person.getPersonendaten().getVorname()) - .dateOfBirth(getTextualBirthday(person.getPersonendaten().getGeburtsdatum())) - .bpk(person.getPersonendaten().getBpkZp()) - .placeOfBirth(selectSingleEidasDocument(person, citizenCountryCode, - EidasConstants.eIDAS_ATTRURN_PLACEOFBIRTH)) - .birthName(selectSingleEidasDocument(person, citizenCountryCode, - EidasConstants.eIDAS_ATTRURN_BIRTHNAME)) - .build(); + return new ErnpPersonRegisterResult( + RegisterResult.builder() + .pseudonym(selectAllEidasDocument(person, citizenCountryCode, + EidasConstants.eIDAS_ATTRURN_PERSONALIDENTIFIER)) + .familyName(person.getPersonendaten().getFamilienname()) + .givenName(person.getPersonendaten().getVorname()) + .dateOfBirth(getTextualBirthday(person.getPersonendaten().getGeburtsdatum())) + .bpk(person.getPersonendaten().getBpkZp()) + .placeOfBirth(selectSingleEidasDocument(person, citizenCountryCode, + EidasConstants.eIDAS_ATTRURN_PLACEOFBIRTH)) + .birthName(selectSingleEidasDocument(person, citizenCountryCode, + EidasConstants.eIDAS_ATTRURN_BIRTHNAME)) + .build(), + isPersonMovedToZmr(person)); } else { log.debug("Entity is not valid anymore. Skip it ... "); @@ -473,7 +482,12 @@ public class ErnpRestClient implements IErnpClient { if (person.getGueltigBis() != null) { LocalDateTime validTo = person.getGueltigBis().toLocalDateTime(); LocalDateTime now = LocalDateTime.now(); - if (validTo.isBefore(now)) { + + if (isPersonMovedToZmr(person)) { + log.debug("Entity has a 'validTo' element, but it's marked as {}. Use it as a ZMR entry", + ERNP_RESPONSE_OPERATION_ZMR_FORWARD); + + } else if (validTo.isBefore(now)) { log.warn("Enity was valid to: {}, but now its: {}. Ignore that entry", validTo, now); return false; @@ -491,6 +505,20 @@ public class ErnpRestClient implements IErnpClient { } + /** + * Check if ERnP person is marked as KITT to ZMR entry. + * + *

If person is marked as ZMR person then it has the same quality as a ZMR match.

+ * + * @param person ERnP person result + * @return true if the person should be in ERnP, otherwise false + */ + private boolean isPersonMovedToZmr(Person person) { + return person.getLetzteOperation() != null + && ERNP_RESPONSE_OPERATION_ZMR_FORWARD.equals(person.getLetzteOperation().getVorgang()); + + } + private Suchdaten mapCountrySpecificSearchData(PersonSuchenRequest personSearchDao) { final Suchdaten searchInfos = new Suchdaten(); searchInfos.setFamilienname(personSearchDao.getNatuerlichePerson().getPersonenName().getFamilienname()); @@ -541,8 +569,8 @@ public class ErnpRestClient implements IErnpClient { generic.getClientRequestTime(), generic.getClientRequestId(), ernpReq); log.trace("Receive response from ERnP for '{}' operation", PROCESS_KITT_IDENITIES_UPDATE); - return new ErnpRegisterResult(Arrays.asList( - mapErnpResponseToRegisterResult(ernpResp.getPerson(), citizenCountryCode))); + return new ErnpRegisterResult(Collections.singletonList( + mapErnpResponseToRegisterResult(ernpResp.getPerson(), citizenCountryCode))); } @@ -896,11 +924,64 @@ public class ErnpRestClient implements IErnpClient { return config; } - @AllArgsConstructor @Getter public static class ErnpRegisterResult { - private final List personResult; + private List fullErnpResults; + + /** + * Build reduced ERnP register result. + * @param list {@link List} of ERnP entities + */ + public ErnpRegisterResult(List list) { + fullErnpResults = list; + + } + + /** + * Get all active ERnP results. + * + * @return ERnP entities + */ + public Stream getPersonResultStream() { + return fullErnpResults.stream() + .filter(el -> !el.isZmrEntryNow()); + + } + + /** + * Get all active ERnP results. + * + * @return ERnP entities + */ + public List getPersonResult() { + return getPersonResultStream() + .collect(Collectors.toList()); + + } + + /** + * Get all ERnP results that are kitted to ZMR entries. + * + * @return entities that are in ZMR now + */ + public Stream getZmrPersonResultStream() { + return fullErnpResults.stream() + .filter(el -> el.isZmrEntryNow()); + + } + + /** + * Get all ERnP results that are kitted to ZMR entries. + * + * @return entities that are in ZMR now + */ + public List getZmrPersonResult() { + return getZmrPersonResultStream() + .collect(Collectors.toList()); + + } + } private GenericRequestParams buildGenericRequestParameters() { diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/ErnpPersonRegisterResult.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/ErnpPersonRegisterResult.java new file mode 100644 index 00000000..1b9454db --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/ErnpPersonRegisterResult.java @@ -0,0 +1,30 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.dao; + +import lombok.Getter; + +/** + * ERnP specific extension of a register result. + * + * @author tlenz + * + */ +@Getter +public class ErnpPersonRegisterResult extends RegisterResult { + + private static final long serialVersionUID = -1250543763613825226L; + + /** + * true in case of person is still found in ERnP, but is in ZMR now. + */ + private final boolean zmrEntryNow; + + public ErnpPersonRegisterResult(RegisterResult result, boolean isZmrEntryNow) { + super(result.getPseudonym(), result.getGivenName(), result.getFamilyName(), result.getDateOfBirth(), + result.getPlaceOfBirth(), result.getBirthName(), result.getTaxNumber(), result.getAddress(), + result.getBpk()); + + zmrEntryNow = isZmrEntryNow; + + } + +} -- cgit v1.2.3