From 759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Wed, 4 Dec 2019 19:43:32 +0100 Subject: common EGIZ code-style refactoring --- .../AbstractRequestSignedSecurityPolicyRule.java | 317 +++++++++++---------- .../verification/PVPAuthRequestSignedRole.java | 66 ----- .../verification/PVPSignedRequestPolicyRule.java | 84 ------ .../verification/PvpAuthRequestSignedRole.java | 56 ++++ .../verification/PvpSignedRequestPolicyRule.java | 82 ++++++ .../impl/verification/SAMLVerificationEngine.java | 207 -------------- .../impl/verification/SamlVerificationEngine.java | 218 ++++++++++++++ 7 files changed, 516 insertions(+), 514 deletions(-) delete mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPAuthRequestSignedRole.java delete mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPSignedRequestPolicyRule.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpAuthRequestSignedRole.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSignedRequestPolicyRule.java delete mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java (limited to 'eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification') diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java index f1dd1269..fc1b6ea8 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java @@ -1,36 +1,29 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, 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 "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * 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. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * 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.gv.egiz.eaaf.modules.pvp2.impl.verification; import javax.xml.namespace.QName; import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.Validator; - +import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; import org.apache.commons.lang3.StringUtils; import org.opensaml.common.SignableSAMLObject; import org.opensaml.common.xml.SAMLConstants; @@ -52,144 +45,154 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Element; import org.xml.sax.SAXException; -import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; - /** + * Signature Policy for SAML2 redirect-binding. + * * @author tlenz * */ public abstract class AbstractRequestSignedSecurityPolicyRule implements SecurityPolicyRule { - private static final Logger log = LoggerFactory.getLogger(AbstractRequestSignedSecurityPolicyRule.class); - - - private SignatureTrustEngine trustEngine = null; - private QName peerEntityRole = null; - /** - * @param peerEntityRole - * - */ - public AbstractRequestSignedSecurityPolicyRule(SignatureTrustEngine trustEngine, QName peerEntityRole) { - this.trustEngine = trustEngine; - this.peerEntityRole = peerEntityRole; - - } - - - /** - * Reload the PVP metadata for a given entity - * - * @param entityID for which the metadata should be refreshed. - * @return true if the refresh was successful, otherwise false - */ - protected abstract boolean refreshMetadataProvider(String entityID); - - - protected abstract SignableSAMLObject getSignedSAMLObject(XMLObject inboundData); - - /* (non-Javadoc) - * @see org.opensaml.ws.security.SecurityPolicyRule#evaluate(org.opensaml.ws.message.MessageContext) - */ - @Override - public void evaluate(MessageContext context) throws SecurityPolicyException { - try { - verifySignature(context); - - } catch (SecurityPolicyException e) { - if (StringUtils.isEmpty(context.getInboundMessageIssuer())) { - throw e; - - } - log.debug("PVP2X message validation FAILED. Reload metadata for entityID: " + context.getInboundMessageIssuer()); - if (!refreshMetadataProvider(context.getInboundMessageIssuer())) - throw e; - - else { - log.trace("PVP2X metadata reload finished. Check validate message again."); - verifySignature(context); - - } - log.trace("Second PVP2X message validation finished"); - - } - - - } - - private void verifySignature(MessageContext context) throws SecurityPolicyException { - SignableSAMLObject samlObj = getSignedSAMLObject(context.getInboundMessage()); - if (samlObj != null && samlObj.getSignature() != null) { - - SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); - try { - profileValidator.validate(samlObj.getSignature()); - performSchemaValidation(samlObj.getDOM()); - - } catch (ValidationException e) { - log.warn("Signature is not conform to SAML signature profile", e); - throw new SecurityPolicyException("Signature is not conform to SAML signature profile"); - - } catch (SchemaValidationException e) { - log.warn("Signature is not conform to SAML signature profile", e); - throw new SecurityPolicyException("Signature is not conform to SAML signature profile"); - - } - - - - CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add( new EntityIDCriteria(context.getInboundMessageIssuer()) ); - criteriaSet.add( new MetadataCriteria(peerEntityRole, SAMLConstants.SAML20P_NS) ); - criteriaSet.add( new UsageCriteria(UsageType.SIGNING) ); - - try { - if (!trustEngine.validate(samlObj.getSignature(), criteriaSet)) { - throw new SecurityPolicyException("Signature validation FAILED."); - - } - log.debug("PVP message signature valid."); - - } catch (org.opensaml.xml.security.SecurityException e) { - log.info("PVP2x message signature validation FAILED. Message:" + e.getMessage()); - throw new SecurityPolicyException("Signature validation FAILED."); - - } - - } else { - throw new SecurityPolicyException("PVP Message is not signed."); - - } - - } - - private void performSchemaValidation(Element source) throws SchemaValidationException { - - String err = null; - try { - Schema test = SAMLSchemaBuilder.getSAML11Schema(); - Validator val = test.newValidator(); - val.validate(new DOMSource(source)); - log.debug("Schema validation check done OK"); - return; - - } catch (SAXException e) { - err = e.getMessage(); - if (log.isDebugEnabled() || log.isTraceEnabled()) - log.warn("Schema validation FAILED with exception:", e); - else - log.warn("Schema validation FAILED with message: "+ e.getMessage()); - - } catch (Exception e) { - err = e.getMessage(); - if (log.isDebugEnabled() || log.isTraceEnabled()) - log.warn("Schema validation FAILED with exception:", e); - else - log.warn("Schema validation FAILED with message: "+ e.getMessage()); - - } - - throw new SchemaValidationException("pvp2.22", new Object[]{err}); - - } + private static final Logger log = + LoggerFactory.getLogger(AbstractRequestSignedSecurityPolicyRule.class); + + + private SignatureTrustEngine trustEngine = null; + private QName peerEntityRole = null; + + /** + * Role initializer. + * + * @param peerEntityRole + * + */ + public AbstractRequestSignedSecurityPolicyRule(final SignatureTrustEngine trustEngine, + final QName peerEntityRole) { + this.trustEngine = trustEngine; + this.peerEntityRole = peerEntityRole; + + } + + + /** + * Reload the PVP metadata for a given entity. + * + * @param entityID for which the metadata should be refreshed. + * @return true if the refresh was successful, otherwise false + */ + protected abstract boolean refreshMetadataProvider(String entityID); + + + protected abstract SignableSAMLObject getSignedSamlObject(XMLObject inboundData); + + /* + * (non-Javadoc) + * + * @see + * org.opensaml.ws.security.SecurityPolicyRule#evaluate(org.opensaml.ws.message.MessageContext) + */ + @Override + public void evaluate(final MessageContext context) throws SecurityPolicyException { + try { + verifySignature(context); + + } catch (final SecurityPolicyException e) { + if (StringUtils.isEmpty(context.getInboundMessageIssuer())) { + throw e; + + } + log.debug("PVP2X message validation FAILED. Reload metadata for entityID: " + + context.getInboundMessageIssuer()); + if (!refreshMetadataProvider(context.getInboundMessageIssuer())) { + throw e; + } else { + log.trace("PVP2X metadata reload finished. Check validate message again."); + verifySignature(context); + + } + log.trace("Second PVP2X message validation finished"); + + } + + + } + + private void verifySignature(final MessageContext context) throws SecurityPolicyException { + final SignableSAMLObject samlObj = getSignedSamlObject(context.getInboundMessage()); + if (samlObj != null && samlObj.getSignature() != null) { + + final SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); + try { + profileValidator.validate(samlObj.getSignature()); + performSchemaValidation(samlObj.getDOM()); + + } catch (final ValidationException e) { + log.warn("Signature is not conform to SAML signature profile", e); + throw new SecurityPolicyException("Signature is not conform to SAML signature profile"); + + } catch (final SchemaValidationException e) { + log.warn("Signature is not conform to SAML signature profile", e); + throw new SecurityPolicyException("Signature is not conform to SAML signature profile"); + + } + + + + final CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add(new EntityIDCriteria(context.getInboundMessageIssuer())); + criteriaSet.add(new MetadataCriteria(peerEntityRole, SAMLConstants.SAML20P_NS)); + criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); + + try { + if (!trustEngine.validate(samlObj.getSignature(), criteriaSet)) { + throw new SecurityPolicyException("Signature validation FAILED."); + + } + log.debug("PVP message signature valid."); + + } catch (final org.opensaml.xml.security.SecurityException e) { + log.info("PVP2x message signature validation FAILED. Message:" + e.getMessage()); + throw new SecurityPolicyException("Signature validation FAILED."); + + } + + } else { + throw new SecurityPolicyException("PVP Message is not signed."); + + } + + } + + private void performSchemaValidation(final Element source) throws SchemaValidationException { + + String err = null; + try { + final Schema test = SAMLSchemaBuilder.getSAML11Schema(); + final Validator val = test.newValidator(); + val.validate(new DOMSource(source)); + log.debug("Schema validation check done OK"); + return; + + } catch (final SAXException e) { + err = e.getMessage(); + if (log.isDebugEnabled() || log.isTraceEnabled()) { + log.warn("Schema validation FAILED with exception:", e); + } else { + log.warn("Schema validation FAILED with message: " + e.getMessage()); + } + + } catch (final Exception e) { + err = e.getMessage(); + if (log.isDebugEnabled() || log.isTraceEnabled()) { + log.warn("Schema validation FAILED with exception:", e); + } else { + log.warn("Schema validation FAILED with message: " + e.getMessage()); + } + + } + + throw new SchemaValidationException("pvp2.22", new Object[] {err}); + + } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPAuthRequestSignedRole.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPAuthRequestSignedRole.java deleted file mode 100644 index 6d5fdff8..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPAuthRequestSignedRole.java +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, 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 "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * 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.gv.egiz.eaaf.modules.pvp2.impl.verification; - -import java.util.List; - -import org.opensaml.common.binding.SAMLMessageContext; -import org.opensaml.saml2.binding.security.SAML2AuthnRequestsSignedRule; -import org.opensaml.ws.transport.http.HTTPInTransport; -import org.opensaml.xml.util.DatatypeHelper; - -/** - * @author tlenz - * - */ -public class PVPAuthRequestSignedRole extends SAML2AuthnRequestsSignedRule { - - @Override - protected boolean isMessageSigned(SAMLMessageContext messageContext) { - // This handles HTTP-Redirect and HTTP-POST-SimpleSign bindings. - HTTPInTransport inTransport = (HTTPInTransport) messageContext.getInboundMessageTransport(); - - //Check signature parameter exists only once and is not empty - List sigParam = inTransport.getParameterValues("Signature"); - boolean isValidSigned = sigParam.size() == 1 && !DatatypeHelper.isEmpty(sigParam.get(0)); - - //Check signature-algorithm parameter exists only once and is not empty - List sigAlgParam = inTransport.getParameterValues("SigAlg"); - boolean isValidSigAlgExists = sigAlgParam.size() == 1 && !DatatypeHelper.isEmpty(sigAlgParam.get(0)); - - //Check signature-content parameter exists only once and is not empty - List samlReqParam = inTransport.getParameterValues("SAMLRequest"); - List samlRespParam = inTransport.getParameterValues("SAMLResponse"); - boolean isValidContent = ( ( samlReqParam.size() == 1 && !DatatypeHelper.isEmpty(samlReqParam.get(0)) ) - || ( samlRespParam.size() == 1 && !DatatypeHelper.isEmpty(samlRespParam.get(0)) ) - ) && !(samlReqParam.size() == 1 && samlRespParam.size() == 1) - ; - - return isValidSigned && isValidSigAlgExists && isValidContent; - - } -} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPSignedRequestPolicyRule.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPSignedRequestPolicyRule.java deleted file mode 100644 index eecaf4f0..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PVPSignedRequestPolicyRule.java +++ /dev/null @@ -1,84 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, 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 "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * 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.gv.egiz.eaaf.modules.pvp2.impl.verification; - -import javax.xml.namespace.QName; - -import org.opensaml.common.SignableSAMLObject; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.signature.SignatureTrustEngine; - -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; - -/** - * @author tlenz - * - */ -public class PVPSignedRequestPolicyRule extends - AbstractRequestSignedSecurityPolicyRule { - - private IRefreshableMetadataProvider metadataProvider = null; - - /** - * @param metadataProvider - * @param trustEngine - * @param peerEntityRole - */ - public PVPSignedRequestPolicyRule(MetadataProvider metadataProvider, SignatureTrustEngine trustEngine, - QName peerEntityRole) { - super(trustEngine, peerEntityRole); - if (metadataProvider instanceof IRefreshableMetadataProvider) - this.metadataProvider = (IRefreshableMetadataProvider) metadataProvider; - - } - - /* (non-Javadoc) - * @see at.gv.egovernment.moa.id.protocols.pvp2x.validation.AbstractRequestSignedSecurityPolicyRule#refreshMetadataProvider(java.lang.String) - */ - @Override - protected boolean refreshMetadataProvider(String entityID) { - if (metadataProvider != null) - return metadataProvider.refreshMetadataProvider(entityID); - - return false; - - } - - /* (non-Javadoc) - * @see at.gv.egovernment.moa.id.protocols.pvp2x.validation.AbstractRequestSignedSecurityPolicyRule#getSignedSAMLObject(org.opensaml.xml.XMLObject) - */ - @Override - protected SignableSAMLObject getSignedSAMLObject(XMLObject inboundData) { - if (inboundData instanceof SignableSAMLObject) - return (SignableSAMLObject) inboundData; - - else - return null; - } - -} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpAuthRequestSignedRole.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpAuthRequestSignedRole.java new file mode 100644 index 00000000..4eb711f9 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpAuthRequestSignedRole.java @@ -0,0 +1,56 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, 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 "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * 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.gv.egiz.eaaf.modules.pvp2.impl.verification; + +import java.util.List; +import org.opensaml.common.binding.SAMLMessageContext; +import org.opensaml.saml2.binding.security.SAML2AuthnRequestsSignedRule; +import org.opensaml.ws.transport.http.HTTPInTransport; +import org.opensaml.xml.util.DatatypeHelper; + +public class PvpAuthRequestSignedRole extends SAML2AuthnRequestsSignedRule { + + @Override + protected boolean isMessageSigned(final SAMLMessageContext messageContext) { + // This handles HTTP-Redirect and HTTP-POST-SimpleSign bindings. + final HTTPInTransport inTransport = + (HTTPInTransport) messageContext.getInboundMessageTransport(); + + // Check signature parameter exists only once and is not empty + final List sigParam = inTransport.getParameterValues("Signature"); + final boolean isValidSigned = sigParam.size() == 1 && !DatatypeHelper.isEmpty(sigParam.get(0)); + + // Check signature-algorithm parameter exists only once and is not empty + final List sigAlgParam = inTransport.getParameterValues("SigAlg"); + final boolean isValidSigAlgExists = + sigAlgParam.size() == 1 && !DatatypeHelper.isEmpty(sigAlgParam.get(0)); + + // Check signature-content parameter exists only once and is not empty + final List samlReqParam = inTransport.getParameterValues("SAMLRequest"); + final List samlRespParam = inTransport.getParameterValues("SAMLResponse"); + final boolean isValidContent = + ((samlReqParam.size() == 1 && !DatatypeHelper.isEmpty(samlReqParam.get(0))) + || (samlRespParam.size() == 1 && !DatatypeHelper.isEmpty(samlRespParam.get(0)))) + && !(samlReqParam.size() == 1 && samlRespParam.size() == 1); + + return isValidSigned && isValidSigAlgExists && isValidContent; + + } +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSignedRequestPolicyRule.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSignedRequestPolicyRule.java new file mode 100644 index 00000000..0d108596 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSignedRequestPolicyRule.java @@ -0,0 +1,82 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, 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 "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * 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.gv.egiz.eaaf.modules.pvp2.impl.verification; + +import javax.xml.namespace.QName; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; +import org.opensaml.common.SignableSAMLObject; +import org.opensaml.saml2.metadata.provider.MetadataProvider; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.signature.SignatureTrustEngine; + +public class PvpSignedRequestPolicyRule extends AbstractRequestSignedSecurityPolicyRule { + + private IRefreshableMetadataProvider metadataProvider = null; + + /** + * EAAF specific signature rule for OpenSAML2 redirect-binding. + * + * @param metadataProvider SAML2 metadata provider + * @param trustEngine SAML2 TrustEngine + * @param peerEntityRole Role of the Entity + */ + public PvpSignedRequestPolicyRule(final MetadataProvider metadataProvider, + final SignatureTrustEngine trustEngine, final QName peerEntityRole) { + super(trustEngine, peerEntityRole); + if (metadataProvider instanceof IRefreshableMetadataProvider) { + this.metadataProvider = (IRefreshableMetadataProvider) metadataProvider; + } + + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.validation.AbstractRequestSignedSecurityPolicyRule# + * refreshMetadataProvider(java.lang.String) + */ + @Override + protected boolean refreshMetadataProvider(final String entityID) { + if (metadataProvider != null) { + return metadataProvider.refreshMetadataProvider(entityID); + } + + return false; + + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.validation.AbstractRequestSignedSecurityPolicyRule# + * getSignedSAMLObject(org.opensaml.xml.XMLObject) + */ + @Override + protected SignableSAMLObject getSignedSamlObject(final XMLObject inboundData) { + if (inboundData instanceof SignableSAMLObject) { + return (SignableSAMLObject) inboundData; + } else { + return null; + } + } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java deleted file mode 100644 index 078e4ac0..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java +++ /dev/null @@ -1,207 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, 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 "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * 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.gv.egiz.eaaf.modules.pvp2.impl.verification; - -import javax.xml.namespace.QName; -import javax.xml.transform.dom.DOMSource; -import javax.xml.validation.Schema; -import javax.xml.validation.Validator; - -import org.apache.commons.lang3.StringUtils; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.common.xml.SAMLSchemaBuilder; -import org.opensaml.saml2.core.RequestAbstractType; -import org.opensaml.saml2.core.StatusResponseType; -import org.opensaml.saml2.metadata.IDPSSODescriptor; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.security.MetadataCriteria; -import org.opensaml.security.SAMLSignatureProfileValidator; -import org.opensaml.xml.security.CriteriaSet; -import org.opensaml.xml.security.credential.UsageType; -import org.opensaml.xml.security.criteria.EntityIDCriteria; -import org.opensaml.xml.security.criteria.UsageCriteria; -import org.opensaml.xml.signature.SignatureTrustEngine; -import org.opensaml.xml.validation.ValidationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - -import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileRequest; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PVPSProfileResponse; - -@Service("SAMLVerificationEngine") -public class SAMLVerificationEngine { - private static final Logger log = LoggerFactory.getLogger(SAMLVerificationEngine.class); - - - @Autowired(required=true) IPVPMetadataProvider metadataProvider; - - public void verify(InboundMessage msg, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception { - try { - if (msg instanceof PVPSProfileRequest && - ((PVPSProfileRequest)msg).getSamlRequest() instanceof RequestAbstractType) - verifyRequest(((RequestAbstractType)((PVPSProfileRequest)msg).getSamlRequest()), sigTrustEngine); - - else - verifyIDPResponse(((PVPSProfileResponse)msg).getResponse(), sigTrustEngine); - - } catch (InvalidProtocolRequestException e) { - if (StringUtils.isEmpty(msg.getEntityID())) { - throw e; - - } - log.debug("PVP2X message validation FAILED. Relead metadata for entityID: " + msg.getEntityID()); - - if (metadataProvider == null || - !(metadataProvider instanceof IRefreshableMetadataProvider) || - !((IRefreshableMetadataProvider)metadataProvider).refreshMetadataProvider(msg.getEntityID())) - throw e; - - else { - log.trace("PVP2X metadata reload finished. Check validate message again."); - - if (msg instanceof PVPSProfileRequest && - ((PVPSProfileRequest)msg).getSamlRequest() instanceof RequestAbstractType) - verifyRequest(((RequestAbstractType)((PVPSProfileRequest)msg).getSamlRequest()), sigTrustEngine); - - else - verifyIDPResponse(((PVPSProfileResponse)msg).getResponse(), sigTrustEngine); - - } - log.trace("Second PVP2X message validation finished"); - } - } - - public void verifySLOResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine ) throws InvalidProtocolRequestException { - verifyResponse(samlObj, sigTrustEngine, SPSSODescriptor.DEFAULT_ELEMENT_NAME); - - } - - public void verifyIDPResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine) throws InvalidProtocolRequestException{ - verifyResponse(samlObj, sigTrustEngine, IDPSSODescriptor.DEFAULT_ELEMENT_NAME); - - } - - private void verifyResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine, QName defaultElementName) throws InvalidProtocolRequestException{ - SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); - try { - profileValidator.validate(samlObj.getSignature()); - performSchemaValidation(samlObj.getDOM()); - - } catch (ValidationException e) { - log.warn("Signature is not conform to SAML signature profile", e); - throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - - } catch (SchemaValidationException e) { - throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); - - } - - CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add( new EntityIDCriteria(samlObj.getIssuer().getValue()) ); - criteriaSet.add( new MetadataCriteria(defaultElementName, SAMLConstants.SAML20P_NS) ); - criteriaSet.add( new UsageCriteria(UsageType.SIGNING) ); - - try { - if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) { - throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - } - } catch (org.opensaml.xml.security.SecurityException e) { - log.warn("PVP2x message signature validation FAILED.", e); - throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - } - } - - private void verifyRequest(RequestAbstractType samlObj, SignatureTrustEngine sigTrustEngine ) throws InvalidProtocolRequestException { - SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); - try { - profileValidator.validate(samlObj.getSignature()); - performSchemaValidation(samlObj.getDOM()); - - } catch (ValidationException e) { - log.warn("Signature is not conform to SAML signature profile", e); - throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - - } catch (SchemaValidationException e) { - throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); - - } - - CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add( new EntityIDCriteria(samlObj.getIssuer().getValue()) ); - criteriaSet.add( new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS) ); - criteriaSet.add( new UsageCriteria(UsageType.SIGNING) ); - - try { - if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) { - throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - } - } catch (org.opensaml.xml.security.SecurityException e) { - log.warn("PVP2x message signature validation FAILED.", e); - throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - } - } - - protected void performSchemaValidation(Element source) throws SchemaValidationException { - - String err = null; - try { - Schema test = SAMLSchemaBuilder.getSAML11Schema(); - Validator val = test.newValidator(); - val.validate(new DOMSource(source)); - log.debug("Schema validation check done OK"); - return; - - } catch (SAXException e) { - err = e.getMessage(); - if (log.isDebugEnabled() || log.isTraceEnabled()) - log.warn("Schema validation FAILED with exception:", e); - else - log.warn("Schema validation FAILED with message: "+ e.getMessage()); - - } catch (Exception e) { - err = e.getMessage(); - if (log.isDebugEnabled() || log.isTraceEnabled()) - log.warn("Schema validation FAILED with exception:", e); - else - log.warn("Schema validation FAILED with message: "+ e.getMessage()); - - } - - throw new SchemaValidationException("pvp2.22", new Object[]{err}); - - } - -} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java new file mode 100644 index 00000000..64eb5247 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SamlVerificationEngine.java @@ -0,0 +1,218 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, 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 "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * 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.gv.egiz.eaaf.modules.pvp2.impl.verification; + +import javax.xml.namespace.QName; +import javax.xml.transform.dom.DOMSource; +import javax.xml.validation.Schema; +import javax.xml.validation.Validator; +import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileResponse; +import org.apache.commons.lang3.StringUtils; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.common.xml.SAMLSchemaBuilder; +import org.opensaml.saml2.core.RequestAbstractType; +import org.opensaml.saml2.core.StatusResponseType; +import org.opensaml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.security.MetadataCriteria; +import org.opensaml.security.SAMLSignatureProfileValidator; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.criteria.EntityIDCriteria; +import org.opensaml.xml.security.criteria.UsageCriteria; +import org.opensaml.xml.signature.SignatureTrustEngine; +import org.opensaml.xml.validation.ValidationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +@Service("SAMLVerificationEngine") +public class SamlVerificationEngine { + private static final Logger log = LoggerFactory.getLogger(SamlVerificationEngine.class); + + + @Autowired(required = true) + IPvpMetadataProvider metadataProvider; + + /** + * Verify signature of a signed SAML2 object. + * + * @param msg SAML2 message + * @param sigTrustEngine TrustEngine + * @throws org.opensaml.xml.security.SecurityException In case of invalid signature + * @throws Exception In case of a general error + */ + public void verify(final InboundMessage msg, final SignatureTrustEngine sigTrustEngine) + throws org.opensaml.xml.security.SecurityException, Exception { + try { + if (msg instanceof PvpSProfileRequest + && ((PvpSProfileRequest) msg).getSamlRequest() instanceof RequestAbstractType) { + verifyRequest(((RequestAbstractType) ((PvpSProfileRequest) msg).getSamlRequest()), + sigTrustEngine); + } else { + verifyIdpResponse(((PvpSProfileResponse) msg).getResponse(), sigTrustEngine); + } + + } catch (final InvalidProtocolRequestException e) { + if (StringUtils.isEmpty(msg.getEntityID())) { + throw e; + + } + log.debug( + "PVP2X message validation FAILED. Relead metadata for entityID: " + msg.getEntityID()); + + if (metadataProvider == null || !(metadataProvider instanceof IRefreshableMetadataProvider) + || !((IRefreshableMetadataProvider) metadataProvider) + .refreshMetadataProvider(msg.getEntityID())) { + throw e; + } else { + log.trace("PVP2X metadata reload finished. Check validate message again."); + + if (msg instanceof PvpSProfileRequest + && ((PvpSProfileRequest) msg).getSamlRequest() instanceof RequestAbstractType) { + verifyRequest(((RequestAbstractType) ((PvpSProfileRequest) msg).getSamlRequest()), + sigTrustEngine); + } else { + verifyIdpResponse(((PvpSProfileResponse) msg).getResponse(), sigTrustEngine); + } + + } + log.trace("Second PVP2X message validation finished"); + } + } + + public void verifySloResponse(final StatusResponseType samlObj, + final SignatureTrustEngine sigTrustEngine) throws InvalidProtocolRequestException { + verifyResponse(samlObj, sigTrustEngine, SPSSODescriptor.DEFAULT_ELEMENT_NAME); + + } + + public void verifyIdpResponse(final StatusResponseType samlObj, + final SignatureTrustEngine sigTrustEngine) throws InvalidProtocolRequestException { + verifyResponse(samlObj, sigTrustEngine, IDPSSODescriptor.DEFAULT_ELEMENT_NAME); + + } + + private void verifyResponse(final StatusResponseType samlObj, + final SignatureTrustEngine sigTrustEngine, final QName defaultElementName) + throws InvalidProtocolRequestException { + final SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); + try { + profileValidator.validate(samlObj.getSignature()); + performSchemaValidation(samlObj.getDOM()); + + } catch (final ValidationException e) { + log.warn("Signature is not conform to SAML signature profile", e); + throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + + } catch (final SchemaValidationException e) { + throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); + + } + + final CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add(new EntityIDCriteria(samlObj.getIssuer().getValue())); + criteriaSet.add(new MetadataCriteria(defaultElementName, SAMLConstants.SAML20P_NS)); + criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); + + try { + if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) { + throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + } + } catch (final org.opensaml.xml.security.SecurityException e) { + log.warn("PVP2x message signature validation FAILED.", e); + throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + } + } + + private void verifyRequest(final RequestAbstractType samlObj, + final SignatureTrustEngine sigTrustEngine) throws InvalidProtocolRequestException { + final SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); + try { + profileValidator.validate(samlObj.getSignature()); + performSchemaValidation(samlObj.getDOM()); + + } catch (final ValidationException e) { + log.warn("Signature is not conform to SAML signature profile", e); + throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + + } catch (final SchemaValidationException e) { + throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); + + } + + final CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add(new EntityIDCriteria(samlObj.getIssuer().getValue())); + criteriaSet + .add(new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); + criteriaSet.add(new UsageCriteria(UsageType.SIGNING)); + + try { + if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) { + throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + } + } catch (final org.opensaml.xml.security.SecurityException e) { + log.warn("PVP2x message signature validation FAILED.", e); + throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); + } + } + + protected void performSchemaValidation(final Element source) throws SchemaValidationException { + + String err = null; + try { + final Schema test = SAMLSchemaBuilder.getSAML11Schema(); + final Validator val = test.newValidator(); + val.validate(new DOMSource(source)); + log.debug("Schema validation check done OK"); + return; + + } catch (final SAXException e) { + err = e.getMessage(); + if (log.isDebugEnabled() || log.isTraceEnabled()) { + log.warn("Schema validation FAILED with exception:", e); + } else { + log.warn("Schema validation FAILED with message: " + e.getMessage()); + } + + } catch (final Exception e) { + err = e.getMessage(); + if (log.isDebugEnabled() || log.isTraceEnabled()) { + log.warn("Schema validation FAILED with exception:", e); + } else { + log.warn("Schema validation FAILED with message: " + e.getMessage()); + } + + } + + throw new SchemaValidationException("pvp2.22", new Object[] {err}); + + } + +} -- cgit v1.2.3