Author: prabath
Date: Tue May 11 06:28:50 2010
New Revision: 943002

URL: http://svn.apache.org/viewvc?rev=943002&view=rev
Log:
Fix for https://issues.apache.org/jira/browse/RAMPART-294 - thanks AmilaJ for 
the patch

Added:
    
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/ServiceNonceCache.java
    
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/UniqueMessageAttributeCache.java
    
axis/axis2/java/rampart/trunk/modules/rampart-tests/src/test/java/org/apache/rampart/NonceCacheTest.java
Modified:
    
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/RampartEngine.java
    
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/errors.properties
    
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/policy/builders/RampartConfigBuilder.java
    
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/policy/model/RampartConfig.java

Modified: 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/RampartEngine.java
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/RampartEngine.java?rev=943002&r1=943001&r2=943002&view=diff
==============================================================================
--- 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/RampartEngine.java
 (original)
+++ 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/RampartEngine.java
 Tue May 11 06:28:50 2010
@@ -18,6 +18,8 @@ package org.apache.rampart;
 
 import org.apache.axiom.om.OMElement;
 import org.apache.axiom.soap.*;
+import org.apache.axiom.soap.SOAP11Constants;
+import org.apache.axiom.soap.SOAP12Constants;
 import org.apache.axis2.AxisFault;
 import org.apache.axis2.context.MessageContext;
 import org.apache.commons.logging.Log;
@@ -30,10 +32,7 @@ import org.apache.rampart.policy.Rampart
 import org.apache.rampart.util.Axis2Util;
 import org.apache.rampart.util.RampartUtil;
 import org.apache.ws.secpolicy.WSSPolicyException;
-import org.apache.ws.security.WSConstants;
-import org.apache.ws.security.WSSecurityEngine;
-import org.apache.ws.security.WSSecurityEngineResult;
-import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.*;
 import org.apache.ws.security.components.crypto.Crypto;
 import org.apache.ws.security.saml.SAMLKeyInfo;
 import org.apache.ws.security.saml.SAMLUtil;
@@ -53,7 +52,8 @@ import java.util.Vector;
 public class RampartEngine {
 
        private static Log log = LogFactory.getLog(RampartEngine.class);
-       private static Log tlog = LogFactory.getLog(RampartConstants.TIME_LOG); 
+       private static Log tlog = LogFactory.getLog(RampartConstants.TIME_LOG);
+    private static ServiceNonceCache serviceNonceCache = new 
ServiceNonceCache();
 
        public Vector process(MessageContext msgCtx) throws WSSPolicyException,
        RampartException, WSSecurityException, AxisFault {
@@ -230,9 +230,42 @@ public class RampartEngine {
 
                 }
             } else if (WSConstants.UT == actInt.intValue()) {
-                String username = ((Principal) 
wser.get(WSSecurityEngineResult.TAG_PRINCIPAL))
-                        .getName();
+
+                       WSUsernameTokenPrincipal userNameTokenPrincipal = 
(WSUsernameTokenPrincipal)wser.get(WSSecurityEngineResult.TAG_PRINCIPAL);
+
+                String username = userNameTokenPrincipal.getName();
                 msgCtx.setProperty(RampartMessageData.USERNAME, username);
+                
+                if (userNameTokenPrincipal.getNonce() != null) {
+                    // Check whether this is a replay attack. To verify that 
we need to check whether nonce value
+                    // is a repeating one
+                    int nonceLifeTimeInSeconds = 0;
+
+                    if (rpd.getRampartConfig() != null) {
+                        
+                        String stringLifeTime = 
rpd.getRampartConfig().getNonceLifeTime();
+
+                        try {
+                            nonceLifeTimeInSeconds = 
Integer.parseInt(stringLifeTime);
+
+                        } catch (NumberFormatException e) {
+                            log.error("Invalid value for nonceLifeTime in 
rampart configuration file.", e);
+                            throw new RampartException(
+                                        "invalidNonceLifeTime", e);
+
+                        }
+                    }
+
+                    String serviceEndpointName = 
msgCtx.getAxisService().getEndpointName();
+
+                    boolean valueRepeating = 
serviceNonceCache.isNonceRepeatingForService(serviceEndpointName, username, 
userNameTokenPrincipal.getNonce());
+
+                    if (valueRepeating){
+                        throw new RampartException("repeatingNonceValue", new 
Object[]{ userNameTokenPrincipal.getNonce(), username} );
+                    }
+
+                    serviceNonceCache.addNonceForService(serviceEndpointName, 
username, userNameTokenPrincipal.getNonce(), nonceLifeTimeInSeconds);
+                }
             } else if (WSConstants.SIGN == actInt.intValue()) {
                 X509Certificate cert = (X509Certificate) 
wser.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
                 msgCtx.setProperty(RampartMessageData.X509_CERT, cert);

Added: 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/ServiceNonceCache.java
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/ServiceNonceCache.java?rev=943002&view=auto
==============================================================================
--- 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/ServiceNonceCache.java
 (added)
+++ 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/ServiceNonceCache.java
 Tue May 11 06:28:50 2010
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2004,2005 The Apache Software Foundation.
+ *
+ * Licensed 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.rampart;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class holds nonce information per service.
+ */
+public class ServiceNonceCache {
+
+    private Map<String, UniqueMessageAttributeCache> mapServiceNonceCache = 
Collections.synchronizedMap(new HashMap<String, UniqueMessageAttributeCache>());
+
+    /**
+     * This method will add a nonce value for a given service.
+     * @param service The service url.
+     * @param userName Given user name.
+     * @param nonceValue Passed nonce value.
+     * @param nonceLifeTime Maximum life span of a nonce value.
+     */
+    public void addNonceForService(String service, String userName, String 
nonceValue, int nonceLifeTime) {
+
+        UniqueMessageAttributeCache nonceCache;
+        if (this.mapServiceNonceCache.containsKey(service)) {
+            nonceCache = this.mapServiceNonceCache.get(service);
+        } else {
+            nonceCache = new NonceCache(nonceLifeTime);
+            this.mapServiceNonceCache.put(service, nonceCache);
+        }
+                
+        nonceCache.addToCache(nonceValue, userName);
+    }
+
+    /**
+     * This method will check whether the nonce value is repeating for the 
given service.
+     * @param service The service url.
+     * @param userName User name.
+     * @param nonceValue Nonce value.
+     * @return true if nonce value is repeating else false.
+     */
+    public boolean isNonceRepeatingForService(String service, String userName, 
String nonceValue){
+
+        if (this.mapServiceNonceCache.containsKey(service)) {
+
+            UniqueMessageAttributeCache nonceCache = 
this.mapServiceNonceCache.get(service);
+            return nonceCache.valueExistsInCache(nonceValue, userName);        
   
+
+        }
+
+        return false;
+
+    }
+
+}

Added: 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/UniqueMessageAttributeCache.java
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/UniqueMessageAttributeCache.java?rev=943002&view=auto
==============================================================================
--- 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/UniqueMessageAttributeCache.java
 (added)
+++ 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/UniqueMessageAttributeCache.java
 Tue May 11 06:28:50 2010
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2004,2005 The Apache Software Foundation.
+ *
+ * Licensed 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.rampart;
+
+/**
+ * An interface to cache nonce/sequence number values coming with messages.
+ * This mainly helps to prevent replay attacks. There are few different ways 
to handle replay attacks.
+ * 1. Cache nonce values.
+ * 2. Use a sequence number.
+ * 
+ * "Web Services Security UsernameToken Profile 1.1 OASIS Standard 
Specification, 1 February 2006" specification only recommends
+ * to cache nonce for a period. But there can be other mechanisms like using 
sequence number.
+ * Therefore cache is implemented as an interface and later if we need to 
support sequence number scenario we can easily extend this. 
+ * User: aj
+ * Date: Apr 30, 2010
+ * Time: 12:15:52 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface UniqueMessageAttributeCache {
+
+    /**
+     * Sets the maximum life time of a message id.
+     * @param maxTime Maximum life time in seconds.
+     */
+    public void setMaximumLifeTimeOfAnAttribute(int maxTime);
+
+     /**
+     * Gets the maximum life time of a message id.
+     * @return Gets message id life time in seconds.
+     */
+    public int getMaximumLifeTimeOfAnAttribute();
+
+    /**
+     * Add value to a cache. Value can be sequence or nonce value.
+     * @param id - Nonce value or sequence number.
+     * @param userName - User name parameter value of the UserNameToken.
+     */
+    public void addToCache(String id, String userName);
+
+    /**
+     * Checks whether value already exists in the cache for a given user name. 
+     * @param id - Nonce or sequence id value of the newly received message.
+     * @param userName - User name parameter value of the UserName token.
+     * @return Returns true if nonce or sequence id is already received for 
given user name. Else false.
+     */
+    public boolean valueExistsInCache(String id, String userName);
+
+    /**
+     * Clears all recorded nonce values/sequence numbers.
+     */
+    public void clearCache();
+}

Modified: 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/errors.properties
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/errors.properties?rev=943002&r1=943001&r2=943002&view=diff
==============================================================================
--- 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/errors.properties
 (original)
+++ 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/errors.properties
 Tue May 11 06:28:50 2010
@@ -95,4 +95,6 @@ signedElementNotSigned = Element must be
 bodyNotSigned = Soap Body must be signed 
 unexprectedSignature = Unexpected signature
 invalidTransport = Expected transport is "https" but incoming transport found 
: \"{0}\" 
-requiredElementsMissing = Required Elements not found in the incoming message 
: {0}
\ No newline at end of file
+requiredElementsMissing = Required Elements not found in the incoming message 
: {0}
+repeatingNonceValue = Nonce value : {0}, already seen before for user name : 
{1}. Possibly this could be a replay attack.
+invalidNonceLifeTime = Invalid value for nonceLifeTime in rampart 
configuration file.
\ No newline at end of file

Modified: 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/policy/builders/RampartConfigBuilder.java
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/policy/builders/RampartConfigBuilder.java?rev=943002&r1=943001&r2=943002&view=diff
==============================================================================
--- 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/policy/builders/RampartConfigBuilder.java
 (original)
+++ 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/policy/builders/RampartConfigBuilder.java
 Tue May 11 06:28:50 2010
@@ -126,6 +126,12 @@ public class RampartConfigBuilder implem
         if (childElement != null) {
             rampartConfig.setTimestampMaxSkew(childElement.getText().trim());
         }
+
+        childElement = element.getFirstChildWithName(new QName(
+                RampartConfig.NS, RampartConfig.NONCE_LIFE_TIME));
+        if (childElement != null) {
+            rampartConfig.setNonceLifeTime(childElement.getText().trim());
+        }
         
                childElement = element.getFirstChildWithName(new QName(
                 RampartConfig.NS, RampartConfig.OPTIMISE_PARTS));

Modified: 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/policy/model/RampartConfig.java
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/policy/model/RampartConfig.java?rev=943002&r1=943001&r2=943002&view=diff
==============================================================================
--- 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/policy/model/RampartConfig.java
 (original)
+++ 
axis/axis2/java/rampart/trunk/modules/rampart-core/src/main/java/org/apache/rampart/policy/model/RampartConfig.java
 Tue May 11 06:28:50 2010
@@ -39,6 +39,7 @@ import javax.xml.stream.XMLStreamWriter;
  *  &lt;ramp:timestampTTL&gt;300&lt;/ramp:timestampTTL&gt;
  *  &lt;ramp:timestampMaxSkew&gt;0&lt;/ramp:timestampMaxSkew&gt;
  *  
&lt;ramp:tokenStoreClass&gt;org.apache.rahas.StorageImpl&lt;/ramp:tokenStoreClass&gt;
+ *  
&lt;ramp:nonceLifeTime&gt;org.apache.rahas.StorageImpl&lt;/ramp:nonceLifeTime&gt;
  *  
  *  &lt;ramp:signatureCrypto&gt;
  *  &lt;ramp:crypto 
provider=&quot;org.apache.ws.security.components.crypto.Merlin&quot;&gt;
@@ -67,6 +68,8 @@ public class RampartConfig implements As
 
     public static final int DEFAULT_TIMESTAMP_MAX_SKEW = 300;
 
+    public static final int DEFAULT_NONCE_LIFE_TIME = 60 * 5; // Default life 
time of a nonce is 5 minutes
+
     public final static String NS = "http://ws.apache.org/rampart/policy";;
 
     public final static String PREFIX = "rampart";
@@ -102,6 +105,8 @@ public class RampartConfig implements As
     public final static String TS_MAX_SKEW_LN = "timestampMaxSkew";
 
     public final static String TOKEN_STORE_CLASS_LN = "tokenStoreClass";
+
+    public final static String NONCE_LIFE_TIME = "nonceLifeTime";
     
     public final static String OPTIMISE_PARTS = "optimizeParts";
 
@@ -138,6 +143,8 @@ public class RampartConfig implements As
     private OptimizePartsConfig optimizeParts;
 
     private String tokenStoreClass;
+
+    private String nonceLifeTime = Integer.toString(DEFAULT_NONCE_LIFE_TIME);
     
     private SSLConfig sslConfig;
     
@@ -165,6 +172,21 @@ public class RampartConfig implements As
         this.tokenStoreClass = tokenStoreClass;
     }
 
+    /**
+     * @return Returns the life time of a nonce in seconds.
+     */
+    public String getNonceLifeTime() {
+        return this.nonceLifeTime;
+    }
+
+    /**
+     * @param nonceLife
+     *            The life time of a nonce to set (in seconds).
+     */
+    public void setNonceLifeTime(String nonceLife) {
+        this.nonceLifeTime = nonceLife;
+    }
+
     public CryptoConfig getDecCryptoConfig() {
         return decCryptoConfig;
     }
@@ -327,6 +349,12 @@ public class RampartConfig implements As
             writer.writeCharacters(getTokenStoreClass());
             writer.writeEndElement();
         }
+
+        if (getNonceLifeTime() != null) {
+            writer.writeStartElement(NS, NONCE_LIFE_TIME);
+            writer.writeCharacters(getNonceLifeTime());
+            writer.writeEndElement();
+        }
         
         if (encrCryptoConfig != null) {
             writer.writeStartElement(NS, ENCR_CRYPTO_LN);

Added: 
axis/axis2/java/rampart/trunk/modules/rampart-tests/src/test/java/org/apache/rampart/NonceCacheTest.java
URL: 
http://svn.apache.org/viewvc/axis/axis2/java/rampart/trunk/modules/rampart-tests/src/test/java/org/apache/rampart/NonceCacheTest.java?rev=943002&view=auto
==============================================================================
--- 
axis/axis2/java/rampart/trunk/modules/rampart-tests/src/test/java/org/apache/rampart/NonceCacheTest.java
 (added)
+++ 
axis/axis2/java/rampart/trunk/modules/rampart-tests/src/test/java/org/apache/rampart/NonceCacheTest.java
 Tue May 11 06:28:50 2010
@@ -0,0 +1,61 @@
+package org.apache.rampart;
+
+import junit.framework.TestCase;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: aj
+ * Date: Apr 30, 2010
+ * Time: 4:15:20 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class NonceCacheTest extends TestCase {
+
+    public NonceCacheTest(String name) {
+        super(name);
+    }
+
+    public void testAddToCache() throws Exception {
+
+        UniqueMessageAttributeCache cache = new NonceCache();
+
+        cache.addToCache("j8EqKYJ/CxOZfN8CySMm0g==", "apache");
+        cache.addToCache("j8EqKYJ/CxOdfN8CySMm0g==", "apache");
+        cache.addToCache("j8EqKYJ/CxOhfN8CySMm0g==", "apache");
+    }
+
+    public void testValueExistsInCache() throws Exception{
+
+        UniqueMessageAttributeCache cache = new NonceCache();
+
+        cache.addToCache("j8EqKYJ/CxOZfN8CySMm0g==", "apache");
+        cache.addToCache("j8EqKYJ/CxOdfN8CySMm0g==", "apache");
+        cache.addToCache("j8EqKYJ/CxOhfN8CySMm0g==", "apache");
+
+        boolean returnValue1 = 
cache.valueExistsInCache("j8EqKYJ/CxOZfN8CySMm0g==", "apache");
+        assertTrue("nonce - j8EqKYJ/CxOZfN8CySMm0g== and apache must exists in 
the cache", returnValue1);
+
+        boolean returnValue2 = 
cache.valueExistsInCache("p8EqKYJ/CxOZfN8CySMm0g==", "apache");
+        assertFalse("nonce - p8EqKYJ/CxOZfN8CySMm0g== and apache should not be 
in the cache", returnValue2);
+    }
+
+    public void testValueExpiration() throws Exception{
+
+        UniqueMessageAttributeCache cache = new NonceCache();
+
+        cache.addToCache("j8EqKYJ/CxOZfN8CySMm0g==", "apache");
+        cache.addToCache("j8EqKYJ/CxOdfN8CySMm0p==", "apache");
+        cache.addToCache("q8EqKYJ/CxOhfN8CySMm0g==", "apache");
+
+        cache.setMaximumLifeTimeOfAnAttribute(1);
+
+        boolean returnValue1 = 
cache.valueExistsInCache("j8EqKYJ/CxOZfN8CySMm0g==", "apache");
+        assertTrue("nonce - j8EqKYJ/CxOZfN8CySMm0g== and apache must exists in 
the cache", returnValue1);
+
+        Thread.sleep(2 * 1000);
+
+        returnValue1 = cache.valueExistsInCache("j8EqKYJ/CxOZfN8CySMm0g==", 
"apache");
+        assertFalse("nonce - j8EqKYJ/CxOZfN8CySMm0g== and apache must not 
exists in the cache", returnValue1);
+
+    }
+}


Reply via email to