CVE-2024-5967
Description
A vulnerability was found in Keycloak. The LDAP testing endpoint allows changing the Connection URL independently without re-entering the currently configured LDAP bind credentials. This flaw allows an attacker with admin access (permission manage-realm) to change the LDAP host URL ("Connection URL") to a machine they control. The Keycloak server will connect to the attacker's host and try to authenticate with the configured credentials, thus leaking them to the attacker. As a consequence, an attacker who has compromised the admin console or compromised a user with sufficient privileges can leak domain credentials and attack the domain.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.keycloak:keycloak-ldap-federationMaven | >= 25.0.0, < 25.0.1 | 25.0.1 |
org.keycloak:keycloak-ldap-federationMaven | < 22.0.12 | 22.0.12 |
org.keycloak:keycloak-ldap-federationMaven | >= 23.0.0, < 24.0.6 | 24.0.6 |
Patches
30d0530046b9cImprovements for ldap test authentication
3 files changed · +72 −3
core/src/main/java/org/keycloak/representations/idm/TestLdapConnectionRepresentation.java+7 −1 modified@@ -16,10 +16,15 @@ public TestLdapConnectionRepresentation() { } public TestLdapConnectionRepresentation(String action, String connectionUrl, String bindDn, String bindCredential, String useTruststoreSpi, String connectionTimeout) { - this(action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, null, null); + this(action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, null, null, null); } public TestLdapConnectionRepresentation(String action, String connectionUrl, String bindDn, String bindCredential, String useTruststoreSpi, String connectionTimeout, String startTls, String authType) { + this(action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, startTls, authType, null); + } + + public TestLdapConnectionRepresentation(String action, String connectionUrl, String bindDn, String bindCredential, + String useTruststoreSpi, String connectionTimeout, String startTls, String authType, String componentId) { this.action = action; this.connectionUrl = connectionUrl; this.bindDn = bindDn; @@ -28,6 +33,7 @@ public TestLdapConnectionRepresentation(String action, String connectionUrl, Str this.connectionTimeout = connectionTimeout; this.startTls = startTls; this.authType = authType; + this.componentId = componentId; } public String getAction() {
federation/ldap/src/main/java/org/keycloak/services/managers/LDAPServerCapabilitiesManager.java+15 −2 modified@@ -16,12 +16,15 @@ */ package org.keycloak.services.managers; +import java.net.URI; import java.util.Collections; +import java.util.Objects; import java.util.Set; import javax.naming.ldap.LdapContext; import org.jboss.logging.Logger; import org.keycloak.common.util.MultivaluedHashMap; +import org.keycloak.component.ComponentModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.LDAPConstants; import org.keycloak.models.RealmModel; @@ -30,6 +33,7 @@ import org.keycloak.services.ServicesLogger; import org.keycloak.storage.ldap.LDAPConfig; import org.keycloak.representations.idm.LDAPCapabilityRepresentation; +import org.keycloak.storage.ldap.idm.model.LDAPDn; import org.keycloak.storage.ldap.idm.store.ldap.LDAPContextManager; import org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore; import org.keycloak.utils.StringUtil; @@ -62,8 +66,17 @@ private static int parseConnectionTimeout(String connectionTimeout) { public static LDAPConfig buildLDAPConfig(TestLdapConnectionRepresentation config, RealmModel realm) { String bindCredential = config.getBindCredential(); - if (config.getComponentId() != null && ComponentRepresentation.SECRET_VALUE.equals(bindCredential)) { - bindCredential = realm.getComponent(config.getComponentId()).getConfig().getFirst(LDAPConstants.BIND_CREDENTIAL); + if (config.getComponentId() != null && !LDAPConstants.AUTH_TYPE.equals(LDAPConstants.AUTH_TYPE_NONE) + && ComponentRepresentation.SECRET_VALUE.equals(bindCredential)) { + // check the connection URL and the bind DN are the same to allow using the same configured password + ComponentModel component = realm.getComponent(config.getComponentId()); + if (component != null) { + LDAPConfig ldapConfig = new LDAPConfig(component.getConfig()); + if (Objects.equals(URI.create(config.getConnectionUrl()), URI.create(ldapConfig.getConnectionUrl())) + && Objects.equals(LDAPDn.fromString(config.getBindDn()), LDAPDn.fromString(ldapConfig.getBindDN()))) { + bindCredential = ldapConfig.getBindCredential(); + } + } } MultivaluedHashMap<String, String> configMap = new MultivaluedHashMap<>(); configMap.putSingle(LDAPConstants.AUTH_TYPE, config.getAuthType());
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationLdapConnectionTest.java+50 −0 modified@@ -18,11 +18,13 @@ package org.keycloak.testsuite.admin; import java.util.List; +import java.util.Map; import org.hamcrest.Matchers; import org.junit.ClassRule; import org.junit.Test; import org.keycloak.models.LDAPConstants; +import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.representations.idm.LDAPCapabilityRepresentation; import org.keycloak.representations.idm.TestLdapConnectionRepresentation; import org.keycloak.services.managers.LDAPServerCapabilitiesManager; @@ -147,6 +149,54 @@ public void testLdapConnectionMoreServers() { } + @Test + public void testLdapConnectionComponentAlreadyCreated() { + // create ldap componnet model using ldaps + Map<String, String> cfg = ldapRule.getConfig(); + cfg.put(LDAPConstants.CONNECTION_URL, "ldaps://localhost:10636"); + cfg.put(LDAPConstants.START_TLS, "false"); + cfg.put(LDAPConstants.USE_TRUSTSTORE_SPI, "true"); + String ldapModelId = testingClient.testing().ldap(REALM_NAME).createLDAPProvider(cfg, false); + try { + // test passing everything with password included + Response response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), cfg.get(LDAPConstants.BIND_DN), cfg.get(LDAPConstants.BIND_CREDENTIAL), + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 204); + + // test passing the secret but not changing anything + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), cfg.get(LDAPConstants.BIND_DN), ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 204); + + // test passing the secret and changing the connection timeout which is allowed + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), cfg.get(LDAPConstants.BIND_DN), ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), "1000", + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 204); + + // test passing the secret but modifying the connection URL to plain ldap (different URL) + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + "ldap://localhost:10389", cfg.get(LDAPConstants.BIND_DN), ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 400); + + // test passing the secret but modifying the user DN + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), "uid=anotheradmin,ou=people,dc=keycloak,dc=org", ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 400); + } finally { + adminClient.realm(REALM_NAME).components().removeComponent(ldapModelId); + } + } + @Test public void testLdapCapabilities() {
1f56a9e48bf9Improvements for ldap test authentication
3 files changed · +72 −3
core/src/main/java/org/keycloak/representations/idm/TestLdapConnectionRepresentation.java+7 −1 modified@@ -16,10 +16,15 @@ public TestLdapConnectionRepresentation() { } public TestLdapConnectionRepresentation(String action, String connectionUrl, String bindDn, String bindCredential, String useTruststoreSpi, String connectionTimeout) { - this(action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, null, null); + this(action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, null, null, null); } public TestLdapConnectionRepresentation(String action, String connectionUrl, String bindDn, String bindCredential, String useTruststoreSpi, String connectionTimeout, String startTls, String authType) { + this(action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, startTls, authType, null); + } + + public TestLdapConnectionRepresentation(String action, String connectionUrl, String bindDn, String bindCredential, + String useTruststoreSpi, String connectionTimeout, String startTls, String authType, String componentId) { this.action = action; this.connectionUrl = connectionUrl; this.bindDn = bindDn; @@ -28,6 +33,7 @@ public TestLdapConnectionRepresentation(String action, String connectionUrl, Str this.connectionTimeout = connectionTimeout; this.startTls = startTls; this.authType = authType; + this.componentId = componentId; } public String getAction() {
federation/ldap/src/main/java/org/keycloak/services/managers/LDAPServerCapabilitiesManager.java+15 −2 modified@@ -16,12 +16,15 @@ */ package org.keycloak.services.managers; +import java.net.URI; import java.util.Collections; +import java.util.Objects; import java.util.Set; import javax.naming.ldap.LdapContext; import org.jboss.logging.Logger; import org.keycloak.common.util.MultivaluedHashMap; +import org.keycloak.component.ComponentModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.LDAPConstants; import org.keycloak.models.RealmModel; @@ -30,6 +33,7 @@ import org.keycloak.services.ServicesLogger; import org.keycloak.storage.ldap.LDAPConfig; import org.keycloak.representations.idm.LDAPCapabilityRepresentation; +import org.keycloak.storage.ldap.idm.model.LDAPDn; import org.keycloak.storage.ldap.idm.store.ldap.LDAPContextManager; import org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore; import org.keycloak.storage.ldap.mappers.membership.group.GroupTreeResolver; @@ -63,8 +67,17 @@ private static int parseConnectionTimeout(String connectionTimeout) { public static LDAPConfig buildLDAPConfig(TestLdapConnectionRepresentation config, RealmModel realm) { String bindCredential = config.getBindCredential(); - if (config.getComponentId() != null && ComponentRepresentation.SECRET_VALUE.equals(bindCredential)) { - bindCredential = realm.getComponent(config.getComponentId()).getConfig().getFirst(LDAPConstants.BIND_CREDENTIAL); + if (config.getComponentId() != null && !LDAPConstants.AUTH_TYPE.equals(LDAPConstants.AUTH_TYPE_NONE) + && ComponentRepresentation.SECRET_VALUE.equals(bindCredential)) { + // check the connection URL and the bind DN are the same to allow using the same configured password + ComponentModel component = realm.getComponent(config.getComponentId()); + if (component != null) { + LDAPConfig ldapConfig = new LDAPConfig(component.getConfig()); + if (Objects.equals(URI.create(config.getConnectionUrl()), URI.create(ldapConfig.getConnectionUrl())) + && Objects.equals(LDAPDn.fromString(config.getBindDn()), LDAPDn.fromString(ldapConfig.getBindDN()))) { + bindCredential = ldapConfig.getBindCredential(); + } + } } MultivaluedHashMap<String, String> configMap = new MultivaluedHashMap<>(); configMap.putSingle(LDAPConstants.AUTH_TYPE, config.getAuthType());
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationLdapConnectionTest.java+50 −0 modified@@ -18,11 +18,13 @@ package org.keycloak.testsuite.admin; import java.util.List; +import java.util.Map; import org.hamcrest.Matchers; import org.junit.ClassRule; import org.junit.Test; import org.keycloak.models.LDAPConstants; +import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.representations.idm.LDAPCapabilityRepresentation; import org.keycloak.representations.idm.TestLdapConnectionRepresentation; import org.keycloak.services.managers.LDAPServerCapabilitiesManager; @@ -147,6 +149,54 @@ public void testLdapConnectionMoreServers() { } + @Test + public void testLdapConnectionComponentAlreadyCreated() { + // create ldap componnet model using ldaps + Map<String, String> cfg = ldapRule.getConfig(); + cfg.put(LDAPConstants.CONNECTION_URL, "ldaps://localhost:10636"); + cfg.put(LDAPConstants.START_TLS, "false"); + cfg.put(LDAPConstants.USE_TRUSTSTORE_SPI, "true"); + String ldapModelId = testingClient.testing().ldap(REALM_NAME).createLDAPProvider(cfg, false); + try { + // test passing everything with password included + Response response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), cfg.get(LDAPConstants.BIND_DN), cfg.get(LDAPConstants.BIND_CREDENTIAL), + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 204); + + // test passing the secret but not changing anything + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), cfg.get(LDAPConstants.BIND_DN), ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 204); + + // test passing the secret and changing the connection timeout which is allowed + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), cfg.get(LDAPConstants.BIND_DN), ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), "1000", + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 204); + + // test passing the secret but modifying the connection URL to plain ldap (different URL) + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + "ldap://localhost:10389", cfg.get(LDAPConstants.BIND_DN), ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 400); + + // test passing the secret but modifying the user DN + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), "uid=anotheradmin,ou=people,dc=keycloak,dc=org", ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 400); + } finally { + adminClient.realm(REALM_NAME).components().removeComponent(ldapModelId); + } + } + @Test public void testLdapCapabilities() {
bde8568d4174Improvements for ldap test authentication
3 files changed · +72 −3
core/src/main/java/org/keycloak/representations/idm/TestLdapConnectionRepresentation.java+7 −1 modified@@ -16,10 +16,15 @@ public TestLdapConnectionRepresentation() { } public TestLdapConnectionRepresentation(String action, String connectionUrl, String bindDn, String bindCredential, String useTruststoreSpi, String connectionTimeout) { - this(action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, null, null); + this(action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, null, null, null); } public TestLdapConnectionRepresentation(String action, String connectionUrl, String bindDn, String bindCredential, String useTruststoreSpi, String connectionTimeout, String startTls, String authType) { + this(action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, startTls, authType, null); + } + + public TestLdapConnectionRepresentation(String action, String connectionUrl, String bindDn, String bindCredential, + String useTruststoreSpi, String connectionTimeout, String startTls, String authType, String componentId) { this.action = action; this.connectionUrl = connectionUrl; this.bindDn = bindDn; @@ -28,6 +33,7 @@ public TestLdapConnectionRepresentation(String action, String connectionUrl, Str this.connectionTimeout = connectionTimeout; this.startTls = startTls; this.authType = authType; + this.componentId = componentId; } public String getAction() {
federation/ldap/src/main/java/org/keycloak/services/managers/LDAPServerCapabilitiesManager.java+15 −2 modified@@ -16,11 +16,14 @@ */ package org.keycloak.services.managers; +import java.net.URI; import java.util.Collections; +import java.util.Objects; import java.util.Set; import org.jboss.logging.Logger; import org.keycloak.common.util.MultivaluedHashMap; +import org.keycloak.component.ComponentModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.LDAPConstants; import org.keycloak.models.RealmModel; @@ -29,6 +32,7 @@ import org.keycloak.services.ServicesLogger; import org.keycloak.storage.ldap.LDAPConfig; import org.keycloak.representations.idm.LDAPCapabilityRepresentation; +import org.keycloak.storage.ldap.idm.model.LDAPDn; import org.keycloak.storage.ldap.idm.store.ldap.LDAPContextManager; import org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore; @@ -45,8 +49,17 @@ public class LDAPServerCapabilitiesManager { public static LDAPConfig buildLDAPConfig(TestLdapConnectionRepresentation config, RealmModel realm) { String bindCredential = config.getBindCredential(); - if (config.getComponentId() != null && ComponentRepresentation.SECRET_VALUE.equals(bindCredential)) { - bindCredential = realm.getComponent(config.getComponentId()).getConfig().getFirst(LDAPConstants.BIND_CREDENTIAL); + if (config.getComponentId() != null && !LDAPConstants.AUTH_TYPE.equals(LDAPConstants.AUTH_TYPE_NONE) + && ComponentRepresentation.SECRET_VALUE.equals(bindCredential)) { + // check the connection URL and the bind DN are the same to allow using the same configured password + ComponentModel component = realm.getComponent(config.getComponentId()); + if (component != null) { + LDAPConfig ldapConfig = new LDAPConfig(component.getConfig()); + if (Objects.equals(URI.create(config.getConnectionUrl()), URI.create(ldapConfig.getConnectionUrl())) + && Objects.equals(LDAPDn.fromString(config.getBindDn()), LDAPDn.fromString(ldapConfig.getBindDN()))) { + bindCredential = ldapConfig.getBindCredential(); + } + } } MultivaluedHashMap<String, String> configMap = new MultivaluedHashMap<>(); configMap.putSingle(LDAPConstants.AUTH_TYPE, config.getAuthType());
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationLdapConnectionTest.java+50 −0 modified@@ -18,11 +18,13 @@ package org.keycloak.testsuite.admin; import java.util.List; +import java.util.Map; import org.hamcrest.Matchers; import org.junit.ClassRule; import org.junit.Test; import org.keycloak.models.LDAPConstants; +import org.keycloak.representations.idm.ComponentRepresentation; import org.keycloak.representations.idm.LDAPCapabilityRepresentation; import org.keycloak.representations.idm.TestLdapConnectionRepresentation; import org.keycloak.services.managers.LDAPServerCapabilitiesManager; @@ -136,6 +138,54 @@ public void testLdapConnectionMoreServers() { } + @Test + public void testLdapConnectionComponentAlreadyCreated() { + // create ldap componnet model using ldaps + Map<String, String> cfg = ldapRule.getConfig(); + cfg.put(LDAPConstants.CONNECTION_URL, "ldaps://localhost:10636"); + cfg.put(LDAPConstants.START_TLS, "false"); + cfg.put(LDAPConstants.USE_TRUSTSTORE_SPI, "true"); + String ldapModelId = testingClient.testing().ldap(REALM_NAME).createLDAPProvider(cfg, false); + try { + // test passing everything with password included + Response response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), cfg.get(LDAPConstants.BIND_DN), cfg.get(LDAPConstants.BIND_CREDENTIAL), + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 204); + + // test passing the secret but not changing anything + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), cfg.get(LDAPConstants.BIND_DN), ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 204); + + // test passing the secret and changing the connection timeout which is allowed + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), cfg.get(LDAPConstants.BIND_DN), ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), "1000", + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 204); + + // test passing the secret but modifying the connection URL to plain ldap (different URL) + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + "ldap://localhost:10389", cfg.get(LDAPConstants.BIND_DN), ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 400); + + // test passing the secret but modifying the user DN + response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, + cfg.get(LDAPConstants.CONNECTION_URL), "uid=anotheradmin,ou=people,dc=keycloak,dc=org", ComponentRepresentation.SECRET_VALUE, + cfg.get(LDAPConstants.USE_TRUSTSTORE_SPI), cfg.get(LDAPConstants.CONNECTION_TIMEOUT), + cfg.get(LDAPConstants.START_TLS), cfg.get(LDAPConstants.AUTH_TYPE), ldapModelId)); + assertStatus(response, 400); + } finally { + adminClient.realm(REALM_NAME).components().removeComponent(ldapModelId); + } + } + @Test public void testLdapCapabilities() {
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
16- github.com/advisories/GHSA-c25h-c27q-5qpvghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-5967ghsaADVISORY
- access.redhat.com/security/cve/CVE-2024-5967nvdWEB
- bugzilla.redhat.com/show_bug.cginvdWEB
- github.com/keycloak/keycloak/commit/0d0530046b9cb4b0d74d2fdefc9bd04f1d20cac0ghsaWEB
- github.com/keycloak/keycloak/commit/1f56a9e48bf96c3bcb18dfc6cd93e3dd16f281f1ghsaWEB
- github.com/keycloak/keycloak/commit/bde8568d4174a7072f7c7bb507d2c7d05824b1a6ghsaWEB
- github.com/keycloak/keycloak/issues/30434ghsaWEB
- github.com/keycloak/keycloak/security/advisories/GHSA-c25h-c27q-5qpvghsaWEB
- access.redhat.com/errata/RHSA-2024:6493nvd
- access.redhat.com/errata/RHSA-2024:6494nvd
- access.redhat.com/errata/RHSA-2024:6495nvd
- access.redhat.com/errata/RHSA-2024:6497nvd
- access.redhat.com/errata/RHSA-2024:6499nvd
- access.redhat.com/errata/RHSA-2024:6500nvd
- access.redhat.com/errata/RHSA-2024:6501nvd
News mentions
0No linked articles in our index yet.