=doc #18968 Document auth options for Java DSL
This commit is contained in:
parent
696cfed51f
commit
af2bc368a2
6 changed files with 247 additions and 1 deletions
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||||
|
*/
|
||||||
|
package docs.http.javadsl.server;
|
||||||
|
|
||||||
|
import akka.http.javadsl.model.HttpRequest;
|
||||||
|
import akka.http.javadsl.model.headers.Host;
|
||||||
|
import akka.http.javadsl.server.Handler1;
|
||||||
|
import akka.http.javadsl.server.RequestContext;
|
||||||
|
import akka.http.javadsl.server.Route;
|
||||||
|
import akka.http.javadsl.server.RouteResult;
|
||||||
|
import akka.http.javadsl.server.values.BasicCredentials;
|
||||||
|
import akka.http.javadsl.server.values.HttpBasicAuthenticator;
|
||||||
|
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||||
|
import akka.http.scaladsl.model.headers.Authorization;
|
||||||
|
import org.junit.Test;
|
||||||
|
import scala.Option;
|
||||||
|
import scala.concurrent.Future;
|
||||||
|
|
||||||
|
public class HttpBasicAuthenticatorExample extends JUnitRouteTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicAuthenticator() {
|
||||||
|
//#basic-authenticator-java
|
||||||
|
final HttpBasicAuthenticator<String> authentication = new HttpBasicAuthenticator<String>("My realm") {
|
||||||
|
|
||||||
|
private final String hardcodedPassword = "correcthorsebatterystaple";
|
||||||
|
|
||||||
|
public Future<Option<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);
|
||||||
|
|
||||||
|
//#basic-authenticator-java
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
||||||
|
*/
|
||||||
|
package docs.http.javadsl.server;
|
||||||
|
|
||||||
|
import akka.http.javadsl.model.HttpRequest;
|
||||||
|
import akka.http.javadsl.model.headers.Host;
|
||||||
|
import akka.http.javadsl.model.headers.OAuth2BearerToken;
|
||||||
|
import akka.http.javadsl.server.Handler1;
|
||||||
|
import akka.http.javadsl.server.RequestContext;
|
||||||
|
import akka.http.javadsl.server.Route;
|
||||||
|
import akka.http.javadsl.server.RouteResult;
|
||||||
|
import akka.http.javadsl.server.values.BasicCredentials;
|
||||||
|
import akka.http.javadsl.server.values.HttpBasicAuthenticator;
|
||||||
|
import akka.http.javadsl.server.values.OAuth2Authenticator;
|
||||||
|
import akka.http.javadsl.server.values.OAuth2Credentials;
|
||||||
|
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||||
|
import akka.http.scaladsl.model.headers.Authorization;
|
||||||
|
import org.junit.Test;
|
||||||
|
import scala.Option;
|
||||||
|
import scala.concurrent.Future;
|
||||||
|
|
||||||
|
public class OAuth2AuthenticatorExample extends JUnitRouteTest {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOAuth2Authenticator() {
|
||||||
|
//#oauth2-authenticator-java
|
||||||
|
final OAuth2Authenticator<String> authentication = new OAuth2Authenticator<String>("My realm") {
|
||||||
|
|
||||||
|
private final String hardcodedToken = "token";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<Option<String>> authenticate(OAuth2Credentials credentials) {
|
||||||
|
// this is where your actual authentication logic would go, looking up the user
|
||||||
|
// based on the token or something in that direction
|
||||||
|
if (credentials.available() && // no anonymous access
|
||||||
|
credentials.verify(hardcodedToken)) {
|
||||||
|
// not a secret + identity pair, so this is actually the token
|
||||||
|
return authenticateAs(credentials.identifier());
|
||||||
|
} else {
|
||||||
|
return refuseAccess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
final Route route =
|
||||||
|
authentication.route(
|
||||||
|
handleWith1(
|
||||||
|
authentication,
|
||||||
|
new Handler1<String>() {
|
||||||
|
public RouteResult apply(RequestContext ctx, String token) {
|
||||||
|
return ctx.complete("The secret token is: " + token);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// tests:
|
||||||
|
final HttpRequest okRequest =
|
||||||
|
HttpRequest
|
||||||
|
.GET("http://akka.io/")
|
||||||
|
.addHeader(Host.create("akka.io"))
|
||||||
|
.addHeader(Authorization.oauth2("token"));
|
||||||
|
testRoute(route).run(okRequest).assertEntity("The secret token is: token");
|
||||||
|
|
||||||
|
final HttpRequest badRequest =
|
||||||
|
HttpRequest
|
||||||
|
.GET("http://akka.io/")
|
||||||
|
.addHeader(Host.create("akka.io"))
|
||||||
|
.addHeader(Authorization.oauth2("wrong"));
|
||||||
|
testRoute(route).run(badRequest).assertStatusCode(401);
|
||||||
|
|
||||||
|
//#oauth2-authenticator-java
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
.. _http-basic-authenticator-java:
|
||||||
|
|
||||||
|
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 ``Future``
|
||||||
|
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`_ .
|
||||||
|
|
||||||
|
.. _Timing Attacks Explained: http://emerose.com/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).
|
||||||
|
|
||||||
|
|
||||||
|
.. includecode:: ../../../code/docs/http/javadsl/server/HttpBasicAuthenticatorExample.java
|
||||||
|
:include: basic-authenticator-java
|
||||||
|
|
@ -43,6 +43,10 @@ akka.http.javadsl.server.values.FormFieldsPathMatchers
|
||||||
Contains request values to match and access URI path segments.
|
Contains request values to match and access URI path segments.
|
||||||
akka.http.javadsl.server.values.FormFieldsCustomRequestVal
|
akka.http.javadsl.server.values.FormFieldsCustomRequestVal
|
||||||
An abstract class to implement arbitrary custom request values.
|
An abstract class to implement arbitrary custom request values.
|
||||||
|
:ref:`akka.http.javadsl.server.values.HttpBasicAuthenticator.scala <http-basic-authenticator-java>`
|
||||||
|
An abstract class to implement HTTP basic authentication
|
||||||
|
:ref:`akka.http.javadsl.server.values.OAuth2Authenticator <oauth2-authenticator-java>`
|
||||||
|
An abstract class to implement Oauth 2 bearer token authentication
|
||||||
|
|
||||||
See also
|
See also
|
||||||
--------
|
--------
|
||||||
|
|
@ -52,3 +56,5 @@ See also
|
||||||
|
|
||||||
form-field-request-vals
|
form-field-request-vals
|
||||||
header-request-vals
|
header-request-vals
|
||||||
|
http-basic-authenticator
|
||||||
|
oauth2-authenticator
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
.. _oauth2-authenticator-java:
|
||||||
|
|
||||||
|
Request Values: OAuth 2 Bearer Token Authentication
|
||||||
|
===================================================
|
||||||
|
|
||||||
|
An abstract class to implement Oauth 2 bearer token authentication
|
||||||
|
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
Allows to protect one of more routes with authentication in the form of a OAuth2 Bearer Token. For more information
|
||||||
|
about OAuth 2 Bearer Token see `RFC6750`_.
|
||||||
|
|
||||||
|
.. _RFC6750: https://tools.ietf.org/html/rfc6750
|
||||||
|
|
||||||
|
To use it you subclass ``OAutht2Authenticator`` and implement the ``authenticate`` method
|
||||||
|
to provide your own logic which verifies the OAuth2 credentials. When verification is done
|
||||||
|
the request can either be refused by returning the return value of ``refuseAccess()`` or completed
|
||||||
|
with an object that is application specific by returning the return value of ``authenticateAs(T)``.
|
||||||
|
|
||||||
|
If the authentication is not very quick in memory, for example calls a separate authentication server
|
||||||
|
to verify the token, make sure you do not block the web server thread by executing that in a separate ``Future``
|
||||||
|
and then ``flatMap`` the result into the authentication result.
|
||||||
|
|
||||||
|
.. note:: OAuth2 Bearer Token sends the token as clear text and should ONLY EVER be used over
|
||||||
|
SSL/TLS
|
||||||
|
|
||||||
|
When you use the OAuth2 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 token 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`_ .
|
||||||
|
|
||||||
|
.. _Timing Attacks Explained: http://emerose.com/timing-attacks-explained
|
||||||
|
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
Authenticating or refusing access to a user based on a hardcoded token and using a ``String`` with the
|
||||||
|
identity as internal representation of a user (in a real application it would probably be an instance of
|
||||||
|
a richer class describing an authenticated user).
|
||||||
|
|
||||||
|
|
||||||
|
.. includecode:: ../../../code/docs/http/javadsl/server/OAuth2AuthenticatorExample.java
|
||||||
|
:include: oauth2-authenticator-java
|
||||||
|
|
@ -19,6 +19,6 @@ object TestUtils {
|
||||||
|
|
||||||
def temporaryServerHostnameAndPort(interface: String = "127.0.0.1"): (String, Int) = {
|
def temporaryServerHostnameAndPort(interface: String = "127.0.0.1"): (String, Int) = {
|
||||||
val socketAddress = temporaryServerAddress(interface)
|
val socketAddress = temporaryServerAddress(interface)
|
||||||
socketAddress.getHostName -> socketAddress.getPort // TODO getHostString in Java7
|
socketAddress.getHostName -> socketAddress.getPort // TODO getHostString in Java7
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue