Securing Dropwizard with Apache Shiro
Sun 29 December 2013 by Stig Inge Lea BjørnsenThis post provides an overview of how to use Apache Shiro for securing an example web browser facing REST API based on Dropwizard.
The example REST API supports the following well known authentication mechanisms:
- No authentication
- HTTP Basic authentication
- Cookie based authentication
The REST API described here uses a Dropwizard bundle for Apache Shiro: http://github.com/silb/dropwizard-shiro
The techniques described in this post can also be implemented by using Jersey without Dropwizard: http://github.com/silb/shiro-jersey
How clients use the REST API
Since the REST API supports anonymous users, authentication is optional. This means that unauthenticated requests cannot be responded with an HTTP basic challenge.
Clients that use HTTP basic authentication must therefore supply their credentials preemptively (before receiving a challenge).
Web browser clients use cookie based authentication by first issuing
an HTTP POST to /session
with the username and password as form
parameters. Subsequent requests are then automatically authenticated
as long as the session is valid.
How the Shiro bundle is configured
The Shiro bundle is added to Dropwizard as described here: http://github.com/silb/dropwizard-shiro
Optional HTTP basic authentication is implemented by overriding the Shiro HTTP basic filter so that it only sends challenge responses to authentication requests that fail:
public class OptionalBasicHttpAuthenticationFilter extends BasicHttpAuthenticationFilter {
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (!isLoginAttempt(request, response)) return true;
if (executeLogin(request, response)) return true;
else return sendChallenge(request, response);
}
}
The Shiro authentication filters are configured in shiro.ini
:
[main]
optionalAuthBasic = OptionalBasicHttpAuthenticationFilter
[urls]
/session/** = anon
/** = noSessionCreation, optionalAuthBasic, anon
The filter noSessionCreation
is used for limiting session to users
that log in through the HTML form. Sessions are not used for storing
anything but the session cookie ID.
The anon
filter allows access for anonymous users. Both filters are
part of Shiro's
default filters.
Form based authentication is implemented by a JAX-RS resource that authenticates users and creates sessions:
@PATH("/session")
public class SessionResource {
@POST
public String login(@FormParam String username, @FormParam String password, @Auth Subject subject) {
subject.login(new UsernamePasswordToken(username, password));
return username;
}
}
Note that the path of /session
corresponds to the shiro.ini
filter config without the noSessionCreation
filter. When logging in a user, Shiro will therefore also create an HTTP session.
Dropwizard does not enable sessions by default. Sessions must be enabled during initialization of the Dropwizard service:
public class ExampleApiService extends Service<ExampleApiConfiguration> {
public void run(ShiroJaxRsConfiguration configuration, Environment environment) throws Exception {
environment.setSessionHandler(new SessionHandler());
}
}
Conclusion
While Dropwizard does provide an authentication bundle, Apache Shiro is a viable alternative for:
- organizations already using Apache Shiro and who have invested in learning and integrating it into their infrastructure.
- applications that need authorization features like Apache Shiro's permission model.