Search code examples
javaplayframeworkplayframework-2.0guiceguice-3

How to mock an Authenticator in play framework with guice injections?


I have a play application with authenticated routes. I implemented an Authenticator, storing users into elasticsearch. My securized methods in my controllers are annotated with the @Security.Authenticated annotation. For my unit tests with mockito, I would like to mock this class but I don't know how to do this.

I am using DI with Guice. So I tried this approach:

  1. Develop an AuthenticatorWrapper as following:

    public class AuthenticatorWrapper extends Security.Authenticator {
    
        private Authenticator authenticator;
    
        @Override
        public String getUsername(Http.Context ctx) {
            return authenticator.getUsername(ctx);
        }
    
        @Override
        public Result onUnauthorized(Http.Context ctx) {
            return authenticator.onUnauthorized(ctx);
        }
    
        @Inject
        public void setAuthenticator(Authenticator authenticator) {
            this.authenticator = authenticator;
        }
    }
    

    This class has an Authenticator as parameter, which is supposed to be injected by Guice when the app starts.

  2. I developed a guice module defining a binding for class Authenticator.class to MyCustomAuthenticator.class

  3. My securized route are annotated with @Security.Authenticated(AuthenticatorWrapper.class)

In my test I can easily provide a mock of class MyCustomAuthenticator my creating the mock, define test scope guice module, and defining a binding from Authenticator.class to my mock.

I thought this should work but this is not the case. Both at normal runtime or from my tests, the binding seems not working. I have nullPointerException from the wrapper when: the Authenticator parameter is not injected by Guice.

So my questions are:

  • Does the Authenticator is a good approach to Inject my authenticator from Guice? Maybe there is an easier way to inject a play Authenticator into annotations from Guice?
  • Is it normal that Authenticator is not injected by Guice into my wrapper? [EDIT -> yes because the annotation manually instantiates my object and doesn't use guice. Am I right?]
  • I can simplify my application by set directly MyCustomAuthenticator into the annotations, but how can I mock this authenticator in my tests?

Thanks :)


Solution

  • A found a workaround. I just used an access method provided by Play framework 2.4 since it fully integrates Guice. Here is my Authentication Wrapper class:

    public class AuthenticatorWrapper extends Security.Authenticator {
    
        private final Security.Authenticator authenticator;
    
        public AuthenticatorWrapper() {
            authenticator = Play.application().injector().instanceOf(Security.Authenticator.class);
        }
    
        @Override
        public String getUsername(Http.Context ctx) {
            return authenticator.getUsername(ctx);
        }
    
        @Override
        public Result onUnauthorized(Http.Context ctx) {
            return authenticator.onUnauthorized(ctx);
        }
    }
    

    I just use the Play.application().injector() accessor to get a Security.Authenticator instance provided by Guice. So in my application.conf, I just configure a Guice Module which binds Security.Authenticator to the wanted implementation.