diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildStep.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildStep.java index 9bc2cae847574..a7e4e41dfbd2f 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildStep.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/OidcBuildStep.java @@ -218,6 +218,7 @@ private static boolean isTenantIdentityProviderType(InjectionPointInfo ip) { @Record(ExecutionTime.RUNTIME_INIT) @BuildStep public SyntheticBeanBuildItem setup( + BeanRegistrationPhaseBuildItem beanRegistration, OidcConfig config, OidcRecorder recorder, CoreVertxBuildItem vertxBuildItem, @@ -225,7 +226,8 @@ public SyntheticBeanBuildItem setup( // 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() @@ -252,15 +254,8 @@ public void registerTenantResolverInterceptor(Capabilities capabilities, OidcRec } } - @BuildStep - void detectUserInfoRequired(BeanRegistrationPhaseBuildItem beanRegistrationPhaseBuildItem, - BuildProducer 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 diff --git a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/UserInfoRequiredDetectionTest.java b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/UserInfoRequiredDetectionTest.java index 10c69b0587693..02a81c23f5610 100644 --- a/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/UserInfoRequiredDetectionTest.java +++ b/extensions/oidc/deployment/src/test/java/io/quarkus/oidc/test/UserInfoRequiredDetectionTest.java @@ -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")); @@ -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")); } @@ -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); + } } } diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java index 0568683eda84a..9cf4b4177e88d 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcRecorder.java @@ -68,6 +68,7 @@ public class OidcRecorder { private static final Map dynamicTenantsConfig = new ConcurrentHashMap<>(); private static final Set tenantsExpectingServerAvailableEvents = ConcurrentHashMap.newKeySet(); + private static volatile boolean userInfoInjectionPointDetected = false; public Supplier setupTokenCache(OidcConfig config, Supplier vertx) { return new Supplier() { @@ -78,7 +79,9 @@ public DefaultTokenIntrospectionUserInfoCache get() { }; } - public Supplier setup(OidcConfig config, Supplier vertx, TlsConfig tlsConfig) { + public Supplier setup(OidcConfig config, Supplier vertx, TlsConfig tlsConfig, + boolean userInfoInjectionPointDetected) { + OidcRecorder.userInfoInjectionPointDetected = userInfoInjectionPointDetected; final Vertx vertxValue = vertx.get(); String defaultTenantId = config.defaultTenant.getTenantId().orElse(DEFAULT_TENANT_ID); @@ -541,6 +544,9 @@ public Uni 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(