aboutsummaryrefslogtreecommitdiff
path: root/connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java
diff options
context:
space:
mode:
Diffstat (limited to 'connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java')
-rw-r--r--connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java446
1 files changed, 231 insertions, 215 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 c49c0b28..0230521c 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
@@ -1,6 +1,6 @@
-/*******************************************************************************
+/*
* Copyright 2018 A-SIT Plus GmbH
- * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
+ * 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
@@ -19,7 +19,8 @@
* 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.connector.verification;
import java.util.ArrayList;
@@ -31,8 +32,8 @@ import org.apache.commons.lang3.StringUtils;
import org.opensaml.saml2.core.AuthnContextClassRef;
import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration;
import org.opensaml.saml2.core.AuthnRequest;
-import org.opensaml.saml2.core.NameID;
import org.opensaml.saml2.core.NameIDPolicy;
+import org.opensaml.saml2.core.NameIDType;
import org.opensaml.saml2.core.RequestedAuthnContext;
import org.opensaml.saml2.core.Scoping;
import org.opensaml.saml2.metadata.SPSSODescriptor;
@@ -41,7 +42,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import at.asitplus.eidas.specific.connector.MSeIDASNodeConstants;
+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;
@@ -58,215 +59,230 @@ import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance;
public class AuthnRequestValidator implements IAuthnRequestValidator {
- private static final Logger log = LoggerFactory.getLogger(AuthnRequestValidator.class);
-
- @Autowired(required=true) private IConfiguration basicConfig;
-
- @Override
- public void validate(HttpServletRequest httpReq, IRequest pendingReq, AuthnRequest authnReq,
- SPSSODescriptor spSSODescriptor) throws AuthnRequestValidatorException {
- try {
- //validate NameIDPolicy
- NameIDPolicy nameIDPolicy = authnReq.getNameIDPolicy();
- if (nameIDPolicy != null) {
- String nameIDFormat = nameIDPolicy.getFormat();
- if (nameIDFormat != null) {
- if ( !(NameID.TRANSIENT.equals(nameIDFormat) ||
- NameID.PERSISTENT.equals(nameIDFormat)) ) {
-
- throw new NameIdFormatNotSupportedException(nameIDFormat);
-
- }
-
- } else
- log.trace("Find NameIDPolicy, but NameIDFormat is 'null'");
- } else
- log.trace("AuthnRequest includes no 'NameIDPolicy'");
-
-
- //post-process RequesterId
- String spEntityId = extractScopeRequsterId(authnReq);
- if (StringUtils.isEmpty(spEntityId)) {
- log.info("NO service-provider entityID in Authn. request. Stop authn. process ... ");
- throw new AuthnRequestValidatorException("pvp2.22",
- new Object[] {"NO relaying-party entityID in Authn. request"}, pendingReq);
-
- } else
- pendingReq.setRawDataToTransaction(MSeIDASNodeConstants.DATA_REQUESTERID, spEntityId);
-
-
- //post-process ProviderName
- String providerName = authnReq.getProviderName();
- if (StringUtils.isEmpty(providerName))
- log.info("Authn. request contains NO SP friendlyName");
- else
- pendingReq.setRawDataToTransaction(MSeIDASNodeConstants.DATA_PROVIDERNAME, spEntityId);
-
- //post-process requested LoA
- List<String> reqLoA = extractLoA(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;
-
- }
-
- log.trace("Validate requested LoA to connector configuration minimum LoA: {} ...", minimumLoAFromConfig);
- List<String> allowedLoA = new ArrayList<>();
- for (String loa : reqLoA) {
- try {
- 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 = intLoa.getValue();
-
- }
-
- if (!allowedLoA.contains(selectedLoA)) {
- log.debug("Allow LoA: {} for Client: {}",
- selectedLoA,
- pendingReq.getServiceProviderConfiguration().getUniqueIdentifier());
- allowedLoA.add(selectedLoA);
-
- }
-
- } catch (IllegalArgumentException e) {
- log.warn("LoA: {} is currently NOT supported and it will be ignored.", loa);
-
- }
-
- }
-
- pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setRequiredLoA(allowedLoA);
-
- //post-process requested LoA comparison-level
- String reqLoAComperison = extractComparisonLevel(authnReq);
- pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setLoAMachtingMode(reqLoAComperison);
-
- //validate and process requested attributes
- boolean sectorDetected = false;
- List<XMLObject> requestedAttributes = authnReq.getExtensions().getUnknownXMLObjects();
- for (XMLObject reqAttrObj : requestedAttributes) {
- if (reqAttrObj instanceof EaafRequestedAttributes) {
- EaafRequestedAttributes reqAttr = (EaafRequestedAttributes)reqAttrObj;
- if (reqAttr.getAttributes() != null && reqAttr.getAttributes().size() != 0 ) {
- for (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) {
- String sectorId = el.getAttributeValues().get(0).getDOM().getTextContent();
- ServiceProviderConfiguration spConfig = pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class);
-
- try {
- spConfig.setbPKTargetIdentifier(sectorId);
- sectorDetected = true;
-
- } catch (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());
-
- }
-
- 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"});
-
- }
-
- } catch (EaafStorageException e) {
- log.info("Can NOT store Authn. Req. data into pendingRequest." , e);
- throw new AuthnRequestValidatorException("internal.02", null, e);
-
- }
-
- }
-
- private String extractComparisonLevel(AuthnRequest authnReq) {
- if (authnReq.getRequestedAuthnContext() != null) {
- RequestedAuthnContext authContext = authnReq.getRequestedAuthnContext();
- return authContext.getComparison().toString();
-
- }
-
- return null;
- }
-
- private List<String> extractLoA(AuthnRequest authnReq) throws AuthnRequestValidatorException {
- List<String> result = new ArrayList<String>();
- if (authnReq.getRequestedAuthnContext() != null) {
- RequestedAuthnContext authContext = authnReq.getRequestedAuthnContext();
- if (authContext.getComparison().equals(AuthnContextComparisonTypeEnumeration.MINIMUM)) {
- if (authContext.getAuthnContextClassRefs().isEmpty()) {
- log.debug("Authn. Req. contains no requested LoA");
-
- } else if (authContext.getAuthnContextClassRefs().size() > 1) {
- log.info("Authn. Req. contains MORE THAN ONE requested LoA, but "
- + AuthnContextComparisonTypeEnumeration.MINIMUM + " allows only one" );
- throw new AuthnRequestValidatorException("pvp2.22",
- new Object[] {"Authn. Req. contains MORE THAN ONE requested LoA, but "
- + AuthnContextComparisonTypeEnumeration.MINIMUM + " allows only one"});
-
- } else
- result.add(authContext.getAuthnContextClassRefs().get(0).getAuthnContextClassRef());
-
- } else if (authContext.getComparison().equals(AuthnContextComparisonTypeEnumeration.EXACT)) {
- for (AuthnContextClassRef el : authContext.getAuthnContextClassRefs())
- result.add(el.getAuthnContextClassRef());
-
- } else {
- log.info("Currently only '" + AuthnContextComparisonTypeEnumeration.MINIMUM + "' and '"
- + AuthnContextComparisonTypeEnumeration.EXACT + "' are supported");
- throw new AuthnRequestValidatorException("pvp2.22",
- new Object[] {"Currently only '" + AuthnContextComparisonTypeEnumeration.MINIMUM + "' and '"
- + AuthnContextComparisonTypeEnumeration.EXACT + "' are supported"});
-
- }
-
- }
-
- return result;
- }
-
- private String extractScopeRequsterId(AuthnRequest authnReq) {
- if (authnReq.getScoping() != null) {
- Scoping scoping = authnReq.getScoping();
- if (scoping.getRequesterIDs() != null &&
- scoping.getRequesterIDs().size() > 0) {
- if (scoping.getRequesterIDs().size() == 1)
- return scoping.getRequesterIDs().get(0).getRequesterID();
-
- else {
- log.info("Authn. request contains more than on RequesterIDs! Only use first one");
- return scoping.getRequesterIDs().get(0).getRequesterID();
-
- }
- }
- }
-
- return null;
- }
-
+ private static final Logger log = LoggerFactory.getLogger(AuthnRequestValidator.class);
+
+ @Autowired(required = true)
+ private IConfiguration basicConfig;
+
+ @Override
+ public void validate(HttpServletRequest httpReq, IRequest pendingReq, AuthnRequest authnReq,
+ SPSSODescriptor spSsoDescriptor) throws AuthnRequestValidatorException {
+ try {
+ // validate NameIDPolicy
+ final NameIDPolicy nameIdPolicy = authnReq.getNameIDPolicy();
+ if (nameIdPolicy != null) {
+ final String nameIdFormat = nameIdPolicy.getFormat();
+ if (nameIdFormat != null) {
+ if (!(NameIDType.TRANSIENT.equals(nameIdFormat)
+ || NameIDType.PERSISTENT.equals(nameIdFormat))) {
+
+ throw new NameIdFormatNotSupportedException(nameIdFormat);
+
+ }
+
+ } else {
+ log.trace("Find NameIDPolicy, but NameIDFormat is 'null'");
+ }
+ } else {
+ log.trace("AuthnRequest includes no 'NameIDPolicy'");
+ }
+
+ // post-process RequesterId
+ final String spEntityId = extractScopeRequsterId(authnReq);
+ if (StringUtils.isEmpty(spEntityId)) {
+ log.info("NO service-provider entityID in Authn. request. Stop authn. process ... ");
+ throw new AuthnRequestValidatorException("pvp2.22",
+ new Object[] { "NO relaying-party entityID in Authn. request" }, pendingReq);
+
+ } else {
+ pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, spEntityId);
+ }
+
+ // post-process ProviderName
+ final String providerName = authnReq.getProviderName();
+ if (StringUtils.isEmpty(providerName)) {
+ log.info("Authn. request contains NO SP friendlyName");
+ } else {
+ pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_PROVIDERNAME, spEntityId);
+ }
+
+ // post-process requested LoA
+ final List<String> reqLoA = extractLoA(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;
+
+ }
+
+ 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 = intLoa.getValue();
+
+ }
+
+ if (!allowedLoA.contains(selectedLoA)) {
+ log.debug("Allow LoA: {} for Client: {}",
+ selectedLoA,
+ pendingReq.getServiceProviderConfiguration().getUniqueIdentifier());
+ allowedLoA.add(selectedLoA);
+
+ }
+
+ } catch (final IllegalArgumentException e) {
+ log.warn("LoA: {} is currently NOT supported and it will be ignored.", loa);
+
+ }
+
+ }
+
+ pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setRequiredLoA(
+ allowedLoA);
+
+ // post-process requested LoA comparison-level
+ final String reqLoAComperison = extractComparisonLevel(authnReq);
+ pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setLoAMachtingMode(
+ reqLoAComperison);
+
+ // validate and process requested attributes
+ boolean sectorDetected = false;
+ 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());
+ }
+
+ }
+
+ 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" });
+
+ }
+
+ } catch (final EaafStorageException e) {
+ log.info("Can NOT store Authn. Req. data into pendingRequest.", e);
+ throw new AuthnRequestValidatorException("internal.02", null, e);
+
+ }
+
+ }
+
+ private String extractComparisonLevel(AuthnRequest authnReq) {
+ if (authnReq.getRequestedAuthnContext() != null) {
+ final RequestedAuthnContext authContext = authnReq.getRequestedAuthnContext();
+ return authContext.getComparison().toString();
+
+ }
+
+ return null;
+ }
+
+ private List<String> extractLoA(AuthnRequest authnReq) throws AuthnRequestValidatorException {
+ final List<String> result = new ArrayList<>();
+ if (authnReq.getRequestedAuthnContext() != null) {
+ final RequestedAuthnContext authContext = authnReq.getRequestedAuthnContext();
+ if (authContext.getComparison().equals(AuthnContextComparisonTypeEnumeration.MINIMUM)) {
+ if (authContext.getAuthnContextClassRefs().isEmpty()) {
+ log.debug("Authn. Req. contains no requested LoA");
+
+ } else if (authContext.getAuthnContextClassRefs().size() > 1) {
+ log.info("Authn. Req. contains MORE THAN ONE requested LoA, but "
+ + AuthnContextComparisonTypeEnumeration.MINIMUM + " allows only one");
+ throw new AuthnRequestValidatorException("pvp2.22",
+ new Object[] { "Authn. Req. contains MORE THAN ONE requested LoA, but "
+ + AuthnContextComparisonTypeEnumeration.MINIMUM + " allows only one" });
+
+ } else {
+ result.add(authContext.getAuthnContextClassRefs().get(0).getAuthnContextClassRef());
+ }
+
+ } else if (authContext.getComparison().equals(AuthnContextComparisonTypeEnumeration.EXACT)) {
+ for (final AuthnContextClassRef el : authContext.getAuthnContextClassRefs()) {
+ result.add(el.getAuthnContextClassRef());
+ }
+
+ } else {
+ log.info("Currently only '" + AuthnContextComparisonTypeEnumeration.MINIMUM + "' and '"
+ + AuthnContextComparisonTypeEnumeration.EXACT + "' are supported");
+ throw new AuthnRequestValidatorException("pvp2.22",
+ new Object[] { "Currently only '" + AuthnContextComparisonTypeEnumeration.MINIMUM + "' and '"
+ + AuthnContextComparisonTypeEnumeration.EXACT + "' are supported" });
+
+ }
+
+ }
+
+ return result;
+ }
+
+ private String extractScopeRequsterId(AuthnRequest authnReq) {
+ if (authnReq.getScoping() != null) {
+ final Scoping scoping = authnReq.getScoping();
+ if (scoping.getRequesterIDs() != null
+ && scoping.getRequesterIDs().size() > 0) {
+ if (scoping.getRequesterIDs().size() == 1) {
+ return scoping.getRequesterIDs().get(0).getRequesterID();
+ } else {
+ log.info("Authn. request contains more than on RequesterIDs! Only use first one");
+ return scoping.getRequesterIDs().get(0).getRequesterID();
+
+ }
+ }
+ }
+
+ return null;
+ }
}