diff options
| author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2020-11-27 09:08:10 +0100 | 
|---|---|---|
| committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2020-11-27 09:08:10 +0100 | 
| commit | 7a62a84f23b3a1a1027ebda31fb790ee072793cc (patch) | |
| tree | 7cf1804c99a2876abc934443a2cbfd8d4f59e99b /connector | |
| parent | d01abea064f33d1c985464aadf3e2326c6ba3219 (diff) | |
| download | National_eIDAS_Gateway-7a62a84f23b3a1a1027ebda31fb790ee072793cc.tar.gz National_eIDAS_Gateway-7a62a84f23b3a1a1027ebda31fb790ee072793cc.tar.bz2 National_eIDAS_Gateway-7a62a84f23b3a1a1027ebda31fb790ee072793cc.zip | |
read unique transactionId from AuthnRequest to reuse it for eIDAS authentication
Diffstat (limited to 'connector')
5 files changed, 205 insertions, 103 deletions
| diff --git a/connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java b/connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java index 26176c49..a9eb06be 100644 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java +++ b/connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java @@ -46,11 +46,13 @@ import at.asitplus.eidas.specific.connector.MsEidasNodeConstants;  import at.asitplus.eidas.specific.connector.config.ServiceProviderConfiguration;  import at.gv.egiz.eaaf.core.api.IRequest;  import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions;  import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions;  import at.gv.egiz.eaaf.core.api.idp.IConfiguration;  import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException;  import at.gv.egiz.eaaf.core.exceptions.EaafException;  import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl;  import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute;  import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttributes;  import at.gv.egiz.eaaf.modules.pvp2.api.validation.IAuthnRequestPostProcessor; @@ -107,120 +109,179 @@ public class AuthnRequestValidator implements IAuthnRequestPostProcessor {        }        // post-process requested LoA -      final List<String> reqLoA = extractLoA(authnReq); -      log.trace("SP requests LoA with: {}", String.join(", ",reqLoA)); +      postprocessLoaLevel(pendingReq, authnReq); + +      // post-process requested LoA comparison-level +      pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setLoAMachtingMode( +          extractComparisonLevel(authnReq)); +       +      //extract information from requested attributes +      extractFromRequestedAttriutes(pendingReq, authnReq); -      LevelOfAssurance minimumLoAFromConfig = LevelOfAssurance.fromString(basicConfig.getBasicConfiguration( -          MsEidasNodeConstants.PROP_EIDAS_REQUEST_LOA_MINIMUM_LEVEL, -          EaafConstants.EIDAS_LOA_HIGH)); -      if (minimumLoAFromConfig == null) { -        log.warn("Can not load minimum LoA from configuration. Use LoA: {} as default", -            EaafConstants.EIDAS_LOA_HIGH); -        minimumLoAFromConfig = LevelOfAssurance.HIGH; +    } catch (final EaafStorageException e) { +      log.info("Can NOT store Authn. Req. data into pendingRequest.", e); +      throw new AuthnRequestValidatorException("internal.02", null, e); -      } -             -      log.trace("Validate requested LoA to connector configuration minimum LoA: {} ...", -          minimumLoAFromConfig);       -      final List<String> allowedLoA = new ArrayList<>(); -      for (final String loa : reqLoA) { -        try { -          final LevelOfAssurance intLoa = LevelOfAssurance.fromString(loa); -          String selectedLoA = EaafConstants.EIDAS_LOA_HIGH; -          if (intLoa != null  -              && intLoa.numericValue() <= minimumLoAFromConfig.numericValue()) { -            log.info("Client: {} requested LoA: {} will be upgraded to: {}", -                pendingReq.getServiceProviderConfiguration().getUniqueIdentifier(), -                loa, -                minimumLoAFromConfig); -            selectedLoA = minimumLoAFromConfig.getValue(); +    } -          } +  } -          if (!allowedLoA.contains(selectedLoA)) { -            log.debug("Allow LoA: {} for Client: {}", -                selectedLoA, -                pendingReq.getServiceProviderConfiguration().getUniqueIdentifier()); -            allowedLoA.add(selectedLoA); +  private void extractFromRequestedAttriutes(IRequest pendingReq, AuthnRequest authnReq)  +      throws AuthnRequestValidatorException { +    // validate and process requested attributes +    boolean sectorDetected = false; +     +    final ServiceProviderConfiguration spConfig = pendingReq.getServiceProviderConfiguration( +        ServiceProviderConfiguration.class); +     +    if (authnReq.getExtensions() != null) { +      final List<XMLObject> requestedAttributes = authnReq.getExtensions().getUnknownXMLObjects(); +      for (final XMLObject reqAttrObj : requestedAttributes) { +        if (reqAttrObj instanceof EaafRequestedAttributes) { +          final EaafRequestedAttributes reqAttr = (EaafRequestedAttributes) reqAttrObj; +          if (reqAttr.getAttributes() != null && reqAttr.getAttributes().size() != 0) { +            for (final EaafRequestedAttribute el : reqAttr.getAttributes()) { +              log.trace("Processing req. attribute '" + el.getName() + "' ... "); +              if (el.getName().equals(PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME)) { +                sectorDetected = extractBpkTargetIdentifier(el, spConfig);  +                +              } else if (el.getName().equals(ExtendedPvpAttributeDefinitions.EID_TRANSACTION_ID_NAME)) { +                extractUniqueTransactionId(el, pendingReq); +                 +              } else { +                log.debug("Ignore req. attribute: " + el.getName()); +                 +              } +            } +          } else { +            log.debug("No requested Attributes in Authn. Request"); +                        } -        } catch (final IllegalArgumentException e) { -          log.warn("LoA: {} is currently NOT supported and it will be ignored.", loa); - +        } else { +          log.info("Ignore unknown requested attribute: " + reqAttrObj.getElementQName().toString()); +                    } -        } +    } +     +    if (!sectorDetected) { +      log.warn("Authn.Req validation FAILED. Reason: Contains NO or NO VALID target-sector information."); +      throw new AuthnRequestValidatorException("pvp2.22", new Object[] { +          "NO or NO VALID target-sector information" }); -      pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setRequiredLoA( -          allowedLoA); +    } +     +  } -      // post-process requested LoA comparison-level -      final String reqLoAComperison = extractComparisonLevel(authnReq); -      pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setLoAMachtingMode( -          reqLoAComperison); +  /** +   * Extract unique transactionId from AuthnRequest. +   *  +   * @param el Requested attribute from AuthnRequest +   * @param pendingReq Current pendingRequest object (has to be of type {@link RequestImpl}) +   * @return <code>true</code> if transactionId extraction was successful, otherwise <code>false</code> +   */ +  private boolean extractUniqueTransactionId(EaafRequestedAttribute el, IRequest pendingReq) { +    if (!(pendingReq instanceof RequestImpl)) { +      log.warn("Can NOT set unique transactionId from AuthnRequest,because 'PendingRequest' is NOT from Type: {}", +          RequestImpl.class.getName()); +       +    } else {         +      if (el.getAttributeValues() != null && el.getAttributeValues().size() == 1) { +        final String transactionId = el.getAttributeValues().get(0).getDOM().getTextContent();       +        ((RequestImpl)pendingReq).setUniqueTransactionIdentifier(transactionId);       +        return true; -      // validate and process requested attributes -      boolean sectorDetected = false; +      } else { +        log.warn("Req. attribute '{}' contains NO or MORE THEN ONE attribute-values. Ignore full req. attribute",  +            el.getName()); +         +      } -      if (authnReq.getExtensions() != null) { -        final List<XMLObject> requestedAttributes = authnReq.getExtensions().getUnknownXMLObjects(); -        for (final XMLObject reqAttrObj : requestedAttributes) { -          if (reqAttrObj instanceof EaafRequestedAttributes) { -            final EaafRequestedAttributes reqAttr = (EaafRequestedAttributes) reqAttrObj; -            if (reqAttr.getAttributes() != null && reqAttr.getAttributes().size() != 0) { -              for (final EaafRequestedAttribute el : reqAttr.getAttributes()) { -                log.trace("Processing req. attribute '" + el.getName() + "' ... "); -                if (el.getName().equals(PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME)) { -                  if (el.getAttributeValues() != null && el.getAttributeValues().size() == 1) { -                    final String sectorId = el.getAttributeValues().get(0).getDOM().getTextContent(); -                    final ServiceProviderConfiguration spConfig = pendingReq.getServiceProviderConfiguration( -                        ServiceProviderConfiguration.class); -   -                    try { -                      spConfig.setBpkTargetIdentifier(sectorId); -                      sectorDetected = true; -   -                    } catch (final EaafException e) { -                      log.info("Requested sector: " + sectorId + " DOES NOT match to allowed sectors for SP: " -                          + spConfig.getUniqueIdentifier()); -                    } -   -                  } else { -                    log.info("Req. attribute '" + el.getName() -                        + "' contains NO or MORE THEN ONE attribute-values. Ignore full req. attribute"); -                  } -   -                } else { -                  log.debug("Ignore req. attribute: " + el.getName()); -                } -   -              } -   -            } else { -              log.debug("No requested Attributes in Authn. Request"); -            } -   -          } else { -            log.info("Ignore unknown requested attribute: " + reqAttrObj.getElementQName().toString()); -          } +    } +     +    return false; +  } + +  /** +   * Extract the bPK target from requested attribute. +   *  +   * @param el Requested attribute from AuthnRequest +   * @param spConfig Service-Provider configuration for current process +   * @return <code>true</code> if bPK target extraction was successful, otherwise <code>false</code> +   */ +  private boolean extractBpkTargetIdentifier(EaafRequestedAttribute el, ServiceProviderConfiguration spConfig) {         +    if (el.getAttributeValues() != null && el.getAttributeValues().size() == 1) { +      final String sectorId = el.getAttributeValues().get(0).getDOM().getTextContent();       +      try { +        spConfig.setBpkTargetIdentifier(sectorId); +        return true; + +      } catch (final EaafException e) { +        log.warn("Requested sector: " + sectorId + " DOES NOT match to allowed sectors for SP: " +            + spConfig.getUniqueIdentifier()); +      } + +    } else { +      log.warn("Req. attribute '" + el.getName() +          + "' contains NO or MORE THEN ONE attribute-values. Ignore full req. attribute"); +    } +     +    return false; +     +  } +  private void postprocessLoaLevel(IRequest pendingReq, AuthnRequest authnReq)  +      throws AuthnRequestValidatorException { +    final List<String> reqLoA = extractLoA(authnReq); +    log.trace("SP requests LoA with: {}", String.join(", ",reqLoA)); +     +    LevelOfAssurance minimumLoAFromConfig = LevelOfAssurance.fromString(basicConfig.getBasicConfiguration( +        MsEidasNodeConstants.PROP_EIDAS_REQUEST_LOA_MINIMUM_LEVEL, +        EaafConstants.EIDAS_LOA_HIGH)); +    if (minimumLoAFromConfig == null) { +      log.warn("Can not load minimum LoA from configuration. Use LoA: {} as default", +          EaafConstants.EIDAS_LOA_HIGH); +      minimumLoAFromConfig = LevelOfAssurance.HIGH; + +    } +           +    log.trace("Validate requested LoA to connector configuration minimum LoA: {} ...", +        minimumLoAFromConfig);       +    final List<String> allowedLoA = new ArrayList<>(); +    for (final String loa : reqLoA) { +      try { +        final LevelOfAssurance intLoa = LevelOfAssurance.fromString(loa); +        String selectedLoA = EaafConstants.EIDAS_LOA_HIGH; +        if (intLoa != null  +            && intLoa.numericValue() <= minimumLoAFromConfig.numericValue()) { +          log.info("Client: {} requested LoA: {} will be upgraded to: {}", +              pendingReq.getServiceProviderConfiguration().getUniqueIdentifier(), +              loa, +              minimumLoAFromConfig); +          selectedLoA = minimumLoAFromConfig.getValue(); +          } -      } -      if (!sectorDetected) { -        log.info("Authn.Req validation FAILED. Reason: Contains NO or NO VALID target-sector information."); -        throw new AuthnRequestValidatorException("pvp2.22", new Object[] { -            "NO or NO VALID target-sector information" }); +        if (!allowedLoA.contains(selectedLoA)) { +          log.debug("Allow LoA: {} for Client: {}", +              selectedLoA, +              pendingReq.getServiceProviderConfiguration().getUniqueIdentifier()); +          allowedLoA.add(selectedLoA); -      } +        } -    } catch (final EaafStorageException e) { -      log.info("Can NOT store Authn. Req. data into pendingRequest.", e); -      throw new AuthnRequestValidatorException("internal.02", null, e); +      } catch (final IllegalArgumentException e) { +        log.warn("LoA: {} is currently NOT supported and it will be ignored.", loa); + +      }      } +    pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setRequiredLoA( +        allowedLoA); +        }    private String extractComparisonLevel(AuthnRequest authnReq) { diff --git a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/AuthnRequestValidatorTest.java b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/AuthnRequestValidatorTest.java index e34c8036..389f561e 100644 --- a/connector/src/test/java/at/asitplus/eidas/specific/connector/test/AuthnRequestValidatorTest.java +++ b/connector/src/test/java/at/asitplus/eidas/specific/connector/test/AuthnRequestValidatorTest.java @@ -33,11 +33,14 @@ import org.xml.sax.SAXException;  import at.asitplus.eidas.specific.connector.MsEidasNodeConstants;  import at.asitplus.eidas.specific.connector.config.ServiceProviderConfiguration;  import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; -import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP;  import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl;  import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl;  import at.gv.egiz.eaaf.core.impl.utils.DomUtils;  import at.gv.egiz.eaaf.modules.pvp2.api.validation.IAuthnRequestPostProcessor; +import at.gv.egiz.eaaf.modules.pvp2.idp.impl.PvpSProfilePendingRequest;  import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer;  import net.shibboleth.utilities.java.support.component.ComponentInitializationException; @@ -53,12 +56,12 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationEx  @DirtiesContext(classMode = ClassMode.BEFORE_CLASS)  public class AuthnRequestValidatorTest { -  @Autowired private IConfiguration basicConfig; +  @Autowired private IConfigurationWithSP basicConfig;    @Autowired protected IAuthnRequestPostProcessor authRequestValidator;    private MockHttpServletRequest httpReq;    private MockHttpServletResponse httpResp; -  private TestRequestImpl pendingReq; +  private PvpSProfilePendingRequest pendingReq;    /**     * jUnit class initializer. @@ -76,10 +79,11 @@ public class AuthnRequestValidatorTest {    /**     * jUnit test set-up. +   * @throws EaafException      *      */    @Before -  public void initialize() { +  public void initialize() throws EaafException {      httpReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector");      httpResp = new MockHttpServletResponse();      RequestContextHolder.resetRequestAttributes(); @@ -88,10 +92,12 @@ public class AuthnRequestValidatorTest {      Map<String, String> spConfig = new HashMap<>();      spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, RandomStringUtils.randomAlphabetic(10)); -    pendingReq = new TestRequestImpl(); -    pendingReq.setAuthUrl("https://localhost/ms_connector"); -    pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); -    pendingReq.setSpConfig(new ServiceProviderConfiguration(spConfig, basicConfig)); +    pendingReq = new PvpSProfilePendingRequest(); +    pendingReq.initialize(httpReq, basicConfig); +    pendingReq.setPendingRequestId(RandomStringUtils.randomAlphanumeric(10)); +    pendingReq.setOnlineApplicationConfiguration(new ServiceProviderConfiguration(spConfig, basicConfig));     +    ((RequestImpl)pendingReq).setUniqueTransactionIdentifier(null); +        }    @Test @@ -128,6 +134,8 @@ public class AuthnRequestValidatorTest {      Assert.assertEquals("bPK target not match", "urn:publicid:gv.at:cdid+BF",           pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()); +    Assert.assertNull("wrong transactionId", pendingReq.getUniqueTransactionIdentifier()); +        }    @Test @@ -164,6 +172,8 @@ public class AuthnRequestValidatorTest {      Assert.assertEquals("bPK target not match", "urn:publicid:gv.at:cdid+BF",           pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()); +    Assert.assertNull("wrong transactionId", pendingReq.getUniqueTransactionIdentifier()); +        }    @Test @@ -200,6 +210,30 @@ public class AuthnRequestValidatorTest {      Assert.assertEquals("bPK target not match", "urn:publicid:gv.at:cdid+XX",           pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()); +    Assert.assertEquals("wrong transactionId", "transId_11223344556677aabbcc",  +        pendingReq.getUniqueTransactionIdentifier()); +     +  } +   +  @Test +  public void transactionIdWrongPendingReqType() throws AuthnRequestValidatorException, ParserConfigurationException,  +      SAXException, IOException, UnmarshallingException { +     +    Map<String, String> spConfig = new HashMap<>(); +    spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, RandomStringUtils.randomAlphabetic(10)); +     +    TestRequestImpl pendingReqLocal = new TestRequestImpl(); +    pendingReqLocal.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); +    pendingReqLocal.setSpConfig(new ServiceProviderConfiguration(spConfig, basicConfig));     +     +    AuthnRequest authReq = getAuthRequest("/data/pvp2_authn_3.xml"); +     +    //test +    authRequestValidator.process(httpReq, pendingReqLocal, authReq, null); +         +    //validate +    Assert.assertNull("wrong transactionId", pendingReqLocal.getUniqueTransactionIdentifier()); +        }    @Test @@ -214,7 +248,7 @@ public class AuthnRequestValidatorTest {      } catch (AuthnRequestValidatorException e) {        Assert.assertEquals("Wrong errorCode", "pvp2.22", e.getErrorId()); -       +                  }                  } diff --git a/connector/src/test/resources/config/junit_config_1.properties b/connector/src/test/resources/config/junit_config_1.properties index f498cac4..3350f947 100644 --- a/connector/src/test/resources/config/junit_config_1.properties +++ b/connector/src/test/resources/config/junit_config_1.properties @@ -1,5 +1,5 @@  ## Basic service configuration -eidas.ms.context.url.prefix= +eidas.ms.context.url.prefix=http://localhost  eidas.ms.context.url.request.validation=false  eidas.ms.context.use.clustermode=true diff --git a/connector/src/test/resources/data/pvp2_authn_2.xml b/connector/src/test/resources/data/pvp2_authn_2.xml index 5f21af05..dbf46622 100644 --- a/connector/src/test/resources/data/pvp2_authn_2.xml +++ b/connector/src/test/resources/data/pvp2_authn_2.xml @@ -28,6 +28,10 @@        <eid:RequestedAttribute FriendlyName="EID-SECTOR-FOR-IDENTIFIER" Name="urn:oid:1.2.40.0.10.2.1.1.261.34" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true">          <eid:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">urn:publicid:gv.at:cdid+BF</eid:AttributeValue>        </eid:RequestedAttribute> +      <eid:RequestedAttribute FriendlyName="transactionId" Name="urn:eidgvat:attributes.transactionId" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"> +        <eid:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">transId_11223344556677aabbcc</eid:AttributeValue> +        <eid:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">transId_second</eid:AttributeValue> +      </eid:RequestedAttribute>      </eid:RequestedAttributes>    </saml2p:Extensions>    <saml2p:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/> diff --git a/connector/src/test/resources/data/pvp2_authn_3.xml b/connector/src/test/resources/data/pvp2_authn_3.xml index bf356da7..35e49b0f 100644 --- a/connector/src/test/resources/data/pvp2_authn_3.xml +++ b/connector/src/test/resources/data/pvp2_authn_3.xml @@ -28,6 +28,9 @@        <eid:RequestedAttribute FriendlyName="EID-SECTOR-FOR-IDENTIFIER" Name="urn:oid:1.2.40.0.10.2.1.1.261.34" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true">          <eid:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">urn:publicid:gv.at:cdid+XX</eid:AttributeValue>        </eid:RequestedAttribute> +      <eid:RequestedAttribute FriendlyName="transactionId" Name="urn:eidgvat:attributes.transactionId" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" isRequired="true"> +        <eid:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">transId_11223344556677aabbcc</eid:AttributeValue> +      </eid:RequestedAttribute>      </eid:RequestedAttributes>    </saml2p:Extensions>    <saml2p:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/> | 
