Adding utility class for working with throwables and updating the cause check to limit the number of iterations on the stacktrace

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Pedro Igor
2025-11-10 16:26:40 -03:00
parent c28cde359c
commit ded372a57f
3 changed files with 43 additions and 26 deletions

View File

@@ -0,0 +1,38 @@
package org.keycloak.common.util;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* A utility class for working with {@link Throwable} instances.
*/
public final class Throwables {
/**
* Checks if the given {@code throwable} or any of its causes (up to a depth of 3) is an instance of any of the specified exception types.
*
* @param throwable
* @param type
* @return
*/
@SafeVarargs
public static boolean isCausedBy(Throwable throwable, Class<? extends Exception>... type) {
Objects.requireNonNull(throwable, "Throwable must not be null");
int limit = 3;
List<Class<? extends Exception>> types = Arrays.asList(type);
Throwable cause = throwable.getCause();
while (cause != null) {
if (limit-- == 0) {
break;
}
if (types.contains(cause.getClass())) {
return true;
}
cause = cause.getCause();
}
return false;
}
}

View File

@@ -49,6 +49,7 @@ import java.util.List;
import java.util.Set;
import static java.util.Collections.unmodifiableSet;
import static org.keycloak.common.util.Throwables.isCausedBy;
/**
* Default IdentityQuery implementation.
@@ -186,17 +187,9 @@ public class LDAPQuery implements AutoCloseable {
result.add(ldapObject);
}
} catch (Exception e) {
// Check if this is an LDAP connectivity issue
Throwable current = e;
while (current != null) {
if (current instanceof NameNotFoundException || current instanceof CommunicationException ||
current instanceof AuthenticationException) {
throw new StorageUnavailableException("LDAP server is unavailable for provider [" +
ldapFedProvider.getModel().getName() + "]", e);
}
current = current.getCause();
if (isCausedBy(e, NameNotFoundException.class, CommunicationException.class, AuthenticationException.class)) {
throw new StorageUnavailableException("LDAP server is unavailable for provider [" + ldapFedProvider.getModel().getName() + "]", e);
}
throw new ModelException("Failed to fetch results from the LDAP [" + ldapFedProvider.getModel().getName() + "] provider", e);
}

View File

@@ -17,7 +17,7 @@
package org.keycloak.models;
import java.util.List;
import org.keycloak.common.util.Throwables;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -52,20 +52,6 @@ public class ModelException extends RuntimeException {
@SafeVarargs
public final boolean isCausedBy(Class<? extends Exception>... type) {
int limit = 3;
List<Class<? extends Exception>> types = List.of(type);
Throwable cause = getCause();
while (cause != null) {
if (limit-- == 0) {
break;
}
if (types.contains(cause.getClass())) {
return true;
}
cause = cause.getCause();
}
return false;
return Throwables.isCausedBy(this, type);
}
}