aboutsummaryrefslogtreecommitdiff
path: root/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java
diff options
context:
space:
mode:
Diffstat (limited to 'eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java')
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java214
1 files changed, 214 insertions, 0 deletions
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java
new file mode 100644
index 00000000..83fdf771
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2021 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.tasks;
+
+import java.util.Enumeration;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Component;
+
+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;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.InvalidUserInputException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.ManualFixNecessaryException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException;
+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.utils.MatchingTaskUtils;
+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.modules.AbstractAuthServletTask;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+
+/**
+ * Task receives the response of {@link GenerateAustrianResidenceGuiTask} and handles it.
+ * This corresponds to Steps 17B, 18, 19 in the eIDAS Matching Concept.
+ * Input:
+ * <ul>
+ * <li>{@link Constants#DATA_SIMPLE_EIDAS} initial login data from user</li>
+ * <li>{@link Constants#DATA_INTERMEDIATE_RESULT} results from search in registers with personIdentifier</li>
+ * </ul>
+ * Output:
+ * <ul>
+ * <li>{@link Constants#DATA_RESULT_MATCHING_BPK} if one register result found</li>
+ * </ul>
+ * Transitions:
+ * <ul>
+ * <li>{@link CreateNewErnpEntryTask} if no results from search with residency data in registers</li>
+ * <li>{@link CreateIdentityLinkTask} if one exact match between initial register search (with MDS) and results
+ * from search with residency data in registers exists</li>
+ * </ul>
+ *
+ * @author amarsalek
+ * @author ckollmann
+ * @author tlenz
+ */
+@Slf4j
+@Component("ReceiveAustrianResidenceGuiResponseTask")
+public class ReceiveAustrianResidenceGuiResponseTask extends AbstractAuthServletTask {
+
+ public static final String PARAM_FORMER_RESIDENCE_AVAILABLE = "formerResidenceAvailable";
+ public static final String PARAM_STREET = "street";
+ public static final String PARAM_CITY = "city";
+ public static final String PARAM_ZIPCODE = "zipcode";
+ private final RegisterSearchService registerSearchService;
+
+ public ReceiveAustrianResidenceGuiResponseTask(RegisterSearchService registerSearchService) {
+ this.registerSearchService = registerSearchService;
+ }
+
+ @Data
+ @AllArgsConstructor
+ @NoArgsConstructor
+ public static class UserInput {
+ private boolean formerResidenceAvailable;
+ private String zipcode;
+ private String city;
+ private String street;
+ }
+
+ @Override
+ public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
+ throws TaskExecutionException {
+ log.trace("Starting ReceiveAustrianResidenceGuiResponseTask");
+
+ UserInput input = parseHtmlInput(request);
+ if (!input.isFormerResidenceAvailable()) {
+ moveToNextTask(executionContext);
+ return;
+
+ }
+
+ //TODO: Here, we need an error handling an can not stop full process if form input was invalid
+ //TODO: check minimum form elements
+ /*TODO: maybe we can switch to custom controller and use WebMVC form-binding feature.
+ * Binding element can be add as attribute to this request
+ */
+ if (input.getStreet().isEmpty() || input.getCity().isEmpty() || input.getZipcode().isEmpty()) {
+ // HTML form should ensure that mandatory fields are set => this should never happen
+ throw new TaskExecutionException(pendingReq, "Invalid user input",
+ new InvalidUserInputException("module.eidasauth.matching.06"));
+
+ }
+
+
+
+ try {
+ SimpleEidasData eidasData = MatchingTaskUtils.getInitialEidasData(pendingReq);
+ RegisterStatusResults initialSearchResult = MatchingTaskUtils.getIntermediateMatchingResult(pendingReq);
+
+ RegisterStatusResults residencyResult =
+ registerSearchService.searchWithResidence(initialSearchResult.getOperationStatus(),
+ eidasData, input.zipcode, input.city, input.street);
+ if (residencyResult.getResultCount() == 0) {
+ //TODO: her we should add a GUI step of result is zero to inform user an forward process by click
+ moveToNextTask(executionContext);
+
+ } else if (residencyResult.getResultCount() == 1) {
+ compareSearchResultWithInitialData(executionContext, residencyResult, eidasData);
+
+ } else {
+ /*TODO: align with form generation task and to better error handling in case of more-than-one result.
+ * Maybe the user has to provide more information.
+ */
+ throw new TaskExecutionException(pendingReq,
+ "Manual Fix necessary", new ManualFixNecessaryException(eidasData));
+
+ }
+
+ } catch (EaafStorageException e) {
+ log.error("Search with residency data failed", e);
+ throw new TaskExecutionException(pendingReq, "Search with residency data failed", e);
+
+ }
+ }
+
+ private void compareSearchResultWithInitialData(ExecutionContext executionContext,
+ RegisterStatusResults residencyResult, SimpleEidasData eidasData)
+ throws TaskExecutionException, EaafStorageException {
+ try {
+ /*TODO: check 'equalsRegisterData' because this method maybe this method evaluate to an invalid result.
+ * See TODO in methods body
+ */
+ if (eidasData.equalsRegisterData(residencyResult.getResult())) {
+ // update register information
+ registerSearchService.step7aKittProcess(residencyResult, eidasData);
+
+ // store search result to re-used in CreateIdentityLink step, because there we need bPK and MDS
+ MatchingTaskUtils.storeFinalMatchingResult(pendingReq,
+ MatchedPersonResult.generateFormMatchingResult(
+ residencyResult.getResult(), eidasData.getCitizenCountryCode()));
+
+ } else {
+ moveToNextTask(executionContext);
+
+ }
+
+ } catch (WorkflowException e) {
+ throw new TaskExecutionException(pendingReq, "Search failed", new ManualFixNecessaryException(eidasData));
+
+ }
+ }
+
+ private void moveToNextTask(ExecutionContext executionContext) {
+ // Later on, this should transition to Step 20
+ executionContext.put(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK, true);
+
+ }
+
+ private @NotNull UserInput parseHtmlInput(HttpServletRequest request) {
+ Enumeration<String> reqParamNames = request.getParameterNames();
+ UserInput result = new UserInput();
+ while (reqParamNames.hasMoreElements()) {
+ final String paramName = reqParamNames.nextElement();
+ String escaped = StringEscapeUtils.escapeHtml(request.getParameter(paramName));
+ if (PARAM_FORMER_RESIDENCE_AVAILABLE.equalsIgnoreCase(paramName)) {
+ result.setFormerResidenceAvailable(Boolean.parseBoolean(escaped));
+
+ } else if (PARAM_STREET.equalsIgnoreCase(paramName)) {
+ result.setStreet(escaped);
+
+ } else if (PARAM_CITY.equalsIgnoreCase(paramName)) {
+ result.setCity(escaped);
+
+ } else if (PARAM_ZIPCODE.equalsIgnoreCase(paramName)) {
+ result.setZipcode(escaped);
+
+ }
+ }
+ return result;
+
+ }
+
+}