3

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 :)

Thibaut M.
  • 299
  • 1
  • 2
  • 10
  • Are you sure Guice is being used to create `AuthenticatorWrapper`? The NPE implies otherwise. One way to check is to use constructor injection instead (which would be better iMHO because then the `authenticator` field can be final – NamshubWriter Mar 19 '15 at 06:38

1 Answers1

0

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.

Thibaut M.
  • 299
  • 1
  • 2
  • 10