Do not fail when querying user federation providers and log messages to indicate the problem

Closes #42276

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Pedro Igor 2025-09-12 11:41:59 -03:00
parent e4114e6c74
commit d65c17ebc7
3 changed files with 57 additions and 11 deletions

View File

@ -35,6 +35,8 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.naming.AuthenticationException; import javax.naming.AuthenticationException;
import javax.naming.CommunicationException;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.naming.directory.SearchControls; import javax.naming.directory.SearchControls;
@ -1123,19 +1125,36 @@ public class LDAPStorageProvider implements UserStorageProvider,
return Stream.iterate(ldapQuery, return Stream.iterate(ldapQuery,
query -> { query -> {
//the very 1st page - Pagination context might not yet be present //the very 1st page - Pagination context might not yet be present
if (query.getPaginationContext() == null) try { if (query.getPaginationContext() == null) {
query.initPagination(); try {
//returning true for first iteration as the LDAP was not queried yet query.initPagination();
return true; //returning true for first iteration as the LDAP was not queried yet
} catch (NamingException e) { return true;
throw new ModelException("Querying of LDAP failed " + query, e); } catch (NameNotFoundException | CommunicationException e) {
logger.errorf(e, "Failed to init LDAP query pagination %s", query);
return false;
} catch (NamingException e) {
throw new ModelException("Querying of LDAP failed " + query, e);
}
} }
return query.getPaginationContext().hasNextPage(); return query.getPaginationContext().hasNextPage();
}, },
query -> query query -> query
).flatMap(query -> { ).flatMap(query -> {
query.setLimit(limit); query.setLimit(limit);
List<LDAPObject> ldapObjects = query.getResultList(); List<LDAPObject> ldapObjects;
try {
ldapObjects = query.getResultList();
} catch (ModelException mde) {
if (mde.isCausedBy(NameNotFoundException.class, CommunicationException.class)) {
logger.errorf(mde, "Failed to query LDAP %s", query);
return Stream.empty();
} else {
throw mde;
}
}
if (ldapObjects.isEmpty()) { if (ldapObjects.isEmpty()) {
return Stream.empty(); return Stream.empty();
} }

View File

@ -163,13 +163,19 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
return user; return user;
} }
UserModel validated = validator.validate(realm, user); try {
UserModel validated = validator.validate(realm, user);
if (validated == null) { if (validated == null) {
return deleteFederatedUser(realm, user); return deleteFederatedUser(realm, user);
}
return validated;
} catch (Exception e) {
logger.warnf(e, "User storage provider %s failed during federated user validation", model.getName());
} }
return validated; return null;
} }
private ReadOnlyUserModelDelegate deleteFederatedUser(RealmModel realm, UserModel user) { private ReadOnlyUserModelDelegate deleteFederatedUser(RealmModel realm, UserModel user) {

View File

@ -17,6 +17,8 @@
package org.keycloak.models; package org.keycloak.models;
import java.util.List;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
@ -47,4 +49,23 @@ public class ModelException extends RuntimeException {
public void setParameters(Object[] parameters) { public void setParameters(Object[] parameters) {
this.parameters = parameters; this.parameters = parameters;
} }
@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;
}
} }