Skip to content

Commit 6fce042

Browse files
authored
KNOX-3432: Advertise RFC 8693 token-exchange and client_credentials grant types in KnoxIDF discovery metadata (#1376)
1 parent 7b90d0d commit 6fce042

4 files changed

Lines changed: 22 additions & 2 deletions

File tree

.github/workflows/tests/test_knoxidf.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,12 @@ def test_discovery(self):
6666
self.assertEqual(config.get("response_types_supported"), ["code"])
6767
self.assertEqual(
6868
config.get("grant_types_supported"),
69-
["authorization_code", "refresh_token"],
69+
[
70+
"authorization_code",
71+
"refresh_token",
72+
"client_credentials",
73+
"urn:ietf:params:oauth:grant-type:token-exchange",
74+
],
7075
)
7176
self.assertEqual(config.get("id_token_signing_alg_values_supported"), ["RS256"])
7277
# DEFAULT_SCOPES is an ImmutableSet, so discovery emits it in insertion order.

gateway-service-knoxidf/src/main/java/org/apache/knox/gateway/service/knoxidf/DiscoveryResource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public Response getConfig(@Context UriInfo uriInfo) {
8585
// field is absent, but stating it tells MCP clients to use dynamic client registration
8686
// (registration_endpoint) rather than a URL client_id. Flip to true only if CIMD is implemented.
8787
config.put("client_id_metadata_document_supported", Boolean.FALSE);
88-
config.put("grant_types_supported", new String[]{KnoxIDFConstants.AUTH_CODE, KnoxIDFConstants.REFRESH_TOKEN});
88+
config.put("grant_types_supported", new String[]{KnoxIDFConstants.AUTH_CODE, KnoxIDFConstants.REFRESH_TOKEN, KnoxIDFConstants.CLIENT_CREDENTIALS, KnoxIDFConstants.TOKEN_EXCHANGE_GRANT_TYPE});
8989
config.put("scopes_supported", KnoxIDFConstants.DEFAULT_SCOPES);
9090
config.put("id_token_signing_alg_values_supported", new String[]{"RS256"});
9191
// Advertise only S256: AuthorizeResource rejects any other code_challenge_method (including

gateway-service-knoxidf/src/test/java/org/apache/knox/gateway/service/knoxidf/DiscoveryResourceMetadataTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import javax.ws.rs.core.Response;
2525
import javax.ws.rs.core.UriInfo;
2626

27+
import org.apache.knox.gateway.util.knoxidf.KnoxIDFConstants;
2728
import org.easymock.EasyMock;
2829
import org.junit.Test;
2930

@@ -65,5 +66,14 @@ public void testAdvertisesSubjectTypesAndRegistrationEndpoint() {
6566
// CIMD is not implemented, so it must be advertised explicitly as false (never true).
6667
assertTrue("client_id_metadata_document_supported must be present and false.",
6768
body.contains("\"client_id_metadata_document_supported\":false"));
69+
70+
assertTrue("grant_types_supported must advertise authorization_code.",
71+
body.contains("grant_types_supported") && body.contains("\"" + KnoxIDFConstants.AUTH_CODE + "\""));
72+
assertTrue("grant_types_supported must advertise refresh_token.",
73+
body.contains("\"" + KnoxIDFConstants.REFRESH_TOKEN + "\""));
74+
assertTrue("grant_types_supported must advertise client_credentials.",
75+
body.contains("\"" + KnoxIDFConstants.CLIENT_CREDENTIALS + "\""));
76+
assertTrue("grant_types_supported must advertise the RFC 8693 token-exchange grant type.",
77+
body.contains("\"" + KnoxIDFConstants.TOKEN_EXCHANGE_GRANT_TYPE + "\""));
6878
}
6979
}

gateway-util-common/src/main/java/org/apache/knox/gateway/util/knoxidf/KnoxIDFConstants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,15 @@ public interface KnoxIDFConstants {
4444
String STATE = "state";
4545
String CODE = "code";
4646
String REFRESH_TOKEN = "refresh_token";
47+
String CLIENT_CREDENTIALS = "client_credentials";
4748
// RFC 8693 §2.2.1: the token endpoint response must advertise the type of the issued token.
4849
String ISSUED_TOKEN_TYPE = "issued_token_type";
4950
//KnoxIDF always mints a JWT so issued_token_type is the JWT URN rather than the generic access_token URN.
5051
String ISSUED_TOKEN_TYPE_JWT_VALUE = "urn:ietf:params:oauth:token-type:jwt";
52+
// This is intentionally duplicated from JWTFederationFilter.TOKEN_EXCHANGE rather than shared:
53+
// it is a fixed standard identifier that will not change, and duplicating it avoids a module
54+
// dependency on the JWT federation provider.
55+
String TOKEN_EXCHANGE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange";
5156
String REFRESH_TOKEN_TTL= "refresh.token.ttl";
5257
long REFRESH_TOKEN_TTL_DEFAULT = 86400000L; // 1 day
5358
String CODE_RESPONSE_TYPE = RESPONSE_TYPE + "=" + CODE;

0 commit comments

Comments
 (0)