Spring Security: Propagating Security Context to Spawned Threads

PROBLEM

Let’s assume we have the following Parent class…

@Service
class Parent {
    @Autowired
    Child child

    void run() {
        println "Parent: ${SecurityContextHolder.context.authentication?.principal}"

        child.run()

        println "Parent: Done"
    }
}

… and Child class…

@Service
class Child {
    @Async
    void run() {
        Thread.sleep(500)
        println "Child: ${SecurityContextHolder.context.authentication?.principal}"
    }
}

Let’s also assume the user has successfully logged in and Spring Security has set up the user authentication info.

The Parent will spawn a new thread (through @Async) to run Child.

When invoking the Parent, this is what we see:-

Parent: USER_PRINCIPAL
Parent: Done
Child: null

The Child, for some reason, doesn’t get the receive the user authentication info.

SOLUTION

By default, SecurityContextHolder uses MODE_THREADLOCAL to store the user authentication info. As a result, this info is not accessible to methods outside the current execution thread.

To fix this, configure SecurityContextHolder to use MODE_INHERITABLETHREADLOCAL to pass the user authentication info to other spawned threads.

@Configuration
@EnableAsync
class AppConfig {
    AppConfig() {
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)
    }
}

When invoking the Parent again, now the Child will also receive the user authentication object:-

Parent: USER_PRINCIPAL
Parent: Done
Child: USER_PRINCIPAL
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s