This is an automated email from the ASF dual-hosted git repository. billblough pushed a commit to branch RAMPART-401 in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-rampart.git
commit ac43b5139717eae61b1cd38d828655b25cb0843b Author: Andreas Veithen <veit...@apache.org> AuthorDate: Mon Feb 6 10:24:19 2017 +0000 RAMPART-401: Apply patch provided by Nathan Clement. --- .../rampart/PolicyBasedResultsValidator.java | 54 +++++++++++++++++++--- .../main/java/org/apache/rampart/errors.properties | 1 + .../org/apache/rampart/PolicyAssertionsTest.java | 37 +++++++++++++++ .../policy/rampart-hashed-password.xml | 18 ++++++++ .../policy/soapmessage-stale-username-token.xml | 17 +++++++ 5 files changed, 120 insertions(+), 7 deletions(-) diff --git a/modules/rampart-core/src/main/java/org/apache/rampart/PolicyBasedResultsValidator.java b/modules/rampart-core/src/main/java/org/apache/rampart/PolicyBasedResultsValidator.java index da258a7..02783b2 100644 --- a/modules/rampart-core/src/main/java/org/apache/rampart/PolicyBasedResultsValidator.java +++ b/modules/rampart-core/src/main/java/org/apache/rampart/PolicyBasedResultsValidator.java @@ -31,6 +31,7 @@ import org.apache.ws.security.components.crypto.Crypto; import org.apache.ws.security.components.crypto.CryptoType; import org.apache.ws.security.message.token.Timestamp; import org.apache.ws.security.util.WSSecurityUtil; +import org.apache.ws.security.util.XmlSchemaDateFormat; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -39,7 +40,10 @@ import org.jaxen.JaxenException; import javax.xml.namespace.QName; import java.math.BigInteger; +import java.security.KeyStore; import java.security.cert.X509Certificate; +import java.text.DateFormat; +import java.text.ParseException; import java.util.*; public class PolicyBasedResultsValidator implements ExtendedPolicyValidatorCallbackHandler { @@ -285,17 +289,18 @@ public class PolicyBasedResultsValidator implements ExtendedPolicyValidatorCallb throws RampartException { //Check for UsernameToken - RampartPolicyData rpd = data.getRampartMessageData().getPolicyData(); + RampartMessageData rmd = data.getRampartMessageData(); + RampartPolicyData rpd = rmd.getPolicyData(); List<SupportingToken> supportingTokens = rpd.getSupportingTokensList(); for (SupportingToken suppTok : supportingTokens) { - handleSupportingTokens(results, suppTok); + handleSupportingTokens(results, suppTok, rmd); } SupportingToken signedSuppToken = rpd.getSignedSupportingTokens(); - handleSupportingTokens(results, signedSuppToken); + handleSupportingTokens(results, signedSuppToken, rmd); SupportingToken signedEndSuppToken = rpd.getSignedEndorsingSupportingTokens(); - handleSupportingTokens(results, signedEndSuppToken); + handleSupportingTokens(results, signedEndSuppToken, rmd); SupportingToken endSuppToken = rpd.getEndorsingSupportingTokens(); - handleSupportingTokens(results, endSuppToken); + handleSupportingTokens(results, endSuppToken, rmd); } /** @@ -303,7 +308,10 @@ public class PolicyBasedResultsValidator implements ExtendedPolicyValidatorCallb * @param suppTok * @throws RampartException */ - protected void handleSupportingTokens(List<WSSecurityEngineResult> results, SupportingToken suppTok) throws RampartException { + protected void handleSupportingTokens(List<WSSecurityEngineResult> results, + SupportingToken suppTok, + RampartMessageData rmd) + throws RampartException { if(suppTok == null) { return; @@ -335,7 +343,9 @@ public class PolicyBasedResultsValidator implements ExtendedPolicyValidatorCallb throw new RampartException("invalidUsernameTokenType"); } - + if (!verifyUsernameTokenTimestamp(wssUt, rmd)) { + throw new RampartException("cannotValidateTimestamp"); + } } else if (token instanceof IssuedToken) { //TODO is is enough to check for ST_UNSIGNED results ?? @@ -710,7 +720,37 @@ public class PolicyBasedResultsValidator implements ExtendedPolicyValidatorCallb return true; } + + /* + * Verify that ut->Created is not before or after 'now' (accounting for clock skew) + */ + protected boolean verifyUsernameTokenTimestamp( + org.apache.ws.security.message.token.UsernameToken token, RampartMessageData rmd) throws RampartException { + + String createdString = token.getCreated(); + if (createdString != null && createdString.length() > 0) { + try { + DateFormat zulu = new XmlSchemaDateFormat(); + Date createdTime = zulu.parse(createdString); + + long now = Calendar.getInstance().getTimeInMillis(); + // adjust 'now' with allowed timeskew + long maxSkew = RampartUtil.getTimestampMaxSkew(rmd); + maxSkew = maxSkew < 0 ? 0 : maxSkew; + maxSkew *= 1000; + + // fail if ts->Created is after or before 'now' (accounting for clock skew) + if (createdTime.getTime() > now + maxSkew || createdTime.getTime() < now - maxSkew) { + return false; + } + } catch (ParseException e) { + throw new RampartException("invalidDateTime", new Object[] {createdString}); + } + } + return true; + } + /** * Evaluate whether a given certificate should be trusted. * Hook to allow subclasses to implement custom validation methods however they see fit. diff --git a/modules/rampart-core/src/main/java/org/apache/rampart/errors.properties b/modules/rampart-core/src/main/java/org/apache/rampart/errors.properties index 1f5053f..ab87de7 100644 --- a/modules/rampart-core/src/main/java/org/apache/rampart/errors.properties +++ b/modules/rampart-core/src/main/java/org/apache/rampart/errors.properties @@ -104,3 +104,4 @@ invalidNonceLifeTime = Invalid value for nonceLifeTime in rampart configuration invalidIssuerAddress = Invalid value for Issuer invalidSignatureAlgo=Invalid signature algorithm for Asymmetric binding invalidUsernameTokenType = Invalid UsernameToken Type. +invalidDateTime = Invalid XML dateTime {0} \ No newline at end of file diff --git a/modules/rampart-tests/src/test/java/org/apache/rampart/PolicyAssertionsTest.java b/modules/rampart-tests/src/test/java/org/apache/rampart/PolicyAssertionsTest.java index 5d5a8ed..e9cb428 100644 --- a/modules/rampart-tests/src/test/java/org/apache/rampart/PolicyAssertionsTest.java +++ b/modules/rampart-tests/src/test/java/org/apache/rampart/PolicyAssertionsTest.java @@ -19,6 +19,8 @@ import org.apache.axis2.context.MessageContext; import org.apache.neethi.Policy; import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.InputStream; public class PolicyAssertionsTest extends MessageBuilderTestBase { @@ -80,4 +82,39 @@ public class PolicyAssertionsTest extends MessageBuilderTestBase { } } + + public void testStaleUsernameToken() throws Exception { + + MessageContext ctx = getMsgCtx(); + + String policyXml = "test-resources/policy/rampart-hashed-password.xml"; + Policy policy = loadPolicy(policyXml); + + ctx.setProperty(RampartMessageData.KEY_RAMPART_POLICY, policy); + + ctx.getOptions().setUserName( "Ron" ); + ctx.getOptions().setPassword( "noR" ); + + // Building the SOAP envelope from the OMElement + SOAPBuilder soapBuilder = new SOAPBuilder(); + InputStream inStream = + new FileInputStream("test-resources/policy/soapmessage-stale-username-token.xml"); + SOAPEnvelope env = (SOAPEnvelope) soapBuilder.processDocument(inStream, "text/xml", ctx); + ctx.setEnvelope(env); + + ctx.setServerSide(true); + + ctx.setProperty(RampartMessageData.KEY_RAMPART_POLICY, policy); + ctx.setProperty(WSHandlerConstants.PW_CALLBACK_REF, new TestCBHandler()); + + RampartEngine engine = new RampartEngine(); + + try { + engine.process(ctx); + fail(" This should have thrown RampartException: The timestamp could not be validated."); + } catch (RampartException expected) { + // Ignore intentionally as the test is supposed to throw an exception + } + + } } diff --git a/modules/rampart-tests/test-resources/policy/rampart-hashed-password.xml b/modules/rampart-tests/test-resources/policy/rampart-hashed-password.xml new file mode 100644 index 0000000..7a250df --- /dev/null +++ b/modules/rampart-tests/test-resources/policy/rampart-hashed-password.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsp:Policy wsu:Id="UTOverTransport" + xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" + xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"> + <wsp:ExactlyOne> + <wsp:All> + <sp:SignedSupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"> + <wsp:Policy> + <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"> + <wsp:Policy> + <sp:HashPassword/> + </wsp:Policy> + </sp:UsernameToken> + </wsp:Policy> + </sp:SignedSupportingTokens> + </wsp:All> + </wsp:ExactlyOne> +</wsp:Policy> diff --git a/modules/rampart-tests/test-resources/policy/soapmessage-stale-username-token.xml b/modules/rampart-tests/test-resources/policy/soapmessage-stale-username-token.xml new file mode 100644 index 0000000..ae71fa9 --- /dev/null +++ b/modules/rampart-tests/test-resources/policy/soapmessage-stale-username-token.xml @@ -0,0 +1,17 @@ +<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:axis2="http://ws.apache.org/namespaces/axis2" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <soapenv:Header xmlns:fabrikam="http://example.com/fabrikam"> + <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soapenv:mustUnderstand="1"> + <wsse:UsernameToken wsu:Id="UsernameToken-23"> + <wsse:Username>Ron</wsse:Username> + <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">6AAnvDR1kc48ztQV9+wxyWY92M4=</wsse:Password> + <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">8b+d7vyjy+qqHf3ElGFehQ==</wsse:Nonce> + <wsu:Created>2013-03-07T00:29:44.106Z</wsu:Created> + </wsse:UsernameToken> + </wsse:Security> + </soapenv:Header> + <soapenv:Body> + <ns1:getBalance xmlns:ns1="http://localhost:8081/axis/services/BankPort" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> + <accountNo href="#id0" /> + </ns1:getBalance> + </soapenv:Body> +</soapenv:Envelope>