diff --git a/federation/ldap/src/main/java/org/keycloak/services/managers/LDAPServerCapabilitiesManager.java b/federation/ldap/src/main/java/org/keycloak/services/managers/LDAPServerCapabilitiesManager.java index 817009f013..fc9bbe11c2 100755 --- a/federation/ldap/src/main/java/org/keycloak/services/managers/LDAPServerCapabilitiesManager.java +++ b/federation/ldap/src/main/java/org/keycloak/services/managers/LDAPServerCapabilitiesManager.java @@ -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 Marek Posolda @@ -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: "; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationLdapConnectionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationLdapConnectionTest.java index d01f90624d..07a69e8b13 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationLdapConnectionTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationLdapConnectionTest.java @@ -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));