You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by Joachim Kanbach <jo...@gmx.de> on 2015/10/13 13:53:01 UTC

How to programmatically forget remembered Subject in the presence of parallel request threads?

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

Re: How to programmatically forget remembered Subject in the presence of parallel request threads?

Posted by Lenny Primak <lp...@hope.nyc.ny.us>.
No, the account can be deleted, just that “in memory” permissions can be cleaned out, so you don’t have any issues
with stale sessions, etc.

> On Oct 14, 2015, at 7:13 AM, Joachim Kanbach <jo...@gmx.de> wrote:
> 
> Hi Lenny,
> 
> thanks for your reply. You mean you don't actually delete the user account, but just clear out all permissions from it (maybe by assigning a special role)? So the user accounts exist forever?
> 
>> I had the same requirement, and satisfied it by clearing out permissions for the user.
>> The user was still able to log in, but couldn’t do anything with the web site because they had no permissions.
>> I called onLogout() for all outstanding realms after clearing out permissions in the DB and that was that.
>> 
>>> On Oct 13, 2015, at 7:53 AM, Joachim Kanbach <jo...@gmx.de> wrote:
>>> 
>>> 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
>>> 
>> 
>> 
> 


Aw: Re: How to programmatically forget remembered Subject in the presence of parallel request threads?

Posted by Joachim Kanbach <jo...@gmx.de>.
Hi Lenny,

thanks for your reply. You mean you don't actually delete the user account, but just clear out all permissions from it (maybe by assigning a special role)? So the user accounts exist forever?

> I had the same requirement, and satisfied it by clearing out permissions for the user.
> The user was still able to log in, but couldn’t do anything with the web site because they had no permissions.
> I called onLogout() for all outstanding realms after clearing out permissions in the DB and that was that.
> 
> > On Oct 13, 2015, at 7:53 AM, Joachim Kanbach <jo...@gmx.de> wrote:
> > 
> > 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
> > 
> 
>

Re: How to programmatically forget remembered Subject in the presence of parallel request threads?

Posted by Lenny Primak <lp...@hope.nyc.ny.us>.
I had the same requirement, and satisfied it by clearing out permissions for the user.
The user was still able to log in, but couldn’t do anything with the web site because they had no permissions.
I called onLogout() for all outstanding realms after clearing out permissions in the DB and that was that.

> On Oct 13, 2015, at 7:53 AM, Joachim Kanbach <jo...@gmx.de> wrote:
> 
> 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
>