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:
… 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