4

Currently, My AuditorAware Implementation uses Spring's SecurityContextHolder to retrieve the current Auditor for saving creation/modification usernames:

@Service
public class AuditorAwareImpl implements AuditorAware<UserDetails> {

    private final UserDetailsService userDetailsService;

    @Autowired
    public AuditorAwareImpl(UserDetailsService userDetailsService){
        this.userDetailsService = userDetailsService;
    }

    @Override
    public UserDetails getCurrentAuditor() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return userDetailsService.loadUserByUsername(authentication.getName());
    }
}

This works fine for most operations except for asynchronous tasks executed by Spring batch's SimpleAsyncTaskExecutor.

By the time entities need saving, since the SecurityContextHolder is wiped after the request has been processed, and the jobLauncher.run(...) returns asynchrnously, the AuditorAwareImpl.getCurrentAuditor() method throws a NullPointerException due to a null getAuthentication():

java.lang.NullPointerException: null
    at com.example.services.AuditorAwareImpl.getCurrentAuditor(AuditorAwareImpl.java:31)
    at com.example.services.AuditorAwareImpl.getCurrentAuditor(AuditorAwareImpl.java:18)

So far I have included the request-invoking user as a non-identifying parameter to the Job but don't know where to proceed from here.

What is a recommended way of leveraging spring's inbuilt auditing when the SecurityContextHolder is not appropriate for finding the invoking "auditor"?

coderatchet
  • 8,120
  • 17
  • 69
  • 125

1 Answers1

5

You can wrap your AsyncTaskExecutor in a DelegatingSecurityContextAsyncTaskExecutor which is specially designed for propagating Spring SecurityContext. Also you will additionally need to set MODE_INHERITABLETHREADLOCAL for the security context.

Shailendra
  • 8,874
  • 2
  • 28
  • 37
  • Take a look here https://stackoverflow.com/questions/40345643/java-future-spring-authentication-is-null-into-auditoraware – Shailendra Oct 23 '17 at 08:33
  • Thank you. Since I am using the SimpleAsyncTaskExecuter, setting the MODE_INHERITABLETHREADLOCAL strategy was enough for me. – Lyannic Oct 02 '20 at 14:14