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 javax.naming.AuthenticationException;
import javax.naming.CommunicationException;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
@ -1123,19 +1125,36 @@ public class LDAPStorageProvider implements UserStorageProvider,
return Stream.iterate(ldapQuery,
query -> {
//the very 1st page - Pagination context might not yet be present
if (query.getPaginationContext() == null) try {
query.initPagination();
//returning true for first iteration as the LDAP was not queried yet
return true;
} catch (NamingException e) {
throw new ModelException("Querying of LDAP failed " + query, e);
if (query.getPaginationContext() == null) {
try {
query.initPagination();
//returning true for first iteration as the LDAP was not queried yet
return true;
} 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();
},
query -> query
).flatMap(query -> {
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()) {
return Stream.empty();
}

View File

@ -163,13 +163,19 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
return user;
}
UserModel validated = validator.validate(realm, user);
try {
UserModel validated = validator.validate(realm, user);
if (validated == null) {
return deleteFederatedUser(realm, user);
if (validated == null) {
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) {

View File

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