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.

Reply via email to