2

I'm trying to convert a sequential series of calls of spring service to be asynchronous.

I have annotated the method with @Async and added taskExecutor configuratinos.

I can see that the method is now being invoked asynchronously but I'm having issues with SecurityContextHolder.getContext() throwing this error:

java.util.concurrent.ExecutionException: java.lang.NullPointerException

Would really appreciate any insights. Thanks!

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Assaf Karmon
  • 915
  • 1
  • 10
  • 23
  • Please see http://stackoverflow.com/questions/3467918/how-to-set-up-spring-security-securitycontextholder-strategy – Ritesh Aug 19 '11 at 18:57

4 Answers4

6

The SecurityContext is stored in a ThreadLocal. So if you access it from a new thread that didn't set it anywhere, then the SecurityContext is null.

Update: Added Threadlocal javadoc link

Brian Kent
  • 3,754
  • 1
  • 26
  • 31
3

I found a solution, changing the startegy to "MODE_INHERITABLETHREADLOCA" solved my problem.

<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>
Assaf Karmon
  • 915
  • 1
  • 10
  • 23
0

Since Spring-Security 3.2 there is a nice annotation @AuthenticationPrincipal described at the end of this answer. This is the best way to go when you use Spring-Security >= 3.2. You can inject it in various ways. For more information look at this answer

Community
  • 1
  • 1
Augustin Ghauratto
  • 1,420
  • 1
  • 19
  • 21
0

If you want to access the security context in the asynchronous calls, You could implement the context aware thread pool executor to store the security context when creating threads like below.

public class CustomExecutor extends ThreadPoolTaskExecutor {
    @Override
    public <T> Future<T> submit(Callable<T> task) {
        return super.submit(new ScopeAwareCallable<T>(task, SecurityContextHolder.getContext()));
    }


    public class ScopeAwareCallable<T> implements Callable<T> {

    private Callable<T> callableTask;
    private SecurityContext securityContext;

    public ScopeAwareCallable(Callable<T> task, SecurityContext secContex) {
        this.callableTask = task;
        this.securityContext = secContex;
    }

    @Override
    public T call() throws Exception {
        if(securityContext != null){
            SecurityContextHolder.setContext(securityContext);
        }
        try {
            return callableTask.call();
        }
        finally {
            SecurityContextHolder.clearContext();
        }
    }
}

configure this as your task executor in the spring configuration. If you're using the Runnable instead of Callable, then override other methods in ThreadPoolTaskExecutor which supports the Runnable execution as well.

Dror Helper
  • 30,292
  • 15
  • 80
  • 129
Sheekat
  • 21
  • 2