Skip to content

Commit f1a7a48

Browse files
shawkinsmabartos
andauthored
fix: adds additional info / warnings to hostname v2 (keycloak#33261)
* fix: adds additional info / warnings to hostname v2 closes: keycloak#24815 Signed-off-by: Steve Hawkins <[email protected]> * refining the proxy-headers language from keycloak#33209 Signed-off-by: Steve Hawkins <[email protected]> * adding hostname-strict-https Signed-off-by: Steve Hawkins <[email protected]> * moving removed property check to the quarkus side Signed-off-by: Steve Hawkins <[email protected]> * Update quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/HostnameV2PropertyMappers.java Co-authored-by: Martin Bartoš <[email protected]> Signed-off-by: Steven Hawkins <[email protected]> * Update docs/guides/server/hostname.adoc Signed-off-by: Steven Hawkins <[email protected]> --------- Signed-off-by: Steve Hawkins <[email protected]> Signed-off-by: Steven Hawkins <[email protected]> Co-authored-by: Martin Bartoš <[email protected]>
1 parent cf2ecf8 commit f1a7a48

File tree

6 files changed

+31
-8
lines changed

6 files changed

+31
-8
lines changed

docs/guides/server/hostname.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ The result of this configuration is that you can continue to access {project_nam
4848

4949
== Using a reverse proxy
5050

51-
When a proxy is in use, the `proxy-headers` should be set. Depending on the hostname settings, some or all of the URL, may be dynamically determined.
51+
When a proxy is forwarding http or reencrypted TLS requests, the `proxy-headers` option should be set. Depending on the hostname settings, some or all of the URL, may be dynamically determined.
5252

5353
WARNING: If either `forwarded` or `xforwarded` is selected, make sure your reverse proxy properly sets and overwrites the `Forwarded` or `X-Forwarded-*` headers respectively. To set these headers, consult the documentation for your reverse proxy. Misconfiguration will leave {project_name} exposed to security vulnerabilities.
5454

docs/guides/server/reverseproxy.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Distributed environments frequently require the use of a reverse proxy. {project
1818
* `forwarded` enables parsing of the `Forwarded` header as per https://www.rfc-editor.org/rfc/rfc7239.html[RFC7239].
1919
* `xforwarded` enables parsing of non-standard `X-Forwarded-*` headers, such as `X-Forwarded-For`, `X-Forwarded-Proto`, `X-Forwarded-Host`, and `X-Forwarded-Port`.
2020

21-
NOTE: If you are using a reverse proxy 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.
21+
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.
2222

2323
For example:
2424

quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/AbstractStartCommand.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import org.keycloak.quarkus.runtime.Messages;
2424
import org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler;
2525
import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
26+
import org.keycloak.quarkus.runtime.configuration.mappers.HostnameV2PropertyMappers;
2627
import org.keycloak.quarkus.runtime.configuration.mappers.HttpPropertyMappers;
28+
import org.keycloak.url.HostnameV2ProviderFactory;
2729

2830
import java.util.EnumSet;
2931
import java.util.List;
@@ -44,6 +46,7 @@ public void run() {
4446
doBeforeRun();
4547
CommandLine cmd = spec.commandLine();
4648
HttpPropertyMappers.validateConfig();
49+
HostnameV2PropertyMappers.validateConfig();
4750
validateConfig();
4851

4952
if (ConfigArgsConfigSource.getAllCliArgs().contains(OPTIMIZED_BUILD_OPTION_LONG) && !wasBuildEverRun()) {

quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/HostnameV2PropertyMappers.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
package org.keycloak.quarkus.runtime.configuration.mappers;
22

3-
import org.keycloak.common.Profile;
4-
import org.keycloak.config.HostnameV2Options;
3+
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
54

5+
import java.util.Arrays;
6+
import java.util.List;
67
import java.util.stream.Stream;
78

8-
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper.fromOption;
9+
import org.jboss.logging.Logger;
10+
import org.keycloak.common.Profile;
11+
import org.keycloak.config.HostnameV2Options;
12+
import org.keycloak.quarkus.runtime.configuration.Configuration;
913

10-
final class HostnameV2PropertyMappers {
14+
public final class HostnameV2PropertyMappers {
15+
16+
private static final Logger LOGGER = Logger.getLogger(PropertyMappers.class);
17+
private static final List<String> REMOVED_OPTIONS = Arrays.asList("hostname-admin-url", "hostname-path", "hostname-port", "hostname-strict-backchannel", "hostname-url", "proxy", "hostname-strict-https");
1118

1219
private HostnameV2PropertyMappers(){}
1320

@@ -28,5 +35,13 @@ public static PropertyMapper<?>[] getHostnamePropertyMappers() {
2835
.map(b -> b.isEnabled(() -> Profile.isFeatureEnabled(Profile.Feature.HOSTNAME_V2), "hostname:v2 feature is enabled").build())
2936
.toArray(s -> new PropertyMapper<?>[s]);
3037
}
38+
39+
public static void validateConfig() {
40+
List<String> inUse = REMOVED_OPTIONS.stream().filter(s -> Configuration.getOptionalKcValue(s).isPresent()).toList();
41+
42+
if (!inUse.isEmpty()) {
43+
LOGGER.errorf("Hostname v1 options %s are still in use, please review your configuration", inUse);
44+
}
45+
}
3146

3247
}

services/src/main/java/org/keycloak/protocol/oidc/endpoints/LoginStatusIframeEndpoint.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public Response preCheck(@QueryParam("client_id") String clientId, @QueryParam("
6868
if (validWebOrigins.contains("*") || validWebOrigins.contains(origin)) {
6969
return Response.noContent().build();
7070
}
71-
logger.debugf("client %s does not allow origin=%s for requestOrigin=%s (as determined by hostname settings), init will return a 403", clientId, origin, requestOrigin);
71+
logger.debugf("client %s does not allow origin=%s for requestOrigin=%s (as determined by the proxy-header setting), init will return a 403", clientId, origin, requestOrigin);
7272
} else {
7373
logger.debugf("client %s does not exist or not enabled, init will return a 403", clientId);
7474
}

services/src/main/java/org/keycloak/url/HostnameV2ProviderFactory.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Arrays;
2222
import java.util.Optional;
2323

24+
import org.jboss.logging.Logger;
2425
import org.keycloak.Config;
2526
import org.keycloak.common.Profile;
2627
import org.keycloak.models.KeycloakSession;
@@ -32,6 +33,9 @@
3233
* @author Vaclav Muzikar <[email protected]>
3334
*/
3435
public class HostnameV2ProviderFactory implements HostnameProviderFactory, EnvironmentDependentProviderFactory {
36+
37+
private static final Logger LOGGER = Logger.getLogger(HostnameV2ProviderFactory.class);
38+
3539
private static final String INVALID_HOSTNAME = "Provided hostname is neither a plain hostname nor a valid URL";
3640
private String hostname;
3741
private URI hostnameUrl;
@@ -41,14 +45,15 @@ public class HostnameV2ProviderFactory implements HostnameProviderFactory, Envir
4145
@Override
4246
public void init(Config.Scope config) {
4347
// Strict mode is used just for enforcing that hostname is set
44-
Boolean strictMode = config.getBoolean("hostname-strict", false);
48+
boolean strictMode = config.getBoolean("hostname-strict", false);
4549

4650
String hostnameRaw = config.get("hostname");
4751
if (strictMode && hostnameRaw == null) {
4852
throw new IllegalArgumentException("hostname is not configured; either configure hostname, or set hostname-strict to false");
4953
} else if (hostnameRaw != null && !strictMode) {
5054
// We might not need this validation as it doesn't matter in this case if strict is true or false. It's just for consistency – hostname XOR !strict.
5155
// throw new IllegalArgumentException("hostname is configured, hostname-strict must be set to true");
56+
LOGGER.info("If hostanme is specified, hostname-strict is effectively ignored");
5257
}
5358

5459
// Set hostname, can be either a full URL, or just hostname

0 commit comments

Comments
 (0)