You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by co...@apache.org on 2013/06/07 17:41:54 UTC

svn commit: r1490690 - in /webservices/wss4j/trunk: ws-security-common/src/main/java/org/apache/wss4j/common/util/ ws-security-dom/src/main/java/org/apache/wss4j/dom/ ws-security-dom/src/main/java/org/apache/wss4j/dom/message/ ws-security-dom/src/main/...

Author: coheigea
Date: Fri Jun  7 15:41:53 2013
New Revision: 1490690

URL: http://svn.apache.org/r1490690
Log:
[WSS-441] - Allow the date/time in the security headers to be spoofed

Added:
    webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/util/WSCurrentTimeSource.java
    webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/util/WSTimeSource.java
Modified:
    webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/WSSConfig.java
    webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecTimestamp.java
    webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecUsernameToken.java
    webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/Timestamp.java
    webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/UsernameToken.java
    webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/TimestampTest.java
    webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/UsernameTokenTest.java

Added: webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/util/WSCurrentTimeSource.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/util/WSCurrentTimeSource.java?rev=1490690&view=auto
==============================================================================
--- webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/util/WSCurrentTimeSource.java (added)
+++ webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/util/WSCurrentTimeSource.java Fri Jun  7 15:41:53 2013
@@ -0,0 +1,34 @@
+/**
+ * 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.wss4j.common.util;
+
+import java.util.Date;
+
+public class WSCurrentTimeSource implements WSTimeSource {
+   
+   /**
+    * Get the current date time
+    * @return the current date/time as a date object
+    */
+   public Date now() {
+       return new Date();
+   }
+   
+}
\ No newline at end of file

Added: webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/util/WSTimeSource.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/util/WSTimeSource.java?rev=1490690&view=auto
==============================================================================
--- webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/util/WSTimeSource.java (added)
+++ webservices/wss4j/trunk/ws-security-common/src/main/java/org/apache/wss4j/common/util/WSTimeSource.java Fri Jun  7 15:41:53 2013
@@ -0,0 +1,37 @@
+/**
+ * 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.wss4j.common.util;
+
+import java.util.Date;
+
+/**
+ * This interface allows the Time Source used to set dates and times to be
+ * overridden by the application.
+ * 
+ */
+public interface WSTimeSource {
+   
+   /**
+    * Get the current date time
+    * @return the current date/time as a date object
+    */
+   public Date now();
+   
+}
\ No newline at end of file

Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/WSSConfig.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/WSSConfig.java?rev=1490690&r1=1490689&r2=1490690&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/WSSConfig.java (original)
+++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/WSSConfig.java Fri Jun  7 15:41:53 2013
@@ -32,6 +32,8 @@ import javax.xml.namespace.QName;
 import org.apache.wss4j.dom.action.Action;
 import org.apache.wss4j.common.crypto.WSProviderConfig;
 import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.util.WSCurrentTimeSource;
+import org.apache.wss4j.common.util.WSTimeSource;
 import org.apache.wss4j.dom.processor.Processor;
 import org.apache.wss4j.dom.validate.Validator;
 import org.apache.xml.security.stax.impl.util.IDGenerator;
@@ -312,6 +314,11 @@ public class WSSConfig {
     private boolean validateSamlSubjectConfirmation = true;
     
     /**
+     * This allows the user to specify a different time than that of the current System time.
+     */
+    private WSTimeSource currentTime;
+    
+    /**
      * The default wsu:Id allocator is a simple "start at 1 and increment up"
      * thing that is very fast.
      */
@@ -764,4 +771,14 @@ public class WSSConfig {
         this.validateSamlSubjectConfirmation = validateSamlSubjectConfirmation;
     }
     
+    public WSTimeSource getCurrentTime() {
+        if (currentTime != null) {
+            return currentTime;
+        }
+        return new WSCurrentTimeSource();
+    }
+
+    public void setCurrentTime(WSTimeSource currentTime) {
+        this.currentTime = currentTime;
+    }
 }

Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecTimestamp.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecTimestamp.java?rev=1490690&r1=1490689&r2=1490690&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecTimestamp.java (original)
+++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecTimestamp.java Fri Jun  7 15:41:53 2013
@@ -68,7 +68,8 @@ public class WSSecTimestamp extends WSSe
      * @param doc The SOAP envelope as W3C document
      */
     public void prepare(Document doc) {
-        ts = new Timestamp(getWsConfig().isPrecisionInMilliSeconds(), doc, timeToLive);
+        ts = new Timestamp(getWsConfig().isPrecisionInMilliSeconds(), doc, 
+                           getWsConfig().getCurrentTime(), timeToLive);
         String tsId = getWsConfig().getIdAllocator().createId("TS-", ts);
         ts.setID(tsId);
     }

Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecUsernameToken.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecUsernameToken.java?rev=1490690&r1=1490689&r2=1490690&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecUsernameToken.java (original)
+++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecUsernameToken.java Fri Jun  7 15:41:53 2013
@@ -169,7 +169,8 @@ public class WSSecUsernameToken extends 
      * @param doc The SOAP envelope as W3C document
      */
     public void prepare(Document doc) {
-        ut = new UsernameToken(getWsConfig().isPrecisionInMilliSeconds(), doc, passwordType);
+        ut = new UsernameToken(getWsConfig().isPrecisionInMilliSeconds(), doc, 
+                               getWsConfig().getCurrentTime(), passwordType);
         ut.setPasswordsAreEncoded(passwordsAreEncoded);
         ut.setName(user);
         if (useDerivedKey) {
@@ -182,7 +183,7 @@ public class WSSecUsernameToken extends 
             ut.addNonce(doc);
         }
         if (created) {
-            ut.addCreated(getWsConfig().isPrecisionInMilliSeconds(), doc);
+            ut.addCreated(getWsConfig().isPrecisionInMilliSeconds(), getWsConfig().getCurrentTime(), doc);
         }
         ut.setID(getWsConfig().getIdAllocator().createId("UsernameToken-", ut));
     }

Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/Timestamp.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/Timestamp.java?rev=1490690&r1=1490689&r2=1490690&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/Timestamp.java (original)
+++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/Timestamp.java Fri Jun  7 15:41:53 2013
@@ -33,6 +33,8 @@ import org.apache.wss4j.common.bsp.BSPRu
 import org.apache.wss4j.common.ext.WSSecurityException;
 import org.apache.wss4j.common.util.DOM2Writer;
 import org.apache.wss4j.common.util.DateUtil;
+import org.apache.wss4j.common.util.WSCurrentTimeSource;
+import org.apache.wss4j.common.util.WSTimeSource;
 import org.apache.wss4j.dom.WSConstants;
 import org.apache.wss4j.dom.WSSConfig;
 import org.apache.wss4j.dom.bsp.BSPEnforcer;
@@ -171,6 +173,17 @@ public class Timestamp {
      * @param ttl the time to live (validity of the security semantics) in seconds
      */
     public Timestamp(boolean milliseconds, Document doc, int ttl) {
+        this(milliseconds, doc, new WSCurrentTimeSource(), ttl);
+    }
+    
+    /**
+     * Constructs a <code>Timestamp</code> object according
+     * to the defined parameters.
+     *
+     * @param doc the SOAP envelope as <code>Document</code>
+     * @param ttl the time to live (validity of the security semantics) in seconds
+     */
+    public Timestamp(boolean milliseconds, Document doc, WSTimeSource timeSource, int ttl) {
 
         customElements = new ArrayList<Element>();
         element = 
@@ -189,11 +202,11 @@ public class Timestamp {
             doc.createElementNS(
                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
             );
-        createdDate = new Date();
+        createdDate = timeSource.now();
         elementCreated.appendChild(doc.createTextNode(zulu.format(createdDate)));
         element.appendChild(elementCreated);
         if (ttl != 0) {
-            expiresDate = new Date();
+            expiresDate = timeSource.now();
             expiresDate.setTime(createdDate.getTime() + ((long)ttl * 1000L));
 
             Element elementExpires =

Modified: webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/UsernameToken.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/UsernameToken.java?rev=1490690&r1=1490689&r2=1490690&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/UsernameToken.java (original)
+++ webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/UsernameToken.java Fri Jun  7 15:41:53 2013
@@ -40,6 +40,8 @@ import org.apache.wss4j.common.principal
 import org.apache.wss4j.common.util.DOM2Writer;
 import org.apache.wss4j.common.util.DateUtil;
 import org.apache.wss4j.common.util.UsernameTokenUtil;
+import org.apache.wss4j.common.util.WSCurrentTimeSource;
+import org.apache.wss4j.common.util.WSTimeSource;
 import org.apache.wss4j.dom.WSConstants;
 import org.apache.wss4j.dom.WSSConfig;
 import org.apache.wss4j.dom.bsp.BSPEnforcer;
@@ -249,6 +251,10 @@ public class UsernameToken {
      *               password required
      */
     public UsernameToken(boolean milliseconds, Document doc, String pwType) {
+        this(milliseconds, doc, new WSCurrentTimeSource(), pwType);
+    }
+    
+    public UsernameToken(boolean milliseconds, Document doc, WSTimeSource timeSource, String pwType) {
         element = 
             doc.createElementNS(WSConstants.WSSE_NS, "wsse:" + WSConstants.USERNAME_TOKEN_LN);
 
@@ -266,7 +272,7 @@ public class UsernameToken {
             passwordType = pwType;
             if (passwordType.equals(WSConstants.PASSWORD_DIGEST)) {
                 addNonce(doc);
-                addCreated(milliseconds, doc);
+                addCreated(milliseconds, timeSource, doc);
             } else {
                 hashed = false;
             }
@@ -313,6 +319,13 @@ public class UsernameToken {
      * Creates and adds a Created element to this UsernameToken
      */
     public void addCreated(boolean milliseconds, Document doc) {
+        addCreated(milliseconds, new WSCurrentTimeSource(), doc);
+    }
+    
+    /**
+     * Creates and adds a Created element to this UsernameToken
+     */
+    public void addCreated(boolean milliseconds, WSTimeSource timeSource, Document doc) {
         if (elementCreated != null) {
             return;
         }
@@ -327,7 +340,7 @@ public class UsernameToken {
             doc.createElementNS(
                 WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
             );
-        Date currentTime = new Date();
+        Date currentTime = timeSource.now();
         elementCreated.appendChild(doc.createTextNode(zulu.format(currentTime)));
         element.appendChild(elementCreated);
     }

Modified: webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/TimestampTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/TimestampTest.java?rev=1490690&r1=1490689&r2=1490690&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/TimestampTest.java (original)
+++ webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/TimestampTest.java Fri Jun  7 15:41:53 2013
@@ -28,6 +28,7 @@ import org.apache.wss4j.dom.common.SOAPU
 import org.apache.wss4j.dom.handler.RequestData;
 import org.apache.wss4j.common.bsp.BSPRule;
 import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.util.WSTimeSource;
 import org.apache.wss4j.common.util.XMLUtils;
 import org.apache.wss4j.dom.message.token.Timestamp;
 import org.apache.wss4j.dom.util.WSSecurityUtil;
@@ -740,6 +741,51 @@ public class TimestampTest extends org.j
     }
     
     /**
+     * This is a test to create a "Spoofed" Timestamp (see WSS-441)
+     */
+    @org.junit.Test
+    public void testSpoofedTimestamp() throws Exception {
+
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader();
+        secHeader.insertSecurityHeader(doc);
+        
+        WSSecTimestamp timestamp = new WSSecTimestamp();
+        timestamp.setTimeToLive(300);
+        
+        WSSConfig config = WSSConfig.getNewInstance();
+        WSTimeSource spoofedTimeSource = new WSTimeSource() {
+
+            public Date now() {
+                Date currentTime = new Date();
+                currentTime.setTime(currentTime.getTime() - (500L * 1000L));
+                return currentTime;
+            }
+            
+        };
+        config.setCurrentTime(spoofedTimeSource);
+        
+        timestamp.setWsConfig(config);
+        Document createdDoc = timestamp.build(doc, secHeader);
+
+        if (LOG.isDebugEnabled()) {
+            String outputString = 
+                XMLUtils.PrettyDocumentToString(createdDoc);
+            LOG.debug(outputString);
+        }
+        
+        //
+        // Do some processing
+        //
+        try {
+            verify(createdDoc, WSSConfig.getNewInstance());
+            fail("Expected failure on an expired timestamp");
+        } catch (WSSecurityException ex) {
+            assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED); 
+        }
+    }
+    
+    /**
      * Verifies the soap envelope
      */
     private List<WSSecurityEngineResult> verify(

Modified: webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/UsernameTokenTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/UsernameTokenTest.java?rev=1490690&r1=1490689&r2=1490690&view=diff
==============================================================================
--- webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/UsernameTokenTest.java (original)
+++ webservices/wss4j/trunk/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/UsernameTokenTest.java Fri Jun  7 15:41:53 2013
@@ -31,6 +31,7 @@ import org.apache.wss4j.dom.common.SOAPU
 import org.apache.wss4j.common.bsp.BSPRule;
 import org.apache.wss4j.common.ext.WSPasswordCallback;
 import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.util.WSTimeSource;
 import org.apache.wss4j.common.util.XMLUtils;
 import org.apache.wss4j.dom.handler.RequestData;
 import org.apache.wss4j.dom.handler.WSHandlerConstants;
@@ -1061,6 +1062,48 @@ public class UsernameTokenTest extends o
         }
     }
     
+    /**
+     * This is a test to create a "Spoofed" UsernameToken (see WSS-441)
+     */
+    @org.junit.Test
+    public void testSpoofedUsernameToken() throws Exception {
+        WSSecUsernameToken builder = new WSSecUsernameToken();
+        builder.setUserInfo("wernerd", "verySecret");
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader();
+        secHeader.insertSecurityHeader(doc);
+        
+        WSSConfig config = WSSConfig.getNewInstance();
+        WSTimeSource spoofedTimeSource = new WSTimeSource() {
+
+            public Date now() {
+                Date currentTime = new Date();
+                currentTime.setTime(currentTime.getTime() - (500L * 1000L));
+                return currentTime;
+            }
+            
+        };
+        config.setCurrentTime(spoofedTimeSource);
+        
+        builder.setWsConfig(config);
+        Document signedDoc = builder.build(doc, secHeader);
+
+        if (LOG.isDebugEnabled()) {
+            String outputString = 
+                XMLUtils.PrettyDocumentToString(signedDoc);
+            LOG.debug(outputString);
+        }
+        
+        try {
+            WSSecurityEngine secEngine = new WSSecurityEngine();
+            secEngine.processSecurityHeader(doc, null, callbackHandler, null);
+            fail("The UsernameToken validation should have failed");
+        } catch (WSSecurityException ex) {
+            assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.MESSAGE_EXPIRED); 
+        }  
+    }
+
+    
     private List<WSSecurityEngineResult> verify(Document doc) throws Exception {
         return verify(doc, false);
     }