Inherit Spring Security Context in Child Threads

2010-04-04

By default, Spring Security context is bound to ThreadLocal, which may catch you by surprise in some cases involving spawned threads.

So I setup my security infrastructure to authenticate users, populate their details from database, grant them authorities, I configure AccessDecisionManager and put @Secured annotations on my business methods to assert those authorities, etc. It all works well until my business code evolves to include asynchronous invocations. Then I find myself wondering: why am I getting AuthenticationCredentialsNotFoundException in places where the user is obviously authenticated?

Turns out that when a new thread is started it knows nothing about the security context of its parent thread. So if AccessDecisionManager gets called (e.g. if a @Secured method is invoked) from within the child thread, you get a security exception.

To work around that, you should change the SecurityContextHolder strategy to use InheritableThreadLocal for storing the security context. You can do that in code:

SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)

… or in XML configuration (which is better since you’ll only need to call the static method once during application startup):

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetClass"
        value="org.springframework.security.context.SecurityContextHolder"/>
    <property name="targetMethod" value="setStrategyName"/>
    <property name="arguments"><list><value>MODE_INHERITABLETHREADLOCAL</value></list></property>
</bean>

Note however, that you cannot share security context among sibling threads (e.g. in a thread pool). This method only works for child threads that are spawned by a thread that already contains a populated SecurityContext.

  1. Andy - December 15th, 2010 at 05:56

    Awesome, very clean and works perfect with Executors.newFixedThreadPool(). Thanks!

  2. Jan Goyvaerts - June 28th, 2012 at 11:58

    Many thanks indeed ! confirming it works for threadpools also with Spring 3.0.6.

    However, the property “targetClass” should now be “org.springframework.security.core.context.SecurityContextHolder”.