authenticateOrRejectWithChallenge

Lifts an authenticator function into a directive.

Description

This directive allows implementing the low level challenge-response type of authentication that some services may require.

More details about challenge-response authentication are available in the RFC 2617, RFC 7616 and RFC 7617.

Example

final HttpChallenge challenge = HttpChallenge.create("MyAuth", new Option.Some<>("MyRealm"));

// your custom authentication logic:
final Function<HttpCredentials, Boolean> auth = credentials -> true;

final Function<Optional<HttpCredentials>, CompletionStage<Either<HttpChallenge, String>>> myUserPassAuthenticator =
  opt -> {
    if (opt.isPresent() && auth.apply(opt.get())) {
      return CompletableFuture.completedFuture(Right.apply("some-user-name-from-creds"));
    } else {
      return CompletableFuture.completedFuture(Left.apply(challenge));
    }
  };

final Route route = path("secured", () ->
  authenticateOrRejectWithChallenge(myUserPassAuthenticator, userName ->
    complete("Authenticated!")
  )
).seal(system(), materializer());

// tests:
testRoute(route).run(HttpRequest.GET("/secured"))
  .assertStatusCode(StatusCodes.UNAUTHORIZED)
  .assertEntity("The resource requires authentication, which was not supplied with the request")
  .assertHeaderExists("WWW-Authenticate", "MyAuth realm=\"MyRealm\"");

final HttpCredentials validCredentials =
  BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validCredentials))
  .assertStatusCode(StatusCodes.OK)
  .assertEntity("Authenticated!");
The source code for this page can be found here.