fix: prevent multiple init when dependsOn is used

closes: #40408

Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
Steven Hawkins 2025-06-17 05:22:24 -04:00 committed by GitHub
parent 61586ff328
commit d4392779f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 66 additions and 11 deletions

View File

@ -138,14 +138,14 @@ public abstract class DefaultKeycloakSessionFactory implements KeycloakSessionFa
Stack<ProviderFactory> recursionPrevention = new Stack<>();
for(Map.Entry<Class<? extends Provider>, Map<String, ProviderFactory>> f : factories.entrySet()) {
if (initializedProviders.contains(f.getKey())) {
continue;
}
initializeProviders(f.getKey(), factories, initializedProviders, recursionPrevention);
}
}
private void initializeProviders(Class<? extends Provider> provider, Map<Class<? extends Provider>, Map<String, ProviderFactory>> factories, Set<Class<? extends Provider>> intializedProviders, Stack<ProviderFactory> recursionPrevention) {
private void initializeProviders(Class<? extends Provider> provider, Map<Class<? extends Provider>, Map<String, ProviderFactory>> factories, Set<Class<? extends Provider>> initializedProviders, Stack<ProviderFactory> recursionPrevention) {
if (initializedProviders.contains(provider)) {
return;
}
for (ProviderFactory<?> factory : factories.get(provider).values()) {
if (factory == componentFactoryPF)
continue;
@ -161,11 +161,11 @@ public abstract class DefaultKeycloakSessionFactory implements KeycloakSessionFa
throw new RuntimeException("No provider factories exists for provider " + providerDep.getSimpleName() + " required by " + factory.getClass().getName() + " (" + factory.getId() + ")");
}
recursionPrevention.push(factory);
initializeProviders(providerDep, factories, intializedProviders, recursionPrevention);
initializeProviders(providerDep, factories, initializedProviders, recursionPrevention);
recursionPrevention.pop();
}
factory.postInit(this);
intializedProviders.add(provider);
initializedProviders.add(provider);
}
}

View File

@ -10,9 +10,13 @@ import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
import org.keycloak.vault.VaultProvider;
import static org.junit.Assert.assertFalse;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class DefaultKeycloakSessionFactoryTest {
@ -30,6 +34,41 @@ public class DefaultKeycloakSessionFactoryTest {
Config.init(new Config.SystemPropertiesConfigProvider());
}
@Test
public void testProviderInitialization() {
DefaultKeycloakSessionFactory factory = new DefaultKeycloakSessionFactory() {
@Override
public KeycloakSession create() {
return null;
}
};
Map<String, ProviderFactory> dependants = Map.of("two", new DummyProviderFactory("two", 2) {
@Override
public Set<Class<? extends Provider>> dependsOn() {
return Set.of(VaultProvider.class);
}
}, "one", new DummyProviderFactory("one", 0) {
@Override
public Set<Class<? extends Provider>> dependsOn() {
return Set.of(VaultProvider.class);
}
});
Map<String, ProviderFactory> vault = Map.of("three", new DummyVaultProviderFactory("three", 3) {
boolean init;
@Override
public void postInit(KeycloakSessionFactory factory) {
assertFalse(init);
init = true;
}
});
factory.initProviderFactories(false, Map.of(Provider.class, dependants, VaultProvider.class, vault));
}
@Test
public void defaultProviderFromConfigTest() {
Map<String, ProviderFactory> map = new HashMap<>(Map.of(
@ -90,18 +129,34 @@ public class DefaultKeycloakSessionFactoryTest {
}
}
private class DummyProviderFactory implements ProviderFactory {
private String id;
private int order;
private class DummyProviderFactory extends SimpleProviderFactory<Provider> {
public DummyProviderFactory(String id, int order) {
super(id, order);
}
}
private class DummyVaultProviderFactory extends SimpleProviderFactory<VaultProvider> {
public DummyVaultProviderFactory(String id, int order) {
super(id, order);
}
}
private class SimpleProviderFactory<T extends Provider> implements ProviderFactory<T> {
String id;
int order;
public SimpleProviderFactory(String id, int order) {
this.id = id;
this.order = order;
}
@Override
public Provider create(KeycloakSession session) {
public T create(KeycloakSession session) {
return null;
}