Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OIDC: Encapsulate static/dynamic tenants maps in TenantConfigBean #43590

Merged
merged 2 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public Uni<OidcTenantConfig> apply(OidcTenantConfig oidcTenantConfig) {
final String tenantId = context.get(OidcUtils.TENANT_ID_ATTRIBUTE);

if (tenantId != null && !isTenantSetByAnnotation(context, tenantId)) {
TenantConfigContext tenantContext = tenantConfigBean.getDynamicTenantsConfig().get(tenantId);
TenantConfigContext tenantContext = tenantConfigBean.getDynamicTenant(tenantId);
if (tenantContext != null) {
return Uni.createFrom().item(tenantContext.getOidcTenantConfig());
}
Expand Down Expand Up @@ -197,7 +197,7 @@ private boolean isTenantSetByAnnotation(RoutingContext context, String tenantId)
}

private TenantConfigContext getStaticTenantContext(String tenantId) {
TenantConfigContext configContext = tenantId != null ? tenantConfigBean.getStaticTenantsConfig().get(tenantId) : null;
var configContext = tenantId != null ? tenantConfigBean.getStaticTenant(tenantId) : null;
if (configContext == null) {
if (tenantId != null && !tenantId.isEmpty()) {
LOG.debugf(
Expand Down Expand Up @@ -261,18 +261,18 @@ private Uni<TenantConfigContext> getDynamicTenantContext(RoutingContext context)
@Override
public Uni<? extends TenantConfigContext> apply(OidcTenantConfig tenantConfig) {
if (tenantConfig != null) {
String tenantId = tenantConfig.getTenantId()
var tenantId = tenantConfig.getTenantId()
.orElseThrow(() -> new OIDCException("Tenant configuration must have tenant id"));
TenantConfigContext tenantContext = tenantConfigBean.getDynamicTenantsConfig().get(tenantId);
var tenantContext = tenantConfigBean.getDynamicTenant(tenantId);
if (tenantContext == null) {
return tenantConfigBean.getTenantConfigContextFactory().apply(tenantConfig);
return tenantConfigBean.createDynamicTenantContext(tenantConfig);
} else {
return Uni.createFrom().item(tenantContext);
}
} else {
final String tenantId = context.get(OidcUtils.TENANT_ID_ATTRIBUTE);
if (tenantId != null && !isTenantSetByAnnotation(context, tenantId)) {
TenantConfigContext tenantContext = tenantConfigBean.getDynamicTenantsConfig().get(tenantId);
TenantConfigContext tenantContext = tenantConfigBean.getDynamicTenant(tenantId);
if (tenantContext != null) {
return Uni.createFrom().item(tenantContext);
}
Expand Down Expand Up @@ -304,14 +304,11 @@ public OidcTenantConfig getResolvedConfig(String sessionTenantId) {
return tenantConfigBean.getDefaultTenant().getOidcTenantConfig();
}

if (tenantConfigBean.getStaticTenantsConfig().containsKey(sessionTenantId)) {
return tenantConfigBean.getStaticTenantsConfig().get(sessionTenantId).getOidcTenantConfig();
var tenant = tenantConfigBean.getStaticTenant(sessionTenantId);
if (tenant == null) {
tenant = tenantConfigBean.getDynamicTenant(sessionTenantId);
}

if (tenantConfigBean.getDynamicTenantsConfig().containsKey(sessionTenantId)) {
return tenantConfigBean.getDynamicTenantsConfig().get(sessionTenantId).getOidcTenantConfig();
}
return null;
return tenant != null ? tenant.getOidcTenantConfig() : null;
}

public String getRootPath() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ public class OidcRecorder {
private static final Logger LOG = Logger.getLogger(OidcRecorder.class);
private static final String SECURITY_EVENTS_ENABLED_CONFIG_KEY = "quarkus.security.events.enabled";

private static final Map<String, TenantConfigContext> dynamicTenantsConfig = new ConcurrentHashMap<>();
private static final Set<String> tenantsExpectingServerAvailableEvents = ConcurrentHashMap.newKeySet();
private static volatile boolean userInfoInjectionPointDetected = false;

Expand Down Expand Up @@ -128,42 +127,30 @@ public TenantConfigBean setup(OidcConfig config, Vertx vertxValue, OidcTlsSuppor
staticTenantInitializer));
}

return new TenantConfigBean(staticTenantsConfig, dynamicTenantsConfig, defaultTenantContext,
new Function<OidcTenantConfig, Uni<TenantConfigContext>>() {
return new TenantConfigBean(staticTenantsConfig, defaultTenantContext,
new TenantConfigBean.TenantContextFactory() {
@Override
public Uni<TenantConfigContext> apply(OidcTenantConfig config) {
return createDynamicTenantContext(vertxValue, config, config.getTenantId().get(),
tlsSupport);
public Uni<TenantConfigContext> create(OidcTenantConfig config) {
return createDynamicTenantContext(vertxValue, config, tlsSupport);
}
});
}

private Uni<TenantConfigContext> createDynamicTenantContext(Vertx vertx,
OidcTenantConfig oidcConfig, String tenantId, OidcTlsSupport tlsSupport) {
OidcTenantConfig oidcConfig, OidcTlsSupport tlsSupport) {

var tenantId = oidcConfig.tenantId.orElseThrow();
if (oidcConfig.logout.backchannel.path.isPresent()) {
throw new ConfigurationException(
"BackChannel Logout is currently not supported for dynamic tenants");
}
if (!dynamicTenantsConfig.containsKey(tenantId)) {
Uni<TenantConfigContext> uniContext = createTenantContext(vertx, oidcConfig, false, tenantId, tlsSupport)
.onFailure().transform(new Function<Throwable, Throwable>() {
@Override
public Throwable apply(Throwable t) {
return logTenantConfigContextFailure(t, tenantId);
}
});
return uniContext.onItem().transform(
new Function<TenantConfigContext, TenantConfigContext>() {
@Override
public TenantConfigContext apply(TenantConfigContext t) {
dynamicTenantsConfig.putIfAbsent(tenantId, t);
return t;
}
});
} else {
return Uni.createFrom().item(dynamicTenantsConfig.get(tenantId));
}
return createTenantContext(vertx, oidcConfig, false, tenantId, tlsSupport)
.onFailure().transform(new Function<Throwable, Throwable>() {
@Override
public Throwable apply(Throwable t) {
return logTenantConfigContextFailure(t, tenantId);
}
});
}

private TenantConfigContext createStaticTenantContext(Vertx vertx,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public String resolve(RoutingContext context) {
String[] pathSegments = context.request().path().split("/");
if (pathSegments.length > 0) {
String lastPathSegment = pathSegments[pathSegments.length - 1];
if (tenantConfigBean.getStaticTenantsConfig().containsKey(lastPathSegment)) {
if (tenantConfigBean.getStaticTenant(lastPathSegment) != null) {
LOG.debugf(
"Tenant id '%s' is selected on the '%s' request path", lastPathSegment, context.normalizedPath());
return lastPathSegment;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.oidc.runtime;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

import jakarta.enterprise.context.spi.CreationalContext;
Expand All @@ -14,33 +15,55 @@ public class TenantConfigBean {
private final Map<String, TenantConfigContext> staticTenantsConfig;
private final Map<String, TenantConfigContext> dynamicTenantsConfig;
private final TenantConfigContext defaultTenant;
private final Function<OidcTenantConfig, Uni<TenantConfigContext>> tenantConfigContextFactory;
private final TenantContextFactory tenantContextFactory;

@FunctionalInterface
public interface TenantContextFactory {
Uni<TenantConfigContext> create(OidcTenantConfig oidcTenantConfig);
}

public TenantConfigBean(
Map<String, TenantConfigContext> staticTenantsConfig,
Map<String, TenantConfigContext> dynamicTenantsConfig,
TenantConfigContext defaultTenant,
Function<OidcTenantConfig, Uni<TenantConfigContext>> tenantConfigContextFactory) {
TenantContextFactory tenantContextFactory) {
this.staticTenantsConfig = Map.copyOf(staticTenantsConfig);
this.dynamicTenantsConfig = dynamicTenantsConfig;
this.dynamicTenantsConfig = new ConcurrentHashMap<>();
this.defaultTenant = defaultTenant;
this.tenantConfigContextFactory = tenantConfigContextFactory;
this.tenantContextFactory = tenantContextFactory;
}

public Uni<TenantConfigContext> createDynamicTenantContext(OidcTenantConfig oidcConfig) {
var tenantId = oidcConfig.tenantId.orElseThrow();

var tenant = dynamicTenantsConfig.get(tenantId);
if (tenant != null) {
return Uni.createFrom().item(tenant);
}

return tenantContextFactory.create(oidcConfig).onItem().transform(
new Function<TenantConfigContext, TenantConfigContext>() {
@Override
public TenantConfigContext apply(TenantConfigContext t) {
dynamicTenantsConfig.putIfAbsent(tenantId, t);
return t;
}
});
}

public Map<String, TenantConfigContext> getStaticTenantsConfig() {
return staticTenantsConfig;
}

public TenantConfigContext getDefaultTenant() {
return defaultTenant;
public TenantConfigContext getStaticTenant(String tenantId) {
return staticTenantsConfig.get(tenantId);
}

public Function<OidcTenantConfig, Uni<TenantConfigContext>> getTenantConfigContextFactory() {
return tenantConfigContextFactory;
public TenantConfigContext getDefaultTenant() {
return defaultTenant;
}

public Map<String, TenantConfigContext> getDynamicTenantsConfig() {
return dynamicTenantsConfig;
public TenantConfigContext getDynamicTenant(String tenantId) {
return dynamicTenantsConfig.get(tenantId);
}

public static class Destroyer implements BeanDestroyer<TenantConfigBean> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public String principalNameMulti2() {
}

private String getClientName() {
OidcTenantConfig oidcConfig = tenantConfigBean.getDynamicTenantsConfig().get(session.getTenantId())
OidcTenantConfig oidcConfig = tenantConfigBean.getDynamicTenant(session.getTenantId())
.getOidcTenantConfig();
return oidcConfig.getClientName().get();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public String sessionExpired(@CookieParam("session_expired") String sessionExpir
// Cookie format: jwt|<tenant id>

String[] pair = sessionExpired.split("\\|");
OidcTenantConfig oidcConfig = tenantConfig.getStaticTenantsConfig().get(pair[1]).getOidcTenantConfig();
OidcTenantConfig oidcConfig = tenantConfig.getStaticTenant(pair[1]).getOidcTenantConfig();
JsonWebToken jwt = new DefaultJWTParser().decrypt(pair[0], oidcConfig.credentials.secret.get());

OidcUtils.removeCookie(context, oidcConfig, "session_expired");
Expand Down