Search code examples
spring-securityspring-cloudjava-threadsnetflix-feign

Feign Client called from a thread + Spring Security


I have situation where I call a feign client. It works fine, until I try putting the feign client inside a thread (simplified version):

@Autowired
UsuarioFeign feignUserClient;

....

final Runnable t = new Runnable() {
    @Override
    public void run() {
        try {
            feignUserClient.findByEmail("[email protected]");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
};
new Thread(t).start();

When I try to do it, I get (printed by the real version, not the simplified one above):

java.lang.NullPointerException
at br.alfa.tutoria.AlfaTutoriaApplication$1.apply(AlfaTutoriaApplication.java:46)
at feign.SynchronousMethodHandler.targetRequest(SynchronousMethodHandler.java:158)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:88)
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76)
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103)
at com.sun.proxy.$Proxy246.findByEmail(Unknown Source)
at br.alfa.tutoria.service.impl.TutoriaServiceImpl.atribuiFuncaoTutor(TutoriaServiceImpl.java:285)
at br.alfa.tutoria.service.impl.TutoriaServiceImpl$2.run(TutoriaServiceImpl.java:270)
at java.lang.Thread.run(Unknown Source)

The feignUserClient is @Autowired (I've tried turn it final, and inject it using a constructor, but it made no difference - anyway, it's value is not null when the code execute).

More info:

Feign Interface:

@FeignClient(name = "authUsers", url = br.alfa.tutoria.config.Url.AUTH_SERVER)
public interface UsuarioFeign {
    @RequestMapping(value = "/user-search-by-email", method = RequestMethod.POST)
    public User findByEmail(String email);
}

The other class, which calls the feign interface... it doesn't matter. I tried it in several diferent classes (all of them annotated with @RestController or @Service). It just stop working if I call the UsuarioFeign.findByEmail from a thread.


Solution

  • At the end, the problem had to do with Spring Security Context. By design, "the Security is stored in a per Thread basis" according to Spring Security docs. That means that if you need something like the security context in a new thread, you won't get it.

    In the docs you can find a way to transfer it as a parameter to a new thread:

    Runnable originalRunnable = new Runnable() {
        public void run() {
            // invoke secured service
        }
    };
    
    SecurityContext context = SecurityContextHolder.getContext();
    DelegatingSecurityContextRunnable wrappedRunnable =
        new DelegatingSecurityContextRunnable(originalRunnable, context);
    
    new Thread(wrappedRunnable).start();