Dropwizard custom security provider for authentication

Sample application showing how to use security providers in your Dropwizard application.

Includes an example custom security provider which can be injected into your service and used in Resource methods to authenticate requests and apply authorisation. Can be extended to implement a full authentication and authorisation for the service.

Introduction

The majority of the provider in this sample project was based off the BasicAuthProvider from Dropwizard auth library, I wanted to do this to understand better how the injectable security provider works and figure out how it could be used to implement authentication and authorisation.

Also wanted to ensure I could easily extend and test any resources using the security, as the overhead for a security system is important in keeping your code clean and not obscuring the intended purpose with security code.

Details

Implementing the custom security provider requires three classes (in com.example.security):

  • ExampleCredentialsHolds the credentials extracted from the request, e.g. username/password or a token from a cookie.
  • ExampleAuthenticatorTakes the credentials and authenticates them, returning a principle (user) object, throwing an AuthenticationException if the credentials are invalid.
  • ExampleSecurityProviderIs injected into the service so any request decorated with the Dropwizard Auth attribute will be handled by this provider. Extracts credentials from requests, uses an authenticator to check them and throws WebExceptions if not authenticated.
    /**
     * An example security provider that will look at each request when received by an endpoint using the auth attribute
     * and check that it has a header value containing a token and will authenticate the token to get the Principle (User)
     * for the request (otherwise throw an AuthenticationException). That Principle is the authenticated User associated
     * with the request and the resource method handling the request can use it to check authorisation to perform actions.
     *
     * @param <T> The Principle class (User) to be returned when a request is authenticated
     */
    public class ExampleSecurityProvider<T> implements InjectableProvider <Auth, Parameter> {
        ...
        public ExampleSecurityProvider(Authenticator<ExampleCredentials, T> authenticator) {
            this.authenticator = authenticator;
        }
        ...
        private static class ExampleSecurityInjectable<T> extends AbstractHttpContextInjectable<T> {
            ...
            @Override
            public T getValue(HttpContext c) {
                // This is where the credentials are extracted from the request
                final String header = c.getRequest().getHeaderValue(CUSTOM_HEADER);
                try {
                    if (header != null) {
                        final Optional<T> result = authenticator.authenticate(new ExampleCredentials(header));
                        if (result.isPresent()) {
                            return result.get();
                        }
                    }
                } catch (AuthenticationException e) {
                    throw new WebApplicationException(Response.Status.UNAUTHORIZED);
                }
    
                if (required) {
                    throw new WebApplicationException(Response.Status.UNAUTHORIZED);
                }
    
                return null;
            }
        }
    

The security provider is injected into the service in the Service class.

public class ExampleService extends com.yammer.dropwizard.Service<ExampleConfiguration> {
    ...
    @Override
    public void run(ExampleConfiguration configuration, Environment environment) throws Exception {
        environment.addResource(new UserResource());

        // Adds security provider so resource methods decorated with auth attribute will use this authenticator
        environment.addProvider(new ExampleSecurityProvider<User>(new ExampleAuthenticator()));
    }

Resources using authentication just add the Auth attribute to their method signature.

@Path("/user")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public class UserResource {
    ...
    /*
    * Using the Auth attribute will use the injected provider to authenticate all requests to this path
    * You can also use the principal to apply authorisation in code dynamically
     */
    @GET
    public List<User> getAll(@Auth User principal){

        if (!principal.getDisplayRole().equals(User.ROLE_ADMIN)) {
            throw new WebApplicationException(Response.Status.UNAUTHORIZED);
        }
        ...

Testing the resources requires injecting a provider into the test service (note, I used the full one but for simplicity you can inject a mock which would return a controllable principal).

public class UserResourceTests extends ResourceTest {
    ...
    @Override
    protected void setUpResources() {
        addResource(new UserResource());

        // Need to add SecurityProvider to all resource tests for resources using Auth, or you get 415 response
        // you can inject the authenticator to mock authentication results while ensuring you test true to how
        // the call will be made
        final ExampleAuthenticator authenticator = new ExampleAuthenticator();
        addProvider(new ExampleSecurityProvider<>(authenticator));
    }

    @Test
    public void getAll() throws Exception {
        List<User> users = client().resource("/user")
                                   .header(ExampleSecurityProvider.CUSTOM_HEADER, "validAdminToken")
                                   .get(new GenericType<List<User>>() {});
        assertEquals(2, users.size());
        assertEquals("user1", users.get(0).getUsername());
    }

    @Test
    public void getAllThrows401WhenNotAuthenticatedToken() throws Exception {
        try {
            client().resource("/user")
                    .get(new GenericType<List<User>>() {});

            fail("Should have thrown 401");
        } catch (UniformInterfaceException ex) {
            assertEquals(ex.getResponse().getStatus(), 401);
        }
    }
    ...

Conclusion

Using the injectable security provider you can implement an extremely flexible authentication and authorisation system in your service, while keeping the code overhead in your resource methods and tests minimal via the Auth attributes. In terms of simplicity it blows away a lot of security libraries I’ve worked with for other frameworks.

Advertisements

8 thoughts on “Dropwizard custom security provider for authentication

  1. Hi Steven, thank you for your the post. it is very informative. Can you please add an example of the request in terms of headers, etc?

    • Thanks firas.

      Typically the header value is a session cookie containing a unique token that can be verified and tried back to the user from a session store.
      E.g. “Cookie: sessionToken=12345”, where 12345 is the id of a valid session stored in a data store linked to a user like “12345,admin,25/5/2015:01:03” so the Security provider can verify the request has a valid session and which user.

  2. Thanks again Steven. I really really appreciate your reply.
    I am saving a uuid on the middle tier database. can i send that uuid in the token as means to verify the user in your code?
    if not, do i still need a session store? Do you have a link or code example of your preferred session manager?

    • Replying to this again since my answer was a bit vague and probably not what you were after.

      The answer for “do i still need a session store?” is better answered by thinking what you gain by having one. A session store gives you a concrete store saying what sessions are active and a way to invalidate them on demand.

      If you don’t need this and only want a way to validate that a request came from an authenticated user (and identify which one) you can avoid a session store by creating an access token from the information you have at authentication then encrypting this. Then when you receive a request with the access token you can decrypt the access token and verify the request from the content. E.g. username + “:” + loginTimestamp + “:” + saltPaddingString — encrypt–> “das432423rdsfsr324fdsfw4r2332fds23ad” –decrypt–> “bob1:25/05/2015-19:01:salt1234”.

      This approach is slightly less secure, as due to the size of string you can save in the cookie (max 4kb) you can’t use big keys and heavy encryption, making it riskier that someone could brute force your key/salt and use that to impersonate a different user.

      • Thanks Steven. AGAIN, i can’t tell you how much your help is valuable to me.
        Yes, this is exactly what i meant.
        initially, the user enters username & password which i use BasecCredentials and Authenticator to valdaite. next, in the reply, i send back a UUID that is saved on the database backl to the smartphone(client), which this client should use in ever subsequent request.
        one problem i am having is that i can’t send the UUID in the body of a GET method, so the client should send it back in the header.
        in your latest reply, what are you using to decypt the header? any specific classes, do you have any example please?
        have a great day Steven 🙂

  3. Steven, I can’t seem to get this code to compile due to missing implementations. This is my first time using InjectableProvider’s. Couple direct questions: How to access the required Field of the parameter annotation, what goes into getInjectable(ComponentContext arg0, Auth arg1, Parameter arg2), and getScope()?

    Any help, or hints would be greatly appreciated.

    Thanks for this write-up!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s