Repository: cxf Updated Branches: refs/heads/3.0.x-fixes ad0f5f1a1 -> 0bdf4ebdc
Weaken SAML Bearer Subject Confirmation Requirements if the Response is signed Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/7a3816ef Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/7a3816ef Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/7a3816ef Branch: refs/heads/3.0.x-fixes Commit: 7a3816efdb97da722e435ed19cfd17461e1ea3f6 Parents: ad0f5f1 Author: Colm O hEigeartaigh <[email protected]> Authored: Mon Feb 1 11:38:10 2016 +0000 Committer: Colm O hEigeartaigh <[email protected]> Committed: Mon Feb 1 11:39:51 2016 +0000 ---------------------------------------------------------------------- .../saml/sso/SAMLProtocolResponseValidator.java | 11 +- .../saml/sso/SamlSSOAssertionValidator.java | 115 +++++++++++++++++++ 2 files changed, 121 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/7a3816ef/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLProtocolResponseValidator.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLProtocolResponseValidator.java b/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLProtocolResponseValidator.java index ef2cda7..7f1d3f6 100644 --- a/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLProtocolResponseValidator.java +++ b/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SAMLProtocolResponseValidator.java @@ -50,7 +50,6 @@ import org.apache.wss4j.dom.WSSConfig; import org.apache.wss4j.dom.handler.RequestData; import org.apache.wss4j.dom.saml.WSSSAMLKeyInfoProcessor; import org.apache.wss4j.dom.validate.Credential; -import org.apache.wss4j.dom.validate.SamlAssertionValidator; import org.apache.wss4j.dom.validate.SignatureTrustValidator; import org.apache.wss4j.dom.validate.Validator; import org.apache.xml.security.encryption.XMLCipher; @@ -79,7 +78,6 @@ public class SAMLProtocolResponseValidator { private static final Logger LOG = LogUtils.getL7dLogger(SAMLProtocolResponseValidator.class); - private Validator assertionValidator = new SamlAssertionValidator(); private Validator signatureValidator = new SignatureTrustValidator(); private boolean keyInfoMustBeAvailable = true; @@ -141,7 +139,7 @@ public class SAMLProtocolResponseValidator { // Validate Assertions for (org.opensaml.saml2.core.Assertion assertion : samlResponse.getAssertions()) { SamlAssertionWrapper wrapper = new SamlAssertionWrapper(assertion); - validateAssertion(wrapper, sigCrypto, callbackHandler, doc); + validateAssertion(wrapper, sigCrypto, callbackHandler, doc, samlResponse.isSigned()); } } @@ -189,7 +187,8 @@ public class SAMLProtocolResponseValidator { for (org.opensaml.saml1.core.Assertion assertion : samlResponse.getAssertions()) { SamlAssertionWrapper wrapper = new SamlAssertionWrapper(assertion); validateAssertion( - wrapper, sigCrypto, callbackHandler, samlResponse.getDOM().getOwnerDocument() + wrapper, sigCrypto, callbackHandler, samlResponse.getDOM().getOwnerDocument(), + samlResponse.isSigned() ); } } @@ -370,7 +369,8 @@ public class SAMLProtocolResponseValidator { SamlAssertionWrapper assertion, Crypto sigCrypto, CallbackHandler callbackHandler, - Document doc + Document doc, + boolean signedResponse ) throws WSSecurityException { Credential credential = new Credential(); credential.setSamlAssertion(assertion); @@ -424,6 +424,7 @@ public class SAMLProtocolResponseValidator { // Validate the Assertion & verify trust in the signature try { + SamlSSOAssertionValidator assertionValidator = new SamlSSOAssertionValidator(signedResponse); assertionValidator.validate(credential, requestData); } catch (WSSecurityException ex) { LOG.log(Level.FINE, "Assertion validation failed: " + ex.getMessage(), ex); http://git-wip-us.apache.org/repos/asf/cxf/blob/7a3816ef/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SamlSSOAssertionValidator.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SamlSSOAssertionValidator.java b/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SamlSSOAssertionValidator.java new file mode 100644 index 0000000..0cc8c19 --- /dev/null +++ b/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/SamlSSOAssertionValidator.java @@ -0,0 +1,115 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ +package org.apache.cxf.rs.security.saml.sso; + +import java.util.List; +import java.util.logging.Logger; + +import org.apache.cxf.common.logging.LogUtils; +import org.apache.wss4j.common.ext.WSSecurityException; +import org.apache.wss4j.common.saml.OpenSAMLUtil; +import org.apache.wss4j.common.saml.SamlAssertionWrapper; +import org.apache.wss4j.common.saml.builder.SAML1Constants; +import org.apache.wss4j.common.saml.builder.SAML2Constants; +import org.apache.wss4j.dom.validate.SamlAssertionValidator; + +/** + * An extension of the WSS4J SamlAssertionValidator. We can weaken the subject confirmation method requirements a bit + * for SAML SSO. A Bearer Assertion does not have to be signed by default if the outer Response is signed. + */ +public class SamlSSOAssertionValidator extends SamlAssertionValidator { + + private static final Logger LOG = LogUtils.getL7dLogger(SamlSSOAssertionValidator.class); + + private final boolean signedResponse; + + public SamlSSOAssertionValidator(boolean signedResponse) { + this.signedResponse = signedResponse; + } + + /** + * Check the Subject Confirmation method requirements + */ + protected void verifySubjectConfirmationMethod( + SamlAssertionWrapper samlAssertion + ) throws WSSecurityException { + + List<String> methods = samlAssertion.getConfirmationMethods(); + if (methods == null || methods.isEmpty()) { + if (super.getRequiredSubjectConfirmationMethod() != null) { + LOG.fine("A required subject confirmation method was not present"); + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, + "invalidSAMLsecurity"); + } else if (super.isRequireStandardSubjectConfirmationMethod()) { + LOG.fine("A standard subject confirmation method was not present"); + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, + "invalidSAMLsecurity"); + } + } + + boolean signed = samlAssertion.isSigned(); + boolean requiredMethodFound = false; + boolean standardMethodFound = false; + for (String method : methods) { + if (OpenSAMLUtil.isMethodHolderOfKey(method)) { + if (samlAssertion.getSubjectKeyInfo() == null) { + LOG.fine("There is no Subject KeyInfo to match the holder-of-key subject conf method"); + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "noKeyInSAMLToken"); + } + + // The assertion must have been signed for HOK + if (!signed) { + LOG.fine("A holder-of-key assertion must be signed"); + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); + } + standardMethodFound = true; + } + + if (method != null) { + if (method.equals(super.getRequiredSubjectConfirmationMethod())) { + requiredMethodFound = true; + } + if (SAML2Constants.CONF_BEARER.equals(method) + || SAML1Constants.CONF_BEARER.equals(method)) { + standardMethodFound = true; + if (super.isRequireBearerSignature() && !signed && !signedResponse) { + LOG.fine("A Bearer Assertion was not signed"); + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, + "invalidSAMLsecurity"); + } + } else if (SAML2Constants.CONF_SENDER_VOUCHES.equals(method) + || SAML1Constants.CONF_SENDER_VOUCHES.equals(method)) { + standardMethodFound = true; + } + } + } + + if (!requiredMethodFound && super.getRequiredSubjectConfirmationMethod() != null) { + LOG.fine("A required subject confirmation method was not present"); + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, + "invalidSAMLsecurity"); + } + + if (!standardMethodFound && super.isRequireStandardSubjectConfirmationMethod()) { + LOG.fine("A standard subject confirmation method was not present"); + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, + "invalidSAMLsecurity"); + } + } +}
