diff options
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.java | 382 |
1 files changed, 0 insertions, 382 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 deleted file mode 100644 index 23702264..00000000 --- a/connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright 2018 A-SIT Plus GmbH - * 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 - * the European Commission - subsequent versions of the EUPL (the "License"); - * You may not use this work except in compliance with the License. - * You may obtain a copy of the License at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * This product combines work with different licenses. See the "NOTICE" text - * 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; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang3.StringUtils; -import org.opensaml.core.xml.XMLObject; -import org.opensaml.saml.saml2.core.AuthnContextClassRef; -import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration; -import org.opensaml.saml.saml2.core.AuthnRequest; -import org.opensaml.saml.saml2.core.NameIDPolicy; -import org.opensaml.saml.saml2.core.NameIDType; -import org.opensaml.saml.saml2.core.RequestedAuthnContext; -import org.opensaml.saml.saml2.core.Scoping; -import org.opensaml.saml.saml2.metadata.SPSSODescriptor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import at.asitplus.eidas.specific.core.MsEidasNodeConstants; -import at.asitplus.eidas.specific.core.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.core.impl.utils.TransactionIdUtils; -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; -import at.gv.egiz.eaaf.modules.pvp2.exception.NameIdFormatNotSupportedException; -import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance; - -public class AuthnRequestValidator implements IAuthnRequestPostProcessor { - - private static final Logger log = LoggerFactory.getLogger(AuthnRequestValidator.class); - - @Autowired(required = true) - private IConfiguration basicConfig; - - @Override - public void process(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, providerName); - } - - // post-process requested LoA - postprocessLoaLevel(pendingReq, authnReq); - - // post-process requested LoA comparison-level - pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).setLoAMachtingMode( - extractComparisonLevel(authnReq)); - - // extract information from requested attributes - extractFromRequestedAttriutes(pendingReq, authnReq); - - } catch (final EaafStorageException e) { - log.info("Can NOT store Authn. Req. data into pendingRequest.", e); - throw new AuthnRequestValidatorException("internal.02", null, e); - - } - - } - - private void extractFromRequestedAttriutes(IRequest pendingReq, AuthnRequest authnReq) - throws AuthnRequestValidatorException, EaafStorageException { - // 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 if (el.getName().equals(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME)) { - extractBindingPublicKey(el, pendingReq); - - } 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.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" }); - - } - - } - - private void extractBindingPublicKey(EaafRequestedAttribute el, IRequest pendingReq) - throws EaafStorageException { - if (el.getAttributeValues() != null && el.getAttributeValues().size() == 1) { - final String bindingPubKey = el.getAttributeValues().get(0).getDOM().getTextContent(); - pendingReq.setRawDataToTransaction(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME, bindingPubKey); - log.info("Find Binding Public-Key. eIDAS authentication will be used to create an ID Austria Binding"); - - } else { - log.warn( - "Req. attribute '{}' contains NO or MORE THEN ONE attribute-values. Ignore full req. attribute", - el.getName()); - - } - } - - /** - * 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); - log.info("Find transactionId: {} from requesting service. Replace old id: {} ", - transactionId, TransactionIdUtils.getTransactionId()); - TransactionIdUtils.setTransactionId(transactionId); - - return true; - - } else { - log.warn( - "Req. attribute '{}' contains NO or MORE THEN ONE attribute-values. Ignore full req. attribute", - el.getName()); - - } - - } - - 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 (!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); - - } - - 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; - } - -} |