Request Values: Http Basic Auth

Request Values: Http Basic Auth

An abstract class to implement HTTP basic authentication

Description

Http basic auth allows for protection of one or more routes with a username and password.

To use it you subclass HttpBasicAuthenticator and provide your authentication logic. There are two factory methods to create the authentication results to return from the authentication logic: authenticateAs(T) and refuseAccess(). If the authentication is not very quick in memory, for example calls a database, make sure you do not block the web server thread by executing that in a separate CompletionStage and then flatMap the result into the authentication result.

When you use the authenticator in your routes you must reference the concrete authenticator twice, first as a directive wrapping all the routes it should be required for, and then as a request value to extract the user object for use inside the logic of the handler.

Note that to protect developers from opening up for a timing attack on the password it is not available directly, instead a constant time string comparison is provided. For more information about timing attacks on passwords see for example Timing Attacks Explained .

Example

Authenticating or refusing access to a user based on a hardcoded password and using a String with the username as internal representation of a user (in a real application it would probably be an instance of a richer class describing an authenticated user).

final HttpBasicAuthenticator<String> authentication = new HttpBasicAuthenticator<String>("My realm") {

    private final String hardcodedPassword = "correcthorsebatterystaple";

    public CompletionStage<Optional<String>> authenticate(BasicCredentials credentials) {
        // this is where your actual authentication logic would go
        if (credentials.available() && // no anonymous access
            credentials.verify(hardcodedPassword)) {
            return authenticateAs(credentials.identifier());
        } else {
            return refuseAccess();
        }
    }
};

final Route route =
    authentication.route(
        handleWith1(
            authentication,
            new Handler1<String>() {
                public RouteResult apply(RequestContext ctx, String user) {
                    return ctx.complete("Hello " + user + "!");
                }

            }
        )
    );


// tests:
final HttpRequest okRequest =
    HttpRequest
        .GET("http://akka.io/")
        .addHeader(Host.create("akka.io"))
        .addHeader(Authorization.basic("randal", "correcthorsebatterystaple"));
testRoute(route).run(okRequest).assertEntity("Hello randal!");

final HttpRequest badRequest =
        HttpRequest
                .GET("http://akka.io/")
                .addHeader(Host.create("akka.io"))
                .addHeader(Authorization.basic("randal", "123abc"));
testRoute(route).run(badRequest).assertStatusCode(401);

Contents