aboutsummaryrefslogtreecommitdiff
path: root/eidas_modules/authmodule-eIDAS-v2/src
diff options
context:
space:
mode:
authorChristian Kollmann <christian.kollmann@a-sit.at>2021-07-12 11:00:48 +0200
committerChristian Kollmann <christian.kollmann@a-sit.at>2021-07-12 11:44:43 +0200
commit09af792ce3ed3df430f8d7ae6099f284756147a0 (patch)
treef188c2d9150ecc403e9a1dc930917e19a4b4cdc4 /eidas_modules/authmodule-eIDAS-v2/src
parent0b896fd9d035ba5719394ecaaba02ef6b5dc5666 (diff)
downloadNational_eIDAS_Gateway-09af792ce3ed3df430f8d7ae6099f284756147a0.tar.gz
National_eIDAS_Gateway-09af792ce3ed3df430f8d7ae6099f284756147a0.tar.bz2
National_eIDAS_Gateway-09af792ce3ed3df430f8d7ae6099f284756147a0.zip
Add option to provide alternative eIDAS login for matching process
Diffstat (limited to 'eidas_modules/authmodule-eIDAS-v2/src')
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java38
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java214
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java1
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java22
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseAlternativeTask.java131
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java1
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml38
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml11
8 files changed, 411 insertions, 45 deletions
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java
index 5edde8a4..70bade43 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java
@@ -29,7 +29,7 @@ public class Constants {
//TODO: should we make it configurable?
public static final String MATCHING_INTERNAL_BPK_TARGET = EaafConstants.URN_PREFIX_CDID + "ZP";
-
+
public static final String ERRORCODE_00 = "module.eidasauth.00";
public static final String DATA_REQUESTERID = "req_requesterId";
@@ -37,6 +37,7 @@ public class Constants {
public static final String DATA_REQUESTED_LOA_LIST = "req_requestedLoA";
public static final String DATA_REQUESTED_LOA_COMPERISON = "req_requestedLoAComperision";
public static final String DATA_FULL_EIDAS_RESPONSE = "resp_fulleIDASResponse";
+ public static final String DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE = "resp_fulleIDASResponseAlternative";
/**
* Stored when one match from register was found.
@@ -115,7 +116,7 @@ public class Constants {
public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEYS_ALIAS = CONIG_PROPS_EIDAS_ZMRCLIENT
+ ".ssl.key.alias";
public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEY_PASSWORD = CONIG_PROPS_EIDAS_ZMRCLIENT
- + ".ssl.key.password";
+ + ".ssl.key.password";
public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_TRUSTSTORE_PATH = CONIG_PROPS_EIDAS_ZMRCLIENT
+ ".ssl.trustStore.path";
public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_TRUSTSTORE_PASSWORD = CONIG_PROPS_EIDAS_ZMRCLIENT
@@ -124,15 +125,15 @@ public class Constants {
+ ".ssl.trustStore.type";
public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_TRUSTSTORE_NAME = CONIG_PROPS_EIDAS_ZMRCLIENT
+ ".ssl.trustStore.name";
-
+
public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_REQ_ORGANIZATION_NR = CONIG_PROPS_EIDAS_ZMRCLIENT
+ ".req.organisation.behoerdennr";
public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_REQ_UPDATE_REASON_CODE = CONIG_PROPS_EIDAS_ZMRCLIENT
+ ".req.update.reason.code";
public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_REQ_UPDATE_REASON_TEXT = CONIG_PROPS_EIDAS_ZMRCLIENT
+ ".req.update.reason.text";
-
-
+
+
// SZR Client configuration properties
public static final String CONIG_PROPS_EIDAS_SZRCLIENT = CONIG_PROPS_EIDAS_PREFIX + ".szrclient";
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_USETESTSERVICE = CONIG_PROPS_EIDAS_SZRCLIENT
@@ -162,7 +163,7 @@ public class Constants {
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYS_ALIAS = CONIG_PROPS_EIDAS_SZRCLIENT
+ ".ssl.key.alias";
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEY_PASSWORD = CONIG_PROPS_EIDAS_SZRCLIENT
- + ".ssl.key.password";
+ + ".ssl.key.password";
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PATH = CONIG_PROPS_EIDAS_SZRCLIENT
+ ".ssl.trustStore.path";
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PASSWORD = CONIG_PROPS_EIDAS_SZRCLIENT
@@ -171,7 +172,7 @@ public class Constants {
+ ".ssl.trustStore.type";
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_NAME = CONIG_PROPS_EIDAS_SZRCLIENT
+ ".ssl.trustStore.name";
-
+
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE = CONIG_PROPS_EIDAS_SZRCLIENT
+ ".params.documenttype";
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ = CONIG_PROPS_EIDAS_SZRCLIENT
@@ -208,7 +209,7 @@ public class Constants {
// eIDAS request parameters
public static final String eIDAS_REQ_NAMEID_FORMAT = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent";
- // eIDAS attribute names
+ // eIDAS attribute names
public static final String eIDAS_ATTR_PERSONALIDENTIFIER = "PersonIdentifier";
public static final String eIDAS_ATTR_DATEOFBIRTH = "DateOfBirth";
public static final String eIDAS_ATTR_CURRENTGIVENNAME = "FirstName";
@@ -221,19 +222,19 @@ public class Constants {
public static final String eIDAS_ATTR_LEGALPERSONIDENTIFIER = "LegalPersonIdentifier";
public static final String eIDAS_ATTR_LEGALNAME = "LegalName";
-
+
//eIDAS attribute URN
public static final String eIDAS_ATTRURN_PREFIX = "http://eidas.europa.eu/attributes/";
public static final String eIDAS_ATTRURN_PREFIX_NATURAL = eIDAS_ATTRURN_PREFIX + "naturalperson/";
-
- public static final String eIDAS_ATTRURN_PERSONALIDENTIFIER =
+
+ public static final String eIDAS_ATTRURN_PERSONALIDENTIFIER =
eIDAS_ATTRURN_PREFIX_NATURAL + eIDAS_ATTR_PERSONALIDENTIFIER;
- public static final String eIDAS_ATTRURN_PLACEOFBIRTH =
+ public static final String eIDAS_ATTRURN_PLACEOFBIRTH =
eIDAS_ATTRURN_PREFIX_NATURAL + eIDAS_ATTR_PLACEOFBIRTH;
- public static final String eIDAS_ATTRURN_BIRTHNAME =
+ public static final String eIDAS_ATTRURN_BIRTHNAME =
eIDAS_ATTRURN_PREFIX_NATURAL + eIDAS_ATTR_BIRTHNAME;
-
-
+
+
public static final String eIDAS_REQ_PARAM_SECTOR_PUBLIC = "public";
public static final String eIDAS_REQ_PARAM_SECTOR_PRIVATE = "private";
@@ -292,9 +293,12 @@ public class Constants {
"TASK_GenerateMobilePhoneSignatureRequestTask";
/**
- * TODO Second eidas login.
+ * {@link at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.GenerateAuthnRequestTask}.
*/
- public static final String TRANSITION_TO_GENERATE_EIDAS_LOGIN = "TASK_TODO";
+ public static final String TRANSITION_TO_GENERATE_EIDAS_LOGIN = "TASK_GenerateAlternativeEidasAuthn";
+ /**
+ * Stores login selection from user.
+ */
public static final String REQ_SELECTED_LOGIN_METHOD_PARAMETER = "loginSelection";
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java
new file mode 100644
index 00000000..fe3a9560
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java
@@ -0,0 +1,214 @@
+/*
+ * 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.tasks;
+
+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;
+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.WorkflowException;
+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.RegisterOperationStatus;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterStatusResults;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils;
+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 com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import eu.eidas.auth.commons.attribute.AttributeDefinition;
+import eu.eidas.auth.commons.attribute.AttributeValue;
+import eu.eidas.auth.commons.light.ILightResponse;
+import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+import org.joda.time.DateTime;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK;
+import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK;
+
+/**
+ * Searches registers (ERnP and ZMR) after alternative eIDAS authn, before adding person to SZR.
+ * Input:
+ * <ul>
+ * <li>{@link Constants#DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE}</li>
+ * </ul>
+ * Output:
+ * <ul>
+ * <li>{@link Constants#DATA_PERSON_MATCH_RESULT} results after second search in registers with MDS</li>
+ * <li>{@link Constants#DATA_RESULT_MATCHING_BPK} if one register result found</li>
+ * </ul>
+ * Transitions:
+ * <ul>
+ * <li>{@link GenerateOtherLoginMethodGuiTask} if no results in registers were found for this user</li>
+ * <li>{@link CreateIdentityLinkTask} if search in register returned one match, user is uniquely identified</li>
+ * </ul>
+ *
+ * @author amarsalek
+ * @author ckollmann
+ * @author tlenz
+ */
+@Slf4j
+@Component("AlternativeSearchTask")
+@SuppressWarnings("PMD.TooManyStaticImports")
+public class AlternativeSearchTask extends AbstractAuthServletTask {
+
+ private final RegisterSearchService registerSearchService;
+ private final ICcSpecificEidProcessingService eidPostProcessor;
+
+ /**
+ * Constructor.
+ *
+ * @param registerSearchService Service for register search access
+ * @param eidPostProcessor Country-Specific post processing of attributes
+ */
+ public AlternativeSearchTask(RegisterSearchService registerSearchService,
+ ICcSpecificEidProcessingService eidPostProcessor) {
+ this.registerSearchService = registerSearchService;
+ this.eidPostProcessor = eidPostProcessor;
+ }
+
+ @Override
+ public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
+ throws TaskExecutionException {
+ try {
+ final SimpleEidasData eidasData = convertEidasAttrToSimpleData();
+ step11RegisterSearchWithPersonIdentifier(executionContext, eidasData);
+ } catch (WorkflowException e) {
+ throw new TaskExecutionException(pendingReq, "Initial search failed", e);
+ } catch (final Exception e) {
+ log.error("Initial search failed", e);
+ throw new TaskExecutionException(pendingReq, "Initial search failed with a generic error", e);
+ }
+ }
+
+ private void step11RegisterSearchWithPersonIdentifier(
+ ExecutionContext executionContext, SimpleEidasData eidasData) throws WorkflowException, EaafStorageException {
+ try {
+ log.trace("Starting step11RegisterSearchWithPersonIdentifier");
+ RegisterStatusResults searchResult = registerSearchService.searchWithPersonIdentifier(eidasData);
+ int resultCount = searchResult.getResultCount();
+ if (resultCount == 0) {
+ step12CountrySpecificSearch(executionContext, searchResult.getOperationStatus(), eidasData);
+ } else if (resultCount == 1) {
+ foundMatchFinalizeTask(searchResult, eidasData);
+ } else {
+ throw new WorkflowException("step11RegisterSearchWithPersonIdentifier",
+ "More than one entry with unique personal-identifier", true);
+ }
+ } catch (WorkflowException e) {
+ //TODO: what we do in case of a workflow error and manual matching are necessary??
+ log.warn("Workflow error during matching step: {}. Reason: {}", e.getProcessStepName(), e.getErrorReason());
+ throw e;
+ }
+ }
+
+ private void step12CountrySpecificSearch(
+ ExecutionContext executionContext, RegisterOperationStatus registerOperationStatus, SimpleEidasData eidasData)
+ throws EaafStorageException, WorkflowException {
+ log.trace("Starting 'step12CountrySpecificSearch' ... ");
+ RegisterStatusResults searchResult = registerSearchService.searchWithCountrySpecifics(
+ registerOperationStatus, eidasData);
+ if (searchResult.getResultCount() == 0) {
+ log.trace("'step12CountrySpecificSearch' ends with no result. Forward to GUI based matching step ... ");
+ log.debug("Forward to GUI based matching steps ... ");
+ executionContext.put(TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK, true);
+ } else if (searchResult.getResultCount() == 1) {
+ log.trace("'step12CountrySpecificSearch' finds a person. Forward to 'step7aKittProcess' step ... ");
+ // TODO is step 7b kitt different from step 7a?
+ registerSearchService.step7aKittProcess(searchResult, eidasData);
+ foundMatchFinalizeTask(searchResult, eidasData);
+ } else {
+ throw new WorkflowException("step12CountrySpecificSearch",
+ "More than one entry with unique country-specific information", true);
+ }
+ }
+
+ private void foundMatchFinalizeTask(RegisterStatusResults searchResult, SimpleEidasData eidasData)
+ throws WorkflowException, EaafStorageException {
+ MatchedPersonResult result = MatchedPersonResult.generateFormMatchingResult(
+ searchResult.getResult(), eidasData.getCitizenCountryCode());
+ MatchingTaskUtils.storeFinalMatchingResult(pendingReq, result);
+ }
+
+ @NotNull
+ private SimpleEidasData convertEidasAttrToSimpleData()
+ throws EidasAttributeException, EidPostProcessingException {
+ final ILightResponse eidasResponse = MatchingTaskUtils.getAuthProcessDataWrapper(pendingReq)
+ .getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, ILightResponse.class);
+ Map<String, Object> simpleMap = convertEidasAttrToSimpleMap(eidasResponse.getAttributes().getAttributeMap());
+ return eidPostProcessor.postProcess(simpleMap);
+ }
+
+ private Map<String, Object> convertEidasAttrToSimpleMap(
+ ImmutableMap<AttributeDefinition<?>, ImmutableSet<? extends AttributeValue<?>>> attributeMap) {
+ final Map<String, Object> result = new HashMap<>();
+ for (final AttributeDefinition<?> el : attributeMap.keySet()) {
+ final Class<?> parameterizedType = el.getParameterizedType();
+ if (DateTime.class.equals(parameterizedType)) {
+ final DateTime attribute = EidasResponseUtils.translateDateAttribute(el, attributeMap.get(el).asList());
+ if (attribute != null) {
+ result.put(el.getFriendlyName(), attribute);
+ log.trace("Find attr '{}' with value: {}", el.getFriendlyName(), attribute);
+ } else {
+ log.info("Ignore empty 'DateTime' attribute");
+ }
+ } else if (PostalAddress.class.equals(parameterizedType)) {
+ final PostalAddress addressAttribute = EidasResponseUtils
+ .translateAddressAttribute(el, attributeMap.get(el).asList());
+ if (addressAttribute != null) {
+ result.put(el.getFriendlyName(), addressAttribute);
+ log.trace("Find attr '{}' with value: {}", el.getFriendlyName(), addressAttribute);
+ } else {
+ log.info("Ignore empty 'PostalAddress' attribute");
+ }
+ } else {
+ final List<String> natPersonIdObj = EidasResponseUtils.translateStringListAttribute(el, attributeMap.get(el));
+ final String stringAttr = natPersonIdObj.get(0);
+ if (StringUtils.isNotEmpty(stringAttr)) {
+ result.put(el.getFriendlyName(), stringAttr);
+ log.trace("Find attr '{}' with value: {}", el.getFriendlyName(), stringAttr);
+ } else {
+ log.info("Ignore empty 'String' attribute");
+ }
+ }
+ }
+ log.debug("Receive #{} attributes with names: {}", result.size(), result.keySet());
+ return result;
+ }
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
index 33d3f175..da9c8174 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
@@ -64,7 +64,6 @@ import java.util.UUID;
/**
* Generates the authn request to the eIDAS Node. This is the first task in the process.
- * <p>
* Input:
* <ul>
* <li>none</li>
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 4103939d..a55af1c4 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
@@ -62,7 +62,7 @@ import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSIT
import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK;
/**
- * Task that searches registers (ERnP and ZMR) before adding person to SZR.
+ * Searches registers (ERnP and ZMR) after initial user auth, before adding person to SZR.
* Input:
* <ul>
* <li>{@link Constants#DATA_FULL_EIDAS_RESPONSE}</li>
@@ -126,12 +126,12 @@ public class InitialSearchTask extends AbstractAuthServletTask {
ExecutionContext executionContext, SimpleEidasData eidasData) throws WorkflowException, EaafStorageException {
try {
log.trace("Starting step2RegisterSearchWithPersonIdentifier");
- RegisterStatusResults initialSearchResult = registerSearchService.searchWithPersonIdentifier(eidasData);
- int resultCount = initialSearchResult.getResultCount();
+ RegisterStatusResults searchResult = registerSearchService.searchWithPersonIdentifier(eidasData);
+ int resultCount = searchResult.getResultCount();
if (resultCount == 0) {
- step6CountrySpecificSearch(executionContext, initialSearchResult.getOperationStatus(), eidasData);
+ step6CountrySpecificSearch(executionContext, searchResult.getOperationStatus(), eidasData);
} else if (resultCount == 1) {
- foundMatchFinalizeTask(initialSearchResult, eidasData);
+ foundMatchFinalizeTask(searchResult, eidasData);
} else {
throw new WorkflowException("step2RegisterSearchWithPersonIdentifier",
"More than one entry with unique personal-identifier", true);
@@ -147,15 +147,15 @@ public class InitialSearchTask extends AbstractAuthServletTask {
ExecutionContext executionContext, RegisterOperationStatus registerOperationStatus, SimpleEidasData eidasData)
throws EaafStorageException, WorkflowException {
log.trace("Starting 'step6CountrySpecificSearch' ... ");
- RegisterStatusResults countrySpecificResult = registerSearchService.searchWithCountrySpecifics(
+ RegisterStatusResults searchResult = registerSearchService.searchWithCountrySpecifics(
registerOperationStatus, eidasData);
- if (countrySpecificResult.getResultCount() == 0) {
+ if (searchResult.getResultCount() == 0) {
log.trace("'step6CountrySpecificSearch' ends with no result. Forward to next matching step ... ");
- step8RegisterSearchWithMds(executionContext, countrySpecificResult.getOperationStatus(), eidasData);
- } else if (countrySpecificResult.getResultCount() == 1) {
+ step8RegisterSearchWithMds(executionContext, searchResult.getOperationStatus(), eidasData);
+ } else if (searchResult.getResultCount() == 1) {
log.trace("'step6CountrySpecificSearch' finds a person. Forward to 'step7aKittProcess' step ... ");
- registerSearchService.step7aKittProcess(countrySpecificResult, eidasData);
- foundMatchFinalizeTask(countrySpecificResult, eidasData);
+ registerSearchService.step7aKittProcess(searchResult, eidasData);
+ foundMatchFinalizeTask(searchResult, eidasData);
} else {
throw new WorkflowException("step6CountrySpecificSearch",
"More than one entry with unique country-specific information", true);
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseAlternativeTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseAlternativeTask.java
new file mode 100644
index 00000000..aa04f55e
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseAlternativeTask.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2018 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 at.asitplus.eidas.specific.connector.MsEidasNodeConstants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasValidationException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.validator.EidasResponseValidator;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+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.auth.data.AuthProcessDataWrapper;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import eu.eidas.auth.commons.light.ILightResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Receives the authn response from the eIDAS Node, containing the (alternative) eIDAS authentication.
+ * Input:
+ * <ul>
+ * <li>none</li>
+ * </ul>
+ * Output:
+ * <ul>
+ * <li>{@link Constants#DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE} the full response details</li>
+ * </ul>
+ * Transitions:
+ * <ul>
+ * <li>{@link InitialSearchTask} to perform search in registers</li>
+ * </ul>
+ *
+ * @author tlenz
+ * @author ckollmann
+ */
+@Slf4j
+@Component("ReceiveAuthnResponseTask")
+public class ReceiveAuthnResponseAlternativeTask extends AbstractAuthServletTask {
+
+ @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
+ @Autowired
+ private IConfiguration basicConfig;
+
+ @Autowired
+ private EidasAttributeRegistry attrRegistry;
+
+ @Override
+ public void execute(ExecutionContext executionContext, HttpServletRequest request,
+ HttpServletResponse response) throws TaskExecutionException {
+ try {
+ final ILightResponse eidasResponse = extractEidasResponse(request);
+ checkStatusCode(eidasResponse);
+ validateMsSpecificResponse(executionContext, eidasResponse);
+ storeInSession(eidasResponse);
+ } catch (final Exception e) {
+ log.warn("eIDAS Response processing FAILED.", e);
+ throw new TaskExecutionException(pendingReq, e.getMessage(),
+ new EidasSAuthenticationException("eidas.05", new Object[]{e.getMessage()}, e));
+ }
+ }
+
+ @NotNull
+ private ILightResponse extractEidasResponse(HttpServletRequest request) throws EidasSAuthenticationException {
+ final ILightResponse eidasResponse = (ILightResponse) request.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE);
+ if (eidasResponse == null) {
+ log.warn("NO eIDAS response-message found.");
+ throw new EidasSAuthenticationException("eidas.01", null);
+ }
+ log.debug("Receive eIDAS response with RespId: {} for ReqId: {}",
+ eidasResponse.getId(), eidasResponse.getInResponseToId());
+ log.trace("Full eIDAS-Resp: {}", eidasResponse);
+ return eidasResponse;
+ }
+
+ private void checkStatusCode(ILightResponse eidasResponse) throws EidasSAuthenticationException {
+ if (!eidasResponse.getStatus().getStatusCode().equals(Constants.SUCCESS_URI)) {
+ log.info("Receive eIDAS Response with StatusCode: {} Subcode: {} Msg: {}",
+ eidasResponse.getStatus().getStatusCode(),
+ eidasResponse.getStatus().getSubStatusCode(),
+ eidasResponse.getStatus().getStatusMessage());
+ throw new EidasSAuthenticationException("eidas.02", new Object[]{eidasResponse.getStatus()
+ .getStatusCode(), eidasResponse.getStatus().getStatusMessage()});
+ }
+ }
+
+ private void validateMsSpecificResponse(ExecutionContext executionContext, ILightResponse eidasResponse)
+ throws EidasValidationException {
+ final String spCountry = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, "AT");
+ final String citizenCountryCode = (String) executionContext.get(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY);
+ EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry);
+ }
+
+ private void storeInSession(ILightResponse eidasResponse) throws EaafException {
+ log.debug("Store eIDAS response information into pending-request.");
+ final AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class);
+ authProcessData.setQaaLevel(eidasResponse.getLevelOfAssurance());
+ authProcessData.setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE, eidasResponse);
+ requestStoreage.storePendingRequest(pendingReq);
+ }
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java
index dcc1b7d5..ae582e91 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java
@@ -48,7 +48,6 @@ import javax.servlet.http.HttpServletResponse;
/**
* Receives the authn response from the eIDAS Node, containing the (initial) eIDAS authentication.
- * <p>
* Input:
* <ul>
* <li>none</li>
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml
index e20fd7aa..2a8a0141 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml
@@ -17,6 +17,9 @@
<pd:Task id="receiveMobilePhoneSignatureResponseTask" class="ReceiveMobilePhoneSignatureResponseTask" />
<pd:Task id="generateAustrianResidenceGuiTask" class="GenerateAustrianResidenceGuiTask" />
<pd:Task id="receiveAustrianResidenceGuiResponseTask" class="ReceiveAustrianResidenceGuiResponseTask" />
+ <pd:Task id="generateAlternativeEidasAuthnRequest" class="GenerateAuthnRequestTask" />
+ <pd:Task id="receiveAlternativeEidasAuthnRequest" class="ReceiveAuthnResponseAlternativeTask" async="true" />
+ <pd:Task id="alternativeRegisterSearch" class="AlternativeSearchTask" />
<pd:StartEvent id="start" />
@@ -24,26 +27,35 @@
<pd:Transition from="generateAuthnRequest" to="receiveAuthnResponse" />
<pd:Transition from="receiveAuthnResponse" to="initialRegisterSearch" />
<!-- TODO start-->
- <pd:Transition from="initialRegisterSearch" to="createNewErnpEntryTask" conditionExpression="ctx['TASK_CreateNewErnpEntryTask']"/>
- <pd:Transition from="initialRegisterSearch" to="generateOtherLoginMethodGuiTask" conditionExpression="ctx['TASK_GenerateOtherLoginMethodGuiTask']"/>
+ <pd:Transition conditionExpression="ctx['TASK_CreateNewErnpEntryTask']"
+ from="initialRegisterSearch" to="createNewErnpEntryTask" />
+ <pd:Transition conditionExpression="ctx['TASK_GenerateOtherLoginMethodGuiTask']"
+ from="initialRegisterSearch" to="generateOtherLoginMethodGuiTask"/>
<pd:Transition from="initialRegisterSearch" to="generateIdentityLink" />
- <pd:Transition from="generateOtherLoginMethodGuiTask" to="receiveOtherLoginMethodGuiResponseTask" />
- <pd:Transition from="receiveOtherLoginMethodGuiResponseTask" to="generateMobilePhoneSignatureRequestTask" conditionExpression="ctx['TASK_GenerateMobilePhoneSignatureRequestTask']"/>
- <pd:Transition from="receiveOtherLoginMethodGuiResponseTask" to="generateAustrianResidenceGuiTask" conditionExpression="ctx['TASK_GenerateAustrianResidenceGuiTask']"/>
- <!-- TRANSITION_TO_GENERATE_EIDAS_LOGIN -->
- <!-- <pd:Transition from="receiveOtherLoginMethodGuiResponseTask" -->
- <!-- to="generateAustrianResidenceGuiTask" -->
- <!-- conditionExpression="ctx['TASK_TODO']"/> -->
+ <pd:Transition from="generateOtherLoginMethodGuiTask" to="receiveOtherLoginMethodGuiResponseTask" />
+ <pd:Transition conditionExpression="ctx['TASK_GenerateAlternativeEidasAuthn']"
+ from="receiveOtherLoginMethodGuiResponseTask" to="generateAlternativeEidasAuthnRequest" />
+ <pd:Transition conditionExpression="ctx['TASK_GenerateMobilePhoneSignatureRequestTask']"
+ from="receiveOtherLoginMethodGuiResponseTask" to="generateMobilePhoneSignatureRequestTask" />
+ <pd:Transition conditionExpression="ctx['TASK_GenerateAustrianResidenceGuiTask']"
+ from="receiveOtherLoginMethodGuiResponseTask" to="generateAustrianResidenceGuiTask" />
+
+ <pd:Transition from="generateAlternativeEidasAuthnRequest" to="receiveAlternativeEidasAuthnRequest" />
+ <pd:Transition from="receiveAlternativeEidasAuthnRequest" to="alternativeRegisterSearch" />
+ <pd:Transition conditionExpression="ctx['TASK_GenerateOtherLoginMethodGuiTask']"
+ from="alternativeRegisterSearch" to="generateIdentityLink" />
+ <pd:Transition from="alternativeRegisterSearch" to="generateIdentityLink" />
<pd:Transition from="generateMobilePhoneSignatureRequestTask" to="receiveMobilePhoneSignatureResponseTask" />
- <pd:Transition from="receiveMobilePhoneSignatureResponseTask" to="generateAustrianResidenceGuiTask" conditionExpression="ctx['TASK_GenerateAustrianResidenceGuiTask']" />
+ <pd:Transition conditionExpression="ctx['TASK_GenerateAustrianResidenceGuiTask']"
+ from="receiveMobilePhoneSignatureResponseTask" to="generateAustrianResidenceGuiTask" />
<pd:Transition from="receiveMobilePhoneSignatureResponseTask" to="generateIdentityLink" />
<pd:Transition from="generateAustrianResidenceGuiTask" to="receiveAustrianResidenceGuiResponseTask" />
-
- <pd:Transition from="receiveAustrianResidenceGuiResponseTask" to="createNewErnpEntryTask" conditionExpression="ctx['TASK_CreateNewErnpEntryTask']"/>
- <pd:Transition from="receiveAustrianResidenceGuiResponseTask" to="generateIdentityLink"/>
+ <pd:Transition conditionExpression="ctx['TASK_CreateNewErnpEntryTask']"
+ from="receiveAustrianResidenceGuiResponseTask" to="createNewErnpEntryTask" />
+ <pd:Transition from="receiveAustrianResidenceGuiResponseTask" to="generateIdentityLink" />
<pd:Transition from="createNewErnpEntryTask" to="generateIdentityLink" />
<!-- TODO end-->
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml
index 09e0234d..5a113550 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml
@@ -100,8 +100,12 @@
scope="prototype" />
<bean id="ReceiveAuthnResponseTask"
- class="at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAuthnResponseTask"
- scope="prototype" />
+ class="at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAuthnResponseTask"
+ scope="prototype" />
+
+ <bean id="ReceiveAuthnResponseAlternativeTask"
+ class="at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAuthnResponseAlternativeTask"
+ scope="prototype" />
<bean id="CreateIdentityLinkTask"
class="at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask"
@@ -111,6 +115,9 @@
class="at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.InitialSearchTask"
scope="prototype" />
+ <bean id="AlternativeSearchTask"
+ class="at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.AlternativeSearchTask"
+ scope="prototype" />
<bean id="CreateNewErnpEntryTask"
class="at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateNewErnpEntryTask"