diff options
| author | Thomas <> | 2022-12-19 15:50:38 +0100 | 
|---|---|---|
| committer | Thomas <> | 2022-12-19 15:50:38 +0100 | 
| commit | d2dec4601c41131c3ca509a8f7907b91af0ba2a6 (patch) | |
| tree | 999634c3edaf5d45774593b4cdece1dada857dab /modules/authmodule-eIDAS-v2/src/main/java | |
| parent | c2fa7fa970f717b8b4e27098b3d2b9341c59fae1 (diff) | |
| download | National_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/java')
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         |       *_____________________________________________________| | 
