+htp #20535 add checkSameOrigin directive to HeaderDirectives (#20560)

*  #20535 add checkSameOrigin directive to WebSocketDirectives

* refactoring + add docs

* refactoring + cleanup in docs

* fix types and conversions in the InvalidOriginHeaderRejection

* simplify InvalidOriginHeaderRejection to InvalidOriginRejection
This commit is contained in:
tjugo 2016-06-02 13:58:20 +04:00 committed by Konrad Malawski
parent 8ba36be6c4
commit 0eda4075ef
16 changed files with 237 additions and 27 deletions

View file

@ -13,12 +13,13 @@ import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.StatusCodes;
import akka.http.javadsl.model.headers.Host;
import akka.http.javadsl.model.headers.HttpOrigin;
import akka.http.javadsl.model.headers.HttpOriginRange;
import akka.http.javadsl.model.headers.Origin;
import akka.http.javadsl.model.headers.RawHeader;
import akka.http.javadsl.server.Rejections;
import akka.http.javadsl.server.Route;
import akka.http.javadsl.testkit.JUnitRouteTest;
import akka.japi.JavaPartialFunction;
import akka.http.javadsl.testkit.TestRoute;
import scala.PartialFunction;
public class HeaderDirectivesExamplesTest extends JUnitRouteTest {
@ -227,4 +228,34 @@ public class HeaderDirectivesExamplesTest extends JUnitRouteTest {
.assertEntity("The port was not provided explicitly");
//#optionalHeaderValuePF
}
@Test
public void testCheckSameOrigin() {
//#checkSameOrigin
final HttpOrigin validOriginHeader =
HttpOrigin.create("http://localhost", Host.create("8080"));
final HttpOriginRange validOriginRange = HttpOriginRange.create(validOriginHeader);
final TestRoute route = testRoute(
checkSameOrigin(validOriginRange,
() -> complete("Result")));
route
.run(HttpRequest.create().addHeader(Origin.create(validOriginHeader)))
.assertStatusCode(StatusCodes.OK)
.assertEntity("Result");
route
.run(HttpRequest.create())
.assertStatusCode(StatusCodes.BAD_REQUEST);
final HttpOrigin invalidOriginHeader =
HttpOrigin.create("http://invalid.com", Host.create("8080"));
route
.run(HttpRequest.create().addHeader(Origin.create(invalidOriginHeader)))
.assertStatusCode(StatusCodes.FORBIDDEN);
//#checkSameOrigin
}
}

View file

@ -19,6 +19,7 @@ Directive Description
:ref:`-authorizeAsync-java-` Applies the given asynchronous authorization check to the request
:ref:`-cancelRejection-java-` Adds a ``TransformationRejection`` cancelling all rejections equal to the given one to the rejections potentially coming back from the inner route.
:ref:`-cancelRejections-java-` Adds a ``TransformationRejection`` cancelling all matching rejections to the rejections potentially coming back from the inner route
:ref:`-checkSameOrigin-java-` Checks that the request comes from the same origin
:ref:`-complete-java-` Completes the request using the given arguments
:ref:`-completeOrRecoverWith-java-` "Unwraps" a ``CompletionStage<T>`` and runs the inner route when the future has failed with the error as an extraction of type ``Throwable``
:ref:`-completeWith-java-` Uses the marshaller for a given type to extract a completion function

View file

@ -0,0 +1,17 @@
.. _-checkSameOrigin-java-:
checkSameOrigin
===============
Description
-----------
Checks that request comes from the same origin. Extracts the ``Origin`` header value and verifies that allowed range
contains the obtained value. In the case of absent of the ``Origin`` header rejects with a ``MissingHeaderRejection``.
If the origin value is not in the allowed range rejects with an ``InvalidOriginHeaderRejection``
and ``StatusCodes.FORBIDDEN`` status.
Example
-------
Checking the ``Origin`` header:
.. includecode:: ../../../../code/docs/http/javadsl/server/directives/HeaderDirectivesExamplesTest.java#checkSameOrigin

View file

@ -17,3 +17,4 @@ response headers use one of the :ref:`RespondWithDirectives-java`.
optionalHeaderValueByName
optionalHeaderValueByType
optionalHeaderValuePF
checkSameOrigin

View file

@ -4,13 +4,11 @@
package docs.http.scaladsl.server.directives
import akka.http.scaladsl.model.StatusCodes._
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.MissingHeaderRejection
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.server.util.ClassMagnet
import akka.http.scaladsl.model.headers._
import akka.http.scaladsl.server.{ InvalidOriginRejection, MissingHeaderRejection, Route }
import docs.http.scaladsl.server.RoutingSpec
import headers._
import StatusCodes._
import org.scalatest.Inside
class HeaderDirectivesExamplesSpec extends RoutingSpec with Inside {
@ -186,4 +184,38 @@ class HeaderDirectivesExamplesSpec extends RoutingSpec with Inside {
responseAs[String] shouldEqual "No Origin header found."
}
}
"checkSameOrigin-0" in {
val correctOrigin = HttpOrigin("http://localhost:8080")
val route = checkSameOrigin(HttpOriginRange(correctOrigin)) {
complete("Result")
}
// tests:
// handle request with correct origin headers
Get("abc") ~> Origin(correctOrigin) ~> route ~> check {
status shouldEqual StatusCodes.OK
responseAs[String] shouldEqual "Result"
}
// reject request with missed origin header
Get("abc") ~> route ~> check {
inside(rejection) {
case MissingHeaderRejection(headerName) headerName shouldEqual Origin.name
}
}
// rejects request with invalid origin headers
val invalidHttpOrigin = HttpOrigin("http://invalid.com")
val invalidOriginHeader = Origin(invalidHttpOrigin)
Get("abc") ~> invalidOriginHeader ~> route ~> check {
inside(rejection) {
case InvalidOriginRejection(invalidOrigins)
invalidOrigins shouldEqual Seq(invalidHttpOrigin)
}
}
Get("abc") ~> invalidOriginHeader ~> Route.seal(route) ~> check {
status shouldEqual StatusCodes.Forbidden
responseAs[String] should include(s"${invalidHttpOrigin.value}")
}
}
}

View file

@ -29,6 +29,7 @@ Directive Description
given one to the rejections potentially coming back from the inner route.
:ref:`-cancelRejections-` Adds a ``TransformationRejection`` cancelling all matching rejections
to the rejections potentially coming back from the inner route
:ref:`-checkSameOrigin-` Checks that the request comes from the same origin
:ref:`-complete-` Completes the request using the given arguments
:ref:`-completeOrRecoverWith-` "Unwraps" a ``Future[T]`` and runs the inner route when the future has
failed with the error as an extraction of type ``Throwable``

View file

@ -0,0 +1,23 @@
.. _-checkSameOrigin-:
checkSameOrigin
===============
Signature
---------
.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/server/directives/HeaderDirectives.scala
:snippet: checkSameOrigin
Description
-----------
Checks that request comes from the same origin. Extracts the ``Origin`` header value and verifies that allowed range
contains the obtained value. In the case of absent of the ``Origin`` header rejects with a ``MissingHeaderRejection``.
If the origin value is not in the allowed range rejects with an ``InvalidOriginHeaderRejection``
and ``StatusCodes.Forbidden`` status.
Example
-------
.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/HeaderDirectivesExamplesSpec.scala
:snippet: checkSameOrigin-0

View file

@ -17,3 +17,4 @@ response headers use one of the :ref:`RespondWithDirectives`.
optionalHeaderValueByName
optionalHeaderValueByType
optionalHeaderValuePF
checkSameOrigin