Return-Path: X-Original-To: apmail-cxf-commits-archive@www.apache.org Delivered-To: apmail-cxf-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id A80C010FB2 for ; Wed, 14 Jan 2015 16:53:42 +0000 (UTC) Received: (qmail 87068 invoked by uid 500); 14 Jan 2015 16:53:44 -0000 Delivered-To: apmail-cxf-commits-archive@cxf.apache.org Received: (qmail 86848 invoked by uid 500); 14 Jan 2015 16:53:44 -0000 Mailing-List: contact commits-help@cxf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cxf.apache.org Delivered-To: mailing list commits@cxf.apache.org Received: (qmail 86766 invoked by uid 99); 14 Jan 2015 16:53:44 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 14 Jan 2015 16:53:44 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 08FF0A42089; Wed, 14 Jan 2015 16:53:44 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: coheigea@apache.org To: commits@cxf.apache.org Date: Wed, 14 Jan 2015 16:53:44 -0000 Message-Id: <53dd5e92e7324384bd3b05066c873e3c@git.apache.org> In-Reply-To: <1f28a01e621744c3b24a479ff2479157@git.apache.org> References: <1f28a01e621744c3b24a479ff2479157@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [2/3] cxf git commit: Adding some more SAML SSO tests Adding some more SAML SSO tests Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/ce2c2f3c Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/ce2c2f3c Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/ce2c2f3c Branch: refs/heads/3.0.x-fixes Commit: ce2c2f3c15914a8b6271706cf40634bb2dfa4563 Parents: 4918290 Author: Colm O hEigeartaigh Authored: Wed Jan 14 16:06:56 2015 +0000 Committer: Colm O hEigeartaigh Committed: Wed Jan 14 16:10:23 2015 +0000 ---------------------------------------------------------------------- .../saml/sso/SAMLProtocolResponseValidator.java | 35 +++++++- .../saml/sso/SAMLResponseValidatorTest.java | 91 ++++++++++++++++++++ 2 files changed, 125 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/ce2c2f3c/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 37c90c9..4e12de9 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 @@ -32,7 +32,6 @@ import javax.security.auth.callback.CallbackHandler; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; - import org.apache.cxf.common.logging.LogUtils; import org.apache.cxf.common.util.Base64Exception; import org.apache.cxf.common.util.Base64Utility; @@ -57,6 +56,7 @@ import org.apache.wss4j.dom.validate.Validator; import org.apache.xml.security.encryption.XMLCipher; import org.apache.xml.security.encryption.XMLEncryptionException; import org.apache.xml.security.utils.Constants; +import org.joda.time.DateTime; import org.opensaml.security.SAMLSignatureProfileValidator; import org.opensaml.xml.encryption.EncryptedData; import org.opensaml.xml.security.x509.BasicX509Credential; @@ -82,6 +82,13 @@ public class SAMLProtocolResponseValidator { private Validator assertionValidator = new SamlAssertionValidator(); private Validator signatureValidator = new SignatureTrustValidator(); private boolean keyInfoMustBeAvailable = true; + + /** + * The time in seconds in the future within which the NotBefore time of an incoming + * Assertion is valid. The default is 60 seconds. + */ + private int futureTTL = 60; + /** * Validate a SAML 2 Protocol Response * @param samlResponse @@ -108,6 +115,15 @@ public class SAMLProtocolResponseValidator { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } + if (samlResponse.getIssueInstant() != null) { + DateTime currentTime = new DateTime(); + currentTime = currentTime.plusSeconds(futureTTL); + if (samlResponse.getIssueInstant().isAfter(currentTime)) { + LOG.fine("SAML Response IssueInstant not met"); + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); + } + } + validateResponseAgainstSchemas(samlResponse); validateResponseSignature(samlResponse, sigCrypto, callbackHandler); @@ -157,6 +173,15 @@ public class SAMLProtocolResponseValidator { throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); } + if (samlResponse.getIssueInstant() != null) { + DateTime currentTime = new DateTime(); + currentTime = currentTime.plusSeconds(futureTTL); + if (samlResponse.getIssueInstant().isAfter(currentTime)) { + LOG.fine("SAML Response IssueInstant not met"); + throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidSAMLsecurity"); + } + } + validateResponseAgainstSchemas(samlResponse); validateResponseSignature(samlResponse, sigCrypto, callbackHandler); @@ -555,4 +580,12 @@ public class SAMLProtocolResponseValidator { this.keyInfoMustBeAvailable = keyInfoMustBeAvailable; } + public int getFutureTTL() { + return futureTTL; + } + + public void setFutureTTL(int futureTTL) { + this.futureTTL = futureTTL; + } + } http://git-wip-us.apache.org/repos/asf/cxf/blob/ce2c2f3c/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/SAMLResponseValidatorTest.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/SAMLResponseValidatorTest.java b/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/SAMLResponseValidatorTest.java index 3e20b96..f8aa84b 100644 --- a/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/SAMLResponseValidatorTest.java +++ b/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/SAMLResponseValidatorTest.java @@ -565,6 +565,97 @@ public class SAMLResponseValidatorTest extends org.junit.Assert { } } + @org.junit.Test + public void testResponseIssueInstant() throws Exception { + DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + docBuilderFactory.setNamespaceAware(true); + DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); + Document doc = docBuilder.newDocument(); + + Status status = + SAML2PResponseComponentBuilder.createStatus( + SAMLProtocolResponseValidator.SAML2_STATUSCODE_SUCCESS, null + ); + Response response = + SAML2PResponseComponentBuilder.createSAMLResponse( + "http://cxf.apache.org/saml", "http://cxf.apache.org/issuer", status + ); + + response.setIssueInstant(new DateTime().plusMinutes(5)); + + // Create an AuthenticationAssertion + SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler(); + callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN); + callbackHandler.setIssuer("http://cxf.apache.org/issuer"); + callbackHandler.setConfirmationMethod(SAML2Constants.CONF_SENDER_VOUCHES); + + SAMLCallback samlCallback = new SAMLCallback(); + SAMLUtil.doSAMLCallback(callbackHandler, samlCallback); + SamlAssertionWrapper assertion = new SamlAssertionWrapper(samlCallback); + + response.getAssertions().add(assertion.getSaml2()); + + Element policyElement = OpenSAMLUtil.toDom(response, doc); + doc.appendChild(policyElement); + assertNotNull(policyElement); + + Response marshalledResponse = (Response)OpenSAMLUtil.fromDom(policyElement); + + // Validate the Response + SAMLProtocolResponseValidator validator = new SAMLProtocolResponseValidator(); + try { + validator.validateSamlResponse(marshalledResponse, null, null); + fail("Expected failure on an invalid Response IssueInstant"); + } catch (WSSecurityException ex) { + // expected + } + } + + @org.junit.Test + public void testAssertionIssueInstant() throws Exception { + DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + docBuilderFactory.setNamespaceAware(true); + DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); + Document doc = docBuilder.newDocument(); + + Status status = + SAML2PResponseComponentBuilder.createStatus( + SAMLProtocolResponseValidator.SAML2_STATUSCODE_SUCCESS, null + ); + Response response = + SAML2PResponseComponentBuilder.createSAMLResponse( + "http://cxf.apache.org/saml", "http://cxf.apache.org/issuer", status + ); + + // Create an AuthenticationAssertion + SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler(); + callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN); + callbackHandler.setIssuer("http://cxf.apache.org/issuer"); + callbackHandler.setConfirmationMethod(SAML2Constants.CONF_SENDER_VOUCHES); + + SAMLCallback samlCallback = new SAMLCallback(); + SAMLUtil.doSAMLCallback(callbackHandler, samlCallback); + SamlAssertionWrapper assertion = new SamlAssertionWrapper(samlCallback); + + assertion.getSaml2().setIssueInstant(new DateTime().plusMinutes(5)); + + response.getAssertions().add(assertion.getSaml2()); + + Element policyElement = OpenSAMLUtil.toDom(response, doc); + doc.appendChild(policyElement); + assertNotNull(policyElement); + + Response marshalledResponse = (Response)OpenSAMLUtil.fromDom(policyElement); + + // Validate the Response + SAMLProtocolResponseValidator validator = new SAMLProtocolResponseValidator(); + try { + validator.validateSamlResponse(marshalledResponse, null, null); + fail("Expected failure on an invalid Assertion IssueInstant"); + } catch (WSSecurityException ex) { + // expected + } + } /** * Sign a SAML Response