From 7a62a84f23b3a1a1027ebda31fb790ee072793cc Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 27 Nov 2020 09:08:10 +0100 Subject: read unique transactionId from AuthnRequest to reuse it for eIDAS authentication --- .../verification/AuthnRequestValidator.java | 247 +++++++++++++-------- 1 file changed, 154 insertions(+), 93 deletions(-) (limited to 'connector/src/main/java/at/asitplus/eidas/specific/connector/verification/AuthnRequestValidator.java') 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 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 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 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 true if transactionId extraction was successful, otherwise false + */ + 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 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 true if bPK target extraction was successful, otherwise false + */ + 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 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 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) { -- cgit v1.2.3