KEYCLOAK-9002 StackOverflowError when reading LDAP-backed users via REST API

This commit is contained in:
mposolda 2018-12-06 17:17:40 +01:00 committed by Marek Posolda
parent 3462be857b
commit 88141320ac
2 changed files with 39 additions and 0 deletions

View file

@ -39,6 +39,7 @@ import org.keycloak.credential.CredentialModel;
import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator; import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator;
import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator; import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator;
import org.keycloak.models.*; import org.keycloak.models.*;
import org.keycloak.models.cache.CachedUserModel;
import org.keycloak.models.utils.DefaultRoles; import org.keycloak.models.utils.DefaultRoles;
import org.keycloak.models.utils.ReadOnlyUserModelDelegate; import org.keycloak.models.utils.ReadOnlyUserModelDelegate;
import org.keycloak.policy.PasswordPolicyManagerProvider; import org.keycloak.policy.PasswordPolicyManagerProvider;
@ -160,6 +161,16 @@ public class LDAPStorageProvider implements UserStorageProvider,
return existing; return existing;
} }
// We need to avoid having CachedUserModel as cache is upper-layer then LDAP. Hence having CachedUserModel here may cause StackOverflowError
if (local instanceof CachedUserModel) {
local = session.userStorageManager().getUserById(local.getId(), realm);
existing = userManager.getManagedProxiedUser(local.getId());
if (existing != null) {
return existing;
}
}
UserModel proxied = local; UserModel proxied = local;
checkDNChanged(realm, local, ldapObject); checkDNChanged(realm, local, ldapObject);

View file

@ -985,6 +985,34 @@ public class LDAPProvidersIntegrationTest extends AbstractLDAPTest {
}); });
} }
// KEYCLOAK-9002
@Test
public void testSearchWithPartiallyCachedUser() {
testingClient.server().run(session -> {
session.userCache().clear();
});
// This will load user from LDAP and partially cache him (including attributes)
testingClient.server().run(session -> {
LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel appRealm = ctx.getRealm();
UserModel user = session.users().getUserByUsername("johnkeycloak", appRealm);
Assert.assertNotNull(user);
user.getAttributes();
});
// Assert search without arguments won't blow up with StackOverflowError
adminClient.realm("test").users().search(null, 0, 10, false);
List<UserRepresentation> users = adminClient.realm("test").users().search("johnkeycloak", 0, 10, false);
Assert.assertTrue(users.stream().anyMatch(userRepresentation -> "johnkeycloak".equals(userRepresentation.getUsername())));
}
@Test @Test
public void testLDAPUserRefreshCache() { public void testLDAPUserRefreshCache() {
testingClient.server().run(session -> { testingClient.server().run(session -> {