Improvements for test connection and authentication in the LDAP provider

Closes #26464

Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
rmartinc 2024-01-31 13:38:36 +01:00 committed by Pedro Igor
parent f468885fdd
commit 509f618992
2 changed files with 39 additions and 5 deletions

View file

@ -18,6 +18,7 @@ package org.keycloak.services.managers;
import java.util.Collections;
import java.util.Set;
import javax.naming.ldap.LdapContext;
import org.jboss.logging.Logger;
import org.keycloak.common.util.MultivaluedHashMap;
@ -31,6 +32,7 @@ import org.keycloak.storage.ldap.LDAPConfig;
import org.keycloak.representations.idm.LDAPCapabilityRepresentation;
import org.keycloak.storage.ldap.idm.store.ldap.LDAPContextManager;
import org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore;
import org.keycloak.utils.StringUtil;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -42,6 +44,21 @@ public class LDAPServerCapabilitiesManager {
public static final String TEST_CONNECTION = "testConnection";
public static final String TEST_AUTHENTICATION = "testAuthentication";
public static final String QUERY_SERVER_CAPABILITIES = "queryServerCapabilities";
public static final int DEFAULT_TEST_TIMEOUT = 30000; // 30s default test timeout
private static int parseConnectionTimeout(String connectionTimeout) {
if (StringUtil.isNotBlank(connectionTimeout)) {
try {
int timeout = Integer.parseInt(connectionTimeout);
if (timeout > 0) {
return timeout;
}
} catch (NumberFormatException e) {
// just use default timeout
}
}
return DEFAULT_TEST_TIMEOUT;
}
public static LDAPConfig buildLDAPConfig(TestLdapConnectionRepresentation config, RealmModel realm) {
String bindCredential = config.getBindCredential();
@ -54,7 +71,11 @@ public class LDAPServerCapabilitiesManager {
configMap.putSingle(LDAPConstants.BIND_CREDENTIAL, bindCredential);
configMap.add(LDAPConstants.CONNECTION_URL, config.getConnectionUrl());
configMap.add(LDAPConstants.USE_TRUSTSTORE_SPI, config.getUseTruststoreSpi());
configMap.putSingle(LDAPConstants.CONNECTION_TIMEOUT, config.getConnectionTimeout());
// set a forced timeout even when the timeout is infinite for testing
// this is needed to not wait forever in the test and force connection creation in ldap
String timeoutStr = Integer.toString(parseConnectionTimeout(config.getConnectionTimeout()));
configMap.putSingle(LDAPConstants.CONNECTION_TIMEOUT, timeoutStr);
configMap.putSingle(LDAPConstants.READ_TIMEOUT, timeoutStr);
configMap.add(LDAPConstants.START_TLS, config.getStartTls());
return new LDAPConfig(configMap);
}
@ -136,7 +157,11 @@ public class LDAPServerCapabilitiesManager {
// Create ldapContextManager in try-with-resource so that ldapContext/tlsResponse/VaultSecret is closed/removed when it
// is not needed anymore
try (LDAPContextManager ldapContextManager = LDAPContextManager.create(session, ldapConfig)) {
ldapContextManager.getLdapContext();
LdapContext ldapContext = ldapContextManager.getLdapContext();
if (TEST_AUTHENTICATION.equals(config.getAction()) && LDAPConstants.AUTH_TYPE_NONE.equals(config.getAuthType())) {
// reconnect to force an anonymous bind operation
ldapContext.reconnect(null);
}
} catch (Exception ne) {
String errorMessage = (TEST_AUTHENTICATION.equals(config.getAction())) ? "Error when authenticating to LDAP: "
: "Error when connecting to LDAP: ";

View file

@ -71,9 +71,9 @@ public class UserFederationLdapConnectionTest extends AbstractAdminTest {
response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, "ldap://localhost:10389", "uid=admin,ou=system", "${vault.ldap_bindCredential}", "false", null));
assertStatus(response, 204);
// Authentication success anonymous bind
// Authentication error for anonymous bind (default ldap rule does not allow anonymous binings)
response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, "ldap://localhost:10389", null, null, "false", null, "false", LDAPConstants.AUTH_TYPE_NONE));
assertStatus(response, 204);
assertStatus(response, 400);
response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, "ldap://localhost:10389", "uid=admin,ou=system", "${vault.ldap_bindCredential}", "false", null));
assertStatus(response, 204);
@ -93,6 +93,15 @@ public class UserFederationLdapConnectionTest extends AbstractAdminTest {
response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_CONNECTION, "ldaps://localhostt:10636", "foo", "bar", "false", null));
assertStatus(response, 400);
response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_CONNECTION, "ldaps://localhost:10389", null, null, "false", null));
assertStatus(response, 400);
response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_CONNECTION, "ldaps://localhost:10389", null, null, "false", "5000"));
assertStatus(response, 400);
response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_CONNECTION, "ldaps://localhost:10389", null, null, "false", "0"));
assertStatus(response, 400);
response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, "ldaps://localhost:10636", "foo", "bar", "false", null));
assertStatus(response, 400);
@ -103,7 +112,7 @@ public class UserFederationLdapConnectionTest extends AbstractAdminTest {
assertStatus(response, 204);
response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, "ldaps://localhost:10636", null, null, "false", null, "false", LDAPConstants.AUTH_TYPE_NONE));
assertStatus(response, 204);
assertStatus(response, 400);
// Authentication success with bindCredential from Vault
response = realm.testLDAPConnection(new TestLdapConnectionRepresentation(LDAPServerCapabilitiesManager.TEST_AUTHENTICATION, "ldaps://localhost:10636", "uid=admin,ou=system", "${vault.ldap_bindCredential}", "true", null));