aboutsummaryrefslogtreecommitdiff
path: root/modules/authmodule-eIDAS-v2/src/main
diff options
context:
space:
mode:
authorThomas <>2022-12-19 15:50:38 +0100
committerThomas <>2022-12-19 15:50:38 +0100
commitd2dec4601c41131c3ca509a8f7907b91af0ba2a6 (patch)
tree999634c3edaf5d45774593b4cdece1dada857dab /modules/authmodule-eIDAS-v2/src/main
parentc2fa7fa970f717b8b4e27098b3d2b9341c59fae1 (diff)
downloadNational_eIDAS_Gateway-d2dec4601c41131c3ca509a8f7907b91af0ba2a6.tar.gz
National_eIDAS_Gateway-d2dec4601c41131c3ca509a8f7907b91af0ba2a6.tar.bz2
National_eIDAS_Gateway-d2dec4601c41131c3ca509a8f7907b91af0ba2a6.zip
feat(eidas-connector): support not-notified LoA
- not-notified LoA is currently used by Ukraine
Diffstat (limited to 'modules/authmodule-eIDAS-v2/src/main')
-rw-r--r--modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java8
-rw-r--r--modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/UaEidProcessor.java83
-rw-r--r--modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java12
-rw-r--r--modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java4
-rw-r--r--modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java51
5 files changed, 113 insertions, 45 deletions
diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java
index 5c2c43ea..fa26e48f 100644
--- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java
+++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java
@@ -26,7 +26,6 @@ package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler;
import static at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils.processCountryCode;
-import static at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils.processDateOfBirthToString;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
@@ -38,7 +37,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
-import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
@@ -98,7 +96,7 @@ public abstract class AbstractEidProcessor implements INationalEidProcessor {
.pseudonym(processPseudonym(eidasAttrMap.get(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER)))
.familyName(processFamilyName(eidasAttrMap.get(EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME)))
.givenName(processGivenName(eidasAttrMap.get(EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME)))
- .dateOfBirth(processDateOfBirthToString(eidasAttrMap.get(EidasConstants.eIDAS_ATTR_DATEOFBIRTH)))
+ .dateOfBirth(processDateOfBirth(eidasAttrMap.get(EidasConstants.eIDAS_ATTR_DATEOFBIRTH)))
// additional attributes
.placeOfBirth(processPlaceOfBirth(eidasAttrMap.get(EidasConstants.eIDAS_ATTR_PLACEOFBIRTH)))
@@ -174,9 +172,9 @@ public abstract class AbstractEidProcessor implements INationalEidProcessor {
* @throws EidasAttributeException if NO attribute is available
* @throws EidPostProcessingException if post-processing fails
*/
- protected DateTime processDateOfBirth(Object dateOfBirthObj) throws EidPostProcessingException,
+ protected String processDateOfBirth(Object dateOfBirthObj) throws EidPostProcessingException,
EidasAttributeException {
- return EidasResponseUtils.processDateOfBirth(dateOfBirthObj);
+ return EidasResponseUtils.processDateOfBirthToString(dateOfBirthObj);
}
diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/UaEidProcessor.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/UaEidProcessor.java
index 6be0a26b..1656ec40 100644
--- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/UaEidProcessor.java
+++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/UaEidProcessor.java
@@ -1,12 +1,21 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Date;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
+import at.asitplus.eidas.specific.core.config.IEidasSpConfiguration;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException;
+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.idp.ISpConfiguration;
import eu.eidas.auth.commons.light.impl.LightRequest.Builder;
@@ -15,8 +24,8 @@ import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
/**
- * Ulraine specific eIDAS AuthnRequest generation.
- *
+ * Ulraine specific eIDAS AuthnRequest generation.
+ *
* @author tlenz
*
*/
@@ -24,45 +33,81 @@ import lombok.extern.slf4j.Slf4j;
public class UaEidProcessor extends AbstractEidProcessor {
private static final String CONFIG_PROP_UA_SPECIFIC_LOA = "auth.eIDAS.node_v2.loa.ua.requested";
-
+ private static final String CONFIG_PROP_UA_WORKAROUND_DATEOFBIRTH =
+ "auth.eIDAS.node_v2.workaround.ua.dateofbirth";
+ private static final String STATIC_DATE_OF_BIRTH = "2000-05-29";
+
private static final String canHandleCC = "UA";
- @Autowired IConfiguration config;
-
+ @Autowired
+ IConfiguration config;
+
@Getter
@Setter
private int priority = 1;
-
+
@Override
public String getName() {
return "UA-PostProcessor";
-
+
}
@Override
public boolean canHandle(String countryCode) {
return countryCode != null && countryCode.equalsIgnoreCase(canHandleCC);
-
+
}
-
+
@Override
protected Map<String, Boolean> getCountrySpecificRequestedAttributes() {
return new HashMap<>();
-
+
}
-
- protected void buildLevelOfAssurance(ISpConfiguration spConfig, Builder authnRequestBuilder) {
-
- // allow override of LoA, because UA maybe only support not-notified LoA levels
- String uaSpecificLoA = config.getBasicConfiguration(CONFIG_PROP_UA_SPECIFIC_LOA);
+
+ @Override
+ protected void buildLevelOfAssurance(ISpConfiguration spConfig, Builder authnRequestBuilder) {
+ // allow override of LoA, because UA maybe only support not-notified LoA levels
+ final String uaSpecificLoA = config.getBasicConfiguration(CONFIG_PROP_UA_SPECIFIC_LOA);
if (StringUtils.isNotEmpty(uaSpecificLoA)) {
authnRequestBuilder.levelsOfAssuranceValues(Arrays.asList(uaSpecificLoA));
- log.info("Set UA specific LoA level to: {}", uaSpecificLoA);
-
+
+ // set non-notified LoA as allowed LoA
+ final List<String> allowedLoa = new ArrayList<>();
+ allowedLoa.addAll(spConfig.getRequiredLoA());
+ allowedLoa.add(uaSpecificLoA);
+ ((IEidasSpConfiguration) spConfig).setRequiredLoA(allowedLoa);
+ ((IEidasSpConfiguration) spConfig).setLoAMachtingMode(EaafConstants.EIDAS_LOA_MATCHING_EXACT);
+ log.info("Set UA specific LoA level to: {} with matching-mode: {}",
+ StringUtils.join(allowedLoa, "|"), EaafConstants.EIDAS_LOA_MATCHING_EXACT);
+
} else {
super.buildLevelOfAssurance(spConfig, authnRequestBuilder);
-
+
}
}
-
+
+ @Override
+ protected String processDateOfBirth(Object dateOfBirthObj) throws EidPostProcessingException,
+ EidasAttributeException {
+ final String dateOfBirth = super.processDateOfBirth(dateOfBirthObj);
+
+ try {
+ final Date dateElement = new SimpleDateFormat("yyyy-MM-dd").parse(dateOfBirth);
+ if (basicConfig.getBasicConfigurationBoolean(CONFIG_PROP_UA_WORKAROUND_DATEOFBIRTH, false)
+ && dateElement.after(new Date())) {
+ log.warn("DateOfBirth: {} is in the future. Use static DateOfBirth as backup", dateOfBirth);
+ return STATIC_DATE_OF_BIRTH;
+
+ } else {
+ return dateOfBirth;
+
+ }
+
+ } catch (final ParseException e) {
+ log.warn("Can not parse dateOfBirth", e);
+ return dateOfBirth;
+
+ }
+ }
+
}
diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
index 93e1033d..cf6ecb8d 100644
--- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
+++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
@@ -119,6 +119,9 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
final LightRequest lightAuthnReq = buildEidasAuthnRequest(citizenCountryCode, issuer);
+ // store pending request after possible updates
+ requestStoreage.storePendingRequest(pendingReq);
+
final BinaryLightToken token = putRequestInCommunicationCache(lightAuthnReq);
final String tokenBase64 = BinaryLightTokenHelper.encodeBinaryLightTokenBase64(token);
workaroundRelayState(lightAuthnReq);
@@ -136,6 +139,10 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
}
revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.EIDAS_NODE_CONNECTED, lightAuthnReq.getId());
+ log.info("Allowed LoA: {}",
+ StringUtils.join(pendingReq.getServiceProviderConfiguration().getRequiredLoA(),", "));
+
+
} catch (final EidasSAuthenticationException e) {
throw new TaskExecutionException(pendingReq, "eIDAS AuthnRequest generation FAILED.", e);
} catch (final Exception e) {
@@ -238,10 +245,7 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
log.info("Inject alternative MS-Connector end-point: {}", alternativReturnEndpoint);
pendingReq.setRawDataToTransaction(
MsEidasNodeConstants.EXECCONTEXT_PARAM_MSCONNECTOR_STAGING, alternativReturnEndpoint);
-
- // store pending request after update
- requestStoreage.storePendingRequest(pendingReq);
-
+
}
}
diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java
index a16da17f..cc497318 100644
--- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java
+++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java
@@ -111,6 +111,10 @@ public class ReceiveAuthnResponseTask extends AbstractAuthServletTask {
storeInSession(eidasResponse);
}
+ log.info("Allowed LoA Response: {}",
+ StringUtils.join(pendingReq.getServiceProviderConfiguration().getRequiredLoA(),", "));
+
+
revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_VALID);
} catch (final EaafException e) {
revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_NOT_VALID);
diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java
index d1962654..b3c5dac1 100644
--- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java
+++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java
@@ -26,8 +26,6 @@ package at.asitplus.eidas.specific.modules.auth.eidas.v2.validator;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableSet;
@@ -40,7 +38,10 @@ import at.gv.egiz.eaaf.core.impl.data.Triple;
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.LevelOfAssurance;
+import eu.eidas.auth.commons.light.LevelOfAssuranceType;
+import eu.eidas.auth.commons.light.impl.LevelOfAssurance;
+import eu.eidas.auth.commons.protocol.eidas.NotifiedLevelOfAssurance;
+import lombok.extern.slf4j.Slf4j;
/**
* eIDAS Response validator implementation.
@@ -48,8 +49,8 @@ import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance;
* @author tlenz
*
*/
+@Slf4j
public class EidasResponseValidator {
- private static final Logger log = LoggerFactory.getLogger(EidasResponseValidator.class);
/**
* Validate an eIDAS Response according to internal state.
@@ -67,24 +68,39 @@ public class EidasResponseValidator {
/*-----------------------------------------------------|
* validate received LoA against minimum required LoA |
*_____________________________________________________|
- */
- final LevelOfAssurance respLoA = LevelOfAssurance.fromString(eidasResponse.getLevelOfAssurance());
+ */
+ final LevelOfAssurance respLoA = LevelOfAssurance.build(eidasResponse.getLevelOfAssurance());
final List<String> allowedLoAs = pendingReq.getServiceProviderConfiguration().getRequiredLoA();
boolean loaValid = false;
for (final String allowedLoaString : allowedLoAs) {
- final LevelOfAssurance allowedLoa = LevelOfAssurance.fromString(allowedLoaString);
- if (respLoA.numericValue() >= allowedLoa.numericValue()) {
- log.debug("Response contains valid LoA. Resume process ... ");
- loaValid = true;
- break;
-
+ final LevelOfAssurance allowedLoa = LevelOfAssurance.build(allowedLoaString);
+ if (LevelOfAssuranceType.NOTIFIED.stringValue().equals(respLoA.getType())) {
+ NotifiedLevelOfAssurance notifiedLoa = NotifiedLevelOfAssurance.fromString(respLoA.getValue());
+ NotifiedLevelOfAssurance notifiedAllowedLoa = NotifiedLevelOfAssurance.fromString(allowedLoa.getValue());
+ if (notifiedLoa.numericValue() >= notifiedAllowedLoa.numericValue()) {
+ log.debug("Response contains valid LoA. Resume process ... ");
+ loaValid = true;
+ break;
+
+ } else {
+ log.trace("Allowed LoA: " + allowedLoaString + " DOES NOT match response LoA: " + eidasResponse
+ .getLevelOfAssurance());
+ }
+
} else {
- log.trace("Allowed LoA: " + allowedLoaString + " DOES NOT match response LoA: " + eidasResponse
- .getLevelOfAssurance());
- }
-
+ if (respLoA.equals(allowedLoa)) {
+ log.info("Find not-notified LoA: {}. Use it as it is ... ", respLoA.getValue());
+ loaValid = true;
+ break;
+
+ } else {
+ log.trace("Allowed LoA: " + allowedLoaString + " DOES NOT match response LoA: " + eidasResponse
+ .getLevelOfAssurance());
+
+ }
+ }
}
-
+
if (!loaValid) {
log.error("eIDAS Response LevelOfAssurance is lower than the required! "
+ "(Resp-LoA:{} Req-LoA:{} )", respLoA.getValue(), allowedLoAs.toArray());
@@ -92,6 +108,7 @@ public class EidasResponseValidator {
}
+
/*-----------------------------------------------------|
* validate 'PersonalIdentifier' attribute |
*_____________________________________________________|