KEYCLOAK-11245 Adapt LDAPConnectionTestManager to use newly introduced LDAPContextManager
This commit is contained in:
parent
6738e063f4
commit
2703388946
6 changed files with 46 additions and 74 deletions
|
@ -17,17 +17,12 @@
|
||||||
package org.keycloak.services.managers;
|
package org.keycloak.services.managers;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.LDAPConstants;
|
import org.keycloak.models.LDAPConstants;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
|
import org.keycloak.storage.ldap.LDAPConfig;
|
||||||
import javax.naming.Context;
|
import org.keycloak.storage.ldap.idm.store.ldap.LDAPContextManager;
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.naming.ldap.InitialLdapContext;
|
|
||||||
import javax.naming.ldap.StartTlsRequest;
|
|
||||||
import javax.naming.ldap.StartTlsResponse;
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
|
||||||
import javax.net.ssl.SSLSession;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -39,86 +34,53 @@ public class LDAPConnectionTestManager {
|
||||||
public static final String TEST_CONNECTION = "testConnection";
|
public static final String TEST_CONNECTION = "testConnection";
|
||||||
public static final String TEST_AUTHENTICATION = "testAuthentication";
|
public static final String TEST_AUTHENTICATION = "testAuthentication";
|
||||||
|
|
||||||
public boolean testLDAP(String action, String connectionUrl, String bindDn, String bindCredential, String useTruststoreSpi, String connectionTimeout, String tls) {
|
public static boolean testLDAP(KeycloakSession session, String action, String connectionUrl, String bindDn,
|
||||||
|
String bindCredential, String useTruststoreSpi, String connectionTimeout, String tls) {
|
||||||
if (!TEST_CONNECTION.equals(action) && !TEST_AUTHENTICATION.equals(action)) {
|
if (!TEST_CONNECTION.equals(action) && !TEST_AUTHENTICATION.equals(action)) {
|
||||||
ServicesLogger.LOGGER.unknownAction(action);
|
ServicesLogger.LOGGER.unknownAction(action);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitialLdapContext ldapContext = null;
|
|
||||||
try {
|
// Prepare MultivaluedHashMap so that it is usable in LDAPContext class
|
||||||
Hashtable<String, Object> env = new Hashtable<String, Object>();
|
MultivaluedHashMap<String, String> ldapConfig = new MultivaluedHashMap<>();
|
||||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
|
||||||
|
|
||||||
if (connectionUrl == null) {
|
if (connectionUrl == null) {
|
||||||
logger.errorf("Unknown connection URL");
|
logger.errorf("Unknown connection URL");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
env.put(Context.PROVIDER_URL, connectionUrl);
|
ldapConfig.putSingle(LDAPConstants.CONNECTION_URL, connectionUrl);
|
||||||
|
ldapConfig.putSingle(LDAPConstants.USE_TRUSTSTORE_SPI, useTruststoreSpi);
|
||||||
LDAPConstants.setTruststoreSpiIfNeeded(useTruststoreSpi, connectionUrl, env);
|
ldapConfig.putSingle(LDAPConstants.CONNECTION_TIMEOUT, connectionTimeout);
|
||||||
|
ldapConfig.putSingle(LDAPConstants.START_TLS, tls);
|
||||||
if (connectionTimeout != null && !connectionTimeout.isEmpty()) {
|
|
||||||
env.put("com.sun.jndi.ldap.connect.timeout", connectionTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(tls != null && Boolean.parseBoolean(tls)) {
|
|
||||||
ldapContext = new InitialLdapContext(env, null);
|
|
||||||
try {
|
|
||||||
StartTlsResponse tlsResponse = (StartTlsResponse) ldapContext.extendedOperation(new StartTlsRequest());
|
|
||||||
tlsResponse.negotiate();
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("Could not negotiate TLS", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TEST_AUTHENTICATION.equals(action)) {
|
if (TEST_AUTHENTICATION.equals(action)) {
|
||||||
ldapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
|
// If AUTHENTICATION action is executed add also dn and credentials to configuration
|
||||||
|
// LDAPContextManager is responsible for correct order of addition of credentials to context in case
|
||||||
|
// tls is true
|
||||||
|
|
||||||
if (bindDn == null) {
|
if (bindDn == null) {
|
||||||
logger.error("Unknown bind DN");
|
logger.error("Unknown bind DN");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ldapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, bindDn);
|
|
||||||
|
|
||||||
char[] bindCredentialChar = null;
|
ldapConfig.putSingle(LDAPConstants.AUTH_TYPE, LDAPConstants.AUTH_TYPE_SIMPLE);
|
||||||
if (bindCredential != null) {
|
ldapConfig.putSingle(LDAPConstants.BIND_DN, bindDn);
|
||||||
bindCredentialChar = bindCredential.toCharArray();
|
ldapConfig.putSingle(LDAPConstants.BIND_CREDENTIAL, bindCredential);
|
||||||
}
|
|
||||||
ldapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, bindCredentialChar);
|
|
||||||
ldapContext.lookup("");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (TEST_AUTHENTICATION.equals(action)) {
|
ldapConfig.putSingle(LDAPConstants.AUTH_TYPE, LDAPConstants.AUTH_TYPE_NONE);
|
||||||
env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
|
||||||
|
|
||||||
if (bindDn == null) {
|
|
||||||
logger.error("Unknown bind DN");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
env.put(Context.SECURITY_PRINCIPAL, bindDn);
|
|
||||||
|
|
||||||
char[] bindCredentialChar = null;
|
|
||||||
if (bindCredential != null) {
|
|
||||||
bindCredentialChar = bindCredential.toCharArray();
|
|
||||||
}
|
|
||||||
env.put(Context.SECURITY_CREDENTIALS, bindCredentialChar);
|
|
||||||
}
|
|
||||||
ldapContext = new InitialLdapContext(env, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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, new LDAPConfig(ldapConfig))) {
|
||||||
|
ldapContextManager.getLdapContext();
|
||||||
|
|
||||||
|
// Connection was successful, no exception was raised returning true
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception ne) {
|
} catch (Exception ne) {
|
||||||
String errorMessage = (TEST_AUTHENTICATION.equals(action)) ? "Error when authenticating to LDAP: " : "Error when connecting to LDAP: ";
|
String errorMessage = (TEST_AUTHENTICATION.equals(action)) ? "Error when authenticating to LDAP: " : "Error when connecting to LDAP: ";
|
||||||
ServicesLogger.LOGGER.errorAuthenticating(ne, errorMessage + ne.getMessage());
|
ServicesLogger.LOGGER.errorAuthenticating(ne, errorMessage + ne.getMessage());
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
|
||||||
if (ldapContext != null) {
|
|
||||||
try {
|
|
||||||
ldapContext.close();
|
|
||||||
} catch (NamingException ne) {
|
|
||||||
ServicesLogger.LOGGER.errorClosingLDAP(ne);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -937,7 +937,7 @@ public class RealmAdminResource {
|
||||||
bindCredential = realm.getComponent(componentId).getConfig().getFirst(LDAPConstants.BIND_CREDENTIAL);
|
bindCredential = realm.getComponent(componentId).getConfig().getFirst(LDAPConstants.BIND_CREDENTIAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean result = new LDAPConnectionTestManager().testLDAP(action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, startTls);
|
boolean result = LDAPConnectionTestManager.testLDAP(session, action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, startTls);
|
||||||
return result ? Response.noContent().build() : ErrorResponse.error("LDAP test error", Response.Status.BAD_REQUEST);
|
return result ? Response.noContent().build() : ErrorResponse.error("LDAP test error", Response.Status.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
secret
|
|
@ -224,6 +224,7 @@
|
||||||
<include>master_smtp__password</include>
|
<include>master_smtp__password</include>
|
||||||
<include>master_ldap__bindCredential</include>
|
<include>master_ldap__bindCredential</include>
|
||||||
<include>test_ldap__bindCredential</include>
|
<include>test_ldap__bindCredential</include>
|
||||||
|
<include>admin-client-test_ldap__bindCredential</include>
|
||||||
</includes>
|
</includes>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -55,6 +55,9 @@ public class UserFederationLdapConnectionTest extends AbstractAdminTest {
|
||||||
response = realm.testLDAPConnection(LDAPConnectionTestManager.TEST_AUTHENTICATION, "ldap://localhost:10389", "uid=admin,ou=system", "secret", "false", null);
|
response = realm.testLDAPConnection(LDAPConnectionTestManager.TEST_AUTHENTICATION, "ldap://localhost:10389", "uid=admin,ou=system", "secret", "false", null);
|
||||||
assertStatus(response, 204);
|
assertStatus(response, 204);
|
||||||
|
|
||||||
|
// Authentication success with bindCredential from Vault
|
||||||
|
response = realm.testLDAPConnection(LDAPConnectionTestManager.TEST_AUTHENTICATION, "ldap://localhost:10389", "uid=admin,ou=system", "${vault.ldap_bindCredential}", "false", null);
|
||||||
|
assertStatus(response, 204);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -74,6 +77,10 @@ public class UserFederationLdapConnectionTest extends AbstractAdminTest {
|
||||||
|
|
||||||
response = realm.testLDAPConnection(LDAPConnectionTestManager.TEST_AUTHENTICATION, "ldaps://localhost:10636", "uid=admin,ou=system", "secret", "true", "10000");
|
response = realm.testLDAPConnection(LDAPConnectionTestManager.TEST_AUTHENTICATION, "ldaps://localhost:10636", "uid=admin,ou=system", "secret", "true", "10000");
|
||||||
assertStatus(response, 204);
|
assertStatus(response, 204);
|
||||||
|
|
||||||
|
// Authentication success with bindCredential from Vault
|
||||||
|
response = realm.testLDAPConnection(LDAPConnectionTestManager.TEST_AUTHENTICATION, "ldaps://localhost:10636", "uid=admin,ou=system", "${vault.ldap_bindCredential}", "true", null);
|
||||||
|
assertStatus(response, 204);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertStatus(Response response, int status) {
|
private void assertStatus(Response response, int status) {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
secret
|
Loading…
Reference in a new issue