This is an automated email from the ASF dual-hosted git repository. lhotari pushed a commit to branch branch-4.1 in repository https://gitbox.apache.org/repos/asf/pulsar.git
commit d5d3d701a9be3c7b6baab7269b6041f4c630a4bd Author: Omar Yasin <[email protected]> AuthorDate: Fri Feb 6 04:46:26 2026 -0800 [improve][broker] Add strictAuthMethod to require explicit authentication method (#25185) Co-authored-by: Ómar K. Yasin <[email protected]> (cherry picked from commit bae91734a8584e7610c3945351d82ba52f0c9fae) --- .../apache/pulsar/broker/ServiceConfiguration.java | 8 ++++++ .../authentication/AuthenticationService.java | 8 ++++++ .../broker/auth/AuthenticationServiceTest.java | 30 ++++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java index 1266c34b6d6..ceabf062b3a 100644 --- a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java +++ b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java @@ -1802,6 +1802,14 @@ public class ServiceConfiguration implements PulsarConfiguration { doc = "Enable authentication" ) private boolean authenticationEnabled = false; + + @FieldContext( + category = CATEGORY_AUTHENTICATION, + doc = "Strictly enforce authentication method. If specified, Pulsar will only attempt to authenticate with " + + "the provided method. If no method is provided, authentication fails." + ) + private boolean strictAuthMethod = false; + @FieldContext( category = CATEGORY_AUTHENTICATION, doc = "Authentication provider name list, which is a list of class names" diff --git a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationService.java b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationService.java index e2bf4dcc015..5b719bd6801 100644 --- a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationService.java +++ b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authentication/AuthenticationService.java @@ -47,6 +47,7 @@ import org.slf4j.LoggerFactory; public class AuthenticationService implements Closeable { private static final Logger LOG = LoggerFactory.getLogger(AuthenticationService.class); private final String anonymousUserRole; + private final boolean strictAuthMethod; private final Map<String, AuthenticationProvider> providers = new LinkedHashMap<>(); @@ -57,6 +58,7 @@ public class AuthenticationService implements Closeable { public AuthenticationService(ServiceConfiguration conf, OpenTelemetry openTelemetry) throws PulsarServerException { anonymousUserRole = conf.getAnonymousUserRole(); + strictAuthMethod = conf.isStrictAuthMethod(); if (conf.isAuthenticationEnabled()) { try { Map<String, List<AuthenticationProvider>> providerMap = new LinkedHashMap<>(); @@ -138,6 +140,12 @@ public class AuthenticationService implements Closeable { throw e; } } else { + if (strictAuthMethod) { + if (LOG.isDebugEnabled()) { + LOG.debug("No authentication method provided while one was is required"); + } + throw new AuthenticationException("Authentication method missing"); + } for (AuthenticationProvider provider : providers.values()) { try { return provider.authenticateHttpRequest(request, response); diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/AuthenticationServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/AuthenticationServiceTest.java index c4e149eb1b8..3c90d573919 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/AuthenticationServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/AuthenticationServiceTest.java @@ -221,6 +221,36 @@ public class AuthenticationServiceTest { (AuthenticationDataSource) null)).isEqualTo("role2"); } + @Test(timeOut = 10000) + public void testStrictAuthMethodEnforcement() throws Exception { + ServiceConfiguration config = new ServiceConfiguration(); + Set<String> providersClassNames = Sets.newHashSet(MockAuthenticationProvider.class.getName()); + config.setAuthenticationProviders(providersClassNames); + config.setAuthenticationEnabled(true); + config.setStrictAuthMethod(true); + @Cleanup + AuthenticationService service = new AuthenticationService(config); + + // Test: Request without auth method header should fail when strictAuthMethod is enabled + HttpServletRequest requestWithoutAuthMethod = mock(HttpServletRequest.class); + when(requestWithoutAuthMethod.getRemoteAddr()).thenReturn("192.168.1.1"); + when(requestWithoutAuthMethod.getRemotePort()).thenReturn(8080); + // No X-Pulsar-Auth-Method-Name header set + + assertThatThrownBy(() -> service.authenticateHttpRequest(requestWithoutAuthMethod, (HttpServletResponse) null)) + .isInstanceOf(AuthenticationException.class) + .hasMessage("Authentication method missing"); + + // Test: Request with auth method header should still succeed + HttpServletRequest requestWithAuthMethod = mock(HttpServletRequest.class); + when(requestWithAuthMethod.getRemoteAddr()).thenReturn("192.168.1.1"); + when(requestWithAuthMethod.getRemotePort()).thenReturn(8080); + when(requestWithAuthMethod.getHeader("X-Pulsar-Auth-Method-Name")).thenReturn("auth"); + + boolean result = service.authenticateHttpRequest(requestWithAuthMethod, (HttpServletResponse) null); + assertTrue(result, "Authentication should succeed when auth method is provided"); + } + public static class MockHttpAuthenticationProvider implements AuthenticationProvider { @Override public void close() throws IOException {
