aboutsummaryrefslogtreecommitdiff
path: root/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus
diff options
context:
space:
mode:
authorThomas <>2021-11-16 08:41:19 +0100
committerThomas <>2021-11-16 08:41:19 +0100
commite385456f79574dac9702b01a6722de444359fff1 (patch)
tree2ad0c83bff8fb9d1ab14e0379383d5eed0a5be7c /eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus
parent85b20a28e3a44e2c0fd68d10c033bcace0b6203c (diff)
downloadNational_eIDAS_Gateway-e385456f79574dac9702b01a6722de444359fff1.tar.gz
National_eIDAS_Gateway-e385456f79574dac9702b01a6722de444359fff1.tar.bz2
National_eIDAS_Gateway-e385456f79574dac9702b01a6722de444359fff1.zip
restructure matching step via alternative-eIDAS-authentication and add jUnit tests
Diffstat (limited to 'eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus')
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java112
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java117
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java27
3 files changed, 181 insertions, 75 deletions
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java
index 232b1d11..047d75ae 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java
@@ -1,5 +1,16 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.service;
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.jetbrains.annotations.Nullable;
+import org.springframework.stereotype.Service;
+
+import com.google.common.collect.Streams;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.IZmrClient;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient.ZmrRegisterResult;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;
@@ -13,15 +24,6 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections4.ListUtils;
-import org.jetbrains.annotations.Nullable;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Nonnull;
-import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
@Slf4j
@Service("registerSearchService")
@@ -57,9 +59,24 @@ public class RegisterSearchService {
@Nonnull
public RegisterStatusResults searchWithPersonIdentifier(SimpleEidasData eidasData)
throws WorkflowException {
+ return searchWithPersonIdentifier(null, eidasData);
+
+ }
+
+ /**
+ * Search with Person Identifier (eIDAS Pseudonym) in ZMR and ERnP.
+ *
+ * @param operationStatus Current register-operation status that contains processing informations
+ * @param eidasData Received eIDAS data
+ * @throws WorkflowException In case of a register interaction error
+ */
+ @Nonnull
+ public RegisterStatusResults searchWithPersonIdentifier(@Nullable RegisterOperationStatus operationStatus,
+ @Nonnull SimpleEidasData eidasData) throws WorkflowException {
try {
final ZmrRegisterResult resultsZmr = zmrClient.searchWithPersonIdentifier(
- null, eidasData.getPseudonym(), eidasData.getCitizenCountryCode());
+ operationStatus != null ? operationStatus.getZmrProcessId() : null,
+ eidasData.getPseudonym(), eidasData.getCitizenCountryCode());
final List<RegisterResult> resultsErnp = ernpClient.searchWithPersonIdentifier(
eidasData.getPersonalIdentifier());
@@ -71,7 +88,7 @@ public class RegisterSearchService {
}
}
-
+
/**
* Search with MDS (Given Name, Family Name, Date of Birth) in ZMR and ERnP.
*
@@ -185,39 +202,70 @@ public class RegisterSearchService {
}
}
+ //TODO: check this method, because it's different to 'step7aKittProcess'???
/**
* Automatic process to fix the register entries.
* Called when the alternative eIDAS authn leads to a match in a register.
*
- * @param registerResult Result of last register search
- * @param initialEidasData Received eidas data from initial authentication
- * @param altEidasData Received eidas data from alternative authentication
+ * @param initialSearchResult Register results from initial authentication
+ * @param initialEidasData Received eIDAS data from initial authentication
+ * @param altSearchResult Register results from alternative authentication
+ * @param altEidasData Received eIDAS data from alternative authentication
* @return
*/
- public RegisterStatusResults step7bKittProcess(RegisterStatusResults registerResult,
- SimpleEidasData initialEidasData, SimpleEidasData altEidasData)
- throws WorkflowException {
+ public RegisterStatusResults step7bKittProcess(
+ RegisterStatusResults initialSearchResult, SimpleEidasData initialEidasData,
+ RegisterStatusResults altSearchResult, SimpleEidasData altEidasData) throws WorkflowException {
log.trace("Starting step7bKittProcess");
- // TODO verify with which data this method gets called
- if (registerResult.getResultCount() != 1) {
+
+ // check if alternative authentication ends in a single result
+ if (altSearchResult.getResultCount() != 1) {
throw new WorkflowException("step7bKittProcess", "getResultCount() != 1");
+
+ }
+
+ // check if alternative authentication result is part of initialSearchResults
+ if (!Streams.concat(initialSearchResult.getResultsZmr().stream(), initialSearchResult.getResultsErnp().stream())
+ .filter(el -> {
+ try {
+ return altSearchResult.getResult().getBpk().equals(el.getBpk());
+
+ } catch (WorkflowException e1) {
+ //can not appear because it's already validated above.
+ return false;
+ }
+ })
+ .findFirst()
+ .isPresent()) {
+ throw new WorkflowException("step7bKittProcess",
+ "Register result from alternativ authentication does not fit into intermediate state");
+
}
+
+ // perform KITT operations
try {
- if (registerResult.getResultsZmr().size() == 1) {
- RegisterResult entryZmr = registerResult.getResultsZmr().get(0);
- ZmrRegisterResult updateAlt = zmrClient
- .update(registerResult.getOperationStatus().getZmrProcessId(), entryZmr, altEidasData);
- ZmrRegisterResult updateInitial = zmrClient
- .update(registerResult.getOperationStatus().getZmrProcessId(), entryZmr, initialEidasData);
- return new RegisterStatusResults(registerResult.getOperationStatus(),
- ListUtils.union(updateAlt.getPersonResult(), updateInitial.getPersonResult()),
- Collections.emptyList());
+ if (altSearchResult.getResultsZmr().size() == 1) {
+ RegisterResult entryZmr = altSearchResult.getResultsZmr().get(0);
+
+ // update ZMR entry by using eIDAS information from initial authentication
+ zmrClient.update(altSearchResult.getOperationStatus().getZmrProcessId(), entryZmr, initialEidasData);
+
+ // update ZMR entry by using eIDAS information from alternative authentication
+ ZmrRegisterResult updateAlt = zmrClient.update(
+ altSearchResult.getOperationStatus().getZmrProcessId(), entryZmr, altEidasData);
+
+ return RegisterStatusResults.fromZmr(updateAlt);
+
} else {
- RegisterResult entryErnp = registerResult.getResultsErnp().get(0);
+ RegisterResult entryErnp = altSearchResult.getResultsErnp().get(0);
+
+ // update ZMR entry by using eIDAS information from initial authentication
+ ernpClient.update(entryErnp, initialEidasData);
+
+ // update ZMR entry by using eIDAS information from alternative authentication
RegisterResult updateAlt = ernpClient.update(entryErnp, altEidasData);
- RegisterResult updateInitial = ernpClient.update(entryErnp, initialEidasData);
- return new RegisterStatusResults(registerResult.getOperationStatus(), Collections.emptyList(),
- Arrays.asList(updateAlt, updateInitial));
+
+ return RegisterStatusResults.fromErnp(altSearchResult.operationStatus, Collections.singletonList(updateAlt));
}
} catch (final EidasSAuthenticationException e) {
throw new WorkflowException("kittMatchedIdentitiess", e.getMessage(),
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java
index 4705c56b..e0273d10 100644
--- 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
@@ -23,6 +23,17 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks;
+import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK;
+
+import java.util.Map;
+import java.util.Objects;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+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;
@@ -40,15 +51,6 @@ import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
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.stereotype.Component;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.Map;
-import java.util.Objects;
-
-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.
@@ -96,74 +98,123 @@ public class AlternativeSearchTask extends AbstractAuthServletTask {
public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
throws TaskExecutionException {
try {
- final SimpleEidasData altEidasData = convertEidasAttrToSimpleData();
+ final SimpleEidasData altEidasData = convertEidasAttrToSimpleData();
final SimpleEidasData initialEidasData = MatchingTaskUtils.getInitialEidasData(pendingReq);
- verifyAlternativeEidasData(altEidasData, initialEidasData);
- step11RegisterSearchWithPersonIdentifier(executionContext, altEidasData, initialEidasData);
+ final RegisterStatusResults intermediateMatchingState =
+ MatchingTaskUtils.getIntermediateMatchingResult(pendingReq);
+
+ //pre-validation of eIDAS data
+ preVerifyAlternativeEidasData(altEidasData, initialEidasData, intermediateMatchingState);
+
+ //perform register search operation based on alterantive eIDAS data
+ step11RegisterSearchWithPersonIdentifier(executionContext, altEidasData,
+ intermediateMatchingState, initialEidasData);
+
} 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 verifyAlternativeEidasData(SimpleEidasData altEidasData, SimpleEidasData initialEidasData)
- throws WorkflowException {
+ /**
+ * Pre-validation of eIDAS information.
+ *
+ * <p>Check if country-code and MDS (givenName, familyName, dateOfBirth) matches.</p>
+ *
+ * @param altEidasData eIDAS data from alternative authentication
+ * @param initialEidasData eIDAS data from initial authentication
+ * @param intermediateMatchingState Intermediate matching result
+ * @throws WorkflowException In case of a validation error
+ */
+ private void preVerifyAlternativeEidasData(SimpleEidasData altEidasData, SimpleEidasData initialEidasData,
+ RegisterStatusResults intermediateMatchingState) throws WorkflowException {
if (initialEidasData == null) {
- throw new WorkflowException("step11", "No initial eIDAS authn data");
+ throw new WorkflowException("step11", "No initial eIDAS authn data", true);
+
+ }
+
+ if (intermediateMatchingState == null) {
+ throw new WorkflowException("step11", "No intermediate matching-state", true);
+
}
+
if (!Objects.equals(altEidasData.getCitizenCountryCode(), initialEidasData.getCitizenCountryCode())) {
throw new WorkflowException("step11", "Country Code of alternative eIDAS authn not matching", true);
+
}
+
if (!altEidasData.equalsMds(initialEidasData)) {
throw new WorkflowException("step11", "MDS of alternative eIDAS authn does not match initial authn", true);
+
}
}
private void step11RegisterSearchWithPersonIdentifier(
- ExecutionContext executionContext, SimpleEidasData initialEidasData, SimpleEidasData altEidasData)
+ ExecutionContext executionContext, SimpleEidasData altEidasData,
+ RegisterStatusResults intermediateMatchingState, SimpleEidasData initialEidasData)
throws WorkflowException, EaafStorageException {
try {
log.trace("Starting step11RegisterSearchWithPersonIdentifier");
- RegisterStatusResults searchResult = registerSearchService.searchWithPersonIdentifier(altEidasData);
- int resultCount = searchResult.getResultCount();
+ RegisterStatusResults altSearchResult = registerSearchService.searchWithPersonIdentifier(
+ intermediateMatchingState.getOperationStatus(), altEidasData);
+
+ int resultCount = altSearchResult.getResultCount();
if (resultCount == 0) {
- step12CountrySpecificSearch(executionContext, searchResult.getOperationStatus(), initialEidasData,
- altEidasData);
+ step12CountrySpecificSearch(executionContext, intermediateMatchingState, initialEidasData,
+ altSearchResult.getOperationStatus(), altEidasData);
+
} else if (resultCount == 1) {
- foundMatchFinalizeTask(searchResult, altEidasData);
+ log.debug("step11RegisterSearchWithPersonIdentifier find single result. Starting KITT operation ... ");
+ RegisterStatusResults matchtedResult = registerSearchService.step7bKittProcess(
+ intermediateMatchingState, initialEidasData, altSearchResult, altEidasData);
+
+ log.debug("KITT operation finished. Finalize matching process ... ");
+ foundMatchFinalizeTask(matchtedResult, altEidasData);
+
} 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,
+ RegisterStatusResults intermediateMatchingState,
SimpleEidasData initialEidasData,
+ RegisterOperationStatus registerOperationStatus,
SimpleEidasData altEidasData)
throws EaafStorageException, WorkflowException {
- log.trace("Starting 'step12CountrySpecificSearch' ... ");
- RegisterStatusResults searchResult = registerSearchService.searchWithCountrySpecifics(
+ log.trace("Starting 'step12CountrySpecificSearch' ... ");
+ RegisterStatusResults ccAltSearchResult = registerSearchService.searchWithCountrySpecifics(
registerOperationStatus, altEidasData);
- if (searchResult.getResultCount() == 0) {
+
+ if (ccAltSearchResult.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 ... ");
- registerSearchService.step7bKittProcess(searchResult, initialEidasData, altEidasData);
- foundMatchFinalizeTask(searchResult, altEidasData);
+
+ } else if (ccAltSearchResult.getResultCount() == 1) {
+ log.debug("'step12CountrySpecificSearch' find single result. Starting KITT operation ... ");
+ RegisterStatusResults matchtedResult = registerSearchService.step7bKittProcess(
+ intermediateMatchingState, initialEidasData, ccAltSearchResult, altEidasData);
+
+ log.debug("KITT operation finished. Finalize matching process ... ");
+ foundMatchFinalizeTask(matchtedResult, altEidasData);
+
} else {
throw new WorkflowException("step12CountrySpecificSearch",
"More than one entry with unique country-specific information", true);
- }
+
+ }
}
private void foundMatchFinalizeTask(RegisterStatusResults searchResult, SimpleEidasData eidasData)
@@ -171,6 +222,10 @@ public class AlternativeSearchTask extends AbstractAuthServletTask {
MatchedPersonResult result = MatchedPersonResult.generateFormMatchingResult(
searchResult.getResult(), eidasData.getCitizenCountryCode());
MatchingTaskUtils.storeFinalMatchingResult(pendingReq, result);
+
+ //remove intermediate matching-state
+ MatchingTaskUtils.storeIntermediateMatchingResult(pendingReq, null);
+
}
@NotNull
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java
index c7631f53..ad641841 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java
@@ -1,5 +1,19 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.utils;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.springframework.lang.NonNull;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
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;
@@ -8,20 +22,9 @@ import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchSe
import at.gv.egiz.eaaf.core.api.IRequest;
import at.gv.egiz.eaaf.core.exceptions.EaafStorageException;
import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;
-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.protocol.eidas.impl.PostalAddress;
-import org.apache.commons.lang3.StringUtils;
-import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.springframework.lang.NonNull;
-
-import javax.annotation.Nullable;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
public class MatchingTaskUtils {
@@ -64,7 +67,7 @@ public class MatchingTaskUtils {
RegisterStatusResults.class);
}
-
+
/**
* Store intermediate matching result into session.
*