diff --git a/src/docs/java/org/springframework/hateoas/ForwardedEnabledConfig.java b/src/docs/java/org/springframework/hateoas/ForwardedEnabledConfig.java new file mode 100644 index 00000000..143d9675 --- /dev/null +++ b/src/docs/java/org/springframework/hateoas/ForwardedEnabledConfig.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.hateoas; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.filter.ForwardedHeaderFilter; +import org.springframework.web.server.adapter.ForwardedHeaderTransformer; + +/** + * @author Greg Turnquist + */ +@Configuration +public class ForwardedEnabledConfig { + + // tag::code-1[] + @Bean + ForwardedHeaderFilter forwardedHeaderFilter() { + return new ForwardedHeaderFilter(); + } + // end::code-1[] + + // tag::code-2[] + @Bean + ForwardedHeaderTransformer forwardedHeaderTransformer() { + return new ForwardedHeaderTransformer(); + } + // end::code-2[] +} diff --git a/src/main/asciidoc/configuration.adoc b/src/main/asciidoc/configuration.adoc new file mode 100644 index 00000000..419cc154 --- /dev/null +++ b/src/main/asciidoc/configuration.adoc @@ -0,0 +1,124 @@ +[[configuration]] += Configuration +:code-dir: ../../../src/docs/java/org/springframework/hateoas +:resource-dir: ../../../src/docs/resources/org/springframework/hateoas + +This section describes how to configure Spring HATEOAS. + +[[configuration.at-enable]] +== Using `@EnableHypermediaSupport` + +To let the `RepresentationModel` subtypes be rendered according to the specification of various hypermedia representations types, you can activate support for a particular hypermedia representation format through `@EnableHypermediaSupport`. The annotation takes a `HypermediaType` enumeration as its argument. Currently, we support http://tools.ietf.org/html/draft-kelly-json-hal[HAL] as well as a default rendering. Using the annotation triggers the following: + +* It registers necessary Jackson modules to render `EntityModel` and `CollectionModel` in the hypermedia specific format. +* If JSONPath is on the classpath, it automatically registers a `LinkDiscoverer` instance to look up links by their `rel` in plain JSON representations (see <>). +* By default, it enables `@EnableEntityLinks` (see <>) and automatically picks up `EntityLinks` implementations and bundles them into a `DelegatingEntityLinks` instance that you can autowire. +* It automatically picks up all `RelProvider` implementations in the `ApplicationContext` and bundles them into a `DelegatingRelProvider` that you can autowire. It registers providers to consider `@Relation` on domain types as well as Spring MVC controllers. If the https://github.com/atteo/evo-inflector[EVO inflector] is on the classpath, collection `rel` values are derived by using the pluralizing algorithm implemented in the library (see <>). + +[[configuration.forwarded-headers]] +== Forwarded header handling + +Spring HATEOAS supports various https://tools.ietf.org/html/rfc7239[RFC-7239 forwarding headers]. They are most commonly used when your application is behind a proxy, behind +a load balancer, or in the cloud. The node that actually receives the web request is part of the infrastructure, and _forwards_ the request +to your application. + +Your application may be running on `localhost:8080`, but to the outside world, you're expected to be at `reallycoolsite.com` (and on +web's standart port 80). By having the proxy include extra headers (which many already do), Spring HATEOAS can transform its generated +links property. + +IMPORTANT: Anything that can change the root URI based on external inputs must be properly guarded. That's why, by default, forwarded +header handling is *disabled*. You MUST enable it to be operational. If you are deploying to the cloud or into a configuration where you +control the proxies and load balancers, then you'll certainly want to use this feature. + +To enable forwarded header handling in a Spring MVC application running inside Spring Boot, you only need add this to your configuration: + +.Registering a `ForwardedHeaderFilter` +==== +[source, java, tabsize=2, indent=0] +---- +include::{code-dir}/ForwardedEnabledConfig.java[tags=code-1] +---- +This will create a servlet filter that processes all the `X-Forwarded-*` headers. And it will register it properly with the servlet handlers. +==== + +For a Spring WebFlux application, the reactive counterpart is `ForwardedHeaderTransformer`: + +.Registering a `ForwardedHeaderTransformer` +==== +[source, java, tabsize=2, indent=0] +---- +include::{code-dir}/ForwardedEnabledConfig.java[tags=code-2] +---- +This will create a function that transforms reactive web requests, processing `X-Forwarded-*` headers. And it will register it properly +with WebFlux. +==== + +Once enabled, you'll be able to use: + +[cols='1,2', options="header"] +|=== +| Header +| Description + +| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded[Forwarded] +| Single header that let's you apply several forwarding attributes. + +| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host[X-Forwarded-Host] +| Originating hostname (NOTE: Does NOT include the port). + +| X-Forwarded-Port +| Originating port number + +| https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto[X-Forwarded-Proto] +| Originating protocol (e.g. `http` or `https`). + +| X-Forwarded-Prefix +| Originating prefix that was stripped off. + +| X-Forwarded-Ssl +| Originating SSL status (e.g. `on`). +|=== + +NOTE: `X-Forwarded-*` headers aren't governed by a spec, but are instead _de facto_ standards. `Forwarded` is governed by +https://tools.ietf.org/html/rfc7239[RFC 7239], a proposed spec aimed at consolidating forwarded header handling. + +You should be able to do this: + +---- +curl -v localhost:8080/employees \ + -H 'X-Forwarded-Proto: https' \ + -H 'X-Forwarded-Host: example.com' \ + -H 'X-Forwarded-Port: 9001' +---- + +...and expect to see hypermedia rendered like this: + +---- +{ + "_embedded": { + "employees": [ + { + "id": 1, + "name": "Bilbo Baggins", + "role": "burglar", + "_links": { + "self": { + "href": "https://example.com:9001/employees/1" + }, + "employees": { + "href": "https://example.com:9001/employees" + } + } + } + ] + }, + "_links": { + "self": { + "href": "https://example.com:9001/employees" + }, + "root": { + "href": "https://example.com:9001" + } + } +} +---- diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc index 3e820c89..61bb219b 100644 --- a/src/main/asciidoc/index.adoc +++ b/src/main/asciidoc/index.adoc @@ -17,21 +17,5 @@ include::migrate-to-1.0.adoc[leveloffset=+2] include::fundamentals.adoc[leveloffset=+1] include::mediatypes.adoc[leveloffset=+1] include::server.adoc[leveloffset=+1] - - -[[configuration]] -== Configuration - -This section describes how to configure Spring HATEOAS. - -[[configuration.at-enable]] -=== Using `@EnableHypermediaSupport` - -To let the `RepresentationModel` subtypes be rendered according to the specification of various hypermedia representations types, you can activate support for a particular hypermedia representation format through `@EnableHypermediaSupport`. The annotation takes a `HypermediaType` enumeration as its argument. Currently, we support https://tools.ietf.org/html/draft-kelly-json-hal[HAL] as well as a default rendering. Using the annotation triggers the following: - -* It registers necessary Jackson modules to render `EntityModel` and `CollectionModel` in the hypermedia specific format. -* If JSONPath is on the classpath, it automatically registers a `LinkDiscoverer` instance to look up links by their `rel` in plain JSON representations (see <>). -* By default, it enables `@EnableEntityLinks` (see <>) and automatically picks up `EntityLinks` implementations and bundles them into a `DelegatingEntityLinks` instance that you can autowire. -* It automatically picks up all `RelProvider` implementations in the `ApplicationContext` and bundles them into a `DelegatingRelProvider` that you can autowire. It registers providers to consider `@Relation` on domain types as well as Spring MVC controllers. If the https://github.com/atteo/evo-inflector[EVO inflector] is on the classpath, collection `rel` values are derived by using the pluralizing algorithm implemented in the library (see <>). - +include::configuration.adoc[leveloffset=+1] include::client.adoc[leveloffset=+1]