Hello all,
I'm using Shiro on a proxy servlet that relays requests to another web module
containing REST web services, provided the user is authenticated *or*
remembered, i.e. I currently treat those two states the same. This works all
nicely, but I'm having some trouble dealing with the situation when an existing
user gets deleted.
As I see it, the Shiro "user" filter (as defined in my shiro.ini) still creates
a valid Subject using the supplied rememberMe cookie. My code that checks the
validity of the Subject therefore still executes the proxy request. It is in
the web service module that the actual check against the database takes place
(also using Shiro), which then results in a HTTP 401 response.
My problem is that I can't find a clean way to programatically delete the
rememberMe cookie *and* the Session owned by the deleted Subject. In my proxy
servlet, I can detect the HTTP 401 response and perform a Subject.logout() in
reaction to that, but then I run into the problem that there are often multiple
parallel requests running, which are created concurrently by the frontend
AngularJS single page app. So if I do a Subject.logout() on one of those
threads, the other threads can run into exceptions when doing a check like
Subject.isAuthenticated() or Subject.isRemembered(), as those are ultimately
delegated to the underlying HttpSession. The stack trace looks like this:
java.lang.IllegalStateException: getAttribute: Session already invalidated
at
org.apache.catalina.session.StandardSession.getAttribute(StandardSession.java:1355)
at
org.apache.catalina.session.StandardSessionFacade.getAttribute(StandardSessionFacade.java:152)
at
org.apache.shiro.web.session.HttpServletSession.getAttribute(HttpServletSession.java:146)
at
org.apache.shiro.session.ProxiedSession.getAttribute(ProxiedSession.java:121)
at
org.apache.shiro.subject.support.DelegatingSubject.getRunAsPrincipalsStack(DelegatingSubject.java:469)
at
org.apache.shiro.subject.support.DelegatingSubject.getPrincipals(DelegatingSubject.java:153)
at
org.apache.shiro.subject.support.DelegatingSubject.isRemembered(DelegatingSubject.java:297)
at
com.lso.proxy.AuthenticatingProxyServlet.service(AuthenticatingProxyServlet.java:65)
[...]
Issuing another Subject.logout() therefore also results in an exception.
While I can catch and swallow all those exceptions, there's another log entry
that's ugly to say the least, which looks like this:
WARN: WELD-000712: Unable to dissociate context
org.jboss.weld.context.http.LazyHttpConversationContextImpl@307f4035 when
destroying request org.apache.catalina.connector.RequestFacade@72507072
I'm using GlassFish 4.1 and I believe the explanation for this warning can be
found here: https://issues.jboss.org/browse/WELD-1813. As I don't use CDI in
this web module *yet*, it seems I would not be affected from the mentioned
thread corruption even though GlassFish 4.1 ships with an affected version of
Weld, but it would still be nicer to get rid of that warning altogether.
Does someone know a more elegant, straight-forward way to deal with this?
I've found a thread about programmatic forgetting of a remembered user here:
http://shiro-user.582556.n2.nabble.com/How-to-force-a-remembered-user-to-be-forgotten-td7579089.html.
But the problem I see with the proposed solution of calling
RememberMeManager.forgetIdentity() is that the Session doesn't get invalidated
at the same time. So the AngularJS app will keep sending the JSESSIONID cookie
and the Subject will still be "authenticated", if they had logged in to the
same Session before the user got deleted. Therefore I believe I really have to
invalidate the Session at the same time.
Best regards,
Joachim Kanbach