I don't really have time to do any additional analysis or testing of
this issue, but based on what I observed I don't believe the IE7
discards the cookie immediately after reading the header. It seems to me
that it must not discard the cookie until a later time, i.e. after the
CSS request that is issued during the processing of the response. (I
could be wrong, but this is the only explanation I have for the issue I
observed and how it was resolved.)
Les Hazlewood wrote:
Hi Brad - if after you sign out, your browser sends another request, that
should be ok - the first response would set a 'deletion cookie', (setting
the max age to 0), telling the browser to remove it, and any subsequent
requests shouldn't have the cookie at all (not until a new loging was
created at least).
That is, if this occurred:
Logout request ---> jsecurity filter --> your webapp -->
SecurityUtils.getSubject().logout();
<---- response
Css request --> jsecurity filter --> your webapp
<---- response
The CSS request should (if working correctly) never send back a rememberMe
cookie.
If you do see the cookie though, even after logout, there is one scenario
that I can think of that would cause this:
Because cookies are part of the HTTP header, they must be set _before_ the
response has started rendering (response output stream is written to). That
means you must ensure the logout() call is made before any HTML is sent to
the output stream. This allows JSecurity to set its 'deletion cookie'
(maxage = 0) to the response at logout() time.
If you call logout() in a controller before any view is rendered, or at the
top of a JSP file before the DOCTYPE declaration, you would be ok. If you
don't do these things, the 'deletion cookie' can't be sent to the browser,
and subsequent requests would have the cookie.
This is why people often perform a redirect immediately after calling
logout() - to ensure HTML rendering can never happen. You don't have to do
this of course - its just a quick way to ensure the problem can't occur.
Best,
Les
On Mon, Feb 9, 2009 at 5:11 PM, Brad Whitaker <[email protected]> wrote:
I've pinpointed the cause of my problem and have been able to fix (or at
least work around it).
After receiving a signout request my server sends back HTML with a
reference to a CSS stylesheet. (In my case the reference is to an IE
specific CSS file, and the reference was bad so it wasn't being cached by
the client). The request for the CSS file from the clien apparently
contained the rememberMe cookie, so the value of the cookie was again
associated with the client.
I don't know enough details about the HTTP specification to know if this
means there is a bug with IE, JSecurity, or whether my case was so unusual
that it just isn't worth worrying about.
Thanks,
Brad
Brad Whitaker wrote:
I'm still blocked by this issue and would appreciate any suggestions. The
problem is that SpringJSecurityFilter is being executed a second time during
my signOut request. I have no idea why this is happening. (The parent class
OncePerRequestFilter cannot really fulfill the mission that its name
implies. The request.setAttribute() value that is set during the first
execution is not present during the second execution.)
response.isCommitted() is also false during the second execution so the
strategy from JSEC-58 is of no use in this case.
I don't understand enough about the servlet filter mechanism to understand
why the filter is being executed twice, or how to stop it. I'm also not
clear if this is a Grails related problem or not.
I have determined that my problem only occurs with IE -- it does not
happen with other browsers such as Firefox.
Thanks,
Brad
Brad Whitaker wrote:
I got some help from the Grails list that enabled me to set the
init-param on DispatcherServlet. (Actually, it's a subclass in Grails called
GrailsDispatcherServlet). Unfortunately neither this change nor my patch has
solved my problem.
I've been looking at my logs and it seems that at the very end of request
processing (i.e. after a Grails filter 'afterView' method has fired) that
Grails is unbinding the request from a thread, and then binding the request
to a new thread. Something is then calling JSecurity code (including
WebRememberMeManager). At this point the "logged out" flag is no longer
associated with the request, and the cookie is read again.
Here's some relevant log output:
02/07 15:05:06 DEBUG
org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet -
Successfully completed request
02/07 15:05:06 DEBUG
org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter - Matched
URI [/auth/signOut] to URL mapping [/(*)/(*)?/(*)?], forwarding to
[/grails/auth/signOut.dispatch] with response [class
org.codehaus.groovy.grails.web.sitemesh.GrailsPageResponseWrapper]
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - Removed value of
type [org.jsecurity.web.DefaultWebSecurityManager] for key
[org.jsecurity.util.ThreadContext_SECURITY_MANAGER_KEY]from thread
[TP-Processor6]
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - Removed value of
type [org.apache.catalina.connector.ResponseFacade] for key
[javax.servlet.ServletResponse_JSECURITY_THREAD_CONTEXT_KEY]from thread
[TP-Processor6]
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - Removed value of
type [org.jsecurity.web.servlet.JSecurityHttpServletRequest] for key
[javax.servlet.ServletRequest_JSECURITY_THREAD_CONTEXT_KEY]from thread
[TP-Processor6]
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - Removed value of
type [java.net.Inet4Address] for key
[org.jsecurity.util.ThreadContext_INET_ADDRESS_KEY]from thread
[TP-Processor6]
02/07 15:05:06 DEBUG
org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter - Cleared
Grails thread-bound request context:
org.apache.catalina.connector.requestfac...@9ada28
02/07 15:05:06 DEBUG
org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter - Bound
Grails request context to thread:
org.apache.catalina.connector.requestfac...@687f95
02/07 15:05:06 TRACE org.jsecurity.web.servlet.OncePerRequestFilter -
Filter not yet executed. Executing now.
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - Bound value of
type [java.net.Inet4Address] for key
[org.jsecurity.util.ThreadContext_INET_ADDRESS_KEY] to thread
[TP-Processor8]
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - Bound value of
type [org.jsecurity.web.servlet.JSecurityHttpServletRequest] for key
[javax.servlet.ServletRequest_JSECURITY_THREAD_CONTEXT_KEY] to thread
[TP-Processor8]
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - Bound value of
type [org.apache.catalina.connector.ResponseFacade] for key
[javax.servlet.ServletResponse_JSECURITY_THREAD_CONTEXT_KEY] to thread
[TP-Processor8]
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - Bound value of
type [org.jsecurity.web.DefaultWebSecurityManager] for key
[org.jsecurity.util.ThreadContext_SECURITY_MANAGER_KEY] to thread
[TP-Processor8]
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - get() - in
thread [TP-Processor8]
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - get() - in
thread [TP-Processor8]
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - get() - in
thread [TP-Processor8]
02/07 15:05:06 TRACE org.jsecurity.util.ThreadContext - Retrieved value
of type [org.jsecurity.web.servlet.JSecurityHttpServletRequest] for key
[javax.servlet.ServletRequest_JSECURITY_THREAD_CONTEXT_KEY] bound to thread
[TP-Processor8]
02/07 15:05:06 TRACE org.jsecurity.web.WebRememberMeManager -
getRememberedPrincipals: not found: FORGET_IDENTITY_ATTRIBUTE_NAME
Brad Whitaker wrote:
I did notice this part of his response but it is not obvious to me how I
make this modification to my Grails app.
Les Hazlewood wrote:
Oops - you might have missed Jeremy's response:
"In my case, Spring was calling request.getUserName(), which under the
hood
called JSecurity's getSubject(). To stop this from happening I had to
set
the publishEvents init-param to false on my Spring DispatcherServlet,
which
stopped Spring from calling the getUserName() function."
Try that. We'll get on the issue and fix it.
Thanks,
Les
On Fri, Feb 6, 2009 at 8:49 PM, Brad Whitaker <[email protected]>
wrote:
Thanks for the response. This is a blocker for me. I disabled all of
my
explicit getSubject() calls but perhaps something else is still making
the
invocation. Would any Spring application be making this call? (In
other
words, would any Grails app being making the same call that you saw?)
Thanks,
Brad
Jeremy Haile wrote:
I just ran into this same problem. I think it is a JSecurity bug.
The
problem is that if any methods invoke getSubject() after logout() is
called,
but during the same request, a new subject will be created. But
since the
remember me cookie is still present, the subject gets created in the
new
Session with the remembered principals.
The problem doesn't occur if getSubject() isn't called after
logout(). In
my case, Spring was calling request.getUserName(), which under the
hood
called JSecurity's getSubject(). To stop this from happening I had
to set
the publishEvents init-param to false on my Spring DispatcherServlet,
which
stopped Spring from calling the getUserName() function.
Still - this shouldn't be necessary and I think the onus is on
JSecurity
to figure out how to make this not happen. Perhaps we can set a
request
attribute that causes the remember me cookie to not be honored for
the
remainder of that request. Any other ideas for how to work around
this
problem?
I filed a bug report here:
https://issues.apache.org/jira/browse/JSEC-57
Jeremy
On Feb 6, 2009, at 6:26 PM, Brad Whitaker wrote:
I'm having a problem that I don't fully understand. After I invoke
logout() the subject.principal becomes null as expected, but upon
redirect
the subject.principal is no longer null -- the user is remembered
again. The
log messages from JSecurity indicate a rememberMe cookie has been
found when
I think it probably shouldn't be found.
The issue does not occur in my devel environment (Grails, HSQLDB)
but
only in production (Tomcat, MySql, war deployed as ROOT). My signout
code
does this:
log.info "signout: enter:
getPrincipal=${SecurityUtils?.getSubject()?.getPrincipal()}"
SecurityUtils.subject?.logout()
log.info "signout: after logout:
getPrincipal=${SecurityUtils?.getSubject()?.getPrincipal()}"
redirect(controller: 'home')
My log shows this. (You'll notice that I have several 'before' and
'after' filters)
02/06 15:10:57 INFO grails.app.controller.AuthController -
signout: enter: [email protected]
02/06 15:10:57 DEBUG org.jsecurity.web.attr.CookieAttribute - No
value found in request Cookies under cookie name [rememberMe]
02/06 15:10:57 INFO grails.app.controller.AuthController -
signout: after logout: getPrincipal=null
02/06 15:10:57 INFO grails.app.filters.SslFilters - DebugFilter:
after: controller=auth action=signOut params=["action":"signOut",
"controller":"auth"] principal=null
02/06 15:10:57 DEBUG org.jsecurity.web.attr.CookieAttribute -
Found
string value
[clJgEjFZVuRRN5lCpInkOsawSaKK4hLwegZK/QgR1Thk380v5wL9pA1NZo7QHr7erlnry1vt2AqIyM8Fj2HBCsl1lierxE9EJ1typI2GpgMeG+HmceNdrlN6KGh4AmjLG3zCUPo8E+QzGVs/EO3PIAGyYYtuYbW++oJDr5xfY9DwK4Omq5GijZSSmdpOHiYelPMa1XLwT0D/kNCUm6EVfG6TKwxViNtGdyzknY7abNU7ucw2UWfjFe24hH0SL0hZMXjPQYtMnPl5J5qfjU4EXX1a/Ijn0IKUEk5BmY+ipc6irMI/Rrmumr7XSSncSHq2cpyNbwJBykFX5s/ydB64hbMenS+LhbUvnQBNt8Xkjyc+IrzntDuVGH4IGfnRIAOwDkU6EZPQ4v36wbd8IB3kUFW1/1z6ZvS4jsIgMA3TS2xMjhGB8FWnIG9RSOrT+nlejddqoRsTWWmEAWUuaOV3tZLci69POQ5k]
from HttpServletRequest Cookie [rememberMe]
02/06 15:10:57 INFO grails.app.filters.SslFilters - DebugFilter:
before: controller=home action=null params=["controller":"home"]
[email protected]
02/06 15:10:57 INFO grails.app.filters.SslFilters - DebugFilter:
after: controller=home action=index params=["controller":"home"]
[email protected]
Is this a bug in JSecurity or am I doing something wrong? Is there a
work
around for this?
Thanks,
Brad