You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by lh...@apache.org on 2010/04/23 22:42:44 UTC

svn commit: r937511 - in /incubator/shiro/trunk/web/src: main/java/org/apache/shiro/web/ main/java/org/apache/shiro/web/attr/ main/java/org/apache/shiro/web/mgt/ main/java/org/apache/shiro/web/servlet/ test/java/org/apache/shiro/web/ test/java/org/apac...

Author: lhazlewood
Date: Fri Apr 23 20:42:43 2010
New Revision: 937511

URL: http://svn.apache.org/viewvc?rev=937511&view=rev
Log:
SHIRO-128:

Cookie/SimpleCookie addition removed need for WebRememberMeManager and the 'attr' components it used - Deprecated the WebRememberMeManager and all attr package components - to be removed immediately prior to the 1.0 release.

Added:
    incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/servlet/SimpleCookieTest.java
Modified:
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/WebRememberMeManager.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/WebUtils.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/AbstractWebAttribute.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/CookieAttribute.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/RequestParamAttribute.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/WebAttribute.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/mgt/CookieRememberMeManager.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java
    incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/SimpleCookie.java
    incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/WebRememberMeManagerTest.java
    incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/config/IniFilterChainResolverFactoryTest.java

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/WebRememberMeManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/WebRememberMeManager.java?rev=937511&r1=937510&r2=937511&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/WebRememberMeManager.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/WebRememberMeManager.java Fri Apr 23 20:42:43 2010
@@ -60,7 +60,10 @@ import javax.servlet.ServletResponse;
  * @author Les Hazlewood
  * @author Luis Arias
  * @since 0.9
+ * @deprecated in favor of the {@link org.apache.shiro.web.mgt.CookieRememberMeManager}.
+ *             THIS CLASS WILL BE DELETED PRIOR TO THE 1.0 RELEASE
  */
+@Deprecated
 public class WebRememberMeManager extends AbstractRememberMeManager {
 
     //TODO - complete JavaDoc

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/WebUtils.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/WebUtils.java?rev=937511&r1=937510&r2=937511&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/WebUtils.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/WebUtils.java Fri Apr 23 20:42:43 2010
@@ -21,9 +21,12 @@ package org.apache.shiro.web;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.session.Session;
 import org.apache.shiro.subject.Subject;
+import org.apache.shiro.subject.SubjectContext;
 import org.apache.shiro.util.StringUtils;
 import org.apache.shiro.util.ThreadContext;
 import org.apache.shiro.web.filter.AccessControlFilter;
+import org.apache.shiro.web.subject.WebSubject;
+import org.apache.shiro.web.subject.WebSubjectContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -67,7 +70,7 @@ public class WebUtils {
 
     /**
      * {@link org.apache.shiro.session.Session Session} key used to save a request and later restore it, for example when redirecting to a
-     * requested page after login, equal to <code>shiroSavedRequest</code>.
+     * requested page after login, equal to {@code shiroSavedRequest}.
      */
     public static final String SAVED_REQUEST_KEY = "shiroSavedRequest";
 
@@ -232,6 +235,166 @@ public class WebUtils {
     }
 
     /**
+     * Returns {@code true} IFF the specified {@code SubjectContext}:
+     * <ol>
+     * <li>A {@link WebSubjectContext} instance</li>
+     * <li>The {@code WebSubjectContext}'s request/response pair are not null</li>
+     * <li>The request is an {@link HttpServletRequest} instance</li>
+     * <li>The response is an {@link HttpServletResponse} instance</li>
+     * </ol>
+     *
+     * @param context the SubjectContext to check to see if it is HTTP compatible.
+     * @return {@code true} IFF the specified context has HTTP request/response objects, {@code false} otherwise.
+     * @since 1.0
+     */
+    public static boolean isHttp(SubjectContext context) {
+        if (context instanceof WebSubjectContext) {
+            WebSubjectContext wsc = (WebSubjectContext) context;
+            ServletRequest request = wsc.getServletRequest();
+            ServletResponse response = wsc.getServletResponse();
+            return request != null && request instanceof HttpServletRequest &&
+                    response != null && response instanceof HttpServletResponse;
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} IFF the specified {@code Subject}:
+     * <ol>
+     * <li>A {@link WebSubject} instance</li>
+     * <li>The {@code WebSubject}'s request/response pair are not null</li>
+     * <li>The request is an {@link HttpServletRequest} instance</li>
+     * <li>The response is an {@link HttpServletResponse} instance</li>
+     * </ol>
+     *
+     * @param subject the {@code Subject} instance to check to see if it is HTTP compatible
+     * @return {@code true} IFF the specified subject has HTTP request/response objects, {@code false} otherwise.
+     * @since 1.0
+     */
+    public static boolean isHttp(Subject subject) {
+        if (subject instanceof WebSubject) {
+            WebSubject ws = (WebSubject) subject;
+            ServletRequest request = ws.getServletRequest();
+            ServletResponse response = ws.getServletResponse();
+            return request != null && request instanceof HttpServletRequest &&
+                    response != null && response instanceof HttpServletResponse;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the {@code Subject}'s associated {@link HttpServletRequest} instance.  This method will
+     * throw an {@link IllegalArgumentException} if the Subject is not a {@link WebSubject} instance or that
+     * {@code WebSubject} does not have an HTTP-compatible request object.  Callers will usually want to call
+     * the {@link #isHttp(Subject) isHttp(subject)} method first to ensure this method can be called successfully.
+     *
+     * @param subject the subject instance from which to retrieve the {@code Subject}'s associated
+     *                {@link HttpServletRequest} instance
+     * @return the subject's associated {@link HttpServletRequest} object.
+     * @throws IllegalArgumentException if the {@code Subject} is not a {@link WebSubject} or that {@code WebSubject}'s
+     *                                  request is not an {@link HttpServletRequest}.
+     * @since 1.0
+     */
+    public static HttpServletRequest getHttpRequest(Subject subject) throws IllegalArgumentException {
+        if (!(subject instanceof WebSubject)) {
+            String msg = "Subject instance is not a " + WebSubject.class.getName() + " instance.  This is required " +
+                    "to obtain a ServletRequest and ServletResponse";
+            throw new IllegalArgumentException(msg);
+        }
+        WebSubject ws = (WebSubject) subject;
+        ServletRequest request = ws.getServletRequest();
+        if (request == null || !(request instanceof HttpServletRequest)) {
+            String msg = "WebSubject's ServletRequest is null or not an instance of HttpServletRequest.";
+            throw new IllegalArgumentException(msg);
+        }
+        return (HttpServletRequest) request;
+    }
+
+    /**
+     * Returns the {@code Subject}'s associated {@link HttpServletResponse} instance.  This method will
+     * throw an {@link IllegalArgumentException} if the Subject is not a {@link WebSubject} instance or that
+     * {@code WebSubject} does not have an HTTP-compatible response object.  Callers will usually want to call
+     * the {@link #isHttp(Subject) isHttp(subject)} method first to ensure this method can be called successfully.
+     *
+     * @param subject the subject instance from which to retrieve the {@code Subject}'s associated
+     *                {@link HttpServletResponse} instance
+     * @return the subject's associated {@link HttpServletResponse} object.
+     * @throws IllegalArgumentException if the {@code Subject} is not a {@link WebSubject} or that {@code WebSubject}'s
+     *                                  response is not an {@link HttpServletResponse}.
+     * @since 1.0
+     */
+    public static HttpServletResponse getHttpResponse(Subject subject) {
+        if (!(subject instanceof WebSubject)) {
+            String msg = "Subject instance is not a " + WebSubject.class.getName() + " instance.  This is required " +
+                    "to obtain a ServletRequest and ServletResponse";
+            throw new IllegalArgumentException(msg);
+        }
+        WebSubject ws = (WebSubject) subject;
+        ServletResponse response = ws.getServletResponse();
+        if (response == null || !(response instanceof HttpServletResponse)) {
+            String msg = "WebSubject's ServletResponse is null or not an instance of HttpServletResponse.";
+            throw new IllegalArgumentException(msg);
+        }
+        return (HttpServletResponse) response;
+    }
+
+    /**
+     * Returns the {@code SubjectContext}'s {@link HttpServletRequest} instance.  This method will
+     * throw an {@link IllegalArgumentException} if the context is not a {@link WebSubjectContext} instance or that
+     * {@code WebSubjectContext} does not have an HTTP-compatible request object.  Callers will usually want to call
+     * the {@link #isHttp(SubjectContext) isHttp(subjectContext)} method first to ensure this method can be called
+     * successfully.
+     *
+     * @param context the subjectContext instance from which to retrieve the associated {@link HttpServletRequest}
+     * @return the context's {@link HttpServletRequest} object.
+     * @throws IllegalArgumentException if the {@code SubjectContext} is not a {@link WebSubjectContext} or that
+     *                                  {@code WebSubjectContext}'s request is not an {@link HttpServletRequest}.
+     * @since 1.0
+     */
+    public static HttpServletRequest getHttpRequest(SubjectContext context) {
+        if (!(context instanceof WebSubjectContext)) {
+            String msg = "SubjectContext instance is not a " + WebSubjectContext.class.getName() + " instance.  " +
+                    "This is required to obtain a ServletRequest and ServletResponse";
+            throw new IllegalArgumentException(msg);
+        }
+        WebSubjectContext wsc = (WebSubjectContext) context;
+        ServletRequest request = wsc.getServletRequest();
+        if (request == null || !(request instanceof HttpServletRequest)) {
+            String msg = "WebSubjectContext's ServletRequest is null or not an instance of HttpServletRequest.";
+            throw new IllegalArgumentException(msg);
+        }
+        return (HttpServletRequest) request;
+    }
+
+    /**
+     * Returns the {@code SubjectContext}'s {@link HttpServletResponse} instance.  This method will
+     * throw an {@link IllegalArgumentException} if the context is not a {@link WebSubjectContext} instance or that
+     * {@code WebSubjectContext} does not have an HTTP-compatible response object.  Callers will usually want to call
+     * the {@link #isHttp(SubjectContext) isHttp(subjectContext)} method first to ensure this method can be called
+     * successfully.
+     *
+     * @param context the subjectContext instance from which to retrieve the associated {@link HttpServletResponse}
+     * @return the context's {@link HttpServletResponse} object.
+     * @throws IllegalArgumentException if the {@code SubjectContext} is not a {@link WebSubjectContext} or that
+     *                                  {@code WebSubjectContext}'s response is not an {@link HttpServletResponse}.
+     * @since 1.0
+     */
+    public static HttpServletResponse getHttpResponse(SubjectContext context) {
+        if (!(context instanceof WebSubjectContext)) {
+            String msg = "SubjectContext instance is not a " + WebSubjectContext.class.getName() + " instance.  " +
+                    "This is required to obtain a ServletRequest and ServletResponse";
+            throw new IllegalArgumentException(msg);
+        }
+        WebSubjectContext wsc = (WebSubjectContext) context;
+        ServletResponse response = wsc.getServletResponse();
+        if (response == null || !(response instanceof HttpServletResponse)) {
+            String msg = "WebSubjectContext's ServletResponse is null or not an instance of HttpServletResponse.";
+            throw new IllegalArgumentException(msg);
+        }
+        return (HttpServletResponse) response;
+    }
+
+    /**
      * A convenience method that merely casts the incoming <code>ServletRequest</code> to an
      * <code>HttpServletRequest</code>:
      * <p/>

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/AbstractWebAttribute.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/AbstractWebAttribute.java?rev=937511&r1=937510&r2=937511&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/AbstractWebAttribute.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/AbstractWebAttribute.java Fri Apr 23 20:42:43 2010
@@ -18,15 +18,14 @@
  */
 package org.apache.shiro.web.attr;
 
-import java.beans.PropertyEditor;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
+import org.apache.shiro.ShiroException;
+import org.apache.shiro.util.ClassUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.shiro.ShiroException;
-import org.apache.shiro.util.ClassUtils;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.beans.PropertyEditor;
 
 /**
  * Convenient superclass for implementations of the {@link WebAttribute} interface.  This class encapsulates
@@ -39,7 +38,10 @@ import org.apache.shiro.util.ClassUtils;
  *
  * @author Les Hazlewood
  * @since 0.2
+ * @deprecated in favor of {@link org.apache.shiro.web.servlet.Cookie} and {@link org.apache.shiro.web.servlet.SimpleCookie}
+ *             usages.  THIS CLASS WILL BE DELETED PRIOR TO THE 1.0 RELEASE
  */
+@Deprecated
 public abstract class AbstractWebAttribute<T> implements WebAttribute<T> {
 
     //TODO - complete JavaDoc

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/CookieAttribute.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/CookieAttribute.java?rev=937511&r1=937510&r2=937511&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/CookieAttribute.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/CookieAttribute.java Fri Apr 23 20:42:43 2010
@@ -19,7 +19,6 @@
 package org.apache.shiro.web.attr;
 
 import org.apache.shiro.util.StringUtils;
-import static org.apache.shiro.web.WebUtils.toHttp;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -30,13 +29,18 @@ import javax.servlet.http.HttpServletReq
 import javax.servlet.http.HttpServletResponse;
 import java.beans.PropertyEditor;
 
+import static org.apache.shiro.web.WebUtils.toHttp;
+
 /**
  * A {@code CookieAttribute} stores an object as a {@link Cookie} for access on later requests.
  *
  * @author Les Hazlewood
  * @author Peter Ledbrook
  * @since 0.2
+ * @deprecated in favor of {@link org.apache.shiro.web.servlet.Cookie} and {@link org.apache.shiro.web.servlet.SimpleCookie}
+ *             usages.  THIS CLASS WILL BE DELETED PRIOR TO THE 1.0 RELEASE
  */
+@Deprecated
 public class CookieAttribute<T> extends AbstractWebAttribute<T> {
 
     //TODO - complete JavaDoc

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/RequestParamAttribute.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/RequestParamAttribute.java?rev=937511&r1=937510&r2=937511&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/RequestParamAttribute.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/RequestParamAttribute.java Fri Apr 23 20:42:43 2010
@@ -18,16 +18,19 @@
  */
 package org.apache.shiro.web.attr;
 
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
 /**
  * @author Les Hazlewood
  * @since 0.2
+ * @deprecated in favor of {@link org.apache.shiro.web.servlet.Cookie} and {@link org.apache.shiro.web.servlet.SimpleCookie}
+ *             usages.  THIS CLASS WILL BE DELETED PRIOR TO THE 1.0 RELEASE
  */
+@Deprecated
 public class RequestParamAttribute<T> extends AbstractWebAttribute<T> {
 
     //TODO - complete JavaDoc

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/WebAttribute.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/WebAttribute.java?rev=937511&r1=937510&r2=937511&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/WebAttribute.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/attr/WebAttribute.java Fri Apr 23 20:42:43 2010
@@ -29,7 +29,10 @@ import javax.servlet.ServletResponse;
  *
  * @author Les Hazlewood
  * @since 0.2
+ * @deprecated in favor of {@link org.apache.shiro.web.servlet.Cookie} and {@link org.apache.shiro.web.servlet.SimpleCookie}
+ *             usages.  THIS CLASS WILL BE DELETED PRIOR TO THE 1.0 RELEASE
  */
+@Deprecated
 public interface WebAttribute<T> {
 
     //TODO - complete JavaDoc

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/mgt/CookieRememberMeManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/mgt/CookieRememberMeManager.java?rev=937511&r1=937510&r2=937511&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/mgt/CookieRememberMeManager.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/mgt/CookieRememberMeManager.java Fri Apr 23 20:42:43 2010
@@ -22,7 +22,6 @@ import org.apache.shiro.codec.Base64;
 import org.apache.shiro.mgt.AbstractRememberMeManager;
 import org.apache.shiro.subject.Subject;
 import org.apache.shiro.subject.SubjectContext;
-import org.apache.shiro.util.CollectionUtils;
 import org.apache.shiro.web.WebUtils;
 import org.apache.shiro.web.servlet.Cookie;
 import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
@@ -33,7 +32,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -43,13 +41,32 @@ import javax.servlet.http.HttpServletRes
  * for later retrieval.
  * <p/>
  * Cookie attributes (path, domain, maxAge, etc) may be set on this class's default
- * {@link #getCookie() cookie} attribute.  The cookie's default name is {@code rememberMe}.
+ * {@link #getCookie() cookie} attribute, which acts as a template to use to set all properties of outgoing cookies
+ * created by this implementation.
+ * <p/>
+ * The default cookie has the following attribute values set:
+ * <table>
+ * <tr>
+ * <th>Attribute Name</th>
+ * <th>Value</th>
+ * </tr>
+ * <tr><td>{@link Cookie#getName() name}</td>
+ * <td>{@code rememberMe}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link Cookie#getPath() path}</td>
+ * <td>{@code /}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link Cookie#getMaxAge() maxAge}</td>
+ * <td>{@link Cookie#ONE_YEAR Cookie.ONE_YEAR}</td>
+ * </tr>
+ * </table>
  * <p/>
  * Note that because this class subclasses the {@link AbstractRememberMeManager} which already provides serialization
  * and encryption logic, this class utilizes both for added security before setting the cookie value.
  *
- * @author Les Hazlewood
- * @author Luis Arias
+ * @author The Apache Shiro Project (shiro-dev@incubator.apache.org)
  * @since 1.0
  */
 public class CookieRememberMeManager extends AbstractRememberMeManager {
@@ -65,30 +82,71 @@ public class CookieRememberMeManager ext
 
     private Cookie cookie;
 
+    /**
+     * Constructs a new {@code CookieRememberMeManager} with a default {@code rememberMe} cookie template.
+     */
     public CookieRememberMeManager() {
         Cookie cookie = new SimpleCookie(DEFAULT_REMEMBER_ME_COOKIE_NAME);
         cookie.setPath(Cookie.ROOT_PATH);
-        //Peter (Apache Shiro developer) said that Jetty didn't like the CookieAttribute.INDEFINITE value
-        // (Tomcat was ok with it), so just default to a few years for now.  If anyone doesn't visit a site in 3 years
-        // after last login, I doubt any Shiro users would mind their end-users to be forced to log in. - LAH.
-        cookie.setMaxAge(Cookie.ONE_YEAR * 3);
+        //One year should be long enough - most sites won't object to requiring a user to log in if they haven't visited
+        //in a year:
+        cookie.setMaxAge(Cookie.ONE_YEAR);
         this.cookie = cookie;
     }
 
+    /**
+     * Returns the cookie 'template' that will be used to set all attributes of outgoing rememberMe cookies created by
+     * this {@code RememberMeManager}.  Outgoing cookies will match this one except for the
+     * {@link Cookie#getValue() value} attribute, which is necessarily set dynamically at runtime.
+     * <p/>
+     * Please see the class-level JavaDoc for the default cookie's attribute values.
+     *
+     * @return the cookie 'template' that will be used to set all attributes of outgoing rememberMe cookies created by
+     *         this {@code RememberMeManager}.
+     */
     public Cookie getCookie() {
         return cookie;
     }
 
+    /**
+     * Sets the cookie 'template' that will be used to set all attributes of outgoing rememberMe cookies created by
+     * this {@code RememberMeManager}.  Outgoing cookies will match this one except for the
+     * {@link Cookie#getValue() value} attribute, which is necessarily set dynamically at runtime.
+     * <p/>
+     * Please see the class-level JavaDoc for the default cookie's attribute values.
+     *
+     * @param cookie the cookie 'template' that will be used to set all attributes of outgoing rememberMe cookies created
+     *               by this {@code RememberMeManager}.
+     */
     public void setCookie(Cookie cookie) {
         this.cookie = cookie;
     }
 
+    /**
+     * Base64-encodes the specified serialized byte array and sets that base64-encoded String as the cookie value.
+     * <p/>
+     * The {@code subject} instance is expected to be a {@link WebSubject} instance with an HTTP Request/Response pair
+     * so an HTTP cookie can be set on the outgoing response.  If it is not a {@code WebSubject} or that
+     * {@code WebSubject} does not have an HTTP Request/Response pair, this implementation does nothing.
+     *
+     * @param subject    the Subject for which the identity is being serialized.
+     * @param serialized the serialized bytes to be persisted.
+     */
     protected void rememberSerializedIdentity(Subject subject, byte[] serialized) {
-        WebSubject webSubject = (WebSubject) subject;
-        ServletRequest servletRequest = webSubject.getServletRequest();
-        ServletResponse servletResponse = webSubject.getServletResponse();
-        HttpServletRequest request = WebUtils.toHttp(servletRequest);
-        HttpServletResponse response = WebUtils.toHttp(servletResponse);
+
+        if (!WebUtils.isHttp(subject)) {
+            if (log.isDebugEnabled()) {
+                String msg = "Subject argument is not an HTTP-aware instance.  This is required to obtain a servlet " +
+                        "request and response in order to set the rememberMe cookie. Returning immediately and " +
+                        "ignoring rememberMe operation.";
+                log.debug(msg);
+            }
+            return;
+        }
+
+
+        HttpServletRequest request = WebUtils.getHttpRequest(subject);
+        HttpServletResponse response = WebUtils.getHttpResponse(subject);
 
         //base 64 encode it and store as a cookie:
         String base64 = Base64.encodeToString(serialized);
@@ -99,24 +157,8 @@ public class CookieRememberMeManager ext
         cookie.saveTo(request, response);
     }
 
-    private ServletRequest getServletRequest(SubjectContext subjectContext) {
-        ServletRequest request = null;
-        if (subjectContext != null && subjectContext instanceof WebSubjectContext) {
-            request = ((WebSubjectContext) subjectContext).getServletRequest();
-        }
-        return request;
-    }
-
-    private ServletResponse getServletResponse(SubjectContext subjectContext) {
-        ServletResponse response = null;
-        if (subjectContext != null && subjectContext instanceof WebSubjectContext) {
-            response = ((WebSubjectContext) subjectContext).getServletResponse();
-        }
-        return response;
-    }
-
-    protected boolean isIdentityRemoved(SubjectContext subjectContext) {
-        ServletRequest request = getServletRequest(subjectContext);
+    private boolean isIdentityRemoved(WebSubjectContext subjectContext) {
+        ServletRequest request = subjectContext.getServletRequest();
         if (request != null) {
             Boolean removed = (Boolean) request.getAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY);
             return removed != null && removed;
@@ -124,24 +166,41 @@ public class CookieRememberMeManager ext
         return false;
     }
 
+
+    /**
+     * Returns a previously serialized identity byte array or {@code null} if the byte array could not be acquired.
+     * This implementation retrieves an HTTP cookie, Base64-decodes the cookie value, and returns the resulting byte
+     * array.
+     * <p/>
+     * The {@code SubjectContext} instance is expected to be a {@link WebSubjectContext} instance with an HTTP
+     * Request/Response pair so an HTTP cookie can be retrieved from the incoming request.  If it is not a
+     * {@code WebSubjectContext} or that {@code WebSubjectContext} does not have an HTTP Request/Response pair, this
+     * implementation returns {@code null}.
+     *
+     * @param subjectContext the contextual data, usually provided by a {@link Subject.Builder} implementation, that
+     *                       is being used to construct a {@link Subject} instance.  To be used to assist with data
+     *                       lookup.
+     * @return a previously serialized identity byte array or {@code null} if the byte array could not be acquired.
+     */
     protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) {
 
-        if (CollectionUtils.isEmpty(subjectContext)) {
-            if (log.isTraceEnabled()) {
-                log.trace("Null or empty SubjectContext - unable to retrieve request/response pair to obtain " +
-                        "a request-based identity.  Returning null.");
+        if (!WebUtils.isHttp(subjectContext)) {
+            if (log.isDebugEnabled()) {
+                String msg = "SubjectContext argument is not an HTTP-aware instance.  This is required to obtain a " +
+                        "servlet request and response in order to retrieve the rememberMe cookie. Returning " +
+                        "immediately and ignoring rememberMe operation.";
+                log.debug(msg);
             }
             return null;
         }
 
-        if (isIdentityRemoved(subjectContext)) {
+        WebSubjectContext wsc = (WebSubjectContext) subjectContext;
+        if (isIdentityRemoved(wsc)) {
             return null;
         }
 
-        ServletRequest servletRequest = getServletRequest(subjectContext);
-        ServletResponse servletResponse = getServletResponse(subjectContext);
-        HttpServletRequest request = WebUtils.toHttp(servletRequest);
-        HttpServletResponse response = WebUtils.toHttp(servletResponse);
+        HttpServletRequest request = WebUtils.getHttpRequest(wsc);
+        HttpServletResponse response = WebUtils.getHttpResponse(wsc);
 
         String base64 = getCookie().readValue(request, response);
 
@@ -182,21 +241,48 @@ public class CookieRememberMeManager ext
         return base64;
     }
 
+    /**
+     * Removes the 'rememberMe' cookie from the associated {@link WebSubject}'s request/response pair.
+     * <p/>
+     * The {@code subject} instance is expected to be a {@link WebSubject} instance with an HTTP Request/Response pair.
+     * If it is not a {@code WebSubject} or that {@code WebSubject} does not have an HTTP Request/Response pair, this
+     * implementation does nothing.
+     *
+     * @param subject the subject instance for which identity data should be forgotten from the underlying persistence
+     */
     protected void forgetIdentity(Subject subject) {
-        WebSubject webSubject = (WebSubject) subject;
-        ServletRequest request = webSubject.getServletRequest();
-        ServletResponse response = webSubject.getServletResponse();
-        forgetIdentity(request, response);
+        if (WebUtils.isHttp(subject)) {
+            HttpServletRequest request = WebUtils.getHttpRequest(subject);
+            HttpServletResponse response = WebUtils.getHttpResponse(subject);
+            forgetIdentity(request, response);
+        }
     }
 
+    /**
+     * Removes the 'rememberMe' cookie from the associated {@link WebSubjectContext}'s request/response pair.
+     * <p/>
+     * The {@code SubjectContext} instance is expected to be a {@link WebSubjectContext} instance with an HTTP
+     * Request/Response pair.  If it is not a {@code WebSubjectContext} or that {@code WebSubjectContext} does not
+     * have an HTTP Request/Response pair, this implementation does nothing.
+     *
+     * @param subjectContext the contextual data, usually provided by a {@link Subject.Builder} implementation
+     */
     protected void forgetIdentity(SubjectContext subjectContext) {
-        ServletRequest request = getServletRequest(subjectContext);
-        ServletResponse response = getServletResponse(subjectContext);
-        forgetIdentity(request, response);
+        if (WebUtils.isHttp(subjectContext)) {
+            HttpServletRequest request = WebUtils.getHttpRequest(subjectContext);
+            HttpServletResponse response = WebUtils.getHttpResponse(subjectContext);
+            forgetIdentity(request, response);
+        }
     }
 
-    protected void forgetIdentity(ServletRequest request, ServletResponse response) {
-        getCookie().removeFrom(WebUtils.toHttp(request), WebUtils.toHttp(response));
+    /**
+     * Removes the rememberMe cookie from the given request/response pair.
+     *
+     * @param request  the incoming HTTP servlet request
+     * @param response the outgoing HTTP servlet response
+     */
+    private void forgetIdentity(HttpServletRequest request, HttpServletResponse response) {
+        getCookie().removeFrom(request, response);
     }
 }
 

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java?rev=937511&r1=937510&r2=937511&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java Fri Apr 23 20:42:43 2010
@@ -532,7 +532,8 @@ public class ShiroFilter extends OncePer
     protected ThreadState bind(ServletRequest request, ServletResponse response) {
         SecurityManager securityManager = getSecurityManager();
         ThreadContext.bind(securityManager);
-        //currently the WebRememberMeManager needs the request/response bound in order to create the subject instance:
+        //TODO - remove:
+        //currently the CookieRememberMeManager needs the request/response bound in order to create the subject instance:
         WebUtils.bind(request);
         WebUtils.bind(response);
 

Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/SimpleCookie.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/SimpleCookie.java?rev=937511&r1=937510&r2=937511&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/SimpleCookie.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/SimpleCookie.java Fri Apr 23 20:42:43 2010
@@ -153,7 +153,7 @@ public class SimpleCookie implements Coo
             path = StringUtils.clean(request.getContextPath());
         }
 
-        //fix for http://issues.apache.org/jira/browse/JSEC-34:
+        //fix for http://issues.apache.org/jira/browse/SHIRO-9:
         if (path == null) {
             path = ROOT_PATH;
         }

Modified: incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/WebRememberMeManagerTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/WebRememberMeManagerTest.java?rev=937511&r1=937510&r2=937511&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/WebRememberMeManagerTest.java (original)
+++ incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/WebRememberMeManagerTest.java Fri Apr 23 20:42:43 2010
@@ -39,11 +39,12 @@ import static org.junit.Assert.assertNot
 import static org.junit.Assert.assertTrue;
 
 /**
- * TODO - class javadoc
- *
  * @author Les Hazlewood
  * @since Apr 23, 2008 9:16:47 AM
+ * @deprecated in favor of {@link org.apache.shiro.web.mgt.CookieRememberMeManagerTest}.
+ *             THIS CLASS WILL BE DELETED PRIOR TO THE 1.0 RELEASE
  */
+@Deprecated
 public class WebRememberMeManagerTest {
 
     @Test

Modified: incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/config/IniFilterChainResolverFactoryTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/config/IniFilterChainResolverFactoryTest.java?rev=937511&r1=937510&r2=937511&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/config/IniFilterChainResolverFactoryTest.java (original)
+++ incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/config/IniFilterChainResolverFactoryTest.java Fri Apr 23 20:42:43 2010
@@ -22,10 +22,6 @@ import org.apache.shiro.config.Configura
 import org.apache.shiro.config.Ini;
 import org.apache.shiro.web.WebTest;
 import org.apache.shiro.web.filter.mgt.FilterChainResolver;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -33,6 +29,11 @@ import javax.servlet.Filter;
 import javax.servlet.FilterConfig;
 import java.util.Map;
 
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
 /**
  * Tests for the {@link IniFilterChainResolverFactory}.
  *
@@ -90,7 +91,7 @@ public class IniFilterChainResolverFacto
         Ini ini = new Ini();
         String config =
                 "[filters]\n" +
-                        "test = org.apache.shiro.web.attr.CookieAttribute\n" + //any non-Filter will do
+                        "test = org.apache.shiro.web.servlet.SimpleCookie\n" + //any non-Filter will do
                         "[urls]\n" +
                         "/index.html = anon";
         ini.load(config);

Added: incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/servlet/SimpleCookieTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/servlet/SimpleCookieTest.java?rev=937511&view=auto
==============================================================================
--- incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/servlet/SimpleCookieTest.java (added)
+++ incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/servlet/SimpleCookieTest.java Fri Apr 23 20:42:43 2010
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2008 Les Hazlewood
+ *
+ * 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.shiro.web.servlet;
+
+import junit.framework.TestCase;
+import org.easymock.IArgumentMatcher;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import static org.easymock.EasyMock.*;
+
+/**
+ * TODO - Class JavaDoc
+ *
+ * @author Les Hazlewood
+ * @since Apr 22, 2010 9:40:47 PM
+ */
+public class SimpleCookieTest extends TestCase {
+
+    private SimpleCookie cookie;
+
+    private HttpServletRequest mockRequest;
+    private HttpServletResponse mockResponse;
+
+    @Before
+    public void setUp() throws Exception {
+        this.mockRequest = createMock(HttpServletRequest.class);
+        this.mockResponse = createMock(HttpServletResponse.class);
+        this.cookie = new SimpleCookie("test");
+    }
+
+    @Test
+    //Verifies fix for JSEC-94
+    public void testRemoveValue() throws Exception {
+
+        javax.servlet.http.Cookie cookie = new javax.servlet.http.Cookie("test", "blah");
+        cookie.setMaxAge(2351234); //doesn't matter what the time is
+        javax.servlet.http.Cookie[] cookies = new javax.servlet.http.Cookie[]{cookie};
+
+        expect(mockRequest.getCookies()).andReturn(cookies);
+        //no path set on the cookie, so we expect to retrieve it from the context path
+        expect(mockRequest.getContextPath()).andReturn("/somepath").times(1);
+        mockResponse.addCookie(cookie);
+        replay(mockRequest);
+        replay(mockResponse);
+
+        this.cookie.removeFrom(mockRequest, mockResponse);
+
+        verify(mockRequest);
+        verify(mockResponse);
+
+        assertTrue(cookie.getMaxAge() == 0);
+        assertTrue(cookie.getPath().equals("/somepath"));
+    }
+
+    private void testContextPath(String contextPath) {
+        this.cookie.setValue("blah");
+
+        javax.servlet.http.Cookie cookie = new javax.servlet.http.Cookie("test", "blah");
+        cookie.setMaxAge(-1);
+        cookie.setPath("/");
+
+        expect(mockRequest.getContextPath()).andReturn(contextPath);
+
+        mockResponse.addCookie(eqCookie(cookie));
+
+        replay(mockRequest);
+        replay(mockResponse);
+
+        this.cookie.saveTo(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 javax.servlet.http.Cookie> T eqCookie(final T in) {
+        reportMatcher(new IArgumentMatcher() {
+            public boolean matches(Object o) {
+                javax.servlet.http.Cookie c = (javax.servlet.http.Cookie) o;
+                return c.getName().equals(in.getName()) &&
+                        c.getValue().equals(in.getValue()) &&
+                        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;
+    }
+
+    @Test
+    //Verifies fix for JSEC-64
+    public void testRemoveValueWithNullContext() throws Exception {
+
+        javax.servlet.http.Cookie cookie = new javax.servlet.http.Cookie("test", "blah");
+        cookie.setMaxAge(2351234); //doesn't matter what the time is
+        javax.servlet.http.Cookie[] cookies = new javax.servlet.http.Cookie[]{cookie};
+
+        expect(mockRequest.getCookies()).andReturn(cookies);
+        //no path set on the cookie, so we expect to retrieve it from the context path
+        expect(mockRequest.getContextPath()).andReturn(null).times(1);
+        mockResponse.addCookie(cookie);
+        replay(mockRequest);
+        replay(mockResponse);
+
+        this.cookie.removeFrom(mockRequest, mockResponse);
+
+        verify(mockRequest);
+        verify(mockResponse);
+
+        assertTrue(cookie.getMaxAge() == 0);
+        assertTrue(cookie.getPath().equals("/"));
+    }
+
+}