(First of: I am a noob, so I apologize in advance if this is stupid,
unreadable, too long or simply not something that should be discussed here,
because technically it's not exactly a Shiro issue.  But since it wasn't
easy for me to find relevant information, I figured posting it may help
other people.)

I have had tremendous problems with a notorious Exception like this:

    org.apache.shiro.session.UnknownSessionException: There is no session
with id [74639e50-5928-4c31-b92a-ca582f49d4d4] 

which would produce a nasty crash every time after invoking
`DelegatingSubject#logout()` in the LogoutPage of my Wicket web application. 

Strangely, though, the `logout()`method itself worked fine - only after the
page redirected to the application's home page would the crash occur.  The
stack traces wouldn't help much - all one could see is a bunch of
`Session#invalidate` statements from both the Shiro and Wicket packages, all
looked perfectly normal and correct, if it hadn't been for the fact that at
the time they were called, the Shiro session no longer existed.

Also interesting: If I removed the `logout()` call and directly called
`getSession().invalidate()` the app would behave as expected.  That, of
course, was not enough, since even without a session, the original Subject
was still in memory.

After a day of thorough debugging and searching the web I have found both
the reason for this odd behavior, and a workaround: Shiro invalidates its
own HttpSession when `logout()` is called.  However, the Wicket HttpSession
it is wrapped in still exists, and that keeps a reference to it, invalid or
no. Wicket, then, automatically invokes its own `Session#invalidate()` from
within the `RequestCycle` after the page is fully rendered, which will try
to find the (now invalid) wrapped `ShiroHttpSession`, and then crash,
because an IllegalStateException is thrown from within Shiro's
`DefaultWebSessionManager#invalidate` method.

There is no way to manually remove the Shiro session from the Wicket
session, nor can the Wicket session be notified when its child session
invalidates, nor can the RequestCycle be told not to invalidate a second
time - these objects are all created and assigned deep within the
frameworks, and thorough encapsulation makes sure all the relevant parts are
inaccessible.

Still, the solution I finally came up with is rather simple:* The call to
`httpSession.invalidate()` within Wicket's HttpSessionStore must be wrapped
into a try/catch block.* 

Implementing this wasn't quite as easy, though, because the `invalidate()`
method  is `final`, and the store is created in a private inner class of
`WebApplication`.  I ended up extending WebApplication and overriding the
`internalInit()`method in the same way Wicket uses it:

        @Override
        protected void internalInit() {
                super.internalInit();
                setSessionStoreProvider( new MyPowerfulSessionStoreProvider() );
        } 

        private class MyPowerfulSessionStoreProvider implements
IProvider<ISessionStore> {

                public ISessionStore get() {
                        return new MyPowerfulSessionStore();
                }
        }  

MyPowerfulSessionStore, then, is a 1:1 copy of Wicket's `HttpSessionStore`
that now includes the above-mentioned try/catch block:

          (...)
          public final void invalidate( final Request request ) {
                HttpSession httpSession = getHttpSession( request, false );
                if( httpSession != null ) {
                        // tell the app server the session is no longer valid
                        try {
                                httpSession.invalidate();
                        } catch( IllegalStateException ignore) {
                                // So what if it's in an illegal state (i.e. 
does not exist) - the
session was supposed to be
                                // invalidated anyway!
                        }
                }
        } 
        (...)

I would have preferred to just extend the original HttpSessionStore, of
course, but as you can see: the method in question is marked `final`...  

Anyhow - it's all smooth sailing now.  If anyone out there has the same
issue: I hope I saved you at least 10 of the >12 hours of work this has cost
me ;)



--
View this message in context: 
http://shiro-user.582556.n2.nabble.com/UnknownSessionException-when-logging-out-from-Wicket-1-5-Shiro-application-tp7579423.html
Sent from the Shiro User mailing list archive at Nabble.com.

Reply via email to