mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
Handle canonical hostname checks for localhost on Windows (#42799)
Closes: #42794 Signed-off-by: Peter Zaoral <pepo48@gmail.com>
This commit is contained in:
parent
4dc398354a
commit
2300b3fc78
9
docs/documentation/release_notes/topics/26_5_0.adoc
Normal file
9
docs/documentation/release_notes/topics/26_5_0.adoc
Normal file
@ -0,0 +1,9 @@
|
||||
// Release notes should contain only headline-worthy new features,
|
||||
// assuming that people who migrate will read the upgrading guide anyway.
|
||||
//
|
||||
== Breaking Fix for Windows in Loopback Hostname Verification
|
||||
|
||||
This release introduces a breaking change for Windows users: setups that previously relied on custom machine names or non-standard hostnames for loopback (e.g., `127.0.0.1` resolving to a custom name) may require updates to their trusted domain configuration. Only `localhost` and `*.localhost` are now recognized for loopback verification.
|
||||
|
||||
Keycloak now consistently normalizes loopback addresses to `localhost` for domain verification across all platforms. This change ensures predictable behavior for trusted domain checks, regardless of the underlying OS.
|
||||
|
||||
@ -175,14 +175,22 @@ public class TrustedHostClientRegistrationPolicy implements ClientRegistrationPo
|
||||
|
||||
logger.debugf("Trying verify request from address '%s' of host '%s' by domains", hostAddress, hostname);
|
||||
|
||||
// On Windows, reverse lookup for loopback may return the IP (e.g., 127.0.0.1) instead of 'localhost'. Normalize to 'localhost' for consistent domain checks.
|
||||
if (hostname.equals(address.getHostAddress()) && address.isLoopbackAddress()) {
|
||||
hostname = "localhost";
|
||||
}
|
||||
|
||||
if (hostname.equals(address.getHostAddress())) {
|
||||
logger.debugf("The hostAddress '%s' was not resolved to a hostname", hostAddress);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Arrays.stream(InetAddress.getAllByName(hostname)).filter(a -> address.equals(a)).findAny().isEmpty()) {
|
||||
logger.debugf("The hostAddress '%s' is not among the direct lookups returned resolving '%s'", hostAddress, hostname);
|
||||
return null;
|
||||
// For loopback, skip strict forward-confirm check after normalizing to 'localhost' to avoid platform differences.
|
||||
if (!address.isLoopbackAddress()) {
|
||||
if (Arrays.stream(InetAddress.getAllByName(hostname)).filter(a -> address.equals(a)).findAny().isEmpty()) {
|
||||
logger.debugf("The hostAddress '%s' is not among the direct lookups returned resolving '%s'", hostAddress, hostname);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
for (String confDomain : trustedDomains) {
|
||||
@ -192,7 +200,17 @@ public class TrustedHostClientRegistrationPolicy implements ClientRegistrationPo
|
||||
}
|
||||
}
|
||||
} catch (UnknownHostException uhe) {
|
||||
logger.debugf(uhe, "Request of address '%s' came from unknown host. Skip verification by domains", hostAddress);
|
||||
logger.debugf(uhe, "Request of address '%s' came from unknown host. Skip verification by domains unless it's within localhost domain", hostAddress);
|
||||
|
||||
String lower = hostAddress == null ? null : hostAddress.toLowerCase();
|
||||
if (lower != null && ("localhost".equals(lower) || lower.endsWith(".localhost"))) {
|
||||
for (String confDomain : trustedDomains) {
|
||||
if (checkTrustedDomain(lower, confDomain)) {
|
||||
logger.debugf("Treating host '%s' as loopback due to localhost domain and returning success by trusted domain '%s'", lower, confDomain);
|
||||
return lower;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@ -102,6 +102,19 @@ public class TrustedHostClientRegistrationPolicyTest {
|
||||
policy.getTrustedHosts(), policy.getTrustedDomains()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalhostDomainFallback() {
|
||||
TrustedHostClientRegistrationPolicyFactory factory = new TrustedHostClientRegistrationPolicyFactory();
|
||||
ComponentModel model = createComponentModel("*.localhost");
|
||||
TrustedHostClientRegistrationPolicy policy = (TrustedHostClientRegistrationPolicy) factory.create(session, model);
|
||||
|
||||
// Simulate a hostname that would fail DNS resolution on some platforms
|
||||
// but matches the trusted domain fallback logic
|
||||
assertTrue(policy.verifyHost("other.localhost"));
|
||||
assertTrue(policy.verifyHost("localhost"));
|
||||
assertFalse(policy.verifyHost("otherlocalhost"));
|
||||
}
|
||||
|
||||
private ComponentModel createComponentModel(String... hosts) {
|
||||
ComponentModel model = new ComponentModel();
|
||||
model.put(TrustedHostClientRegistrationPolicyFactory.HOST_SENDING_REGISTRATION_REQUEST_MUST_MATCH, "true");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user