+doc example snippet for akka http java dsl: SecurityDirectives (#20717)
This commit is contained in:
parent
f246c56087
commit
cc22ed4560
13 changed files with 442 additions and 11 deletions
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2016 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
package docs.http.javadsl.server.directives;
|
||||
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.model.StatusCodes;
|
||||
import akka.http.javadsl.model.headers.BasicHttpCredentials;
|
||||
import akka.http.javadsl.model.headers.HttpChallenge;
|
||||
import akka.http.javadsl.model.headers.HttpCredentials;
|
||||
import akka.http.javadsl.server.Route;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.japi.JavaPartialFunction;
|
||||
import org.junit.Test;
|
||||
import scala.PartialFunction;
|
||||
import scala.util.Either;
|
||||
import scala.util.Left;
|
||||
import scala.util.Right;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.function.Function;
|
||||
import java.util.Optional;
|
||||
|
||||
public class SecurityDirectivesExamplesTest extends JUnitRouteTest {
|
||||
|
||||
@Test
|
||||
public void testAuthenticateBasic() {
|
||||
//#authenticateBasic
|
||||
final Function<Optional<ProvidedCredentials>, Optional<String>> myUserPassAuthenticator =
|
||||
credentials ->
|
||||
credentials.filter(c -> c.verify("p4ssw0rd")).map(ProvidedCredentials::identifier);
|
||||
|
||||
final Route route = path("secured", () ->
|
||||
authenticateBasic("secure site", myUserPassAuthenticator, userName ->
|
||||
complete("The user is '" + userName + "'")
|
||||
)
|
||||
).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", "Basic realm=\"secure site\"");
|
||||
|
||||
final HttpCredentials validCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validCredentials))
|
||||
.assertEntity("The user is 'John'");
|
||||
|
||||
final HttpCredentials invalidCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(invalidCredentials))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The supplied authentication is invalid")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
//#authenticateBasic
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAuthenticateBasicPF() {
|
||||
//#authenticateBasicPF
|
||||
final PartialFunction<Optional<ProvidedCredentials>, String> myUserPassAuthenticator =
|
||||
new JavaPartialFunction<Optional<ProvidedCredentials>, String>() {
|
||||
@Override
|
||||
public String apply(Optional<ProvidedCredentials> opt, boolean isCheck) throws Exception {
|
||||
if (opt.filter(c -> (c != null) && c.verify("p4ssw0rd")).isPresent()) {
|
||||
if (isCheck) return null;
|
||||
else return opt.get().identifier();
|
||||
} else if (opt.filter(c -> (c != null) && c.verify("p4ssw0rd-special")).isPresent()) {
|
||||
if (isCheck) return null;
|
||||
else return opt.get().identifier() + "-admin";
|
||||
} else {
|
||||
throw noMatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = path("secured", () ->
|
||||
authenticateBasicPF("secure site", myUserPassAuthenticator, userName ->
|
||||
complete("The user is '" + userName + "'")
|
||||
)
|
||||
).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", "Basic realm=\"secure site\"");
|
||||
|
||||
final HttpCredentials validCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validCredentials))
|
||||
.assertEntity("The user is 'John'");
|
||||
|
||||
final HttpCredentials validAdminCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd-special");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validAdminCredentials))
|
||||
.assertEntity("The user is 'John-admin'");
|
||||
|
||||
final HttpCredentials invalidCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(invalidCredentials))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The supplied authentication is invalid")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
//#authenticateBasicPF
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateBasicPFAsync() {
|
||||
//#authenticateBasicPFAsync
|
||||
class User {
|
||||
private final String id;
|
||||
public User(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
final PartialFunction<Optional<ProvidedCredentials>, CompletionStage<User>> myUserPassAuthenticator =
|
||||
new JavaPartialFunction<Optional<ProvidedCredentials>,CompletionStage<User>>() {
|
||||
@Override
|
||||
public CompletionStage<User> apply(Optional<ProvidedCredentials> opt, boolean isCheck) throws Exception {
|
||||
if (opt.filter(c -> (c != null) && c.verify("p4ssw0rd")).isPresent()) {
|
||||
if (isCheck) return CompletableFuture.completedFuture(null);
|
||||
else return CompletableFuture.completedFuture(new User(opt.get().identifier()));
|
||||
} else {
|
||||
throw noMatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = path("secured", () ->
|
||||
authenticateBasicPFAsync("secure site", myUserPassAuthenticator, user ->
|
||||
complete("The user is '" + user.getId() + "'"))
|
||||
).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", "Basic realm=\"secure site\"");
|
||||
|
||||
final HttpCredentials validCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validCredentials))
|
||||
.assertEntity("The user is 'John'");
|
||||
|
||||
final HttpCredentials invalidCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(invalidCredentials))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The supplied authentication is invalid")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
//#authenticateBasicPFAsync
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateBasicAsync() {
|
||||
//#authenticateBasicAsync
|
||||
final Function<Optional<ProvidedCredentials>, CompletionStage<Optional<String>>> myUserPassAuthenticator = opt -> {
|
||||
if (opt.filter(c -> (c != null) && c.verify("p4ssw0rd")).isPresent()) {
|
||||
return CompletableFuture.completedFuture(Optional.of(opt.get().identifier()));
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(Optional.empty());
|
||||
}
|
||||
};
|
||||
|
||||
final Route route = path("secured", () ->
|
||||
authenticateBasicAsync("secure site", myUserPassAuthenticator, userName ->
|
||||
complete("The user is '" + userName + "'")
|
||||
)
|
||||
).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", "Basic realm=\"secure site\"");
|
||||
|
||||
final HttpCredentials validCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(validCredentials))
|
||||
.assertEntity("The user is 'John'");
|
||||
|
||||
final HttpCredentials invalidCredentials =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/secured").addCredentials(invalidCredentials))
|
||||
.assertStatusCode(StatusCodes.UNAUTHORIZED)
|
||||
.assertEntity("The supplied authentication is invalid")
|
||||
.assertHeaderExists("WWW-Authenticate", "Basic realm=\"secure site\"");
|
||||
//#authenticateBasicAsync
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateOrRejectWithChallenge() {
|
||||
//#authenticateOrRejectWithChallenge
|
||||
final HttpChallenge challenge = HttpChallenge.create("MyAuth", "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!");
|
||||
//#authenticateOrRejectWithChallenge
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthorize() {
|
||||
//#authorize
|
||||
class User {
|
||||
private final String name;
|
||||
public User(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// authenticate the user:
|
||||
final Function<Optional<ProvidedCredentials>, Optional<User>> myUserPassAuthenticator =
|
||||
opt -> {
|
||||
if (opt.isPresent()) {
|
||||
return Optional.of(new User(opt.get().identifier()));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
};
|
||||
|
||||
// check if user is authorized to perform admin actions:
|
||||
final Set<String> admins = new HashSet<>();
|
||||
admins.add("Peter");
|
||||
final Function<User, Boolean> hasAdminPermissions = user -> admins.contains(user.getName());
|
||||
|
||||
final Route route = authenticateBasic("secure site", myUserPassAuthenticator, user ->
|
||||
path("peters-lair", () ->
|
||||
authorize(() -> hasAdminPermissions.apply(user), () ->
|
||||
complete("'" + user.getName() +"' visited Peter's lair")
|
||||
)
|
||||
)
|
||||
).seal(system(), materializer());
|
||||
|
||||
// tests:
|
||||
final HttpCredentials johnsCred =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/peters-lair").addCredentials(johnsCred))
|
||||
.assertStatusCode(StatusCodes.FORBIDDEN)
|
||||
.assertEntity("The supplied authentication is not authorized to access this resource");
|
||||
|
||||
final HttpCredentials petersCred =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/peters-lair").addCredentials(petersCred))
|
||||
.assertEntity("'Peter' visited Peter's lair");
|
||||
//#authorize
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthorizeAsync() {
|
||||
//#authorizeAsync
|
||||
class User {
|
||||
private final String name;
|
||||
public User(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// authenticate the user:
|
||||
final Function<Optional<ProvidedCredentials>, Optional<User>> myUserPassAuthenticator =
|
||||
opt -> {
|
||||
if (opt.isPresent()) {
|
||||
return Optional.of(new User(opt.get().identifier()));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
};
|
||||
|
||||
// check if user is authorized to perform admin actions,
|
||||
// this could potentially be a long operation so it would return a Future
|
||||
final Set<String> admins = new HashSet<>();
|
||||
admins.add("Peter");
|
||||
final Set<String> synchronizedAdmins = Collections.synchronizedSet(admins);
|
||||
|
||||
final Function<User, CompletionStage<Object>> hasAdminPermissions =
|
||||
user -> CompletableFuture.completedFuture(synchronizedAdmins.contains(user.getName()));
|
||||
|
||||
final Route route = authenticateBasic("secure site", myUserPassAuthenticator, user ->
|
||||
path("peters-lair", () ->
|
||||
authorizeAsync(() -> hasAdminPermissions.apply(user), () ->
|
||||
complete("'" + user.getName() +"' visited Peter's lair")
|
||||
)
|
||||
)
|
||||
).seal(system(), materializer());
|
||||
|
||||
// tests:
|
||||
final HttpCredentials johnsCred =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/peters-lair").addCredentials(johnsCred))
|
||||
.assertStatusCode(StatusCodes.FORBIDDEN)
|
||||
.assertEntity("The supplied authentication is not authorized to access this resource");
|
||||
|
||||
final HttpCredentials petersCred =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("Peter", "pan");
|
||||
testRoute(route).run(HttpRequest.GET("/peters-lair").addCredentials(petersCred))
|
||||
.assertEntity("'Peter' visited Peter's lair");
|
||||
//#authorizeAsync
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractCredentials() {
|
||||
//#extractCredentials
|
||||
final Route route = extractCredentials(optCreds -> {
|
||||
if (optCreds.isPresent()) {
|
||||
return complete("Credentials: " + optCreds.get());
|
||||
} else {
|
||||
return complete("No credentials");
|
||||
}
|
||||
});
|
||||
|
||||
// tests:
|
||||
final HttpCredentials johnsCred =
|
||||
BasicHttpCredentials.createBasicHttpCredentials("John", "p4ssw0rd");
|
||||
testRoute(route).run(HttpRequest.GET("/").addCredentials(johnsCred))
|
||||
.assertEntity("Credentials: Basic Sm9objpwNHNzdzByZA==");
|
||||
|
||||
testRoute(route).run(HttpRequest.GET("/"))
|
||||
.assertEntity("No credentials");
|
||||
//#extractCredentials
|
||||
}
|
||||
}
|
||||
|
|
@ -27,4 +27,5 @@ See :ref:`credentials-and-timing-attacks-java` for details about verifying the s
|
|||
|
||||
Example
|
||||
-------
|
||||
TODO: Example snippets for JavaDSL are subject to community contributions! Help us complete the docs, read more about it here: `write example snippets for Akka HTTP Java DSL #20466 <https://github.com/akka/akka/issues/20466>`_.
|
||||
|
||||
.. includecode:: ../../../../code/docs/http/javadsl/server/directives/SecurityDirectivesExamplesTest.java#authenticateBasic
|
||||
|
|
|
|||
|
|
@ -25,4 +25,5 @@ See :ref:`credentials-and-timing-attacks-java` for details about verifying the s
|
|||
|
||||
Example
|
||||
-------
|
||||
TODO: Example snippets for JavaDSL are subject to community contributions! Help us complete the docs, read more about it here: `write example snippets for Akka HTTP Java DSL #20466 <https://github.com/akka/akka/issues/20466>`_.
|
||||
|
||||
.. includecode:: ../../../../code/docs/http/javadsl/server/directives/SecurityDirectivesExamplesTest.java#authenticateBasicAsync
|
||||
|
|
|
|||
|
|
@ -25,4 +25,5 @@ See :ref:`credentials-and-timing-attacks-java` for details about verifying the s
|
|||
|
||||
Example
|
||||
-------
|
||||
TODO: Example snippets for JavaDSL are subject to community contributions! Help us complete the docs, read more about it here: `write example snippets for Akka HTTP Java DSL #20466 <https://github.com/akka/akka/issues/20466>`_.
|
||||
|
||||
.. includecode:: ../../../../code/docs/http/javadsl/server/directives/SecurityDirectivesExamplesTest.java#authenticateBasicPF
|
||||
|
|
|
|||
|
|
@ -22,4 +22,5 @@ See :ref:`credentials-and-timing-attacks-java` for details about verifying the s
|
|||
|
||||
Example
|
||||
-------
|
||||
TODO: Example snippets for JavaDSL are subject to community contributions! Help us complete the docs, read more about it here: `write example snippets for Akka HTTP Java DSL #20466 <https://github.com/akka/akka/issues/20466>`_.
|
||||
|
||||
.. includecode:: ../../../../code/docs/http/javadsl/server/directives/SecurityDirectivesExamplesTest.java#authenticateBasicPFAsync
|
||||
|
|
|
|||
|
|
@ -16,4 +16,5 @@ More details about challenge-response authentication are available in the `RFC 2
|
|||
|
||||
Example
|
||||
-------
|
||||
TODO: Example snippets for JavaDSL are subject to community contributions! Help us complete the docs, read more about it here: `write example snippets for Akka HTTP Java DSL #20466 <https://github.com/akka/akka/issues/20466>`_.
|
||||
|
||||
.. includecode:: ../../../../code/docs/http/javadsl/server/directives/SecurityDirectivesExamplesTest.java#authenticateOrRejectWithChallenge
|
||||
|
|
|
|||
|
|
@ -24,4 +24,5 @@ See also :ref:`-authorize-java-` for the asynchronous version of this directive.
|
|||
|
||||
Example
|
||||
-------
|
||||
TODO: Example snippets for JavaDSL are subject to community contributions! Help us complete the docs, read more about it here: `write example snippets for Akka HTTP Java DSL #20466 <https://github.com/akka/akka/issues/20466>`_.
|
||||
|
||||
.. includecode:: ../../../../code/docs/http/javadsl/server/directives/SecurityDirectivesExamplesTest.java#authorize
|
||||
|
|
|
|||
|
|
@ -25,4 +25,5 @@ See also :ref:`-authorize-java-` for the synchronous version of this directive.
|
|||
|
||||
Example
|
||||
-------
|
||||
TODO: Example snippets for JavaDSL are subject to community contributions! Help us complete the docs, read more about it here: `write example snippets for Akka HTTP Java DSL #20466 <https://github.com/akka/akka/issues/20466>`_.
|
||||
|
||||
.. includecode:: ../../../../code/docs/http/javadsl/server/directives/SecurityDirectivesExamplesTest.java#authorizeAsync
|
||||
|
|
|
|||
|
|
@ -13,4 +13,5 @@ See :ref:`credentials-and-timing-attacks-java` for details about verifying the s
|
|||
|
||||
Example
|
||||
-------
|
||||
TODO: Example snippets for JavaDSL are subject to community contributions! Help us complete the docs, read more about it here: `write example snippets for Akka HTTP Java DSL #20466 <https://github.com/akka/akka/issues/20466>`_.
|
||||
|
||||
.. includecode:: ../../../../code/docs/http/javadsl/server/directives/SecurityDirectivesExamplesTest.java#extractCredentials
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package akka.http.javadsl.model;
|
|||
|
||||
import akka.Done;
|
||||
import akka.stream.Materializer;
|
||||
import akka.http.javadsl.model.headers.HttpCredentials;
|
||||
import akka.util.ByteString;
|
||||
import scala.concurrent.Future;
|
||||
|
||||
|
|
@ -113,6 +114,11 @@ public interface HttpMessage {
|
|||
*/
|
||||
Self addHeaders(Iterable<HttpHeader> headers);
|
||||
|
||||
/**
|
||||
* Returns a copy of this message with the given http credential header added to the list of headers.
|
||||
*/
|
||||
Self addCredentials(HttpCredentials credentials);
|
||||
|
||||
/**
|
||||
* Returns a copy of this message with all headers of the given name (case-insensitively) removed.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -109,6 +109,8 @@ sealed trait HttpMessage extends jm.HttpMessage {
|
|||
|
||||
def addHeader(header: jm.HttpHeader): Self = mapHeaders(_ :+ header.asInstanceOf[HttpHeader])
|
||||
|
||||
def addCredentials(credentials: jm.headers.HttpCredentials): Self = addHeader(jm.headers.Authorization.create(credentials))
|
||||
|
||||
/** Removes the header with the given name (case-insensitive) */
|
||||
def removeHeader(headerName: String): Self = {
|
||||
val lowerHeaderName = headerName.toRootLowerCase
|
||||
|
|
|
|||
|
|
@ -12,9 +12,11 @@ import scala.compat.java8.FutureConverters._
|
|||
import scala.compat.java8.OptionConverters._
|
||||
import akka.http.javadsl.model.headers.HttpChallenge
|
||||
import akka.http.javadsl.model.headers.HttpCredentials
|
||||
import akka.http.javadsl.server.{ RequestContext, Route }
|
||||
import akka.http.javadsl.server.{ Route, RequestContext }
|
||||
import akka.http.scaladsl
|
||||
import akka.http.scaladsl.server.{ AuthorizationFailedRejection, Directives ⇒ D }
|
||||
import akka.http.scaladsl.server.{ Directives ⇒ D }
|
||||
|
||||
import scala.concurrent.{ ExecutionContextExecutor, Future }
|
||||
|
||||
object SecurityDirectives {
|
||||
/**
|
||||
|
|
@ -68,6 +70,50 @@ abstract class SecurityDirectives extends SchemeDirectives {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the inner route with Http Basic authentication support.
|
||||
* The given authenticator determines whether the credentials in the request are valid
|
||||
* and, if so, which user object to supply to the inner route.
|
||||
*
|
||||
* Authentication is required in this variant, i.e. the request is rejected if [authenticator] returns Optional.empty.
|
||||
*/
|
||||
def authenticateBasicPF[T](realm: String, authenticator: PartialFunction[Optional[ProvidedCredentials], T],
|
||||
inner: JFunction[T, Route]): Route = RouteAdapter {
|
||||
def pf: PartialFunction[scaladsl.server.directives.Credentials, Option[T]] = {
|
||||
case c ⇒ Option(authenticator.applyOrElse(toJava(c), (_: Any) ⇒ null.asInstanceOf[T]))
|
||||
}
|
||||
|
||||
D.authenticateBasic(realm, pf) { t ⇒
|
||||
inner.apply(t).delegate
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the inner route with Http Basic authentication support.
|
||||
* The given authenticator determines whether the credentials in the request are valid
|
||||
* and, if so, which user object to supply to the inner route.
|
||||
*
|
||||
* Authentication is required in this variant, i.e. the request is rejected if [authenticator] returns Optional.empty.
|
||||
*/
|
||||
def authenticateBasicPFAsync[T](realm: String, authenticator: PartialFunction[Optional[ProvidedCredentials], CompletionStage[T]],
|
||||
inner: JFunction[T, Route]): Route = RouteAdapter {
|
||||
def pf(implicit ec: ExecutionContextExecutor): PartialFunction[scaladsl.server.directives.Credentials, Future[Option[T]]] = {
|
||||
case credentials ⇒
|
||||
val jCredentials = toJava(credentials)
|
||||
if (authenticator isDefinedAt jCredentials) {
|
||||
authenticator(jCredentials).toScala.map(Some(_))
|
||||
} else {
|
||||
Future.successful(None)
|
||||
}
|
||||
}
|
||||
|
||||
D.extractExecutionContext { implicit ec ⇒
|
||||
D.authenticateBasicAsync(realm, pf) { t ⇒
|
||||
inner.apply(t).delegate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the inner route with Http Basic authentication support using a given `Authenticator[T]`.
|
||||
* The given authenticator determines whether the credentials in the request are valid
|
||||
|
|
|
|||
|
|
@ -886,6 +886,11 @@ object MiMa extends AutoPlugin {
|
|||
|
||||
// #20288 migrate BodyPartRenderer to GraphStage
|
||||
ProblemFilters.exclude[IncompatibleResultTypeProblem]("akka.http.impl.engine.rendering.BodyPartRenderer.streamed")
|
||||
),
|
||||
"2.4.8" -> Seq(
|
||||
// #20717 example snippet for akka http java dsl: SecurityDirectives
|
||||
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.http.javadsl.model.HttpMessage#MessageTransformations.addCredentials"),
|
||||
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.http.scaladsl.model.HttpMessage.addCredentials")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue