This is an automated email from the ASF dual-hosted git repository.

wuchong pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fluss.git


The following commit(s) were added to refs/heads/main by this push:
     new e3ed5b452 [client] Restrict the use of 
client.security.sasl.jaas.config to PlainLoginModule exclusively. (#3425)
e3ed5b452 is described below

commit e3ed5b4525ecfb4bb5e1664ef3f308e2aeafd26f
Author: Hongshun Wang <[email protected]>
AuthorDate: Mon Jun 8 16:52:46 2026 +0800

    [client] Restrict the use of client.security.sasl.jaas.config to 
PlainLoginModule exclusively. (#3425)
---
 .../org/apache/fluss/config/ConfigOptions.java     |  5 ++-
 .../authenticator/SaslClientAuthenticator.java     | 44 +++++++++++++++++++++-
 .../rpc/netty/authenticate/AuthenticationTest.java | 19 ++++++++++
 .../authenticate/SaslAuthenticationITCase.java     |  8 ++--
 4 files changed, 70 insertions(+), 6 deletions(-)

diff --git 
a/fluss-common/src/main/java/org/apache/fluss/config/ConfigOptions.java 
b/fluss-common/src/main/java/org/apache/fluss/config/ConfigOptions.java
index ec819f575..3cb61db27 100644
--- a/fluss-common/src/main/java/org/apache/fluss/config/ConfigOptions.java
+++ b/fluss-common/src/main/java/org/apache/fluss/config/ConfigOptions.java
@@ -1413,7 +1413,10 @@ public class ConfigOptions {
                     .stringType()
                     .noDefaultValue()
                     .withDescription(
-                            "JAAS configuration string for the client. If not 
provided, uses the JVM option -Djava.security.auth.login.config. \n"
+                            "JAAS configuration string for the client. This 
option is retained for backward "
+                                    + "compatibility only. Since only 
SASL/PLAIN is currently supported, only "
+                                    + "PlainLoginModule is accepted. Prefer 
using 'client.security.sasl.username' "
+                                    + "and 'client.security.sasl.password' 
directly.\n"
                                     + "Example: 
org.apache.fluss.security.auth.sasl.plain.PlainLoginModule required 
username=\"admin\" password=\"admin-secret\";");
 
     public static final ConfigOption<String> CLIENT_SASL_JAAS_USERNAME =
diff --git 
a/fluss-common/src/main/java/org/apache/fluss/security/auth/sasl/authenticator/SaslClientAuthenticator.java
 
b/fluss-common/src/main/java/org/apache/fluss/security/auth/sasl/authenticator/SaslClientAuthenticator.java
index 1b8be5d42..8e4fcdf18 100644
--- 
a/fluss-common/src/main/java/org/apache/fluss/security/auth/sasl/authenticator/SaslClientAuthenticator.java
+++ 
b/fluss-common/src/main/java/org/apache/fluss/security/auth/sasl/authenticator/SaslClientAuthenticator.java
@@ -20,11 +20,14 @@ package org.apache.fluss.security.auth.sasl.authenticator;
 import org.apache.fluss.config.Configuration;
 import org.apache.fluss.exception.AuthenticationException;
 import org.apache.fluss.security.auth.ClientAuthenticator;
+import org.apache.fluss.security.auth.sasl.jaas.JaasConfig;
 import org.apache.fluss.security.auth.sasl.jaas.JaasContext;
 import org.apache.fluss.security.auth.sasl.jaas.LoginManager;
+import org.apache.fluss.security.auth.sasl.plain.PlainLoginModule;
 import org.apache.fluss.security.auth.sasl.plain.PlainSaslServer;
 
 import javax.annotation.Nullable;
+import javax.security.auth.login.AppConfigurationEntry;
 import javax.security.auth.login.LoginException;
 import javax.security.sasl.SaslClient;
 
@@ -50,7 +53,13 @@ public class SaslClientAuthenticator implements 
ClientAuthenticator {
     public SaslClientAuthenticator(Configuration configuration) {
         this.mechanism = 
configuration.get(CLIENT_SASL_MECHANISM).toUpperCase();
         String jaasConfigStr = 
configuration.getString(CLIENT_SASL_JAAS_CONFIG);
-        if (jaasConfigStr == null && 
mechanism.equals(PlainSaslServer.PLAIN_MECHANISM)) {
+        if (jaasConfigStr != null) {
+            // Validate that only PlainLoginModule is allowed in the JAAS 
config.
+            // Fluss uses a plugin-based authentication system and does not 
support
+            // custom SASL mechanisms. The jaas.config option is retained for 
backward
+            // compatibility only.
+            validatePlainLoginModule(jaasConfigStr);
+        } else if (mechanism.equals(PlainSaslServer.PLAIN_MECHANISM)) {
             String username = configuration.get(CLIENT_SASL_JAAS_USERNAME);
             String password = configuration.get(CLIENT_SASL_JAAS_PASSWORD);
             if (username != null || password != null) {
@@ -68,6 +77,39 @@ public class SaslClientAuthenticator implements 
ClientAuthenticator {
         this.pros = configuration.toMap();
     }
 
+    /**
+     * Validates that the provided JAAS configuration string only uses {@link 
PlainLoginModule}.
+     *
+     * @param jaasConfigStr the JAAS configuration string to validate
+     * @throws AuthenticationException if the JAAS config uses a login module 
other than
+     *     PlainLoginModule
+     */
+    private static void validatePlainLoginModule(String jaasConfigStr) {
+        JaasConfig jaasConfig = new JaasConfig("FlussClient", jaasConfigStr);
+        AppConfigurationEntry[] entries = 
jaasConfig.getAppConfigurationEntry("FlussClient");
+        if (entries == null || entries.length == 0) {
+            throw new AuthenticationException(
+                    "JAAS config property does not contain any login modules");
+        }
+        if (entries.length != 1) {
+            throw new AuthenticationException(
+                    "JAAS config property contains "
+                            + entries.length
+                            + " login modules, should be 1 module");
+        }
+        String loginModuleName = entries[0].getLoginModuleName();
+        if (!PlainLoginModule.class.getName().equals(loginModuleName)) {
+            throw new AuthenticationException(
+                    String.format(
+                            "Only '%s' is supported in '%s'. "
+                                    + "Fluss uses a plugin-based 
authentication system and does not support "
+                                    + "custom SASL mechanisms. Got: '%s'",
+                            PlainLoginModule.class.getName(),
+                            CLIENT_SASL_JAAS_CONFIG.key(),
+                            loginModuleName));
+        }
+    }
+
     @Override
     public String protocol() {
         return mechanism;
diff --git 
a/fluss-rpc/src/test/java/org/apache/fluss/rpc/netty/authenticate/AuthenticationTest.java
 
b/fluss-rpc/src/test/java/org/apache/fluss/rpc/netty/authenticate/AuthenticationTest.java
index e96fa283a..6f4977f8b 100644
--- 
a/fluss-rpc/src/test/java/org/apache/fluss/rpc/netty/authenticate/AuthenticationTest.java
+++ 
b/fluss-rpc/src/test/java/org/apache/fluss/rpc/netty/authenticate/AuthenticationTest.java
@@ -78,6 +78,25 @@ public class AuthenticationTest {
         }
     }
 
+    @Test
+    void testJaasConfigRejectsNonPlainLoginModule() throws Exception {
+        Configuration clientConfig = new Configuration();
+        clientConfig.set(ConfigOptions.CLIENT_SECURITY_PROTOCOL, "sasl");
+        clientConfig.set(ConfigOptions.CLIENT_SASL_MECHANISM, "plain");
+        clientConfig.setString(
+                "client.security.sasl.jaas.config",
+                "com.sun.security.auth.module.JndiLoginModule required 
username=\"root\" password=\"password\";");
+        try (NettyClient nettyClient =
+                new NettyClient(clientConfig, 
TestingClientMetricGroup.newInstance())) {
+            assertThatThrownBy(
+                            () -> verifyGetTableNamesList(nettyClient, 
usernamePasswordServerNode))
+                    .isInstanceOf(AuthenticationException.class)
+                    .hasMessageContaining(
+                            "Only 
'org.apache.fluss.security.auth.sasl.plain.PlainLoginModule' is supported")
+                    .hasMessageContaining("Got: 
'com.sun.security.auth.module.JndiLoginModule'");
+        }
+    }
+
     @Test
     void testMutualAuthenticate() throws Exception {
         Configuration clientConfig = new Configuration();
diff --git 
a/fluss-rpc/src/test/java/org/apache/fluss/rpc/netty/authenticate/SaslAuthenticationITCase.java
 
b/fluss-rpc/src/test/java/org/apache/fluss/rpc/netty/authenticate/SaslAuthenticationITCase.java
index 92e837e18..b02e02d63 100644
--- 
a/fluss-rpc/src/test/java/org/apache/fluss/rpc/netty/authenticate/SaslAuthenticationITCase.java
+++ 
b/fluss-rpc/src/test/java/org/apache/fluss/rpc/netty/authenticate/SaslAuthenticationITCase.java
@@ -106,9 +106,9 @@ public class SaslAuthenticationITCase {
         clientConfig.setString("client.security.sasl.mechanism", "FAKE");
         clientConfig.setString("client.security.sasl.jaas.config", 
jaasClientInfo);
         assertThatThrownBy(() -> testAuthentication(clientConfig))
-                .cause()
                 .isExactlyInstanceOf(AuthenticationException.class)
-                .hasMessage("Failed to load login manager");
+                .hasMessageContaining(
+                        "Only 
'org.apache.fluss.security.auth.sasl.plain.PlainLoginModule' is supported in 
'client.security.sasl.jaas.config'.");
     }
 
     @Test
@@ -120,9 +120,9 @@ public class SaslAuthenticationITCase {
         clientConfig.setString("client.security.sasl.mechanism", "DIGEST-MD5");
         clientConfig.setString("client.security.sasl.jaas.config", 
jaasClientInfo);
         assertThatThrownBy(() -> testAuthentication(clientConfig))
-                .cause()
                 .isExactlyInstanceOf(AuthenticationException.class)
-                .hasMessage("SASL server enables [PLAIN] while protocol of 
client is 'DIGEST-MD5'");
+                .hasMessageContaining(
+                        "Only 
'org.apache.fluss.security.auth.sasl.plain.PlainLoginModule' is supported in 
'client.security.sasl.jaas.config'.");
     }
 
     @Test

Reply via email to