From a28e79c1c63c4cb55a7703de8d2aa7943320a784 Mon Sep 17 00:00:00 2001 From: hoguni Date: Fri, 28 Nov 2025 19:16:00 +0900 Subject: [PATCH 1/6] configure authorization server metadata in AuthenticationOAuth2 --- .../oauth2/AuthenticationFactoryOAuth2.java | 13 ++++++++++ .../auth/oauth2/ClientCredentialsFlow.java | 7 ++++-- .../client/impl/auth/oauth2/FlowBase.java | 8 +++++-- .../protocol/DefaultMetadataResolver.java | 24 ++++++++++++++++--- .../AuthenticationFactoryOAuth2Test.java | 4 +++- .../auth/oauth2/AuthenticationOAuth2Test.java | 7 ++++++ 6 files changed, 55 insertions(+), 8 deletions(-) diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java index 033d5308a2a96..ed1104db6c4b7 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java @@ -78,6 +78,7 @@ public static class ClientCredentialsBuilder { private Duration connectTimeout; private Duration readTimeout; private String trustCertsFilePath; + private String wellKnownMetadataPath; private ClientCredentialsBuilder() { } @@ -163,6 +164,17 @@ public ClientCredentialsBuilder trustCertsFilePath(String trustCertsFilePath) { return this; } + /** + * Optional well-known metadata path + * + * @param wellKnownMetadataPath the well-known metadata path + * @return the builder + */ + public ClientCredentialsBuilder wellKnownMetadataPath(String wellKnownMetadataPath) { + this.wellKnownMetadataPath = wellKnownMetadataPath; + return this; + } + /** * Authenticate with client credentials. * @@ -177,6 +189,7 @@ public Authentication build() { .connectTimeout(connectTimeout) .readTimeout(readTimeout) .trustCertsFilePath(trustCertsFilePath) + .wellKnownMetadataPath(wellKnownMetadataPath) .build(); return new AuthenticationOAuth2(flow, Clock.systemDefaultZone()); } diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/ClientCredentialsFlow.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/ClientCredentialsFlow.java index 7f64c0b18ac73..509542aee879c 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/ClientCredentialsFlow.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/ClientCredentialsFlow.java @@ -62,8 +62,9 @@ class ClientCredentialsFlow extends FlowBase { @Builder public ClientCredentialsFlow(URL issuerUrl, String audience, String privateKey, String scope, - Duration connectTimeout, Duration readTimeout, String trustCertsFilePath) { - super(issuerUrl, connectTimeout, readTimeout, trustCertsFilePath); + Duration connectTimeout, Duration readTimeout, String trustCertsFilePath, + String wellKnownMetadataPath) { + super(issuerUrl, connectTimeout, readTimeout, trustCertsFilePath, wellKnownMetadataPath); this.audience = audience; this.privateKey = privateKey; this.scope = scope; @@ -84,6 +85,7 @@ public static ClientCredentialsFlow fromParameters(Map params) { Duration connectTimeout = parseParameterDuration(params, CONFIG_PARAM_CONNECT_TIMEOUT); Duration readTimeout = parseParameterDuration(params, CONFIG_PARAM_READ_TIMEOUT); String trustCertsFilePath = params.get(CONFIG_PARAM_TRUST_CERTS_FILE_PATH); + String wellKnownMetadataPath = params.get(CONFIG_PARAM_WELL_KNOWN_METADATA_PATH); return ClientCredentialsFlow.builder() .issuerUrl(issuerUrl) @@ -93,6 +95,7 @@ public static ClientCredentialsFlow fromParameters(Map params) { .connectTimeout(connectTimeout) .readTimeout(readTimeout) .trustCertsFilePath(trustCertsFilePath) + .wellKnownMetadataPath(wellKnownMetadataPath) .build(); } diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/FlowBase.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/FlowBase.java index 6cc9f8e41b5e4..4530a02c74636 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/FlowBase.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/FlowBase.java @@ -47,6 +47,7 @@ abstract class FlowBase implements Flow { public static final String CONFIG_PARAM_CONNECT_TIMEOUT = "connectTimeout"; public static final String CONFIG_PARAM_READ_TIMEOUT = "readTimeout"; public static final String CONFIG_PARAM_TRUST_CERTS_FILE_PATH = "trustCertsFilePath"; + public static final String CONFIG_PARAM_WELL_KNOWN_METADATA_PATH = "wellKnownMetadataPath"; protected static final Duration DEFAULT_CONNECT_TIMEOUT = Duration.ofSeconds(10); protected static final Duration DEFAULT_READ_TIMEOUT = Duration.ofSeconds(30); @@ -55,12 +56,15 @@ abstract class FlowBase implements Flow { protected final URL issuerUrl; protected final AsyncHttpClient httpClient; + protected final String wellKnownMetadataPath; protected transient Metadata metadata; - protected FlowBase(URL issuerUrl, Duration connectTimeout, Duration readTimeout, String trustCertsFilePath) { + protected FlowBase(URL issuerUrl, Duration connectTimeout, Duration readTimeout, String trustCertsFilePath, + String wellKnownMetadataPath) { this.issuerUrl = issuerUrl; this.httpClient = defaultHttpClient(readTimeout, connectTimeout, trustCertsFilePath); + this.wellKnownMetadataPath = wellKnownMetadataPath; } private AsyncHttpClient defaultHttpClient(Duration readTimeout, Duration connectTimeout, @@ -110,7 +114,7 @@ public void initialize() throws PulsarClientException { } protected MetadataResolver createMetadataResolver() { - return DefaultMetadataResolver.fromIssuerUrl(issuerUrl, httpClient); + return DefaultMetadataResolver.fromIssuerUrl(issuerUrl, httpClient, wellKnownMetadataPath); } static String parseParameterString(Map params, String name) { diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java index 19d0c1acadd15..06394692841bf 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java @@ -36,6 +36,8 @@ */ public class DefaultMetadataResolver implements MetadataResolver { + private static final String DEFAULT_WELL_KNOWN_METADATA_PATH = "/.well-known/openid-configuration"; + private final URL metadataUrl; private final ObjectReader objectReader; private final AsyncHttpClient httpClient; @@ -50,9 +52,14 @@ public DefaultMetadataResolver(URL metadataUrl, AsyncHttpClient httpClient) { * Gets a well-known metadata URL for the given OAuth issuer URL. * * @param issuerUrl The authorization server's issuer identifier + * @param httpClient The HTTP client + * @param wellKnownMetadataPath The well-known metadata path * @return a resolver */ - public static DefaultMetadataResolver fromIssuerUrl(URL issuerUrl, AsyncHttpClient httpClient) { + public static DefaultMetadataResolver fromIssuerUrl(URL issuerUrl, AsyncHttpClient httpClient, String wellKnownMetadataPath) { + if (wellKnownMetadataPath != null) { + return new DefaultMetadataResolver(getWellKnownMetadataUrl(issuerUrl, wellKnownMetadataPath), httpClient); + } return new DefaultMetadataResolver(getWellKnownMetadataUrl(issuerUrl), httpClient); } @@ -60,18 +67,29 @@ public static DefaultMetadataResolver fromIssuerUrl(URL issuerUrl, AsyncHttpClie * Gets a well-known metadata URL for the given OAuth issuer URL. * * @param issuerUrl The authorization server's issuer identifier + * @param wellKnownMetadataPath The well-known metadata path * @return a URL * @see * OAuth Discovery: Obtaining Authorization Server Metadata */ - public static URL getWellKnownMetadataUrl(URL issuerUrl) { + public static URL getWellKnownMetadataUrl(URL issuerUrl, String wellKnownMetadataPath) { try { - return URI.create(issuerUrl.toExternalForm() + "/.well-known/openid-configuration").normalize().toURL(); + return URI.create(issuerUrl.toExternalForm() + wellKnownMetadataPath).normalize().toURL(); } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } } + /** + * Gets a well-known metadata URL for the given OAuth issuer URL using the default path. + * + * @param issuerUrl The authorization server's issuer identifier + * @return a URL + */ + public static URL getWellKnownMetadataUrl(URL issuerUrl) { + return getWellKnownMetadataUrl(issuerUrl, DEFAULT_WELL_KNOWN_METADATA_PATH); + } + /** * Resolves the authorization metadata. * diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2Test.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2Test.java index 602aafa7b6c91..b2535facdd26e 100644 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2Test.java +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2Test.java @@ -36,11 +36,13 @@ public void testBuilder() throws IOException { Duration connectTimeout = Duration.parse("PT11S"); Duration readTimeout = Duration.ofSeconds(31); String trustCertsFilePath = null; + String wellKnownMetadataPath = "/.well-known/custom-path"; try (Authentication authentication = AuthenticationFactoryOAuth2.clientCredentialsBuilder().issuerUrl(issuerUrl) .credentialsUrl(credentialsUrl).audience(audience).scope(scope) .connectTimeout(connectTimeout).readTimeout(readTimeout) - .trustCertsFilePath(trustCertsFilePath).build()) { + .trustCertsFilePath(trustCertsFilePath) + .wellKnownMetadataPath(wellKnownMetadataPath).build()) { assertTrue(authentication instanceof AuthenticationOAuth2); } } diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java index aef69be74e120..43d8484514fb1 100644 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java @@ -85,6 +85,7 @@ public void testConfigure() throws Exception { params.put("issuerUrl", "http://localhost"); params.put("audience", "http://localhost"); params.put("scope", "http://localhost"); + params.put("wellKnownMetadataPath", "/.well-known/custom-path"); ObjectMapper mapper = new ObjectMapper(); String authParams = mapper.writeValueAsString(params); this.auth.configure(authParams); @@ -134,6 +135,12 @@ public void testGetAuthData() throws Exception { public void testMetadataResolver() throws MalformedURLException { URL url = DefaultMetadataResolver.getWellKnownMetadataUrl(URI.create("http://localhost/path/oauth").toURL()); assertEquals("http://localhost/path/oauth/.well-known/openid-configuration", url.toString()); + + // custom wellKnownMetadataPath + URL customUrl = DefaultMetadataResolver.getWellKnownMetadataUrl( + URI.create("http://localhost/path/oauth").toURL(), + "/.well-known/custom-path"); + assertEquals("http://localhost/path/oauth/.well-known/custom-path", customUrl.toString()); } @Test From 131bcc5b4153be8dff128ce52ce11de44f0bbf2d Mon Sep 17 00:00:00 2001 From: hoguni Date: Thu, 4 Dec 2025 19:14:40 +0900 Subject: [PATCH 2/6] check well-known metadata prefix --- .../oauth2/AuthenticationFactoryOAuth2.java | 2 +- .../protocol/DefaultMetadataResolver.java | 16 ++++++++++---- .../auth/oauth2/AuthenticationOAuth2Test.java | 22 ++++++++++++++++++- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java index ed1104db6c4b7..6131c3be06139 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java @@ -167,7 +167,7 @@ public ClientCredentialsBuilder trustCertsFilePath(String trustCertsFilePath) { /** * Optional well-known metadata path * - * @param wellKnownMetadataPath the well-known metadata path + * @param wellKnownMetadataPath the well-known metadata path (must start with "/.well-known/") * @return the builder */ public ClientCredentialsBuilder wellKnownMetadataPath(String wellKnownMetadataPath) { diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java index 06394692841bf..d720ba951caa5 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java @@ -36,7 +36,8 @@ */ public class DefaultMetadataResolver implements MetadataResolver { - private static final String DEFAULT_WELL_KNOWN_METADATA_PATH = "/.well-known/openid-configuration"; + private static final String WELL_KNOWN_PREFIX = "/.well-known/"; + private static final String DEFAULT_WELL_KNOWN_METADATA_PATH = WELL_KNOWN_PREFIX + "openid-configuration"; private final URL metadataUrl; private final ObjectReader objectReader; @@ -53,7 +54,7 @@ public DefaultMetadataResolver(URL metadataUrl, AsyncHttpClient httpClient) { * * @param issuerUrl The authorization server's issuer identifier * @param httpClient The HTTP client - * @param wellKnownMetadataPath The well-known metadata path + * @param wellKnownMetadataPath The well-known metadata path (must start with "/.well-known/") * @return a resolver */ public static DefaultMetadataResolver fromIssuerUrl(URL issuerUrl, AsyncHttpClient httpClient, String wellKnownMetadataPath) { @@ -67,14 +68,21 @@ public static DefaultMetadataResolver fromIssuerUrl(URL issuerUrl, AsyncHttpClie * Gets a well-known metadata URL for the given OAuth issuer URL. * * @param issuerUrl The authorization server's issuer identifier - * @param wellKnownMetadataPath The well-known metadata path + * @param wellKnownMetadataPath The well-known metadata path (must start with "/.well-known/") * @return a URL * @see * OAuth Discovery: Obtaining Authorization Server Metadata */ public static URL getWellKnownMetadataUrl(URL issuerUrl, String wellKnownMetadataPath) { try { - return URI.create(issuerUrl.toExternalForm() + wellKnownMetadataPath).normalize().toURL(); + if (wellKnownMetadataPath == null || wellKnownMetadataPath.isEmpty()) { + return URI.create(issuerUrl.toExternalForm() + DEFAULT_WELL_KNOWN_METADATA_PATH).normalize().toURL(); + } + if (wellKnownMetadataPath.startsWith(WELL_KNOWN_PREFIX)) { + return URI.create(issuerUrl.toExternalForm() + wellKnownMetadataPath).normalize().toURL(); + } else { + throw new IllegalArgumentException("Metadata path must start with '" + WELL_KNOWN_PREFIX + "', but was: " + wellKnownMetadataPath); + } } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java index 43d8484514fb1..fcbba9e8b4b65 100644 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java @@ -136,11 +136,31 @@ public void testMetadataResolver() throws MalformedURLException { URL url = DefaultMetadataResolver.getWellKnownMetadataUrl(URI.create("http://localhost/path/oauth").toURL()); assertEquals("http://localhost/path/oauth/.well-known/openid-configuration", url.toString()); - // custom wellKnownMetadataPath + // custom wellKnownMetadataPath with full well-known prefix URL customUrl = DefaultMetadataResolver.getWellKnownMetadataUrl( URI.create("http://localhost/path/oauth").toURL(), "/.well-known/custom-path"); assertEquals("http://localhost/path/oauth/.well-known/custom-path", customUrl.toString()); + + // null wellKnownMetadataPath (should use default) + URL customUrl2 = DefaultMetadataResolver.getWellKnownMetadataUrl( + URI.create("http://localhost/path/oauth").toURL(), + null); + assertEquals("http://localhost/path/oauth/.well-known/openid-configuration", customUrl2.toString()); + + // empty wellKnownMetadataPath (should use default) + URL customUrl3 = DefaultMetadataResolver.getWellKnownMetadataUrl( + URI.create("http://localhost/path/oauth").toURL(), + ""); + assertEquals("http://localhost/path/oauth/.well-known/openid-configuration", customUrl3.toString()); + } + + @Test(expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = ".*Metadata path must start with.*") + public void testMetadataResolverWithInvalidPath() throws MalformedURLException { + DefaultMetadataResolver.getWellKnownMetadataUrl( + URI.create("http://localhost/path/oauth").toURL(), + "/custom-path"); } @Test From 22faad9f85732bd8fddbaa2012fe5136c24fe951 Mon Sep 17 00:00:00 2001 From: hoguni Date: Mon, 8 Dec 2025 12:01:01 +0900 Subject: [PATCH 3/6] add OAuth2 standard metadata path --- .../oauth2/AuthenticationFactoryOAuth2.java | 14 +++- ...thenticationOAuth2StandardAuthzServer.java | 70 +++++++++++++++++++ .../protocol/DefaultMetadataResolver.java | 16 ++++- .../AuthenticationFactoryOAuth2Test.java | 13 ++++ ...ticationOAuth2StandardAuthzServerTest.java | 50 +++++++++++++ .../auth/oauth2/AuthenticationOAuth2Test.java | 18 +++-- 6 files changed, 172 insertions(+), 9 deletions(-) create mode 100644 pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java create mode 100644 pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServerTest.java diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java index 6131c3be06139..0a5ce9a1d6514 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java @@ -22,6 +22,7 @@ import java.time.Clock; import java.time.Duration; import org.apache.pulsar.client.api.Authentication; +import org.apache.pulsar.client.impl.auth.oauth2.protocol.DefaultMetadataResolver; /** * Factory class that allows to create {@link Authentication} instances @@ -69,6 +70,17 @@ public static ClientCredentialsBuilder clientCredentialsBuilder() { return new ClientCredentialsBuilder(); } + /** + * A builder to create an authentication with client credentials using standard OAuth 2.0 metadata path + * as defined in RFC 8414 ("/.well-known/oauth-authorization-server"). + * + * @return the builder pre-configured to use standard OAuth 2.0 metadata path + */ + public static ClientCredentialsBuilder clientCredentialsWithStandardAuthzServerBuilder() { + return new ClientCredentialsBuilder() + .wellKnownMetadataPath(DefaultMetadataResolver.getOAuthWellKnownMetadataPath()); + } + public static class ClientCredentialsBuilder { private URL issuerUrl; @@ -165,7 +177,7 @@ public ClientCredentialsBuilder trustCertsFilePath(String trustCertsFilePath) { } /** - * Optional well-known metadata path + * Optional well-known metadata path. * * @param wellKnownMetadataPath the well-known metadata path (must start with "/.well-known/") * @return the builder diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java new file mode 100644 index 0000000000000..bd40c93a56e54 --- /dev/null +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java @@ -0,0 +1,70 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.pulsar.client.impl.auth.oauth2; + +import java.io.IOException; +import java.time.Clock; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; +import org.apache.pulsar.client.impl.AuthenticationUtil; +import org.apache.pulsar.client.impl.auth.oauth2.protocol.DefaultMetadataResolver; + +/** + * Pulsar client authentication provider based on OAuth 2.0 using RFC 8414 standard metadata path. + * This class is identical to {@link AuthenticationOAuth2} but it always uses the standard + * "/.well-known/oauth-authorization-server" metadata path as defined in RFC 8414. + */ +public class AuthenticationOAuth2StandardAuthzServer extends AuthenticationOAuth2 { + + private static final long serialVersionUID = 1L; + + public AuthenticationOAuth2StandardAuthzServer() { + super(); + } + + AuthenticationOAuth2StandardAuthzServer(Flow flow, Clock clock) { + super(flow, clock); + } + + @Override + public void configure(String encodedAuthParamString) { + if (StringUtils.isBlank(encodedAuthParamString)) { + throw new IllegalArgumentException("No authentication parameters were provided"); + } + Map params; + try { + params = AuthenticationUtil.configureFromJsonString(encodedAuthParamString); + } catch (IOException e) { + throw new IllegalArgumentException("Malformed authentication parameters", e); + } + + // Always set the OAuth 2.0 standard metadata path + params.put(FlowBase.CONFIG_PARAM_WELL_KNOWN_METADATA_PATH, + DefaultMetadataResolver.getOAuthWellKnownMetadataPath()); + + String type = params.getOrDefault(CONFIG_PARAM_TYPE, TYPE_CLIENT_CREDENTIALS); + switch(type) { + case TYPE_CLIENT_CREDENTIALS: + this.flow = ClientCredentialsFlow.fromParameters(params); + break; + default: + throw new IllegalArgumentException("Unsupported authentication type: " + type); + } + } +} \ No newline at end of file diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java index d720ba951caa5..6d50d61a3ffaf 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java @@ -38,6 +38,7 @@ public class DefaultMetadataResolver implements MetadataResolver { private static final String WELL_KNOWN_PREFIX = "/.well-known/"; private static final String DEFAULT_WELL_KNOWN_METADATA_PATH = WELL_KNOWN_PREFIX + "openid-configuration"; + private static final String OAUTH_WELL_KNOWN_METADATA_PATH = WELL_KNOWN_PREFIX + "oauth-authorization-server"; private final URL metadataUrl; private final ObjectReader objectReader; @@ -49,6 +50,15 @@ public DefaultMetadataResolver(URL metadataUrl, AsyncHttpClient httpClient) { this.httpClient = httpClient; } + /** + * Gets the OAuth 2.0 Authorization Server Metadata path as defined in RFC 8414. + * + * @return the OAuth 2.0 Authorization Server Metadata path + */ + public static String getOAuthWellKnownMetadataPath() { + return OAUTH_WELL_KNOWN_METADATA_PATH; + } + /** * Gets a well-known metadata URL for the given OAuth issuer URL. * @@ -57,7 +67,8 @@ public DefaultMetadataResolver(URL metadataUrl, AsyncHttpClient httpClient) { * @param wellKnownMetadataPath The well-known metadata path (must start with "/.well-known/") * @return a resolver */ - public static DefaultMetadataResolver fromIssuerUrl(URL issuerUrl, AsyncHttpClient httpClient, String wellKnownMetadataPath) { + public static DefaultMetadataResolver fromIssuerUrl(URL issuerUrl, AsyncHttpClient httpClient, + String wellKnownMetadataPath) { if (wellKnownMetadataPath != null) { return new DefaultMetadataResolver(getWellKnownMetadataUrl(issuerUrl, wellKnownMetadataPath), httpClient); } @@ -81,7 +92,8 @@ public static URL getWellKnownMetadataUrl(URL issuerUrl, String wellKnownMetadat if (wellKnownMetadataPath.startsWith(WELL_KNOWN_PREFIX)) { return URI.create(issuerUrl.toExternalForm() + wellKnownMetadataPath).normalize().toURL(); } else { - throw new IllegalArgumentException("Metadata path must start with '" + WELL_KNOWN_PREFIX + "', but was: " + wellKnownMetadataPath); + throw new IllegalArgumentException("Metadata path must start with '" + WELL_KNOWN_PREFIX + + "', but was: " + wellKnownMetadataPath); } } catch (MalformedURLException e) { throw new IllegalArgumentException(e); diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2Test.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2Test.java index b2535facdd26e..f76fee6e10dfa 100644 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2Test.java +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2Test.java @@ -47,6 +47,19 @@ public void testBuilder() throws IOException { } } + @Test + public void testStandardAuthzServerBuilder() throws IOException { + URL issuerUrl = new URL("http://localhost"); + URL credentialsUrl = new URL("http://localhost"); + String audience = "audience"; + String scope = "scope"; + try (Authentication authentication = + AuthenticationFactoryOAuth2.clientCredentialsWithStandardAuthzServerBuilder().issuerUrl(issuerUrl) + .credentialsUrl(credentialsUrl).audience(audience).scope(scope).build()) { + assertTrue(authentication instanceof AuthenticationOAuth2); + } + } + @Test public void testClientCredentials() throws IOException { URL issuerUrl = new URL("http://localhost"); diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServerTest.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServerTest.java new file mode 100644 index 0000000000000..dcd89320fe90b --- /dev/null +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServerTest.java @@ -0,0 +1,50 @@ +/* + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.pulsar.client.impl.auth.oauth2; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import org.apache.pulsar.client.impl.auth.oauth2.protocol.DefaultMetadataResolver; +import org.testng.annotations.Test; + +public class AuthenticationOAuth2StandardAuthzServerTest { + + @Test + public void testConfigureWithOAuth2MetadataPath() throws Exception { + Map params = new HashMap<>(); + params.put("type", "client_credentials"); + params.put("privateKey", "data:base64,e30="); + params.put("issuerUrl", "http://localhost"); + params.put("audience", "test-audience"); + ObjectMapper mapper = new ObjectMapper(); + String authParams = mapper.writeValueAsString(params); + AuthenticationOAuth2StandardAuthzServer auth = new AuthenticationOAuth2StandardAuthzServer(); + auth.configure(authParams); + assertTrue(auth.flow instanceof ClientCredentialsFlow); + ClientCredentialsFlow flow = (ClientCredentialsFlow) auth.flow; + Field wellKnownMetadataPathField = FlowBase.class.getDeclaredField("wellKnownMetadataPath"); + wellKnownMetadataPathField.setAccessible(true); + String wellKnownMetadataPath = (String) wellKnownMetadataPathField.get(flow); + assertEquals(wellKnownMetadataPath, DefaultMetadataResolver.getOAuthWellKnownMetadataPath()); + } +} diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java index fcbba9e8b4b65..6c5ae45760f04 100644 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java @@ -135,26 +135,32 @@ public void testGetAuthData() throws Exception { public void testMetadataResolver() throws MalformedURLException { URL url = DefaultMetadataResolver.getWellKnownMetadataUrl(URI.create("http://localhost/path/oauth").toURL()); assertEquals("http://localhost/path/oauth/.well-known/openid-configuration", url.toString()); - + // custom wellKnownMetadataPath with full well-known prefix URL customUrl = DefaultMetadataResolver.getWellKnownMetadataUrl( - URI.create("http://localhost/path/oauth").toURL(), + URI.create("http://localhost/path/oauth").toURL(), "/.well-known/custom-path"); assertEquals("http://localhost/path/oauth/.well-known/custom-path", customUrl.toString()); - + // null wellKnownMetadataPath (should use default) URL customUrl2 = DefaultMetadataResolver.getWellKnownMetadataUrl( URI.create("http://localhost/path/oauth").toURL(), null); assertEquals("http://localhost/path/oauth/.well-known/openid-configuration", customUrl2.toString()); - + // empty wellKnownMetadataPath (should use default) URL customUrl3 = DefaultMetadataResolver.getWellKnownMetadataUrl( - URI.create("http://localhost/path/oauth").toURL(), + URI.create("http://localhost/path/oauth").toURL(), ""); assertEquals("http://localhost/path/oauth/.well-known/openid-configuration", customUrl3.toString()); + + // using RFC8414 OAuth2 metadata path + URL oauthUrl = DefaultMetadataResolver.getWellKnownMetadataUrl( + URI.create("http://localhost/path/oauth").toURL(), + DefaultMetadataResolver.getOAuthWellKnownMetadataPath()); + assertEquals("http://localhost/path/oauth/.well-known/oauth-authorization-server", oauthUrl.toString()); } - + @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = ".*Metadata path must start with.*") public void testMetadataResolverWithInvalidPath() throws MalformedURLException { From 8b03b9a60c5b5eceb3bb0ac3f13953d1ff7fd329 Mon Sep 17 00:00:00 2001 From: hoguni Date: Mon, 8 Dec 2025 12:01:24 +0900 Subject: [PATCH 4/6] fix check style --- .../auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java | 2 +- .../pulsar/client/impl/auth/oauth2/ClientCredentialsFlow.java | 2 +- .../org/apache/pulsar/client/impl/auth/oauth2/FlowBase.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java index bd40c93a56e54..1cff27cf81720 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java @@ -67,4 +67,4 @@ public void configure(String encodedAuthParamString) { throw new IllegalArgumentException("Unsupported authentication type: " + type); } } -} \ No newline at end of file +} diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/ClientCredentialsFlow.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/ClientCredentialsFlow.java index 509542aee879c..fe7beb47ed21f 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/ClientCredentialsFlow.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/ClientCredentialsFlow.java @@ -62,7 +62,7 @@ class ClientCredentialsFlow extends FlowBase { @Builder public ClientCredentialsFlow(URL issuerUrl, String audience, String privateKey, String scope, - Duration connectTimeout, Duration readTimeout, String trustCertsFilePath, + Duration connectTimeout, Duration readTimeout, String trustCertsFilePath, String wellKnownMetadataPath) { super(issuerUrl, connectTimeout, readTimeout, trustCertsFilePath, wellKnownMetadataPath); this.audience = audience; diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/FlowBase.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/FlowBase.java index 4530a02c74636..8a90712d7ead0 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/FlowBase.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/FlowBase.java @@ -60,7 +60,7 @@ abstract class FlowBase implements Flow { protected transient Metadata metadata; - protected FlowBase(URL issuerUrl, Duration connectTimeout, Duration readTimeout, String trustCertsFilePath, + protected FlowBase(URL issuerUrl, Duration connectTimeout, Duration readTimeout, String trustCertsFilePath, String wellKnownMetadataPath) { this.issuerUrl = issuerUrl; this.httpClient = defaultHttpClient(readTimeout, connectTimeout, trustCertsFilePath); From 3f4049cae2fa4624da99ef1232270b1d8f715b91 Mon Sep 17 00:00:00 2001 From: hoguni Date: Tue, 9 Dec 2025 15:53:38 +0900 Subject: [PATCH 5/6] OAUTH_WELL_KNOWN_METADATA_PATH private->pubilc --- .../auth/oauth2/AuthenticationFactoryOAuth2.java | 2 +- .../AuthenticationOAuth2StandardAuthzServer.java | 2 +- .../oauth2/protocol/DefaultMetadataResolver.java | 14 ++++---------- ...uthenticationOAuth2StandardAuthzServerTest.java | 2 +- .../impl/auth/oauth2/AuthenticationOAuth2Test.java | 2 +- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java index 0a5ce9a1d6514..7c89c6cde6d0c 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationFactoryOAuth2.java @@ -78,7 +78,7 @@ public static ClientCredentialsBuilder clientCredentialsBuilder() { */ public static ClientCredentialsBuilder clientCredentialsWithStandardAuthzServerBuilder() { return new ClientCredentialsBuilder() - .wellKnownMetadataPath(DefaultMetadataResolver.getOAuthWellKnownMetadataPath()); + .wellKnownMetadataPath(DefaultMetadataResolver.OAUTH_WELL_KNOWN_METADATA_PATH); } public static class ClientCredentialsBuilder { diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java index 1cff27cf81720..c61d6d7b09747 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServer.java @@ -56,7 +56,7 @@ public void configure(String encodedAuthParamString) { // Always set the OAuth 2.0 standard metadata path params.put(FlowBase.CONFIG_PARAM_WELL_KNOWN_METADATA_PATH, - DefaultMetadataResolver.getOAuthWellKnownMetadataPath()); + DefaultMetadataResolver.OAUTH_WELL_KNOWN_METADATA_PATH); String type = params.getOrDefault(CONFIG_PARAM_TYPE, TYPE_CLIENT_CREDENTIALS); switch(type) { diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java index 6d50d61a3ffaf..b99ade66c63e9 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java @@ -38,7 +38,10 @@ public class DefaultMetadataResolver implements MetadataResolver { private static final String WELL_KNOWN_PREFIX = "/.well-known/"; private static final String DEFAULT_WELL_KNOWN_METADATA_PATH = WELL_KNOWN_PREFIX + "openid-configuration"; - private static final String OAUTH_WELL_KNOWN_METADATA_PATH = WELL_KNOWN_PREFIX + "oauth-authorization-server"; + /** + * The OAuth 2.0 Authorization Server Metadata path as defined in RFC 8414. + */ + public static final String OAUTH_WELL_KNOWN_METADATA_PATH = WELL_KNOWN_PREFIX + "oauth-authorization-server"; private final URL metadataUrl; private final ObjectReader objectReader; @@ -50,15 +53,6 @@ public DefaultMetadataResolver(URL metadataUrl, AsyncHttpClient httpClient) { this.httpClient = httpClient; } - /** - * Gets the OAuth 2.0 Authorization Server Metadata path as defined in RFC 8414. - * - * @return the OAuth 2.0 Authorization Server Metadata path - */ - public static String getOAuthWellKnownMetadataPath() { - return OAUTH_WELL_KNOWN_METADATA_PATH; - } - /** * Gets a well-known metadata URL for the given OAuth issuer URL. * diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServerTest.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServerTest.java index dcd89320fe90b..e1403b3aa4ba5 100644 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServerTest.java +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2StandardAuthzServerTest.java @@ -45,6 +45,6 @@ public void testConfigureWithOAuth2MetadataPath() throws Exception { Field wellKnownMetadataPathField = FlowBase.class.getDeclaredField("wellKnownMetadataPath"); wellKnownMetadataPathField.setAccessible(true); String wellKnownMetadataPath = (String) wellKnownMetadataPathField.get(flow); - assertEquals(wellKnownMetadataPath, DefaultMetadataResolver.getOAuthWellKnownMetadataPath()); + assertEquals(wellKnownMetadataPath, DefaultMetadataResolver.OAUTH_WELL_KNOWN_METADATA_PATH); } } diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java index 6c5ae45760f04..f2cdc2132f73b 100644 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java @@ -157,7 +157,7 @@ public void testMetadataResolver() throws MalformedURLException { // using RFC8414 OAuth2 metadata path URL oauthUrl = DefaultMetadataResolver.getWellKnownMetadataUrl( URI.create("http://localhost/path/oauth").toURL(), - DefaultMetadataResolver.getOAuthWellKnownMetadataPath()); + DefaultMetadataResolver.OAUTH_WELL_KNOWN_METADATA_PATH); assertEquals("http://localhost/path/oauth/.well-known/oauth-authorization-server", oauthUrl.toString()); } From 4a7a41e964c8ab0402732eb7c057e8a0b5bae4b2 Mon Sep 17 00:00:00 2001 From: hoguni Date: Thu, 18 Dec 2025 18:37:13 +0900 Subject: [PATCH 6/6] insert well-known path before the issuer URL path for OAuth2 --- .../protocol/DefaultMetadataResolver.java | 23 +++++++------------ .../auth/oauth2/AuthenticationOAuth2Test.java | 14 ++++++++--- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java index b99ade66c63e9..e43117bb7df2a 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java @@ -63,10 +63,7 @@ public DefaultMetadataResolver(URL metadataUrl, AsyncHttpClient httpClient) { */ public static DefaultMetadataResolver fromIssuerUrl(URL issuerUrl, AsyncHttpClient httpClient, String wellKnownMetadataPath) { - if (wellKnownMetadataPath != null) { - return new DefaultMetadataResolver(getWellKnownMetadataUrl(issuerUrl, wellKnownMetadataPath), httpClient); - } - return new DefaultMetadataResolver(getWellKnownMetadataUrl(issuerUrl), httpClient); + return new DefaultMetadataResolver(getWellKnownMetadataUrl(issuerUrl, wellKnownMetadataPath), httpClient); } /** @@ -84,7 +81,13 @@ public static URL getWellKnownMetadataUrl(URL issuerUrl, String wellKnownMetadat return URI.create(issuerUrl.toExternalForm() + DEFAULT_WELL_KNOWN_METADATA_PATH).normalize().toURL(); } if (wellKnownMetadataPath.startsWith(WELL_KNOWN_PREFIX)) { - return URI.create(issuerUrl.toExternalForm() + wellKnownMetadataPath).normalize().toURL(); + String issuerUrlString = issuerUrl.toExternalForm(); + // For OAuth2, insert well-known path before the issuer URL path + URL url = new URL(issuerUrlString); + String path = url.getPath(); + String basePath = issuerUrlString.substring(0, + issuerUrlString.length() - (path.isEmpty() ? 0 : path.length())); + return URI.create(basePath + wellKnownMetadataPath + path).normalize().toURL(); } else { throw new IllegalArgumentException("Metadata path must start with '" + WELL_KNOWN_PREFIX + "', but was: " + wellKnownMetadataPath); @@ -94,16 +97,6 @@ public static URL getWellKnownMetadataUrl(URL issuerUrl, String wellKnownMetadat } } - /** - * Gets a well-known metadata URL for the given OAuth issuer URL using the default path. - * - * @param issuerUrl The authorization server's issuer identifier - * @return a URL - */ - public static URL getWellKnownMetadataUrl(URL issuerUrl) { - return getWellKnownMetadataUrl(issuerUrl, DEFAULT_WELL_KNOWN_METADATA_PATH); - } - /** * Resolves the authorization metadata. * diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java index f2cdc2132f73b..d430d8f0e4066 100644 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/auth/oauth2/AuthenticationOAuth2Test.java @@ -133,14 +133,16 @@ public void testGetAuthData() throws Exception { @Test public void testMetadataResolver() throws MalformedURLException { - URL url = DefaultMetadataResolver.getWellKnownMetadataUrl(URI.create("http://localhost/path/oauth").toURL()); + URL url = DefaultMetadataResolver.getWellKnownMetadataUrl( + URI.create("http://localhost/path/oauth").toURL(), + null); assertEquals("http://localhost/path/oauth/.well-known/openid-configuration", url.toString()); // custom wellKnownMetadataPath with full well-known prefix URL customUrl = DefaultMetadataResolver.getWellKnownMetadataUrl( URI.create("http://localhost/path/oauth").toURL(), "/.well-known/custom-path"); - assertEquals("http://localhost/path/oauth/.well-known/custom-path", customUrl.toString()); + assertEquals("http://localhost/.well-known/custom-path/path/oauth", customUrl.toString()); // null wellKnownMetadataPath (should use default) URL customUrl2 = DefaultMetadataResolver.getWellKnownMetadataUrl( @@ -158,7 +160,13 @@ public void testMetadataResolver() throws MalformedURLException { URL oauthUrl = DefaultMetadataResolver.getWellKnownMetadataUrl( URI.create("http://localhost/path/oauth").toURL(), DefaultMetadataResolver.OAUTH_WELL_KNOWN_METADATA_PATH); - assertEquals("http://localhost/path/oauth/.well-known/oauth-authorization-server", oauthUrl.toString()); + assertEquals("http://localhost/.well-known/oauth-authorization-server/path/oauth", oauthUrl.toString()); + + // test with issuer URL without path + URL oauthUrlNoPath = DefaultMetadataResolver.getWellKnownMetadataUrl( + URI.create("http://localhost").toURL(), + DefaultMetadataResolver.OAUTH_WELL_KNOWN_METADATA_PATH); + assertEquals("http://localhost/.well-known/oauth-authorization-server", oauthUrlNoPath.toString()); } @Test(expectedExceptions = IllegalArgumentException.class,