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