Dropwizard – BasicAuth Security Example

Using dropwizard, we have learned about creating REST APIs, writing client code and adding health-check filters. In this tutorial, we will learn to add username/password based authentication and role based authorization capabilities into REST APIs using Basic Authentication.

Table of Contents

Include Dropwizard Auth Module Maven Dependency
Add Custom Principal Object
Add Custom Authenticator
Add Custom Authorizer
Configure BasicCredentialAuthFilter
Secure REST APIs with @Auth Annotation
Test Dropwizard Basic Auth Code

Include Dropwizard Auth Module Maven Dependency

Authentication capabilities are added as separate module in dropwizard application.

<properties>
	<dropwizard.version>1.0.0</dropwizard.version>
</properties>
<dependency>
	<groupId>io.dropwizard</groupId>
	<artifactId>dropwizard-auth</artifactId>
	<version>${dropwizard.version}</version>
</dependency>

Add Custom Principal Object

In security, principal object represent the user for which credentials have been supplied with request. It implements java.security.Principal interface.

package com.howtodoinjava.rest.auth;

import java.security.Principal;
import java.util.Set;

public class User implements Principal {
    private final String name;

    private final Set<String> roles;

    public User(String name) {
        this.name = name;
        this.roles = null;
    }

    public User(String name, Set<String> roles) {
        this.name = name;
        this.roles = roles;
    }

    public String getName() {
        return name;
    }

    public int getId() {
        return (int) (Math.random() * 100);
    }

    public Set<String> getRoles() {
        return roles;
    }
}

Add Custom Authenticator

Authenticator class is responsible for verifying username/password credentials included in Basic Auth header. In enterprise application, you may fetch the user’s password from database and if it matches then you set the user roles into principal object. In dropwizard, you will need to implements io.dropwizard.auth.Authenticator interface to put your application logic.

package com.howtodoinjava.rest.auth;

import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;

import java.util.Map;
import java.util.Optional;
import java.util.Set;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

public class AppBasicAuthenticator implements Authenticator<BasicCredentials, User> 
{
    private static final Map<String, Set<String>> VALID_USERS = ImmutableMap.of(
        "guest", ImmutableSet.of(),
        "user", ImmutableSet.of("USER"),
        "admin", ImmutableSet.of("ADMIN", "USER")
    );

    @Override
    public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException 
    {
        if (VALID_USERS.containsKey(credentials.getUsername()) && "password".equals(credentials.getPassword())) 
        {
            return Optional.of(new User(credentials.getUsername(), VALID_USERS.get(credentials.getUsername())));
        }
        return Optional.empty();
    }
}

Add Custom Authorizer

Authorizer class is responsible for matching the roles and decide whether user is allowed to perform certain action or not.

package com.howtodoinjava.rest.auth;

import io.dropwizard.auth.Authorizer;

public class AppAuthorizer implements Authorizer<User> 
{
    @Override
    public boolean authorize(User user, String role) {
        return user.getRoles() != null && user.getRoles().contains(role);
    }
}

Configure BasicCredentialAuthFilter

Now let’s register our custom classes into dropwizard security framework.

package com.howtodoinjava.rest;

import io.dropwizard.Application;
import io.dropwizard.Configuration;
import io.dropwizard.auth.AuthDynamicFeature;
import io.dropwizard.auth.AuthValueFactoryProvider;
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
import io.dropwizard.client.JerseyClientBuilder;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;

import javax.ws.rs.client.Client;

import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;

import com.howtodoinjava.rest.auth.AppAuthorizer;
import com.howtodoinjava.rest.auth.AppBasicAuthenticator;
import com.howtodoinjava.rest.auth.User;
import com.howtodoinjava.rest.controller.EmployeeRESTController;
import com.howtodoinjava.rest.controller.RESTClientController;
import com.howtodoinjava.rest.healthcheck.AppHealthCheck;
import com.howtodoinjava.rest.healthcheck.HealthCheckController;

public class App extends Application<Configuration> {

	@Override
	public void initialize(Bootstrap<Configuration> b) {
	}

	@Override
	public void run(Configuration c, Environment e) throws Exception {
		e.jersey().register(new EmployeeRESTController(e.getValidator()));

		final Client client = new JerseyClientBuilder(e).build("DemoRESTClient");
		e.jersey().register(new RESTClientController(client));

		// Application health check
		e.healthChecks().register("APIHealthCheck", new AppHealthCheck(client));

		// Run multiple health checks
		e.jersey().register(new HealthCheckController(e.healthChecks()));

		//****** Dropwizard security - custom classes ***********/
		e.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>()
								.setAuthenticator(new AppBasicAuthenticator())
								.setAuthorizer(new AppAuthorizer())
								.setRealm("BASIC-AUTH-REALM")
								.buildAuthFilter()));
		e.jersey().register(RolesAllowedDynamicFeature.class);
	    e.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));
	}

	public static void main(String[] args) throws Exception {
		new App().run(args);
	}
}

Secure REST APIs with @Auth Annotation

Adding @Auth annotation will trigger authentication filter on any API where it is put as parameter.

1) User must be authenticated. API is allowed to all users.

@PermitAll
@GET
public Response getEmployees(@Auth User user) {
	return Response.ok(EmployeeDB.getEmployees()).build();
}

2) User must be authenticated. API is allowed to all users with role “ADMIN” only.

@RolesAllowed({ "ADMIN" })
@GET
@Path("/{id}")
public Response getEmployeeById(@PathParam("id") Integer id, @Auth User user) {
	Employee employee = EmployeeDB.getEmployee(id);
	if (employee != null)
		return Response.ok(employee).build();
	else
		return Response.status(Status.NOT_FOUND).build();
}

In this way, you can add various authentication schemes in all your APIs as per your need.

Test Dropwizard Basic Auth Code

Let’s test out our secured APIs.

Call Any secured API

Basic Authentication Screen
Basic Authentication Screen

http://localhost:8080/employees

Authenticated and allowed to all roles
Authenticated and allowed to all roles

http://localhost:8080/employees/1

Authenticated and allowed to ADMIN role only
Authenticated and allowed to ADMIN role only

Drop me your questions in comments section.

Happy Learning !!

Leave a Reply

1 Comment
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial