diff --git a/extensions/oidc-token-propagation-reactive/runtime/src/main/java/io/quarkus/oidc/token/propagation/reactive/AccessTokenRequestReactiveFilter.java b/extensions/oidc-token-propagation-reactive/runtime/src/main/java/io/quarkus/oidc/token/propagation/reactive/AccessTokenRequestReactiveFilter.java index 9f3b7c601061e..df1636fcec8a3 100644 --- a/extensions/oidc-token-propagation-reactive/runtime/src/main/java/io/quarkus/oidc/token/propagation/reactive/AccessTokenRequestReactiveFilter.java +++ b/extensions/oidc-token-propagation-reactive/runtime/src/main/java/io/quarkus/oidc/token/propagation/reactive/AccessTokenRequestReactiveFilter.java @@ -33,7 +33,7 @@ @Priority(Priorities.AUTHENTICATION) public class AccessTokenRequestReactiveFilter implements ResteasyReactiveClientRequestFilter { private static final Logger LOG = Logger.getLogger(AccessTokenRequestReactiveFilter.class); - private static final String BEARER_SCHEME_WITH_SPACE = "Bearer "; + private static final String BEARER_SCHEME = "Bearer"; private static final String ERROR_MSG = "OIDC Token Propagation Reactive requires a safe (isolated) Vert.x sub-context because configuration property 'quarkus.rest-client-oidc-token-propagation.enabled-during-authentication' has been set to true, but the current context hasn't been flagged as such."; private final boolean enabledDuringAuthentication; private final Instance accessToken; @@ -118,13 +118,17 @@ protected String getClientName() { public void propagateToken(ResteasyReactiveClientRequestContext requestContext, String accessToken) { if (accessToken != null) { - requestContext.getHeaders().putSingle(HttpHeaders.AUTHORIZATION, BEARER_SCHEME_WITH_SPACE + accessToken); + requestContext.getHeaders().putSingle(HttpHeaders.AUTHORIZATION, getAuthorizationScheme() + " " + accessToken); } else { LOG.debugf("Access token is null, aborting the request with HTTP 401 error"); abortRequest(requestContext); } } + protected String getAuthorizationScheme() { + return BEARER_SCHEME; + } + protected boolean verifyTokenInstance(ResteasyReactiveClientRequestContext requestContext) { if (enabledDuringAuthentication) { // TokenCredential cannot be accessed from CDI during authentication process diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java index 27ff7831062b6..26c4ecadc4835 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/OidcTenantConfig.java @@ -1176,6 +1176,11 @@ public enum ResponseMode { */ public Optional userInfoRequired = Optional.empty(); + /** + * Authorization scheme for requesting UserInfo. + */ + public String userInfoScheme = OidcConstants.BEARER_SCHEME; + /** * Session age extension in minutes. * The user session age property is set to the value of the ID token life-span by default and @@ -2032,6 +2037,7 @@ public static enum Provider { MASTODON, MICROSOFT, SLACK, + SNYK, SPOTIFY, STRAVA, TWITCH, diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java index 8acddaf876a62..cdd968b4e39c1 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcProviderClient.java @@ -133,7 +133,8 @@ public Uni apply(Throwable t) { } private Uni doGetUserInfo(OidcRequestContextProperties requestProps, String token, List cookies) { - LOG.debugf("Get UserInfo on: %s auth: %s", metadata.getUserInfoUri(), OidcConstants.BEARER_SCHEME + " " + token); + LOG.debugf("Get UserInfo on: %s auth: %s", metadata.getUserInfoUri(), + oidcConfig.authentication.userInfoScheme + " " + token); HttpRequest request = client.getAbs(metadata.getUserInfoUri()); if (!cookies.isEmpty()) { @@ -142,7 +143,7 @@ private Uni doGetUserInfo(OidcRequestContextProperties request return OidcCommonUtils .sendRequest(vertx, filterHttpRequest(requestProps, OidcEndpoint.Type.USERINFO, request, null) - .putHeader(AUTHORIZATION_HEADER, OidcConstants.BEARER_SCHEME + " " + token), + .putHeader(AUTHORIZATION_HEADER, oidcConfig.authentication.userInfoScheme + " " + token), oidcConfig.useBlockingDnsLookup) .onItem().transform(resp -> getUserInfo(requestProps, resp)); } diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcTenantConfig.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcTenantConfig.java index f3c9c1463458c..360b60765de3a 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcTenantConfig.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/OidcTenantConfig.java @@ -770,6 +770,12 @@ enum ResponseMode { @ConfigDocDefault("true when UserInfo bean is injected, false otherwise") Optional userInfoRequired(); + /** + * Authorization scheme for requesting UserInfo. + */ + @WithDefault(OidcConstants.BEARER_SCHEME) + String userInfoScheme(); + /** * Session age extension in minutes. * The user session age property is set to the value of the ID token life-span by default and diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/providers/KnownOidcProviders.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/providers/KnownOidcProviders.java index 9c0208d2511ee..05b451e1e0ef1 100644 --- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/providers/KnownOidcProviders.java +++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/providers/KnownOidcProviders.java @@ -20,6 +20,7 @@ public static OidcTenantConfig provider(OidcTenantConfig.Provider provider) { case MASTODON -> mastodon(); case MICROSOFT -> microsoft(); case SLACK -> slack(); + case SNYK -> snyk(); case SPOTIFY -> spotify(); case STRAVA -> strava(); case TWITCH -> twitch(); @@ -215,4 +216,19 @@ private static OidcTenantConfig discord() { return ret; } + + private static OidcTenantConfig snyk() { + OidcTenantConfig ret = new OidcTenantConfig(); + ret.setAuthServerUrl("https://app.snyk.io/oauth2"); + ret.setApplicationType(OidcTenantConfig.ApplicationType.WEB_APP); + ret.setDiscoveryEnabled(false); + ret.setAuthorizationPath("authorize"); + ret.setTokenPath("token"); + ret.getAuthentication().setScopes(List.of("org.read")); + ret.getAuthentication().setIdTokenRequired(false); + ret.getAuthentication().userInfoScheme = "token"; + ret.getToken().setVerifyAccessTokenWithUserInfo(true); + ret.setUserInfoPath("https://api.snyk.io/rest/self"); + return ret; + } } diff --git a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java index b71efbcb8f78c..94f9abc865efd 100644 --- a/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java +++ b/extensions/oidc/runtime/src/test/java/io/quarkus/oidc/runtime/OidcTenantConfigImpl.java @@ -8,6 +8,7 @@ import java.util.Optional; import java.util.OptionalInt; +import io.quarkus.oidc.common.runtime.OidcConstants; import io.quarkus.runtime.configuration.TrimmedStringConverter; import io.smallrye.config.WithConverter; @@ -143,6 +144,7 @@ enum ConfigMappingMethods { AUTHENTICATION_ALLOW_MULTIPLE_CODE_FLOWS, AUTHENTICATION_FAIL_ON_MISSING_STATE_PARAM, AUTHENTICATION_USER_INFO_REQUIRED, + AUTHENTICATION_USER_INFO_SCHEME, AUTHENTICATION_SESSION_AGE_EXTENSION, AUTHENTICATION_STATE_COOKIE_AGE, AUTHENTICATION_JAVASCRIPT_AUTO_REDIRECT, @@ -691,6 +693,12 @@ public boolean failOnMissingStateParam() { return false; } + @Override + public String userInfoScheme() { + invocationsRecorder.put(ConfigMappingMethods.AUTHENTICATION_USER_INFO_SCHEME, true); + return OidcConstants.BEARER_SCHEME; + } + @Override public Optional userInfoRequired() { invocationsRecorder.put(ConfigMappingMethods.AUTHENTICATION_USER_INFO_REQUIRED, true);