mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-31 03:49:31 -06:00
fix: adding support for xforwarded prefix (#45699)
closes: #35298 Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
@@ -12,6 +12,10 @@ In minor or patch releases, {project_name} will only introduce breaking changes
|
||||
Notable changes may include internal behavior changes that prevent common misconfigurations, bugs that are fixed, or changes to simplify running {project_name}.
|
||||
It also lists significant changes to internal APIs.
|
||||
|
||||
=== `X-Forwarded-Prefix` Header is now supported
|
||||
|
||||
With `proxy-headers` set to `xforwarded`, the server can determine the proxy context path from the `X-Forwarded-Prefix` header.
|
||||
|
||||
=== New database indexes on the `BROKER_LINK` table
|
||||
|
||||
The `BROKER_LINK` table now contains two additional indexes `IDX_BROKER_LINK_USER_ID` and `IDX_BROKER_LINK_IDENTITY_PROVIDER` to improve performance.
|
||||
|
||||
@@ -66,7 +66,7 @@ The `proxy-headers` option can be also used to resolve the URL partially dynamic
|
||||
|
||||
<@kc.start parameters="--hostname my.keycloak.org --proxy-headers xforwarded"/>
|
||||
|
||||
In this case, scheme, and port are resolved dynamically from X-Forwarded-* headers, while hostname is statically defined as `my.keycloak.org`.
|
||||
In this case, scheme, port, and context-path are resolved dynamically from X-Forwarded-* headers, while hostname is statically defined as `my.keycloak.org`.
|
||||
|
||||
=== Fixed URLs
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ You only need to proxy port `8443` (or `8080`) even when you use different host
|
||||
|
||||
* By default if the option is not specified, no reverse proxy headers are parsed. This should be used when no proxy is in use or with https passthrough.
|
||||
* `forwarded` enables parsing of the `Forwarded` header as per https://www.rfc-editor.org/rfc/rfc7239.html[RFC 7239].
|
||||
* `xforwarded` enables parsing of non-standard `X-Forwarded-*` headers, such as `X-Forwarded-For`, `X-Forwarded-Proto`, `X-Forwarded-Host`, and `X-Forwarded-Port`.
|
||||
* `xforwarded` enables parsing of non-standard `X-Forwarded-*` headers, such as `X-Forwarded-For`, `X-Forwarded-Proto`, `X-Forwarded-Host`, `X-Forwarded-Port`, and `X-Forwarded-Prefix`.
|
||||
|
||||
NOTE: If you are using a reverse proxy for anything other than https passthrough and do not set the `proxy-headers` option, then by default you will see 403 Forbidden responses to requests via the proxy that perform origin checking.
|
||||
|
||||
@@ -47,14 +47,14 @@ NOTE: When using the `xforwarded` setting, the `X-Forwarded-Port` takes preceden
|
||||
|
||||
NOTE: If the TLS connection is terminated at the reverse proxy (edge termination), enabling HTTP through the `http-enabled` setting is required.
|
||||
|
||||
== Different context-path on reverse proxy
|
||||
== Different context path on reverse proxy
|
||||
|
||||
{project_name} assumes it is exposed through the reverse proxy under the same context path as {project_name} is configured for. By default {project_name} is exposed through the root (`/`), which means it expects to be exposed through the reverse proxy on `/` as well.
|
||||
You can use a full URL for the `hostname` option in these cases, for example using `--hostname=https://my.keycloak.org/auth` if {project_name} is exposed through the reverse proxy on `/auth`.
|
||||
|
||||
For more details on exposing {project_name} on different hostname or context-path incl. Administration REST API and Console, see <@links.server id="hostname"/>.
|
||||
|
||||
Alternatively you can also change the context path of {project_name} itself to match the context path for the reverse proxy using the `http-relative-path` option, which will change the context-path of {project_name} itself to match the context path used by the reverse proxy.
|
||||
By default {project_name} is exposed through the root context path (`/`). If the proxy is using a different context path than {project_name}, one of the following must be done:
|
||||
- Use a simple hostname for the `hostname` option, `xforwarded` for the `proxy-headers` option, and have the proxy set the `X-Forwarded-Prefix` header.
|
||||
- Use a full URL for the `hostname` option including the proxy context path, for example using `--hostname=https://my.keycloak.org/auth` if {project_name} is exposed through the reverse proxy on `/auth`.
|
||||
- Change the context path of {project_name} itself to match the context path for the reverse proxy using the `http-relative-path` option.
|
||||
|
||||
For more details on exposing {project_name} on different hostname or context path incl. Administration REST API and Console, see <@links.server id="hostname"/>.
|
||||
|
||||
== Enable sticky sessions
|
||||
|
||||
@@ -141,7 +141,7 @@ The following table shows the recommended paths to expose.
|
||||
We assume you run {project_name} on the root path `/` on your reverse proxy/gateway's public API.
|
||||
If not, prefix the path with your desired one.
|
||||
|
||||
NOTE: If you configured a `http-relative-path` on the server, proceed as follows to use discovery wih RFC 8414: Configure a reverse proxy to map the `/.well-known/` path without the prefix to the path with the prefix on the server.
|
||||
NOTE: If you configured a `http-relative-path` on the server, proceed as follows to use discovery with RFC 8414: Configure a reverse proxy to map the `/.well-known/` path without the prefix to the path with the prefix on the server.
|
||||
|
||||
== Trusted Proxies
|
||||
|
||||
|
||||
@@ -35,6 +35,11 @@ public class ProxyOptions {
|
||||
.defaultValue(Boolean.FALSE)
|
||||
.build();
|
||||
|
||||
public static final Option<Boolean> PROXY_X_FORWARDED_PREFIX_HEADER_ENABLED = new OptionBuilder<>("proxy-allow-x-forwarded-prefix-header", Boolean.class)
|
||||
.category(OptionCategory.PROXY)
|
||||
.defaultValue(Boolean.FALSE)
|
||||
.build();
|
||||
|
||||
public static final Option<Boolean> PROXY_TRUSTED_HEADER_ENABLED = new OptionBuilder<>("proxy-trusted-header-enabled", Boolean.class)
|
||||
.category(OptionCategory.PROXY)
|
||||
.defaultValue(Boolean.FALSE)
|
||||
|
||||
@@ -41,6 +41,10 @@ final class ProxyPropertyMappers implements PropertyMapperGrouping{
|
||||
.to("quarkus.http.proxy.allow-x-forwarded")
|
||||
.mapFrom(ProxyOptions.PROXY_HEADERS, (v, c) -> proxyEnabled(ProxyOptions.Headers.xforwarded, v, c))
|
||||
.build(),
|
||||
fromOption(ProxyOptions.PROXY_X_FORWARDED_PREFIX_HEADER_ENABLED)
|
||||
.to("quarkus.http.proxy.enable-forwarded-prefix")
|
||||
.mapFrom(ProxyOptions.PROXY_HEADERS, (v, c) -> proxyEnabled(ProxyOptions.Headers.xforwarded, v, c))
|
||||
.build(),
|
||||
fromOption(ProxyOptions.PROXY_TRUSTED_HEADER_ENABLED)
|
||||
.to("quarkus.http.proxy.enable-trusted-proxy-header")
|
||||
.mapFrom(ProxyOptions.PROXY_HEADERS, (v, c) -> proxyEnabled(null, v, c))
|
||||
|
||||
@@ -27,7 +27,8 @@ public class ConstantsDebugHostname {
|
||||
"X-Forwarded-Host",
|
||||
"X-Forwarded-Proto",
|
||||
"X-Forwarded-Port",
|
||||
"X-Forwarded-For"
|
||||
"X-Forwarded-For",
|
||||
"X-Forwarded-Prefix"
|
||||
};
|
||||
|
||||
public static final String FORWARDED_PROXY_HEADER = "Forwarded";
|
||||
|
||||
@@ -121,6 +121,14 @@ public class ProxyHostnameV2DistTest {
|
||||
assertXForwardedHeaders();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Launch({ "start-dev", "--hostname=fixed", "--proxy-headers=xforwarded" })
|
||||
public void testXForwardedProxyHeadersWithHostname() {
|
||||
given().header("X-Forwarded-Prefix", "/prefix").when().get("http://localhost:8080").then().header(HttpHeaders.LOCATION, containsString("http://fixed:8080/prefix/admin"));
|
||||
given().header("X-Forwarded-Host", "test:123").when().get("https://localhost:8443").then().header(HttpHeaders.LOCATION, containsString("https://fixed:123/admin"));
|
||||
given().header("X-Forwarded-Proto", "https").when().get("http://localhost:8080").then().header(HttpHeaders.LOCATION, containsString("https://fixed/admin"));
|
||||
}
|
||||
|
||||
private void assertForwardedHeader() {
|
||||
// trigger a login error
|
||||
assertForwardedHeader("http://mykeycloak.org:8080/realms/master/protocol/openid-connect/auth?client_id=security-admin-console", "https://test:1234/admin", ADDRESS);
|
||||
@@ -139,6 +147,7 @@ public class ProxyHostnameV2DistTest {
|
||||
}
|
||||
|
||||
private void assertXForwardedHeaders() {
|
||||
given().header("X-Forwarded-Prefix", "/prefix").when().get("http://localhost:8080").then().header(HttpHeaders.LOCATION, containsString("http://localhost:8080/prefix/admin"));
|
||||
given().header("X-Forwarded-Host", "test:123").when().get("http://mykeycloak.org:8080").then().header(HttpHeaders.LOCATION, containsString("http://test:123/admin"));
|
||||
given().header("X-Forwarded-Host", "test:123").when().get("http://localhost:8080").then().header(HttpHeaders.LOCATION, containsString("http://test:123/admin"));
|
||||
given().header("X-Forwarded-Host", "test:123").when().get("https://localhost:8443").then().header(HttpHeaders.LOCATION, containsString("https://test:123/admin"));
|
||||
|
||||
Reference in New Issue
Block a user