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 D6FF41842C for ; Fri, 31 Jul 2015 13:15:33 +0000 (UTC) Received: (qmail 98971 invoked by uid 500); 31 Jul 2015 13:15:33 -0000 Delivered-To: apmail-cxf-commits-archive@cxf.apache.org Received: (qmail 98910 invoked by uid 500); 31 Jul 2015 13:15:33 -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 98901 invoked by uid 99); 31 Jul 2015 13:15:33 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 31 Jul 2015 13:15:33 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 9F566DFBC9; Fri, 31 Jul 2015 13:15:33 +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 Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: cxf-fediz git commit: Adding some wrapping tests Date: Fri, 31 Jul 2015 13:15:33 +0000 (UTC) Repository: cxf-fediz Updated Branches: refs/heads/master 2eab7d841 -> 3e2f6642b Adding some wrapping tests Project: http://git-wip-us.apache.org/repos/asf/cxf-fediz/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf-fediz/commit/3e2f6642 Tree: http://git-wip-us.apache.org/repos/asf/cxf-fediz/tree/3e2f6642 Diff: http://git-wip-us.apache.org/repos/asf/cxf-fediz/diff/3e2f6642 Branch: refs/heads/master Commit: 3e2f6642b7bb0f23ecf191c2b1df27d6879b8c7e Parents: 2eab7d8 Author: Colm O hEigeartaigh Authored: Fri Jul 31 14:15:22 2015 +0100 Committer: Colm O hEigeartaigh Committed: Fri Jul 31 14:15:22 2015 +0100 ---------------------------------------------------------------------- .../core/federation/FederationResponseTest.java | 308 ++++++++++++++----- 1 file changed, 238 insertions(+), 70 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/3e2f6642/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationResponseTest.java ---------------------------------------------------------------------- diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationResponseTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationResponseTest.java index 02b8370..125a2ec 100644 --- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationResponseTest.java +++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/FederationResponseTest.java @@ -32,7 +32,6 @@ import javax.security.auth.callback.UnsupportedCallbackException; import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.Node; import org.apache.cxf.fediz.common.STSUtil; import org.apache.cxf.fediz.common.SecurityTestUtil; import org.apache.cxf.fediz.core.AbstractSAMLCallbackHandler; @@ -76,6 +75,7 @@ import org.apache.wss4j.common.saml.bean.ConditionsBean; import org.apache.wss4j.common.saml.builder.SAML1Constants; import org.apache.wss4j.common.saml.builder.SAML2Constants; import org.apache.wss4j.common.util.DOM2Writer; +import org.apache.wss4j.common.util.XMLUtils; import org.apache.wss4j.dom.WSConstants; import org.apache.wss4j.dom.message.WSSecEncrypt; import org.joda.time.DateTime; @@ -90,6 +90,20 @@ import static org.junit.Assert.fail; * Some tests for the WS-Federation "FederationProcessor". */ public class FederationResponseTest { + public static final String SAMPLE_MULTIPLE_RSTR_COLL_MSG = + "" + + " " + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + static final String TEST_USER = "alice"; static final String TEST_RSTR_ISSUER = "FedizSTSIssuer"; static final String TEST_AUDIENCE = "https://localhost/fedizhelloworld"; @@ -760,6 +774,221 @@ public class FederationResponseTest { } } + @org.junit.Test + public void testUnsignedAssertionAfterSignedAssertion() throws Exception { + // First assertion + SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler(); + callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR); + callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER); + callbackHandler.setIssuer(TEST_RSTR_ISSUER); + callbackHandler.setSubjectName(TEST_USER); + ConditionsBean cp = new ConditionsBean(); + AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean(); + audienceRestriction.getAudienceURIs().add(TEST_AUDIENCE); + cp.setAudienceRestrictions(Collections.singletonList(audienceRestriction)); + callbackHandler.setConditions(cp); + + SAMLCallback samlCallback = new SAMLCallback(); + SAMLUtil.doSAMLCallback(callbackHandler, samlCallback); + SamlAssertionWrapper assertion1 = new SamlAssertionWrapper(samlCallback); + + // Second assertion + SAML2CallbackHandler callbackHandler2 = new SAML2CallbackHandler(); + callbackHandler2.setStatement(SAML2CallbackHandler.Statement.ATTR); + callbackHandler2.setConfirmationMethod(SAML2Constants.CONF_BEARER); + callbackHandler2.setIssuer(TEST_RSTR_ISSUER); + callbackHandler2.setSubjectName("bob"); + ConditionsBean cp2 = new ConditionsBean(); + AudienceRestrictionBean audienceRestriction2 = new AudienceRestrictionBean(); + audienceRestriction2.getAudienceURIs().add(TEST_AUDIENCE); + cp2.setAudienceRestrictions(Collections.singletonList(audienceRestriction2)); + callbackHandler2.setConditions(cp2); + + SAMLCallback samlCallback2 = new SAMLCallback(); + SAMLUtil.doSAMLCallback(callbackHandler2, samlCallback2); + SamlAssertionWrapper assertion2 = new SamlAssertionWrapper(samlCallback2); + + Element rstrElement = + createResponseWithMultipleAssertions(assertion1, true, assertion2, false, "mystskey"); + String rstr = DOM2Writer.nodeToString(rstrElement); + FedizRequest wfReq = new FedizRequest(); + wfReq.setAction(FederationConstants.ACTION_SIGNIN); + wfReq.setResponseToken(rstr); + + // Load and update the config to enforce an error + configurator = null; + FedizContext config = getFederationConfigurator().getFedizContext("ROOT"); + + FedizProcessor wfProc = new FederationProcessorImpl(); + FedizResponse fedizResponse = wfProc.processRequest(wfReq, config); + Assert.assertEquals(TEST_USER, fedizResponse.getUsername()); + } + + @org.junit.Test + public void testSignedAssertionAfterUnsignedAssertion() throws Exception { + // First assertion + SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler(); + callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR); + callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER); + callbackHandler.setIssuer(TEST_RSTR_ISSUER); + callbackHandler.setSubjectName(TEST_USER); + ConditionsBean cp = new ConditionsBean(); + AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean(); + audienceRestriction.getAudienceURIs().add(TEST_AUDIENCE); + cp.setAudienceRestrictions(Collections.singletonList(audienceRestriction)); + callbackHandler.setConditions(cp); + + SAMLCallback samlCallback = new SAMLCallback(); + SAMLUtil.doSAMLCallback(callbackHandler, samlCallback); + SamlAssertionWrapper assertion1 = new SamlAssertionWrapper(samlCallback); + + // Second assertion + SAML2CallbackHandler callbackHandler2 = new SAML2CallbackHandler(); + callbackHandler2.setStatement(SAML2CallbackHandler.Statement.ATTR); + callbackHandler2.setConfirmationMethod(SAML2Constants.CONF_BEARER); + callbackHandler2.setIssuer(TEST_RSTR_ISSUER); + callbackHandler2.setSubjectName("bob"); + ConditionsBean cp2 = new ConditionsBean(); + AudienceRestrictionBean audienceRestriction2 = new AudienceRestrictionBean(); + audienceRestriction2.getAudienceURIs().add(TEST_AUDIENCE); + cp2.setAudienceRestrictions(Collections.singletonList(audienceRestriction2)); + callbackHandler2.setConditions(cp2); + + SAMLCallback samlCallback2 = new SAMLCallback(); + SAMLUtil.doSAMLCallback(callbackHandler2, samlCallback2); + SamlAssertionWrapper assertion2 = new SamlAssertionWrapper(samlCallback2); + + Element rstrElement = + createResponseWithMultipleAssertions(assertion2, false, assertion1, true, "mystskey"); + String rstr = DOM2Writer.nodeToString(rstrElement); + FedizRequest wfReq = new FedizRequest(); + wfReq.setAction(FederationConstants.ACTION_SIGNIN); + wfReq.setResponseToken(rstr); + + // Load and update the config to enforce an error + configurator = null; + FedizContext config = getFederationConfigurator().getFedizContext("ROOT"); + + FedizProcessor wfProc = new FederationProcessorImpl(); + try { + wfProc.processRequest(wfReq, config); + Assert.fail("Processing must fail because of missing signature"); + } catch (ProcessingException ex) { + if (!TYPE.TOKEN_NO_SIGNATURE.equals(ex.getType())) { + fail("Expected ProcessingException with TOKEN_NO_SIGNATURE type"); + } + } + } + + @org.junit.Test + public void testWrappingAttack() throws Exception { + // First assertion + SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler(); + callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR); + callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER); + callbackHandler.setIssuer(TEST_RSTR_ISSUER); + callbackHandler.setSubjectName(TEST_USER); + ConditionsBean cp = new ConditionsBean(); + AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean(); + audienceRestriction.getAudienceURIs().add(TEST_AUDIENCE); + cp.setAudienceRestrictions(Collections.singletonList(audienceRestriction)); + callbackHandler.setConditions(cp); + + SAMLCallback samlCallback = new SAMLCallback(); + SAMLUtil.doSAMLCallback(callbackHandler, samlCallback); + SamlAssertionWrapper assertion1 = new SamlAssertionWrapper(samlCallback); + + // Second assertion + SAML2CallbackHandler callbackHandler2 = new SAML2CallbackHandler(); + callbackHandler2.setStatement(SAML2CallbackHandler.Statement.ATTR); + callbackHandler2.setConfirmationMethod(SAML2Constants.CONF_BEARER); + callbackHandler2.setIssuer(TEST_RSTR_ISSUER); + callbackHandler2.setSubjectName("bob"); + ConditionsBean cp2 = new ConditionsBean(); + AudienceRestrictionBean audienceRestriction2 = new AudienceRestrictionBean(); + audienceRestriction2.getAudienceURIs().add(TEST_AUDIENCE); + cp2.setAudienceRestrictions(Collections.singletonList(audienceRestriction2)); + callbackHandler2.setConditions(cp2); + + SAMLCallback samlCallback2 = new SAMLCallback(); + SAMLUtil.doSAMLCallback(callbackHandler2, samlCallback2); + SamlAssertionWrapper assertion2 = new SamlAssertionWrapper(samlCallback2); + + WSPasswordCallback[] cb = { + new WSPasswordCallback("mystskey", WSPasswordCallback.SIGNATURE) + }; + cbPasswordHandler.handle(cb); + String password = cb[0].getPassword(); + + assertion1.signAssertion("mystskey", password, crypto, false); + assertion2.signAssertion("mystskey", password, crypto, false); + + Document doc = STSUtil.toSOAPPart(SAMPLE_MULTIPLE_RSTR_COLL_MSG); + Element token1 = assertion2.toDOM(doc); + Element token2 = assertion1.toDOM(doc); + + // Now modify the first Signature to point to the other Element + Element sig1 = XMLUtils.findElement(token1, "Signature", WSConstants.SIG_NS); + Element sig2 = XMLUtils.findElement(token2, "Signature", WSConstants.SIG_NS); + sig1.getParentNode().replaceChild(sig2.cloneNode(true), sig1); + + List requestedTokenElements = + XMLUtils.findElements(doc, "RequestedSecurityToken", FederationConstants.WS_TRUST_13_NS); + Assert.assertEquals(2, requestedTokenElements.size()); + requestedTokenElements.get(0).appendChild(token1); + requestedTokenElements.get(1).appendChild(token2); + + Element rstrElement = doc.getDocumentElement(); + + String rstr = DOM2Writer.nodeToString(rstrElement); + FedizRequest wfReq = new FedizRequest(); + wfReq.setAction(FederationConstants.ACTION_SIGNIN); + wfReq.setResponseToken(rstr); + + // Load and update the config to enforce an error + configurator = null; + FedizContext config = getFederationConfigurator().getFedizContext("ROOT"); + + FedizProcessor wfProc = new FederationProcessorImpl(); + try { + wfProc.processRequest(wfReq, config); + Assert.fail("Processing must fail because of bad signature"); + } catch (ProcessingException ex) { + // expected + } + } + + private Element createResponseWithMultipleAssertions(SamlAssertionWrapper assertion1, + boolean signFirstAssertion, + SamlAssertionWrapper assertion2, + boolean signSecondAssertion, + String alias) throws Exception { + WSPasswordCallback[] cb = { + new WSPasswordCallback(alias, WSPasswordCallback.SIGNATURE) + }; + cbPasswordHandler.handle(cb); + String password = cb[0].getPassword(); + + if (signFirstAssertion) { + assertion1.signAssertion(alias, password, crypto, false); + } + if (signSecondAssertion) { + assertion2.signAssertion(alias, password, crypto, false); + } + + Document doc = STSUtil.toSOAPPart(SAMPLE_MULTIPLE_RSTR_COLL_MSG); + Element token1 = assertion1.toDOM(doc); + Element token2 = assertion2.toDOM(doc); + + List requestedTokenElements = + XMLUtils.findElements(doc, "RequestedSecurityToken", FederationConstants.WS_TRUST_13_NS); + Assert.assertEquals(2, requestedTokenElements.size()); + requestedTokenElements.get(0).appendChild(token1); + requestedTokenElements.get(1).appendChild(token2); + + return doc.getDocumentElement(); + } + /** * Validate SAML 2 token twice which causes an exception * due to replay attack @@ -1147,10 +1376,10 @@ public class FederationResponseTest { Document doc = STSUtil.toSOAPPart(STSUtil.SAMPLE_RSTR_COLL_MSG); Element token = assertion.toDOM(doc); - Element e = FederationResponseTest.findElement(doc, "RequestedSecurityToken", + Element e = XMLUtils.findElement(doc, "RequestedSecurityToken", FederationConstants.WS_TRUST_13_NS); if (e == null) { - e = FederationResponseTest.findElement(doc, "RequestedSecurityToken", + e = XMLUtils.findElement(doc, "RequestedSecurityToken", FederationConstants.WS_TRUST_2005_02_NS); } e.appendChild(token); @@ -1284,10 +1513,10 @@ public class FederationResponseTest { issueDateTime = issueDateTime.plusSeconds(1); token.setAttributeNS(null, "IssueInstant", issueDateTime.toString()); - Element e = FederationResponseTest.findElement(doc, "RequestedSecurityToken", + Element e = XMLUtils.findElement(doc, "RequestedSecurityToken", FederationConstants.WS_TRUST_13_NS); if (e == null) { - e = FederationResponseTest.findElement(doc, "RequestedSecurityToken", + e = XMLUtils.findElement(doc, "RequestedSecurityToken", FederationConstants.WS_TRUST_2005_02_NS); } e.appendChild(token); @@ -1358,10 +1587,10 @@ public class FederationResponseTest { Document doc = STSUtil.toSOAPPart(STSUtil.SAMPLE_RSTR_COLL_MSG); Element token = assertion.toDOM(doc); - Element e = FederationResponseTest.findElement(doc, "RequestedSecurityToken", + Element e = XMLUtils.findElement(doc, "RequestedSecurityToken", FederationConstants.WS_TRUST_13_NS); if (e == null) { - e = FederationResponseTest.findElement(doc, "RequestedSecurityToken", + e = XMLUtils.findElement(doc, "RequestedSecurityToken", FederationConstants.WS_TRUST_2005_02_NS); } e.appendChild(token); @@ -1404,77 +1633,16 @@ public class FederationResponseTest { Document doc = STSUtil.toSOAPPart(rstr); Element token = assertion.toDOM(doc); - Element e = FederationResponseTest.findElement(doc, "RequestedSecurityToken", + Element e = XMLUtils.findElement(doc, "RequestedSecurityToken", FederationConstants.WS_TRUST_13_NS); if (e == null) { - e = FederationResponseTest.findElement(doc, "RequestedSecurityToken", + e = XMLUtils.findElement(doc, "RequestedSecurityToken", FederationConstants.WS_TRUST_2005_02_NS); } e.appendChild(token); return DOM2Writer.nodeToString(doc); } - - - - /** - * Returns the first element that matches name and - * namespace.

This is a replacement for a XPath lookup - * //name with the given namespace. It's somewhat faster than - * XPath, and we do not deal with prefixes, just with the real namespace URI - * - * @param startNode Where to start the search - * @param name Local name of the element - * @param namespace Namespace URI of the element - * @return The found element or null - */ - public static Element findElement(Node startNode, String name, String namespace) { - // - // Replace the formerly recursive implementation with a depth-first-loop - // lookup - // - if (startNode == null) { - return null; - } - Node startParent = startNode.getParentNode(); - Node processedNode = null; - - while (startNode != null) { - // start node processing at this point - if (startNode.getNodeType() == Node.ELEMENT_NODE - && startNode.getLocalName().equals(name)) { - String ns = startNode.getNamespaceURI(); - if (ns != null && ns.equals(namespace)) { - return (Element)startNode; - } - - if ((namespace == null || namespace.length() == 0) - && (ns == null || ns.length() == 0)) { - return (Element)startNode; - } - } - processedNode = startNode; - startNode = startNode.getFirstChild(); - - // no child, this node is done. - if (startNode == null) { - // close node processing, get sibling - startNode = processedNode.getNextSibling(); - } - // no more siblings, get parent, all children - // of parent are processed. - while (startNode == null) { - processedNode = processedNode.getParentNode(); - if (processedNode == startParent) { - return null; - } - // close parent node processing (processed node now) - startNode = processedNode.getNextSibling(); - } - } - return null; - } - private void assertClaims(List claims, String roleClaimType) { for (Claim c : claims) { Assert.assertTrue("Invalid ClaimType URI: " + c.getClaimType(),