From d4392779f6ebd15afda33e8e5555d292b8527fdb Mon Sep 17 00:00:00 2001 From: Steven Hawkins Date: Tue, 17 Jun 2025 05:22:24 -0400 Subject: [PATCH] fix: prevent multiple init when dependsOn is used closes: #40408 Signed-off-by: Steve Hawkins --- .../DefaultKeycloakSessionFactory.java | 12 ++-- .../DefaultKeycloakSessionFactoryTest.java | 65 +++++++++++++++++-- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java index 530c245080e..30cb49cf515 100755 --- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java +++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java @@ -138,14 +138,14 @@ public abstract class DefaultKeycloakSessionFactory implements KeycloakSessionFa Stack recursionPrevention = new Stack<>(); for(Map.Entry, Map> f : factories.entrySet()) { - if (initializedProviders.contains(f.getKey())) { - continue; - } initializeProviders(f.getKey(), factories, initializedProviders, recursionPrevention); } } - private void initializeProviders(Class provider, Map, Map> factories, Set> intializedProviders, Stack recursionPrevention) { + private void initializeProviders(Class provider, Map, Map> factories, Set> initializedProviders, Stack 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); } } diff --git a/services/src/test/java/org/keycloak/services/DefaultKeycloakSessionFactoryTest.java b/services/src/test/java/org/keycloak/services/DefaultKeycloakSessionFactoryTest.java index 3a8db0a6c5d..d3322b03839 100644 --- a/services/src/test/java/org/keycloak/services/DefaultKeycloakSessionFactoryTest.java +++ b/services/src/test/java/org/keycloak/services/DefaultKeycloakSessionFactoryTest.java @@ -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 dependants = Map.of("two", new DummyProviderFactory("two", 2) { + @Override + public Set> dependsOn() { + return Set.of(VaultProvider.class); + } + }, "one", new DummyProviderFactory("one", 0) { + @Override + public Set> dependsOn() { + return Set.of(VaultProvider.class); + } + }); + + Map 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 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 { public DummyProviderFactory(String id, int order) { + super(id, order); + } + + } + + private class DummyVaultProviderFactory extends SimpleProviderFactory { + + public DummyVaultProviderFactory(String id, int order) { + super(id, order); + } + + } + + private class SimpleProviderFactory implements ProviderFactory { + + 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; }