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/318501bf Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/318501bf Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/318501bf Branch: refs/heads/master Commit: 318501bf351df22e3cdde6fc58f4c67d4e8ab3d2 Parents: e222570 Author: Colm O hEigeartaigh <[email protected]> Authored: Wed Jan 14 16:06:56 2015 +0000 Committer: Colm O hEigeartaigh <[email protected]> Committed: Wed Jan 14 16:06:56 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/318501bf/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 ef21cda..0444bfa 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); @@ -556,4 +581,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/318501bf/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
