Skip to content

Commit

Permalink
Merge pull request #40456 from michalvavrik/feature/oidc-user-info-re…
Browse files Browse the repository at this point in the history
…quired-autoenablement-tweaks

Do not require UserInfo when its injection point is detected for OIDC tenants without the UserInfo endpoint
  • Loading branch information
sberyozkin authored May 4, 2024
2 parents 29bae6b + 7c0ffd4 commit 251439e
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,16 @@ private static boolean isTenantIdentityProviderType(InjectionPointInfo ip) {
@Record(ExecutionTime.RUNTIME_INIT)
@BuildStep
public SyntheticBeanBuildItem setup(
BeanRegistrationPhaseBuildItem beanRegistration,
OidcConfig config,
OidcRecorder recorder,
CoreVertxBuildItem vertxBuildItem,
TlsConfig tlsConfig,
// this is required for setup ordering: we need CP set up
ContextPropagationInitializedBuildItem cpInitializedBuildItem) {
return SyntheticBeanBuildItem.configure(TenantConfigBean.class).unremovable().types(TenantConfigBean.class)
.supplier(recorder.setup(config, vertxBuildItem.getVertx(), tlsConfig))
.supplier(
recorder.setup(config, vertxBuildItem.getVertx(), tlsConfig, detectUserInfoRequired(beanRegistration)))
.destroyer(TenantConfigBean.Destroyer.class)
.scope(Singleton.class) // this should have been @ApplicationScoped but fails for some reason
.setRuntimeInit()
Expand All @@ -252,15 +254,8 @@ public void registerTenantResolverInterceptor(Capabilities capabilities, OidcRec
}
}

@BuildStep
void detectUserInfoRequired(BeanRegistrationPhaseBuildItem beanRegistrationPhaseBuildItem,
BuildProducer<RunTimeConfigurationDefaultBuildItem> runtimeConfigDefaultProducer) {
if (isInjected(beanRegistrationPhaseBuildItem, USER_INFO_NAME, null)) {
runtimeConfigDefaultProducer.produce(
new RunTimeConfigurationDefaultBuildItem("quarkus.oidc.authentication.user-info-required", "true"));
runtimeConfigDefaultProducer.produce(
new RunTimeConfigurationDefaultBuildItem("quarkus.oidc.*.authentication.user-info-required", "true"));
}
private static boolean detectUserInfoRequired(BeanRegistrationPhaseBuildItem beanRegistrationPhaseBuildItem) {
return isInjected(beanRegistrationPhaseBuildItem, USER_INFO_NAME, null);
}

@BuildStep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public class UserInfoRequiredDetectionTest {
quarkus.oidc.named.auth-server-url=${quarkus.oidc.auth-server-url}
quarkus.oidc.named.tenant-paths=/user-info/named-tenant
quarkus.oidc.named.user-info-path=http://${quarkus.http.host}:${quarkus.http.port}/user-info-endpoint
quarkus.oidc.named-2.auth-server-url=${quarkus.oidc.auth-server-url}
quarkus.oidc.named-2.tenant-paths=/user-info/named-tenant-2
quarkus.oidc.named-2.discovery-enabled=false
quarkus.oidc.named-2.jwks-path=protocol/openid-connect/certs
quarkus.http.auth.proactive=false
"""),
"application.properties"));
Expand All @@ -53,6 +57,12 @@ public void testNamedTenant() {
.body(Matchers.is("alice"));
}

@Test
public void testUserInfoNotRequiredWhenMissingUserInfoEndpoint() {
RestAssured.given().auth().oauth2(getAccessToken()).get("/user-info/named-tenant-2").then().statusCode(200)
.body(Matchers.is("false"));
}

private static String getAccessToken() {
return new KeycloakTestClient().getAccessToken("alice", "alice", "quarkus-service-app", "secret", List.of("openid"));
}
Expand Down Expand Up @@ -94,6 +104,13 @@ public String getNamedTenantName() {
}
return userInfo.getPreferredUserName();
}

@PermissionsAllowed("openid")
@Path("named-tenant-2")
@GET
public boolean getNamed2TenantUserInfoRequired() {
return config.namedTenants.get("named-2").authentication.userInfoRequired.orElse(false);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public class OidcRecorder {

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

public Supplier<DefaultTokenIntrospectionUserInfoCache> setupTokenCache(OidcConfig config, Supplier<Vertx> vertx) {
return new Supplier<DefaultTokenIntrospectionUserInfoCache>() {
Expand All @@ -78,7 +79,9 @@ public DefaultTokenIntrospectionUserInfoCache get() {
};
}

public Supplier<TenantConfigBean> setup(OidcConfig config, Supplier<Vertx> vertx, TlsConfig tlsConfig) {
public Supplier<TenantConfigBean> setup(OidcConfig config, Supplier<Vertx> vertx, TlsConfig tlsConfig,
boolean userInfoInjectionPointDetected) {
OidcRecorder.userInfoInjectionPointDetected = userInfoInjectionPointDetected;
final Vertx vertxValue = vertx.get();

String defaultTenantId = config.defaultTenant.getTenantId().orElse(DEFAULT_TENANT_ID);
Expand Down Expand Up @@ -541,6 +544,9 @@ public Uni<OidcProviderClient> apply(OidcConfigurationMetadata metadata, Throwab
"The application supports RP-Initiated Logout but the OpenID Provider does not advertise the end_session_endpoint"));
}
}
if (userInfoInjectionPointDetected && metadata.getUserInfoUri() != null) {
enableUserInfo(oidcConfig);
}
if (oidcConfig.authentication.userInfoRequired.orElse(false) && metadata.getUserInfoUri() == null) {
client.close();
return Uni.createFrom().failure(new ConfigurationException(
Expand Down

0 comments on commit 251439e

Please sign in to comment.