Improve error messages when testing LDAP connection (#21013)
Closes #15434
This commit is contained in:
parent
0fc4d6120b
commit
91e543f415
6 changed files with 86 additions and 20 deletions
|
@ -71,11 +71,52 @@ public class LDAPServerCapabilitiesManager {
|
|||
return new LDAPIdentityStore(session, ldapConfig).queryServerCapabilities();
|
||||
}
|
||||
|
||||
public static boolean testLDAP(TestLdapConnectionRepresentation config, KeycloakSession session, RealmModel realm) {
|
||||
public static class InvalidBindDNException extends javax.naming.NamingException {
|
||||
public InvalidBindDNException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getErrorCode(Throwable throwable) {
|
||||
String errorMsg = "UnknownError";
|
||||
if (throwable instanceof javax.naming.NamingException)
|
||||
errorMsg = "NamingError";
|
||||
if (throwable instanceof javax.naming.AuthenticationException)
|
||||
errorMsg = "AuthenticationFailure";
|
||||
if (throwable instanceof javax.naming.CommunicationException)
|
||||
errorMsg = "CommunicationError";
|
||||
if (throwable instanceof javax.naming.ServiceUnavailableException)
|
||||
errorMsg = "ServiceUnavailable";
|
||||
if (throwable instanceof javax.naming.InvalidNameException)
|
||||
errorMsg = "InvalidName";
|
||||
if (throwable instanceof javax.naming.ServiceUnavailableException)
|
||||
errorMsg = "ServiceUnavailable";
|
||||
if (throwable instanceof InvalidBindDNException)
|
||||
errorMsg = "InvalidBindDN";
|
||||
|
||||
if (throwable instanceof javax.naming.NamingException) {
|
||||
Throwable rootCause = ((javax.naming.NamingException)throwable).getRootCause();
|
||||
if (rootCause instanceof java.net.MalformedURLException)
|
||||
errorMsg = "MalformedURL";
|
||||
if (rootCause instanceof java.net.NoRouteToHostException)
|
||||
errorMsg = "NoRouteToHost";
|
||||
if (rootCause instanceof java.net.ConnectException)
|
||||
errorMsg = "ConnectionFailed";
|
||||
if (rootCause instanceof java.net.UnknownHostException)
|
||||
errorMsg = "UnknownHost";
|
||||
if (rootCause instanceof javax.net.ssl.SSLHandshakeException)
|
||||
errorMsg = "SSLHandshakeFailed";
|
||||
if (rootCause instanceof java.net.SocketException)
|
||||
errorMsg = "SocketReset";
|
||||
}
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
public static void testLDAP(TestLdapConnectionRepresentation config, KeycloakSession session, RealmModel realm) throws javax.naming.NamingException {
|
||||
|
||||
if (!TEST_CONNECTION.equals(config.getAction()) && !TEST_AUTHENTICATION.equals(config.getAction())) {
|
||||
ServicesLogger.LOGGER.unknownAction(config.getAction());
|
||||
return false;
|
||||
throw new javax.naming.NamingException("testLDAP unknown action");
|
||||
}
|
||||
|
||||
if (TEST_AUTHENTICATION.equals(config.getAction())) {
|
||||
|
@ -83,8 +124,7 @@ public class LDAPServerCapabilitiesManager {
|
|||
// LDAPContextManager is responsible for correct order of addition of credentials to context in case
|
||||
// tls is true
|
||||
if ((config.getBindDn() == null || config.getBindDn().isEmpty()) && LDAPConstants.AUTH_TYPE_SIMPLE.equals(config.getAuthType())) {
|
||||
logger.error("Unknown bind DN");
|
||||
return false;
|
||||
throw new InvalidBindDNException("Unknown bind DN");
|
||||
}
|
||||
} else {
|
||||
// only test the connection.
|
||||
|
@ -97,14 +137,11 @@ public class LDAPServerCapabilitiesManager {
|
|||
// is not needed anymore
|
||||
try (LDAPContextManager ldapContextManager = LDAPContextManager.create(session, ldapConfig)) {
|
||||
ldapContextManager.getLdapContext();
|
||||
|
||||
// Connection was successful, no exception was raised returning true
|
||||
return true;
|
||||
} catch (Exception ne) {
|
||||
String errorMessage = (TEST_AUTHENTICATION.equals(config.getAction())) ? "Error when authenticating to LDAP: "
|
||||
: "Error when connecting to LDAP: ";
|
||||
ServicesLogger.LOGGER.errorAuthenticating(ne, errorMessage + ne.getMessage());
|
||||
return false;
|
||||
throw ne;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,10 +72,13 @@ public class TestLdapConnectionResource {
|
|||
|
||||
TestLdapConnectionRepresentation config = new TestLdapConnectionRepresentation(action, connectionUrl, bindDn, bindCredential, useTruststoreSpi, connectionTimeout, startTls, LDAPConstants.AUTH_TYPE_SIMPLE);
|
||||
config.setComponentId(componentId);
|
||||
if (! LDAPServerCapabilitiesManager.testLDAP(config, session, realm)) {
|
||||
throw ErrorResponse.error("LDAP test error", Response.Status.BAD_REQUEST);
|
||||
try {
|
||||
LDAPServerCapabilitiesManager.testLDAP(config, session, realm);
|
||||
return Response.noContent().build();
|
||||
} catch(Exception e) {
|
||||
String errorMsg = LDAPServerCapabilitiesManager.getErrorCode(e);
|
||||
throw ErrorResponse.error(errorMsg, Response.Status.BAD_REQUEST);
|
||||
}
|
||||
return Response.noContent().build();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,10 +89,13 @@ public class TestLdapConnectionResource {
|
|||
@NoCache
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response testLDAPConnection(TestLdapConnectionRepresentation config) {
|
||||
if (! LDAPServerCapabilitiesManager.testLDAP(config, session, realm)) {
|
||||
throw ErrorResponse.error("LDAP test error", Response.Status.BAD_REQUEST);
|
||||
try {
|
||||
LDAPServerCapabilitiesManager.testLDAP(config, session, realm);
|
||||
return Response.noContent().build();
|
||||
} catch(Exception e) {
|
||||
String errorMsg = LDAPServerCapabilitiesManager.getErrorCode(e);
|
||||
throw ErrorResponse.error(errorMsg, Response.Status.BAD_REQUEST);
|
||||
}
|
||||
return Response.noContent().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -123,7 +123,9 @@ public final class LDAPContextManager implements AutoCloseable {
|
|||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Could not negotiate TLS", e);
|
||||
throw new AuthenticationException("Could not negotiate TLS");
|
||||
NamingException ne = new AuthenticationException("Could not negotiate TLS");
|
||||
ne.setRootCause(e);
|
||||
throw ne;
|
||||
}
|
||||
|
||||
// throws AuthenticationException when authentication fails
|
||||
|
|
|
@ -93,8 +93,7 @@ const userImportingDisabledFailMessage =
|
|||
"User federation provider could not be saved: Can not disable Importing users when LDAP provider mode is UNSYNCED";
|
||||
|
||||
const ldapTestSuccessMsg = "Successfully connected to LDAP";
|
||||
const ldapTestFailMsg =
|
||||
"Error when trying to connect to LDAP. See server.log for details. LDAP test error";
|
||||
const ldapTestFailMsg = "Error when trying to connect to LDAP: 'SocketReset'";
|
||||
|
||||
describe("User Federation LDAP tests", () => {
|
||||
beforeEach(() => {
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
"queryExtensions": "Query Supported Extensions",
|
||||
"testAuthentication": "Test authentication",
|
||||
"testSuccess": "Successfully connected to LDAP",
|
||||
"testError": "Error when trying to connect to LDAP. See server.log for details. {{error}}",
|
||||
"testError": "Error when trying to connect to LDAP: '{{error}}'",
|
||||
"learnMore": "Learn more",
|
||||
"managePriorities": "Manage priorities",
|
||||
"managePriorityOrder": "Manage priority order",
|
||||
|
|
|
@ -26,6 +26,8 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.services.ServicesLogger;
|
||||
import org.keycloak.storage.managers.UserStorageSyncManager;
|
||||
import org.keycloak.services.ErrorResponse;
|
||||
import org.keycloak.services.managers.LDAPServerCapabilitiesManager;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
|
@ -42,6 +44,7 @@ import jakarta.ws.rs.Produces;
|
|||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.HttpHeaders;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -74,6 +77,15 @@ public class UserStorageProviderResource {
|
|||
this.headers = session.getContext().getRequestHeaders();
|
||||
}
|
||||
|
||||
public static String getErrorCode(Throwable throwable) {
|
||||
if (throwable instanceof org.keycloak.models.ModelException) {
|
||||
if (throwable.getCause() != null) {
|
||||
return getErrorCode(throwable.getCause());
|
||||
}
|
||||
}
|
||||
return LDAPServerCapabilitiesManager.getErrorCode(throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Need this for admin console to display simple name of provider when displaying user detail
|
||||
*
|
||||
|
@ -138,9 +150,19 @@ public class UserStorageProviderResource {
|
|||
UserStorageSyncManager syncManager = new UserStorageSyncManager();
|
||||
SynchronizationResult syncResult;
|
||||
if ("triggerFullSync".equals(action)) {
|
||||
syncResult = syncManager.syncAllUsers(session.getKeycloakSessionFactory(), realm.getId(), providerModel);
|
||||
try {
|
||||
syncResult = syncManager.syncAllUsers(session.getKeycloakSessionFactory(), realm.getId(), providerModel);
|
||||
} catch(Exception e) {
|
||||
String errorMsg = getErrorCode(e);
|
||||
throw ErrorResponse.error(errorMsg, Response.Status.BAD_REQUEST);
|
||||
}
|
||||
} else if ("triggerChangedUsersSync".equals(action)) {
|
||||
syncResult = syncManager.syncChangedUsers(session.getKeycloakSessionFactory(), realm.getId(), providerModel);
|
||||
try {
|
||||
syncResult = syncManager.syncChangedUsers(session.getKeycloakSessionFactory(), realm.getId(), providerModel);
|
||||
} catch(Exception e) {
|
||||
String errorMsg = getErrorCode(e);
|
||||
throw ErrorResponse.error(errorMsg, Response.Status.BAD_REQUEST);
|
||||
}
|
||||
} else if (action == null || action == "") {
|
||||
logger.debug("Missing action");
|
||||
throw new BadRequestException("Missing action");
|
||||
|
|
Loading…
Reference in a new issue