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;
* <ramp:timestampTTL>300</ramp:timestampTTL>
* <ramp:timestampMaxSkew>0</ramp:timestampMaxSkew>
*
<ramp:tokenStoreClass>org.apache.rahas.StorageImpl</ramp:tokenStoreClass>
+ *
<ramp:nonceLifeTime>org.apache.rahas.StorageImpl</ramp:nonceLifeTime>
*
* <ramp:signatureCrypto>
* <ramp:crypto
provider="org.apache.ws.security.components.crypto.Merlin">
@@ -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);
+
+ }
+}