From 69c8b78e98a33da23f85792ca7edc077dd3bc09d Mon Sep 17 00:00:00 2001
From: Konstantinos Georgilakis
Date: Wed, 23 Mar 2022 12:46:31 +0200
Subject: [PATCH] Include 'urn:ietf:params:oauth:grant-type:token-exchange' in
grant_types_supported field of Keycloak OP metadata, if token-exchange is
enabled
closes #10888
---
.../protocol/oidc/OIDCWellKnownProvider.java | 13 +++++++++----
.../oidc/OIDCWellKnownProviderTest.java | 16 ++++++++++++++++
2 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
index 7fd982b2949e..930917fc9ef1 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
@@ -22,6 +22,7 @@
import org.keycloak.authentication.ClientAuthenticator;
import org.keycloak.authentication.ClientAuthenticatorFactory;
import org.keycloak.authentication.authenticators.util.LoAUtil;
+import org.keycloak.common.Profile;
import org.keycloak.crypto.CekManagementProvider;
import org.keycloak.crypto.ClientSignatureVerifierProvider;
import org.keycloak.crypto.ContentEncryptionProvider;
@@ -70,10 +71,7 @@
*/
public class OIDCWellKnownProvider implements WellKnownProvider {
- public static final List DEFAULT_GRANT_TYPES_SUPPORTED = list(OAuth2Constants.AUTHORIZATION_CODE,
- OAuth2Constants.IMPLICIT, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD, OAuth2Constants.CLIENT_CREDENTIALS,
- OAuth2Constants.DEVICE_CODE_GRANT_TYPE,
- OAuth2Constants.CIBA_GRANT_TYPE);
+ public final List DEFAULT_GRANT_TYPES_SUPPORTED;
public static final List DEFAULT_RESPONSE_TYPES_SUPPORTED = list(OAuth2Constants.CODE, OIDCResponseType.NONE, OIDCResponseType.ID_TOKEN, OIDCResponseType.TOKEN, "id_token token", "code id_token", "code token", "code id_token token");
@@ -100,6 +98,13 @@ public OIDCWellKnownProvider(KeycloakSession session) {
}
public OIDCWellKnownProvider(KeycloakSession session, Map openidConfigOverride, boolean includeClientScopes) {
+ DEFAULT_GRANT_TYPES_SUPPORTED = Stream.of(OAuth2Constants.AUTHORIZATION_CODE,
+ OAuth2Constants.IMPLICIT, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD, OAuth2Constants.CLIENT_CREDENTIALS,
+ OAuth2Constants.DEVICE_CODE_GRANT_TYPE,
+ OAuth2Constants.CIBA_GRANT_TYPE).collect(Collectors.toList());
+ if (Profile.isFeatureEnabled(Profile.Feature.TOKEN_EXCHANGE)) {
+ DEFAULT_GRANT_TYPES_SUPPORTED.add(OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE);
+ }
this.session = session;
this.openidConfigOverride = openidConfigOverride;
this.includeClientScopes = includeClientScopes;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java
index 68edb1aea303..af15a52db1aa 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java
@@ -26,6 +26,7 @@
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.broker.provider.util.SimpleHttp;
+import org.keycloak.common.Profile;
import org.keycloak.crypto.Algorithm;
import org.keycloak.jose.jwe.JWEConstants;
import org.keycloak.jose.jwk.JSONWebKeySet;
@@ -46,6 +47,7 @@
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.admin.AbstractAdminTest;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
+import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.forms.BrowserFlowTest;
import org.keycloak.testsuite.forms.LevelOfAssuranceFlowTest;
import org.keycloak.testsuite.util.AdminClientUtil;
@@ -133,6 +135,7 @@ public void testDiscovery() {
// Support standard + implicit + hybrid flow
assertContains(oidcConfig.getResponseTypesSupported(), OAuth2Constants.CODE, OIDCResponseType.ID_TOKEN, "id_token token", "code id_token", "code token", "code id_token token");
+ assertEquals(oidcConfig.getGrantTypesSupported().size(),7);
assertContains(oidcConfig.getGrantTypesSupported(), OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.IMPLICIT,
OAuth2Constants.DEVICE_CODE_GRANT_TYPE);
assertContains(oidcConfig.getResponseModesSupported(), "query", "fragment", "form_post", "jwt", "query.jwt", "fragment.jwt", "form_post.jwt");
@@ -382,6 +385,19 @@ public void testDefaultProviderCustomizations() throws IOException {
}
}
+ @Test
+ @EnableFeature(value = Profile.Feature.TOKEN_EXCHANGE, skipRestart = true)
+ public void testGrantTypesSupportedWithTokenExchange() throws IOException {
+ Client client = AdminClientUtil.createResteasyClient();
+ try {
+ OIDCConfigurationRepresentation oidcConfig = getOIDCDiscoveryRepresentation(client, OAuthClient.AUTH_SERVER_ROOT);
+ assertEquals(oidcConfig.getGrantTypesSupported().size(),8);
+ assertContains(oidcConfig.getGrantTypesSupported(), OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE);
+ } finally {
+ client.close();
+ }
+ }
+
private void assertScopesSupportedMatchesWithRealm(OIDCConfigurationRepresentation oidcConfig) {
Assert.assertNames(oidcConfig.getScopesSupported(), OAuth2Constants.SCOPE_OPENID, OAuth2Constants.OFFLINE_ACCESS,
OAuth2Constants.SCOPE_PROFILE, OAuth2Constants.SCOPE_EMAIL, OAuth2Constants.SCOPE_PHONE, OAuth2Constants.SCOPE_ADDRESS, OIDCLoginProtocolFactory.ACR_SCOPE,