Thursday 18 September 2014

Spring Security + @Async problem: (SecurityContextHolder is empty)


Problem: I annotated a method with @Async and @PreAuthorize so that is executed asynchronously and be secured.
But it seems the security context (SecurityContextHolder) is not populated (althouth user has authenticated).
This happens only if the method is annotated with @Async.

Solution: From SecurityContextHolder we can get e.g. the logged in username (e.g. check this). SecurityContextHolder is saved in
current thread [1]. When we spawn a new thread the current thread's SecurityContextHolder  (which is a ThreadLocals)
is not copied/inherited.

In order to inherit it do the following:

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


All possible modes:
  • MODE_THREADLOCAL (default strategy)
  • MODE_INHERITABLETHREADLOCAL: spawned threads inherit SecurityContext of the parent thread
  • MODE_THREADLOCAL
  • SYSTEM_PROPERTY

[1] From the Spring Reference: "By default the SecurityContextHolder uses a ThreadLocal to store these details, which means that the security context is always available to methods in the same thread of execution ..."

No comments:

Post a Comment