This is an automated email from the ASF dual-hosted git repository. smolnar82 pushed a commit to branch knox_idf in repository https://gitbox.apache.org/repos/asf/knox.git
commit 7341b1b89031c6affe302de5d876ae3476dbca3d Author: Sandor Molnar <[email protected]> AuthorDate: Wed Aug 12 00:44:00 2026 +0200 KNOX-3414: complete OIDC discovery metadata for OAuth/MCP client integration The .well-known/openid-configuration document was missing a REQUIRED field and several fields clients rely on to integrate without out-of-band config. - subject_types_supported: ["public"] -- REQUIRED by OpenID Connect Discovery 1.0; its absence makes the document non-conformant. Knox derives 'sub' as a deterministic UUIDv5 over a fixed namespace and the user identity (the same for every client), so the subject identifier type is "public", not pairwise. - registration_endpoint -> the /client dynamic client registration resource KnoxIDF already serves. This is the spec-sanctioned path for MCP clients that cannot pre-register. - token_endpoint_auth_methods_supported: ["client_secret_post", "none"] -- matches what the token endpoint actually reads: confidential clients send client_secret in request params (client_secret_post), public clients use PKCE with no secret ("none"). client_secret_basic is intentionally excluded because the endpoint does not read HTTP Basic credentials. - client_id_metadata_document_supported: false -- stated explicitly (the CIMD draft default when absent) so MCP clients use registration_endpoint rather than an HTTPS-URL client_id; Knox does not resolve URL client_ids to fetched metadata documents. Test: DiscoveryResourceMetadataTest asserts the added fields and that neither client_secret_basic nor CIMD support is falsely advertised. Co-Authored-By: Claude Opus 4.8 <[email protected]> --- .../gateway/service/knoxidf/DiscoveryResource.java | 17 ++++++ .../knoxidf/DiscoveryResourceMetadataTest.java | 69 ++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/gateway-service-knoxidf/src/main/java/org/apache/knox/gateway/service/knoxidf/DiscoveryResource.java b/gateway-service-knoxidf/src/main/java/org/apache/knox/gateway/service/knoxidf/DiscoveryResource.java index e55ea817d..26b6a8cbe 100644 --- a/gateway-service-knoxidf/src/main/java/org/apache/knox/gateway/service/knoxidf/DiscoveryResource.java +++ b/gateway-service-knoxidf/src/main/java/org/apache/knox/gateway/service/knoxidf/DiscoveryResource.java @@ -66,8 +66,25 @@ public class DiscoveryResource { } config.put("token_endpoint", tokenEndpoint); config.put("userinfo_endpoint", userInfoEndpoint); + // Dynamic client registration is served on the current topology (no token-exchange + // substitution); advertise it so clients can discover it per OIDC Dynamic Client Registration. + config.put("registration_endpoint", baseUrl + RegistrationResource.RESOURCE_PATH); config.put("jwks_uri", baseUrl + JwksResource.RESOURCE_PATH); config.put("response_types_supported", new String[]{KnoxIDFConstants.CODE}); + // REQUIRED by OpenID Connect Discovery 1.0. Knox derives 'sub' as a deterministic UUIDv5 over + // a fixed namespace and the user identity -- the same for every client -- so the subject + // identifier type is "public" (not "pairwise"). + config.put("subject_types_supported", new String[]{"public"}); + // The token endpoint reads client credentials only from request parameters (no HTTP Basic): + // confidential clients send client_secret in the body (client_secret_post); public clients + // authenticate with PKCE and no secret ("none"). client_secret_basic is intentionally absent + // because it is not honored. + config.put("token_endpoint_auth_methods_supported", new String[]{"client_secret_post", "none"}); + // Explicitly false: Knox does not resolve an HTTPS-URL client_id to a fetched Client ID + // Metadata Document (OAuth CIMD draft, referenced by MCP). This is the spec default when the + // field is absent, but stating it tells MCP clients to use dynamic client registration + // (registration_endpoint) rather than a URL client_id. Flip to true only if CIMD is implemented. + config.put("client_id_metadata_document_supported", Boolean.FALSE); config.put("grant_types_supported", new String[]{KnoxIDFConstants.AUTH_CODE, KnoxIDFConstants.REFRESH_TOKEN}); config.put("scopes_supported", KnoxIDFConstants.DEFAULT_SCOPES); config.put("id_token_signing_alg_values_supported", new String[]{"RS256"}); diff --git a/gateway-service-knoxidf/src/test/java/org/apache/knox/gateway/service/knoxidf/DiscoveryResourceMetadataTest.java b/gateway-service-knoxidf/src/test/java/org/apache/knox/gateway/service/knoxidf/DiscoveryResourceMetadataTest.java new file mode 100644 index 000000000..4f5c90689 --- /dev/null +++ b/gateway-service-knoxidf/src/test/java/org/apache/knox/gateway/service/knoxidf/DiscoveryResourceMetadataTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.knox.gateway.service.knoxidf; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.net.URI; + +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +import org.easymock.EasyMock; +import org.junit.Test; + +/** + * Verifies the discovery document carries required/expected OIDC provider metadata. + * subject_types_supported is REQUIRED by OpenID Connect Discovery 1.0; a strict client or + * conformance validator rejects a document that omits it. registration_endpoint must point at the + * dynamic client registration resource that KnoxIDF actually serves. + */ +public class DiscoveryResourceMetadataTest { + + @Test + public void testAdvertisesSubjectTypesAndRegistrationEndpoint() { + final UriInfo uriInfo = EasyMock.createNiceMock(UriInfo.class); + EasyMock.expect(uriInfo.getBaseUri()).andReturn(URI.create("https://knox:8443/gateway/knoxidf/")).anyTimes(); + EasyMock.replay(uriInfo); + + final Response response = new DiscoveryResource().getConfig(uriInfo); + final String body = String.valueOf(response.getEntity()); + + // subject_types_supported is REQUIRED; Knox uses a shared (non-pairwise) subject -> "public". + assertTrue("subject_types_supported must be present (REQUIRED by OIDC Discovery).", + body.contains("subject_types_supported")); + assertTrue("subject_types_supported must advertise 'public'.", + body.contains("\"public\"")); + + // registration_endpoint must resolve to the dynamic client registration resource. + assertTrue("registration_endpoint must point at the /client registration resource.", + body.contains("registration_endpoint") && body.contains(RegistrationResource.RESOURCE_PATH)); + + // The token endpoint authenticates clients via body params only: client_secret_post + none (PKCE). + assertTrue("token_endpoint_auth_methods_supported must advertise client_secret_post and none.", + body.contains("token_endpoint_auth_methods_supported") + && body.contains("client_secret_post") && body.contains("\"none\"")); + // It must NOT claim HTTP Basic client auth, which the token endpoint does not read. + assertFalse("Discovery must not advertise client_secret_basic, which is not honored.", + body.contains("client_secret_basic")); + + // CIMD is not implemented, so it must be advertised explicitly as false (never true). + assertTrue("client_id_metadata_document_supported must be present and false.", + body.contains("\"client_id_metadata_document_supported\":false")); + } +}
