JSEC-34 - added logic to add '/' if the request contextPath is null or empty, accompanied by two test cases for verification

git-svn-id: https://svn.apache.org/repos/asf/incubator/jsecurity/trunk@736234 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/web/src/org/jsecurity/web/attr/CookieAttribute.java b/web/src/org/jsecurity/web/attr/CookieAttribute.java
index 5b887fa..4666ee3 100644
--- a/web/src/org/jsecurity/web/attr/CookieAttribute.java
+++ b/web/src/org/jsecurity/web/attr/CookieAttribute.java
@@ -20,6 +20,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.jsecurity.util.StringUtils;
 import static org.jsecurity.web.WebUtils.toHttp;
 
 import javax.servlet.ServletRequest;
@@ -39,9 +40,11 @@
 public class CookieAttribute<T> extends AbstractWebAttribute<T> {
 
     //TODO - complete JavaDoc
-    
-    /** Private internal log instance. */
-    private static final Log log = LogFactory.getLog(CookieAttribute.class);    
+
+    /**
+     * Private internal log instance.
+     */
+    private static final Log log = LogFactory.getLog(CookieAttribute.class);
 
     /**
      * The number of seconds in one year (= 60 * 60 * 24 * 365).
@@ -58,6 +61,11 @@
      * <code>null</code>, indicating the cookie should be set on the request context root.
      */
     public static final String DEFAULT_PATH = null;
+
+    /**
+     * Root path to use when the path hasn't been set and request context root is empty or null.
+     */
+    public static final String ROOT_PATH = "/";
     /**
      * <code>-1</code>, indicating the cookie should expire when the browser closes.
      */
@@ -233,7 +241,7 @@
 
         String stringValue;
         Cookie cookie = getCookie(toHttp(request), getName());
-        if (cookie != null && cookie.getMaxAge() != 0 ) {
+        if (cookie != null && cookie.getMaxAge() != 0) {
             stringValue = cookie.getValue();
             if (log.isInfoEnabled()) {
                 log.info("Found string value [" + stringValue + "] from HttpServletRequest Cookie [" + getName() + "]");
@@ -257,6 +265,12 @@
         int maxAge = getMaxAge();
         String path = getPath() != null ? getPath() : request.getContextPath();
 
+        //fix for http://issues.apache.org/jira/browse/JSEC-34:
+        path = StringUtils.clean(path);
+        if (path == null) {
+            path = ROOT_PATH;
+        }
+
         String stringValue = toStringValue(value);
         Cookie cookie = new Cookie(name, stringValue);
         cookie.setMaxAge(maxAge);
diff --git a/web/test/org/jsecurity/web/attr/CookieAttributeTest.java b/web/test/org/jsecurity/web/attr/CookieAttributeTest.java
index 836349b..6855bc3 100644
--- a/web/test/org/jsecurity/web/attr/CookieAttributeTest.java
+++ b/web/test/org/jsecurity/web/attr/CookieAttributeTest.java
@@ -20,6 +20,7 @@
 
 import junit.framework.TestCase;
 import static org.easymock.EasyMock.*;
+import org.easymock.IArgumentMatcher;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -67,4 +68,57 @@
         assertTrue(cookie.getMaxAge() == 0);
         assertTrue(cookie.getPath().equals("/somepath"));
     }
+
+    private void testContextPath(String contextPath) {
+        Cookie cookie = new Cookie("test", "blah");
+        cookie.setMaxAge(-1);
+        cookie.setPath("/");
+
+        expect(mockRequest.getContextPath()).andReturn(contextPath);
+
+        mockResponse.addCookie(eqCookie(cookie));
+
+        replay(mockRequest);
+        replay(mockResponse);
+
+        cookieAttribute.setName("test");
+        cookieAttribute.storeValue("blah", mockRequest, mockResponse);
+
+        verify(mockRequest);
+        verify(mockResponse);
+    }
+
+    @Test
+    /** Verifies fix for <a href="http://issues.apache.org/jira/browse/JSEC-34">JSEC-34</a> (1 of 2)*/
+    public void testEmptyContextPath() throws Exception {
+        testContextPath("");
+    }
+
+
+    @Test
+    /** Verifies fix for <a href="http://issues.apache.org/jira/browse/JSEC-34">JSEC-34</a> (2 of 2)*/
+    public void testNullContextPath() throws Exception {
+        testContextPath(null);
+    }
+
+    private static <T extends Cookie> T eqCookie(final T in) {
+        reportMatcher(new IArgumentMatcher() {
+            public boolean matches(Object o) {
+                Cookie c = (Cookie) o;
+                return c.getName().equals(in.getName()) &&
+                        c.getPath().equals(in.getPath()) &&
+                        c.getMaxAge() == in.getMaxAge() &&
+                        c.getSecure() == in.getSecure() &&
+                        c.getValue().equals(in.getValue());
+            }
+
+            public void appendTo(StringBuffer sb) {
+                sb.append("eqCookie(");
+                sb.append(in.getClass().getName());
+                sb.append(")");
+
+            }
+        });
+        return null;
+    }
 }