Embracing the Messiness in Search of Epic Solutions

Spring Security: Propagating Security Context to Spawned Threads

Posted

in

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

Comments

Leave a Reply