The EnvironmentLoaderListener only sets up Shiro's environment for a webapp (SecurityManager, filters, etc).
The ShiroFilter is the component that uses the environment to construct Subject instances and make them available on the current thread at runtime. If other non-filtered components (like other Listeners) need a Shiro Subject, they must acquire the Environment and create a Subject instance to use themselves. As a warning, I should note that your example works, but probably only as a side effect that the same thread used to initialize Shiro happens to be the same thread that initializes your other Servlet Context Listener. It is possible that the thread used to shut down the listener is not the same as the one that initialized it, so the ThreadContext.remove() call might not do anything meaningful. The ThreadContext is a low-level infrastructural component used by Shiro's internals and should only be referenced directly in very specific circumstances. Most of the time using the Subject.Builder and calling execute on the built subject (subject.execute(work)) is the 'safe' way to guarantee thread cleanup. This same technique (subject.execute) is used by the ShiroFilter for example: http://shiro.apache.org/static/current/apidocs/src-html/org/apache/shiro/web/servlet/AbstractShiroFilter.html#line.362 This should ideally be repeated by other infrastructural components when possible to guarantee thread cleanup. Thanks for the post! Cheers, -- Les Hazlewood CTO, Stormpath | http://stormpath.com | 888.391.5282 twitter: @lhazlewood | http://twitter.com/lhazlewood blog: http://leshazlewood.com stormpath blog: http://www.stormpath.com/blog On Thu, Apr 26, 2012 at 6:37 AM, Stexxen <[email protected]> wrote: > Hi, > I have been struggling with getting Shiro working in another Listener in > Tomcat. I finally got it working so I am writing what I found here. > > Within web.xml I have the usual EnvironmentLoaderListener > <listener> > > <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> > </listener> > > I also have another Listener > <listener> > <listener-class>org.somethingelse.OtherClass</listener-class> > </listener> > > Any code executed by OtherClass couldn't get a Subject because the > ThreadContext.getSecurityManager returned null. Whenever you executed > SecurityUtils.getSubject() you would get the following exception > > > org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager > accessible to the calling code, either bound to the > org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an > invalid application configuration. > > To resolve I had to populate the ThreadContext in OtherClass, > Within OtherClass:contextInitialized > > WebEnvironment wm = > WebUtils.getRequiredWebEnvironment(servletContextEvent.getServletContext()); > WebSecurityManager wsm = wm.getWebSecurityManager(); > ThreadContext.bind(wsm); > > and in OtherClass:contextDestroyed > ThreadContext.unbindSecurityManager(); > ThreadContext.remove(); > > Now any calls to SecurityUtils.getSubject() would return a Subject. > > Hope this may help someone in future. > > Now the thought has crossed my mind that I have missed some vital part of > the documentation that would make what I have done above unnecessary. If so > please let me know what it is. > > Thanks, > S.
