diff options
Diffstat (limited to 'modules/authmodule-eIDAS-v2/src')
16 files changed, 288 insertions, 47 deletions
diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java index e766fc49..3c41bf0a 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java @@ -128,7 +128,15 @@ public class Constants { public static final String CONIG_PROPS_EIDAS_COMMON_CLIENT_SSL_TRUSTSTORE_NAME = CONIG_PROPS_EIDAS_COMMON_CLIENT + ".ssl.trustStore.name"; - + /** Enable / Disable matching based on address search. **/ + public static final String CONFIG_PROP_MATCHING_BY_ADDRESS = + EidasConstants.CONIG_PROPS_EIDAS_PREFIX + ".matching.byaddress.enable"; + + public static final String CONFIG_PROP_MATCHING_BY_ADDRESS_MAX_RESULTS = + EidasConstants.CONIG_PROPS_EIDAS_PREFIX + ".matching.byaddress.maxresults"; + public static final String DEFAULT_MATCHING_BY_ADDRESS_MAX_RESULTS = "250"; + + // ZMR Client configuration properties public static final String CONIG_PROPS_EIDAS_ZMRCLIENT = EidasConstants.CONIG_PROPS_EIDAS_PREFIX + ".zmrclient"; @@ -312,6 +320,7 @@ public class Constants { // UI options + public static final String HTML_FORM_ENABLE_MATCHING_BY_ADDRESS_SEARCH = "enableMatchingByAddressSearch"; public static final String HTML_FORM_CREATE_NEW_ERNP_ENTRY = "createNewErnpEntry"; public static final String HTML_FORM_ADVANCED_MATCHING_FAILED = "advancedMatchingFailed"; public static final String HTML_FORM_ADVANCED_MATCHING_FAILED_REASON = diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/controller/AdresssucheController.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/controller/AdresssucheController.java index 6f49c700..a08128d3 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/controller/AdresssucheController.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/controller/AdresssucheController.java @@ -25,6 +25,7 @@ package at.asitplus.eidas.specific.modules.auth.eidas.v2.controller; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -40,12 +41,14 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrAddressSoapClient; import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; 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.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; import lombok.AllArgsConstructor; @@ -67,17 +70,19 @@ public class AdresssucheController { public static final String PARAM_VILLAGE = "village"; public static final String PARAM_STREET = "street"; public static final String PARAM_NUMBER = "number"; - + + @Autowired IConfiguration basicConfig; + @Autowired private ZmrAddressSoapClient client; @Autowired private IPendingRequestIdGenerationStrategy pendingReqGeneration; - + /** * Performs search for addresses in ZMR. */ - @RequestMapping(value = {MsEidasNodeConstants.ENDPOINT_RESIDENCY_SEARCH}, method = {RequestMethod.POST}) + @RequestMapping(value = { MsEidasNodeConstants.ENDPOINT_RESIDENCY_SEARCH }, method = { RequestMethod.POST }) public ResponseEntity<AdresssucheResult> search( @RequestParam(PARAM_POSTLEITZAHL) String postleitzahl, @RequestParam(PARAM_MUNIPICALITY) String municipality, @@ -90,26 +95,26 @@ public class AdresssucheController { municipality.replaceAll("[\r\n]", ""), village.replaceAll("[\r\n]", ""), street.replaceAll("[\r\n]", ""), - number.replaceAll("[\r\n]", "")); + number.replaceAll("[\r\n]", "")); try { pendingReqGeneration.validateAndGetPendingRequestId(pendingId); - - } catch (PendingReqIdValidationException e) { + + } catch (final PendingReqIdValidationException e) { log.warn("Search with pendingId '{}' is not valid", pendingId.replaceAll("[\r\n]", "")); return ResponseEntity.badRequest().build(); - + } - + try { - Adressdaten searchInput = buildSearchInput(postleitzahl, municipality, village, street, number); - ZmrAddressSoapClient.AddressInfo searchOutput = client.searchAddress(searchInput); - AdresssucheResult output = buildResponse(searchOutput); + final Adressdaten searchInput = buildSearchInput(postleitzahl, municipality, village, street, number); + final ZmrAddressSoapClient.AddressInfo searchOutput = client.searchAddress(searchInput); + final AdresssucheResult output = buildResponse(searchOutput); return ResponseEntity.ok(output); - - } catch (EidasSAuthenticationException e) { + + } catch (final EidasSAuthenticationException e) { log.warn("Search failed", e); return ResponseEntity.badRequest().build(); - + } } @@ -117,27 +122,45 @@ public class AdresssucheController { if (searchOutput.getPersonResult().isEmpty()) { log.warn("No result from ZMR"); return new AdresssucheResult(Collections.emptyList(), 0); - + } - + log.info("Result level is {}", searchOutput.getLevel()); - Set<AdresssucheOutput> result = searchOutput.getPersonResult().stream() + final Set<AdresssucheOutput> result = searchOutput.getPersonResult().stream() .map(Adressdaten::getPostAdresse) .map(it -> new AdresssucheOutput(it.getPostleitzahl(), it.getGemeinde(), it.getOrtschaft(), it.getZustelladresse().getStrassenname(), it.getZustelladresse().getOrientierungsnummer())) .collect(Collectors.toSet()); // TODO Add configuration option for the limit of 30 - List<AdresssucheOutput> sorted = result.stream().sorted().limit(30).collect(Collectors.toList()); - return new AdresssucheResult(sorted, result.size()); + + final List<AdresssucheOutput> sorted = result.stream() + .sorted() + .limit(getMaxResults()) + .collect(Collectors.toList()); + return new AdresssucheResult(sorted, result.size()); + + } + + private long getMaxResults() { + String maxSearchResults = basicConfig.getBasicConfiguration( + Constants.CONFIG_PROP_MATCHING_BY_ADDRESS_MAX_RESULTS, + Constants.DEFAULT_MATCHING_BY_ADDRESS_MAX_RESULTS); + try { + return Long.valueOf(maxSearchResults); + + } catch (Exception e) { + log.warn("Invalid number of max. addressSearchResults. Using default value", e); + return Long.valueOf(Constants.DEFAULT_MATCHING_BY_ADDRESS_MAX_RESULTS); + } } private Adressdaten buildSearchInput(String postleitzahl, - String municipality, - String village, - String street, - String number) { - PostAdresseTyp postAdresse = new PostAdresseTyp(); + String municipality, + String village, + String street, + String number) { + final PostAdresseTyp postAdresse = new PostAdresseTyp(); if (StringUtils.isNotBlank(postleitzahl)) { postAdresse.setPostleitzahl(postleitzahl); } @@ -148,7 +171,7 @@ public class AdresssucheController { postAdresse.setOrtschaft(village); } if (StringUtils.isNotBlank(street) || StringUtils.isNotBlank(number)) { - ZustelladresseTyp zustelladresse = new ZustelladresseTyp(); + final ZustelladresseTyp zustelladresse = new ZustelladresseTyp(); if (StringUtils.isNotBlank(street)) { zustelladresse.setStrassenname(street); } @@ -157,10 +180,10 @@ public class AdresssucheController { } postAdresse.setZustelladresse(zustelladresse); } - Adressdaten searchInput = new Adressdaten(); + final Adressdaten searchInput = new Adressdaten(); searchInput.setPostAdresse(postAdresse); return searchInput; - + } @Data @@ -187,9 +210,41 @@ public class AdresssucheController { .append(this.municipality, o.municipality) .append(this.village, o.village) .append(this.street, o.street) - .append(this.number, o.number) + + /* + * TODO: implement better sort method, because current version results to 1, 10, + * 11, .... 2, 20, 21 + */ + .appendSuper(getCustomIntegerComperatpr().compare(this.number, o.number)) + .toComparison(); } + + private Comparator<String> getCustomIntegerComperatpr() { + return new Comparator<String>() { + @Override + public int compare(String o1, String o2) { + return extractInt(o1) - extractInt(o2); + } + + int extractInt(String s) { + if (StringUtils.isNotEmpty(s)) { + final String num = s.replaceAll("\\D", ""); + try { + // return 0 if no digits found + return num.isEmpty() ? 0 : Integer.parseInt(num); + + } catch (Exception e) { + log.info("Can not parse number from ZMR", e); + + } + } + + return 0; + + } + }; + } } } diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SelectedLoginMethod.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SelectedLoginMethod.java index 70904e4f..c8a2da88 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SelectedLoginMethod.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SelectedLoginMethod.java @@ -1,5 +1,5 @@ package at.asitplus.eidas.specific.modules.auth.eidas.v2.dao; public enum SelectedLoginMethod { - EIDAS_LOGIN, MOBILE_PHONE_SIGNATURE_LOGIN, NO_OTHER_LOGIN, ADD_ME_AS_NEW + EIDAS_LOGIN, MOBILE_PHONE_SIGNATURE_LOGIN, NO_OTHER_LOGIN, ADD_ME_AS_NEW, REQUESTING_NEW_ENTRY, STOP_MATCHING_PROCESS } diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java index e8fb5b6b..dd46bfea 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java @@ -36,6 +36,7 @@ import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Component; +import at.asitplus.eidas.specific.core.MsEidasNodeConstants.MatchingStates; 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; @@ -243,6 +244,7 @@ public class AlternativeSearchTask extends AbstractAuthServletTask { throws WorkflowException, EaafStorageException { MatchedPersonResult result = MatchedPersonResult.generateFormMatchingResult( searchResult.getResult(), eidasData.getCitizenCountryCode()); + MatchingTaskUtils.setMatchingState(pendingReq, MatchingStates.BY_EIDAS); MatchingTaskUtils.storeFinalMatchingResult(pendingReq, result); //remove intermediate matching-state diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateNewErnpEntryTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateNewErnpEntryTask.java index c7843be5..563a66ba 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateNewErnpEntryTask.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateNewErnpEntryTask.java @@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import at.asitplus.eidas.specific.core.MsEidasNodeConstants.MatchingStates; import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; 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; @@ -91,7 +92,8 @@ public class CreateNewErnpEntryTask extends AbstractAuthServletTask { } // finish matching process, because new user-entry uniquly matches - log.info("User successfully registerred into ERnP and matching tasks are finished "); + log.info("User successfully registerred into ERnP and matching tasks are finished "); + MatchingTaskUtils.setMatchingState(pendingReq, MatchingStates.BY_NEW_ERNP_ENTRY); MatchingTaskUtils.storeFinalMatchingResult(pendingReq, MatchedPersonResult.generateFormMatchingResult( resp.getPersonResult().get(0), simpleEidasData.getCitizenCountryCode())); diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateOtherLoginMethodGuiTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateOtherLoginMethodGuiTask.java index a90c5929..94b29b8e 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateOtherLoginMethodGuiTask.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateOtherLoginMethodGuiTask.java @@ -87,6 +87,11 @@ public class GenerateOtherLoginMethodGuiTask extends AbstractLocaleAuthServletTa } } + // inject flag for matching-by-address allowed + config.putCustomParameter(AbstractGuiFormBuilderConfiguration.PARAM_GROUP_UIOPTIONS, + Constants.HTML_FORM_ENABLE_MATCHING_BY_ADDRESS_SEARCH, + String.valueOf(basicConfig.getBasicConfigurationBoolean(Constants.CONFIG_PROP_MATCHING_BY_ADDRESS))); + // inject request to create a new ERnP entry config.putCustomParameter(AbstractGuiFormBuilderConfiguration.PARAM_GROUP_UIOPTIONS, Constants.HTML_FORM_CREATE_NEW_ERNP_ENTRY, diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java index 3a775837..8e6c7790 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java @@ -34,6 +34,7 @@ import javax.servlet.http.HttpServletResponse; import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Component; +import at.asitplus.eidas.specific.core.MsEidasNodeConstants.MatchingStates; 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.RegisterResult; @@ -123,7 +124,8 @@ public class InitialSearchTask extends AbstractAuthServletTask { step6CountrySpecificSearch(executionContext, searchResult.getOperationStatus(), eidasData); } else if (resultCount == 1) { - RegisterResult updatedResult = step3CheckRegisterUpdateNecessary(searchResult, eidasData); + RegisterResult updatedResult = step3CheckRegisterUpdateNecessary(searchResult, eidasData); + MatchingTaskUtils.setMatchingState(pendingReq, MatchingStates.BY_PERSONALID); foundMatchFinalizeTask(updatedResult, eidasData); } else { @@ -151,6 +153,7 @@ public class InitialSearchTask extends AbstractAuthServletTask { } else if (searchResult.getResultCount() == 1) { log.trace("'step6CountrySpecificSearch' finds a person. Forward to 'step7aKittProcess' step ... "); RegisterStatusResults updatedResult = registerSearchService.step7aKittProcess(searchResult, eidasData); + MatchingTaskUtils.setMatchingState(pendingReq, MatchingStates.BY_COUNTRY_SPECIFIC); foundMatchFinalizeTask(updatedResult.getResult(), eidasData); } else { diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java index b8fe12fe..403c3355 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java @@ -41,6 +41,7 @@ import org.springframework.stereotype.Component; import com.google.common.collect.Sets; +import at.asitplus.eidas.specific.core.MsEidasNodeConstants.MatchingStates; 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; @@ -186,7 +187,8 @@ public class ReceiveAustrianResidenceGuiResponseTask extends AbstractLocaleAuthS // update register information RegisterStatusResults updateResult = registerSearchService.step7aKittProcess(residencyResult, eidasData); - // store updated result to re-used in CreateIdentityLink step, because there we need bPK and MDS + // store updated result to re-used in CreateIdentityLink step, because there we need bPK and MDS + MatchingTaskUtils.setMatchingState(pendingReq, MatchingStates.BY_ADDRESS); MatchingTaskUtils.storeFinalMatchingResult(pendingReq, MatchedPersonResult.generateFormMatchingResult( updateResult.getResult(), eidasData.getCitizenCountryCode())); @@ -194,6 +196,7 @@ public class ReceiveAustrianResidenceGuiResponseTask extends AbstractLocaleAuthS } else { log.warn("Suspect state FOUND. Matching by residence was neccessary but NO register-update are required!"); // no update required. Data can be used as it is. + MatchingTaskUtils.setMatchingState(pendingReq, MatchingStates.BY_ADDRESS); MatchingTaskUtils.storeFinalMatchingResult(pendingReq, MatchedPersonResult.generateFormMatchingResult( residencyResult.getResult(), eidasData.getCitizenCountryCode())); diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java index b212d133..57790b01 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java @@ -47,6 +47,7 @@ import org.opensaml.saml.saml2.core.StatusCode; import org.opensaml.saml.saml2.metadata.IDPSSODescriptor; import org.springframework.stereotype.Component; +import at.asitplus.eidas.specific.core.MsEidasNodeConstants.MatchingStates; 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.RegisterResult; @@ -204,6 +205,7 @@ public class ReceiveMobilePhoneSignatureResponseTask extends AbstractAuthServlet registerSearchService.step7aKittProcess(registerResult, eidasData); // store search result to re-used in CreateIdentityLink step, because there we need bPK and MDS + MatchingTaskUtils.setMatchingState(pendingReq, MatchingStates.BY_ID_AUSTRIA); MatchingTaskUtils.storeFinalMatchingResult(pendingReq, MatchedPersonResult.generateFormMatchingResult(registerResult.getResult(), eidasData.getCitizenCountryCode())); diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveOtherLoginMethodGuiResponseTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveOtherLoginMethodGuiResponseTask.java index 184ad499..03414f9e 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveOtherLoginMethodGuiResponseTask.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveOtherLoginMethodGuiResponseTask.java @@ -34,9 +34,13 @@ import org.springframework.stereotype.Component; import com.google.common.collect.Sets; +import at.asitplus.eidas.specific.core.MsEidasNodeConstants.MatchingStates; 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.utils.MatchingTaskUtils; 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.controller.tasks.AbstractLocaleAuthServletTask; import lombok.extern.slf4j.Slf4j; @@ -73,15 +77,18 @@ public class ReceiveOtherLoginMethodGuiResponseTask extends AbstractLocaleAuthSe @Override public void executeWithLocale(ExecutionContext executionContext, HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) throws TaskExecutionException { try { SelectedLoginMethod selection = SelectedLoginMethod.valueOf(extractUserSelection(request)); executionContext.put(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK, false); executionContext.put(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER, selection.name()); executionContext.remove(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED); - executionContext.remove(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON); - transitionToNextTask(executionContext, selection); + executionContext.remove(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED_REASON); + transitionToNextTask(executionContext, selection, request, response); + } catch (TaskExecutionException e) { + throw e; + } catch (final Exception e) { log.error("Parsing selected login method FAILED.", e); executionContext.put(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED, true); @@ -100,8 +107,15 @@ public class ReceiveOtherLoginMethodGuiResponseTask extends AbstractLocaleAuthSe return null; } - private void transitionToNextTask(ExecutionContext executionContext, SelectedLoginMethod selection) { + private void transitionToNextTask(ExecutionContext executionContext, SelectedLoginMethod selection, + HttpServletRequest request, HttpServletResponse response) throws TaskExecutionException { switch (selection) { + case STOP_MATCHING_PROCESS: + log.info("Matching process WAS stopped by entity. Stopping auth. process ... "); + MatchingTaskUtils.setMatchingState(pendingReq, MatchingStates.CANCELED_BY_USER); + stopProcessFromUserDecision(executionContext, request, response); + return; + case EIDAS_LOGIN: executionContext.put(Constants.TRANSITION_TO_GENERATE_EIDAS_LOGIN, true); return; @@ -111,9 +125,22 @@ public class ReceiveOtherLoginMethodGuiResponseTask extends AbstractLocaleAuthSe return; case NO_OTHER_LOGIN: + if (!authConfig.getBasicConfigurationBoolean(Constants.CONFIG_PROP_MATCHING_BY_ADDRESS)) { + log.error("Matching by address was requested but it's disabled by configuration!"); + throw new TaskExecutionException(pendingReq, + "Matching by address was requested but it's disabled by configuration!", + new EaafException("module.eidasauth.matching.98")); + + } + executionContext.put(Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK, true); return; + + case REQUESTING_NEW_ENTRY: + executionContext.put(Constants.TRANSITION_TO_REQUESTING_NEW_ERNP_ENTRY_TASK, true); + return; + case ADD_ME_AS_NEW: executionContext.put(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK, true); return; diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java index c8a1f190..c350cb05 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java @@ -15,6 +15,8 @@ import org.springframework.lang.NonNull; 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.MsEidasNodeConstants.MatchingStates; 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; @@ -27,7 +29,9 @@ import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; import eu.eidas.auth.commons.attribute.AttributeDefinition; import eu.eidas.auth.commons.attribute.AttributeValue; import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class MatchingTaskUtils { /** @@ -105,7 +109,6 @@ public class MatchingTaskUtils { * @param personInfos Person information after a successful match * @throws EaafStorageException In case of data can not be add into session */ - @Nullable public static void storeFinalMatchingResult(IRequest pendingReq, MatchedPersonResult personInfos) throws EaafStorageException { getAuthProcessDataWrapper(pendingReq).setGenericDataToSession( @@ -114,6 +117,23 @@ public class MatchingTaskUtils { } /** + * Store matching result-state. + * + * @param pendingReq Current pendingRequest + * @param state Operation that results into a person match + */ + public static void setMatchingState(IRequest pendingReq, MatchingStates state) { + try { + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_MATCHING_STATE, state); + + } catch (EaafStorageException e) { + log.warn("Can NOT set matching-state for statistic logging.", e); + + } + } + + + /** * Get holder for authentication information for the current process. * * @param pendingReq Current pendingRequest diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml b/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml index dfa8622c..e57f9ca6 100644 --- a/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml +++ b/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml @@ -45,6 +45,8 @@ from="receiveOtherLoginMethodGuiResponseTask" to="generateMobilePhoneSignatureRequestTask" /> <pd:Transition conditionExpression="ctx['TASK_GenerateAustrianResidenceGuiTask']" from="receiveOtherLoginMethodGuiResponseTask" to="generateAustrianResidenceGuiTask" /> + <pd:Transition conditionExpression="ctx['TASK_RequestingNewErnpEntryTask']" + from="receiveOtherLoginMethodGuiResponseTask" to="generateOtherLoginMethodGuiTask" /> <pd:Transition conditionExpression="ctx['TASK_CreateNewErnpEntryTask']" from="receiveOtherLoginMethodGuiResponseTask" to="createNewErnpEntryTask" /> diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/messages/eidas_connector_message.properties b/modules/authmodule-eIDAS-v2/src/main/resources/messages/eidas_connector_message.properties index 6d73c43a..dafa7ce3 100644 --- a/modules/authmodule-eIDAS-v2/src/main/resources/messages/eidas_connector_message.properties +++ b/modules/authmodule-eIDAS-v2/src/main/resources/messages/eidas_connector_message.properties @@ -30,5 +30,6 @@ module.eidasauth.matching.24=Matching be using Austrian Identity not possible. U module.eidasauth.matching.25=Matching be using alternative eIDAS authentication not possible. Provide more or other data or use another method for matching. module.eidasauth.matching.26=Matching be using alternative eIDAS authentication not possible, because Name or Country not matched. Provide more or other data or use another method for matching. +module.eidasauth.matching.98=Matching failed, because a method was selected that was not allowed. module.eidasauth.matching.99=Matching failed, because of an unexpected processing error. Reason: {0} 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 index 496158fa..6d08a731 100644 --- 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 @@ -29,6 +29,7 @@ import org.springframework.web.context.request.ServletRequestAttributes; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.json.JsonMapper; +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.SelectedLoginMethod; import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.GenerateOtherLoginMethodGuiTask; @@ -53,6 +54,8 @@ public class GenerateOtherLoginMethodGuiTaskTest { private static final String TEST_PATTER_REQ_PARAM = "<input type=\"hidden\" name=\"loginSelection\" value=\"{0}\">"; + @Autowired MsConnectorDummyConfigMap config; + @Autowired GenerateOtherLoginMethodGuiTask task; @@ -86,6 +89,9 @@ public class GenerateOtherLoginMethodGuiTaskTest { executionContext = new ExecutionContextImpl(); + config.putConfigValue("auth.eIDAS.matching.byaddress.enable", "false"); + + LocaleContextHolder.resetLocaleContext(); } @@ -172,6 +178,10 @@ public class GenerateOtherLoginMethodGuiTaskTest { assertNotNull("createNewErnpEntry", json.get(Constants.HTML_FORM_CREATE_NEW_ERNP_ENTRY)); assertFalse("createNewErnpEntry", json.get(Constants.HTML_FORM_CREATE_NEW_ERNP_ENTRY).asBoolean()); + assertNotNull("enableMatchingByAddressSearch", json.get(Constants.HTML_FORM_CREATE_NEW_ERNP_ENTRY)); + assertFalse("enableMatchingByAddressSearch", json.get(Constants.HTML_FORM_CREATE_NEW_ERNP_ENTRY).asBoolean()); + + assertNotNull("pendingRequest not stored", storage.getPendingRequest(pendingReq.getPendingRequestId())); @@ -199,10 +209,11 @@ public class GenerateOtherLoginMethodGuiTaskTest { @Test public void advancedMatchingFailedMsg() throws TaskExecutionException, UnsupportedEncodingException { executionContext.put(Constants.CONTEXT_FLAG_ADVANCED_MATCHING_FAILED, true); - + config.putConfigValue("auth.eIDAS.matching.byaddress.enable", "true"); + task.execute(pendingReq, executionContext); - String html = doBasicValidation(); + String html = doBasicValidation(true); Assert.assertFalse("Missing eIDAS infos", html.contains(MessageFormat.format(TEST_PATTER_REQ_PARAM, SelectedLoginMethod.ADD_ME_AS_NEW))); Assert.assertTrue("missing errorfield", @@ -218,7 +229,7 @@ public class GenerateOtherLoginMethodGuiTaskTest { task.execute(pendingReq, executionContext); - String html = doBasicValidation(); + String html = doBasicValidation(false); Assert.assertTrue("missing errorfield", html.contains("<div id=\"matchingError\"")); Assert.assertTrue("missing errorfield", @@ -231,7 +242,7 @@ public class GenerateOtherLoginMethodGuiTaskTest { task.execute(pendingReq, executionContext); - doBasicValidation(); + doBasicValidation(false); } @@ -242,7 +253,7 @@ public class GenerateOtherLoginMethodGuiTaskTest { task.execute(pendingReq, executionContext); - doBasicValidation(); + doBasicValidation(false); } @@ -252,7 +263,7 @@ public class GenerateOtherLoginMethodGuiTaskTest { task.execute(pendingReq, executionContext); - doBasicValidation(); + doBasicValidation(false); } @@ -263,11 +274,11 @@ public class GenerateOtherLoginMethodGuiTaskTest { task.execute(pendingReq, executionContext); - doBasicValidation(); + doBasicValidation(false); } - private String doBasicValidation() throws UnsupportedEncodingException { + private String doBasicValidation(boolean addressSearchAllowed) throws UnsupportedEncodingException { Assert.assertEquals("Wrong http StatusCode", 200, httpResp.getStatus()); Assert.assertEquals("Wrong http ContentType", "text/html;charset=UTF-8", httpResp.getContentType()); @@ -278,7 +289,8 @@ public class GenerateOtherLoginMethodGuiTaskTest { 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))); + html.contains(MessageFormat.format(TEST_PATTER_REQ_PARAM, + addressSearchAllowed ? SelectedLoginMethod.NO_OTHER_LOGIN : SelectedLoginMethod.REQUESTING_NEW_ENTRY))); Assert.assertTrue("Missing eIDAS infos", html.contains(MessageFormat.format(TEST_PATTER_REQ_PARAM, SelectedLoginMethod.EIDAS_LOGIN))); 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 index 750a17ce..66867fce 100644 --- 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 @@ -4,6 +4,8 @@ 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 org.apache.commons.lang3.RandomStringUtils; import org.junit.Before; @@ -21,9 +23,11 @@ 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.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.SelectedLoginMethod; import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveOtherLoginMethodGuiResponseTask; +import at.gv.egiz.eaaf.core.exceptions.EaafException; 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; @@ -37,6 +41,8 @@ import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; @WebAppConfiguration public class ReceiveOtherLoginMethodGuiResponseTaskTest { + @Autowired MsConnectorDummyConfigMap config; + @Autowired private ReceiveOtherLoginMethodGuiResponseTask task; @@ -68,10 +74,22 @@ public class ReceiveOtherLoginMethodGuiResponseTaskTest { pendingReq.setAuthUrl("https://localhost/ms_connector"); pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); + config.putConfigValue("auth.eIDAS.matching.byaddress.enable", "false"); + LocaleContextHolder.resetLocaleContext(); } @Test + public void withStopMatchingSelection() throws TaskExecutionException { +httpReq.setParameter(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER, SelectedLoginMethod.STOP_MATCHING_PROCESS.name()); + + task.execute(pendingReq, executionContext); + + assertTrue("stoppedByUser", pendingReq.isAbortedByUser()); + + } + + @Test public void withMobileSignatureSelection() throws TaskExecutionException { testTransition(SelectedLoginMethod.MOBILE_PHONE_SIGNATURE_LOGIN, Constants.TRANSITION_TO_GENERATE_MOBILE_PHONE_SIGNATURE_REQUEST_TASK); assertEquals("return to selection", false, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); @@ -87,18 +105,40 @@ public class ReceiveOtherLoginMethodGuiResponseTaskTest { @Test public void withNoOtherLoginSelection() throws TaskExecutionException { + config.putConfigValue("auth.eIDAS.matching.byaddress.enable", "true"); + testTransition(SelectedLoginMethod.NO_OTHER_LOGIN, Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK); assertEquals("return to selection", false, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); } @Test + public void withNoOtherLoginSelectionDisabled() throws TaskExecutionException { + httpReq.setParameter(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER, SelectedLoginMethod.NO_OTHER_LOGIN.name()); + + TaskExecutionException error = assertThrows("wrong exception", TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + assertEquals("wrong errorCode", "module.eidasauth.matching.98", + ((EaafException) error.getOriginalException()).getErrorId()); + + } + + @Test public void withAddMeAsNewSelection() throws TaskExecutionException { testTransition(SelectedLoginMethod.ADD_ME_AS_NEW, Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK); assertEquals("return to selection", false, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK)); } + @Test + public void withRequestingNewEntrySelection() throws TaskExecutionException { + testTransition(SelectedLoginMethod.REQUESTING_NEW_ENTRY, Constants.TRANSITION_TO_REQUESTING_NEW_ERNP_ENTRY_TASK); + assertEquals("return to selection", true, executionContext.get(Constants.TRANSITION_TO_REQUESTING_NEW_ERNP_ENTRY_TASK)); + assertEquals("return to selection", false, executionContext.get(Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_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); @@ -109,6 +149,8 @@ public class ReceiveOtherLoginMethodGuiResponseTaskTest { 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.name(), 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)); diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/utils/AddressSearchResultTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/utils/AddressSearchResultTest.java new file mode 100644 index 00000000..fef157db --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/utils/AddressSearchResultTest.java @@ -0,0 +1,56 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.utils; + +import static org.junit.Assert.assertArrayEquals; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.mockito.internal.util.collections.Sets; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.controller.AdresssucheController.AdresssucheOutput; + +@RunWith(BlockJUnit4ClassRunner.class) +public class AddressSearchResultTest { + + @Test + public void checkNumbers() { + + Set<AdresssucheOutput> result = Sets.newSet( + buildRandom("2"), + buildRandom("3"), + buildRandom("1"), + buildRandom("10"), + buildRandom(null), + buildRandom("10-12"), + buildRandom("15") + ); + + final List<String> sorted = result.stream().sorted().limit(30) + .map(el -> el.getNumber()) + .collect(Collectors.toList()); + + + assertArrayEquals("wrong order", + new Object[]{null, "1", "2", "3", "10", "15", "10-12"}, + sorted.toArray()); + + + + + } + + private AdresssucheOutput buildRandom(String number) { + return AdresssucheOutput.builder() + .municipality("aaaaaaaa") + .postleitzahl("8080") + .street("bbbbb") + .number(number) + .village("cccccc") + .build(); + } + +} |