Fix NPE for component creation when realm unset but config known

Fixes #9019
This commit is contained in:
Hynek Mlnarik 2021-12-06 15:55:45 +01:00 committed by Hynek Mlnařík
parent 43c46dbcf8
commit 95614e8b40
3 changed files with 17 additions and 9 deletions

View file

@ -306,7 +306,7 @@ public final class KeycloakModelUtils {
String componentId = config.get("componentId");
if (realmId == null || componentId == null) {
realmId = "ROOT";
ComponentModel cm = new ScopeComponentModel(providerClass, config, spiName);
ComponentModel cm = new ScopeComponentModel(providerClass, config, spiName, realmId);
return factory.getProviderFactory(providerClass, realmId, cm.getId(), k -> cm);
} else {
return factory.getProviderFactory(providerClass, realmId, componentId, componentModelGetter(realmId, componentId));
@ -318,14 +318,16 @@ public final class KeycloakModelUtils {
private final String componentId;
private final String providerId;
private final String providerType;
private final String realmId;
private final Scope config;
public ScopeComponentModel(Class<?> providerClass, Scope baseConfiguration, String spiName) {
public ScopeComponentModel(Class<?> providerClass, Scope baseConfiguration, String spiName, String realmId) {
final String pr = baseConfiguration.get("provider", Config.getProvider(spiName));
this.providerId = pr == null ? "default" : pr;
this.config = baseConfiguration.scope(this.providerId);
this.componentId = spiName + "-" + this.providerId;
this.componentId = spiName + "- " + (realmId == null ? "" : "f:" + realmId + ":") + this.providerId;
this.realmId = realmId;
this.providerType = providerClass.getName();
}
@ -349,6 +351,11 @@ public final class KeycloakModelUtils {
return componentId;
}
@Override
public String getParentId() {
return realmId;
}
@Override
public boolean get(String key, boolean defaultValue) {
return config.getBoolean(key, defaultValue);
@ -366,7 +373,6 @@ public final class KeycloakModelUtils {
@Override
public String get(String key, String defaultValue) {
return config.get(key, defaultValue);
}

View file

@ -143,7 +143,12 @@ public class DefaultComponentFactoryProviderFactory implements ComponentFactoryP
newFactory.init(configScope);
newFactory.postInit(factory);
dependentInvalidations.computeIfAbsent(realmId, k -> ConcurrentHashMap.newKeySet()).add(componentId);
if (realmId == null) {
realmId = configScope.getComponentParentId();
}
if (realmId != null) {
dependentInvalidations.computeIfAbsent(realmId, k -> ConcurrentHashMap.newKeySet()).add(componentId);
}
dependentInvalidations.computeIfAbsent(newFactory.getClass(), k -> ConcurrentHashMap.newKeySet()).add(componentId);
return newFactory;

View file

@ -354,15 +354,12 @@ public class DefaultKeycloakSession implements KeycloakSession {
Integer hash = clazz.hashCode() + componentId.hashCode();
T provider = (T) providers.get(hash);
final RealmModel realm = getContext().getRealm();
if (realm == null) {
throw new IllegalArgumentException("Realm not set in the context.");
}
// KEYCLOAK-11890 - Avoid using HashMap.computeIfAbsent() to implement logic in outer if() block below,
// since per JDK-8071667 the remapping function should not modify the map during computation. While
// allowed on JDK 1.8, attempt of such a modification throws ConcurrentModificationException with JDK 9+
if (provider == null) {
final String realmId = realm.getId();
final String realmId = realm == null ? null : realm.getId();
ProviderFactory<T> providerFactory = factory.getProviderFactory(clazz, realmId, componentId, modelGetter);
if (providerFactory != null) {
provider = providerFactory.create(this);