From 2b98fcdecbf599872714c61e7f9c2686dbe8ef52 Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Wed, 15 Feb 2023 19:00:57 -0300 Subject: [PATCH] Support for standard Forwarded header Closes #11580 --- docs/guides/src/main/server/reverseproxy.adoc | 8 +++++--- .../main/java/org/keycloak/config/ProxyOptions.java | 10 ++++++++++ .../configuration/mappers/ProxyPropertyMappers.java | 10 ++++++++++ .../java/org/keycloak/it/cli/dist/ProxyDistTest.java | 6 ++++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/guides/src/main/server/reverseproxy.adoc b/docs/guides/src/main/server/reverseproxy.adoc index fdcd4825efd..a845e8b20e7 100644 --- a/docs/guides/src/main/server/reverseproxy.adoc +++ b/docs/guides/src/main/server/reverseproxy.adoc @@ -33,13 +33,15 @@ To select the proxy mode, enter this command: == Configure the reverse proxy Some Keycloak features rely on the assumption that the remote address of the HTTP request connecting to Keycloak is the real IP address of the clients machine. -When you have a reverse proxy or a load balancer in front of Keycloak, this might not be the case, so please make sure your reverse proxy is configured correctly by performing these actions: +When you have a reverse proxy or a load balancer in front of Keycloak, please make sure your reverse proxy is overriding the following headers: -* Set the X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host HTTP headers. +* `Forwarded` as per https://www.rfc-editor.org/rfc/rfc7239.html[RFC7239] +* Non-standard `X-Forwarded` +* Non-standard `X-Forwarded-*`, such as `X-Forwarded-For`, `X-Forwarded-Proto`, `X-Forwarded-Host`, and `X-Forwarded-Port` To set these headers, consult the documentation for your reverse proxy. -Take extra precautions to ensure that the X-Forwarded-For header is set by your reverse proxy. +Take extra precautions to ensure that the client address is properly set by your reverse proxy via the `Forwarded` or `X-Forwarded-For` headers. If this header is incorrectly configured, rogue clients can set this header and trick Keycloak into thinking the client is connected from a different IP address than the actual address. This precaution can be more critical if you do any deny or allow listing of IP addresses. diff --git a/quarkus/config-api/src/main/java/org/keycloak/config/ProxyOptions.java b/quarkus/config-api/src/main/java/org/keycloak/config/ProxyOptions.java index 25233a1b322..96a9375bb3c 100644 --- a/quarkus/config-api/src/main/java/org/keycloak/config/ProxyOptions.java +++ b/quarkus/config-api/src/main/java/org/keycloak/config/ProxyOptions.java @@ -19,4 +19,14 @@ public enum Mode { .category(OptionCategory.PROXY) .defaultValue(Boolean.FALSE) .build(); + + public static final Option PROXY_FORWARDED_HEADER_ENABLED = new OptionBuilder<>("proxy-allow-forwarded-header", Boolean.class) + .category(OptionCategory.PROXY) + .defaultValue(Boolean.FALSE) + .build(); + + public static final Option PROXY_X_FORWARDED_HEADER_ENABLED = new OptionBuilder<>("proxy-allow-x-forwarded-header", Boolean.class) + .category(OptionCategory.PROXY) + .defaultValue(Boolean.FALSE) + .build(); } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/ProxyPropertyMappers.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/ProxyPropertyMappers.java index efc0f46bca3..b07c984d459 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/ProxyPropertyMappers.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/ProxyPropertyMappers.java @@ -26,6 +26,16 @@ public static PropertyMapper[] getProxyPropertyMappers() { .to("quarkus.http.proxy.enable-forwarded-host") .mapFrom("proxy") .transformer(ProxyPropertyMappers::getResolveEnableForwardedHost) + .build(), + fromOption(ProxyOptions.PROXY_FORWARDED_HEADER_ENABLED) + .to("quarkus.http.proxy.allow-forwarded") + .mapFrom("proxy") + .transformer(ProxyPropertyMappers::getResolveEnableForwardedHost) + .build(), + fromOption(ProxyOptions.PROXY_X_FORWARDED_HEADER_ENABLED) + .to("quarkus.http.proxy.allow-x-forwarded") + .mapFrom("proxy") + .transformer(ProxyPropertyMappers::getResolveEnableForwardedHost) .build() }; } diff --git a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/ProxyDistTest.java b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/ProxyDistTest.java index d5b9a2216be..93a761357a8 100644 --- a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/ProxyDistTest.java +++ b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/ProxyDistTest.java @@ -55,6 +55,12 @@ public void testXForwardedHeadersWithEdge() { assertXForwardedHeaders(); } + @Test + @Launch({ "start-dev", "--hostname=mykeycloak.org", "--proxy=edge" }) + public void testForwardedHeadersWithEdge() { + given().header("Forwarded", "for=12.34.56.78;host=test:1234;proto=https, for=23.45.67.89").when().get("http://mykeycloak.org:8080").then().body(containsString("https://test:1234/admin")); + } + @Test @Launch({ "start-dev", "--hostname=mykeycloak.org", "--proxy=reencrypt" }) public void testXForwardedHeadersWithReencrypt() {