Skip to content

Commit e3ed5b4

Browse files
[client] Restrict the use of client.security.sasl.jaas.config to PlainLoginModule exclusively. (#3425)
1 parent 6d3ba38 commit e3ed5b4

4 files changed

Lines changed: 70 additions & 6 deletions

File tree

fluss-common/src/main/java/org/apache/fluss/config/ConfigOptions.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1413,7 +1413,10 @@ public class ConfigOptions {
14131413
.stringType()
14141414
.noDefaultValue()
14151415
.withDescription(
1416-
"JAAS configuration string for the client. If not provided, uses the JVM option -Djava.security.auth.login.config. \n"
1416+
"JAAS configuration string for the client. This option is retained for backward "
1417+
+ "compatibility only. Since only SASL/PLAIN is currently supported, only "
1418+
+ "PlainLoginModule is accepted. Prefer using 'client.security.sasl.username' "
1419+
+ "and 'client.security.sasl.password' directly.\n"
14171420
+ "Example: org.apache.fluss.security.auth.sasl.plain.PlainLoginModule required username=\"admin\" password=\"admin-secret\";");
14181421

14191422
public static final ConfigOption<String> CLIENT_SASL_JAAS_USERNAME =

fluss-common/src/main/java/org/apache/fluss/security/auth/sasl/authenticator/SaslClientAuthenticator.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
import org.apache.fluss.config.Configuration;
2121
import org.apache.fluss.exception.AuthenticationException;
2222
import org.apache.fluss.security.auth.ClientAuthenticator;
23+
import org.apache.fluss.security.auth.sasl.jaas.JaasConfig;
2324
import org.apache.fluss.security.auth.sasl.jaas.JaasContext;
2425
import org.apache.fluss.security.auth.sasl.jaas.LoginManager;
26+
import org.apache.fluss.security.auth.sasl.plain.PlainLoginModule;
2527
import org.apache.fluss.security.auth.sasl.plain.PlainSaslServer;
2628

2729
import javax.annotation.Nullable;
30+
import javax.security.auth.login.AppConfigurationEntry;
2831
import javax.security.auth.login.LoginException;
2932
import javax.security.sasl.SaslClient;
3033

@@ -50,7 +53,13 @@ public class SaslClientAuthenticator implements ClientAuthenticator {
5053
public SaslClientAuthenticator(Configuration configuration) {
5154
this.mechanism = configuration.get(CLIENT_SASL_MECHANISM).toUpperCase();
5255
String jaasConfigStr = configuration.getString(CLIENT_SASL_JAAS_CONFIG);
53-
if (jaasConfigStr == null && mechanism.equals(PlainSaslServer.PLAIN_MECHANISM)) {
56+
if (jaasConfigStr != null) {
57+
// Validate that only PlainLoginModule is allowed in the JAAS config.
58+
// Fluss uses a plugin-based authentication system and does not support
59+
// custom SASL mechanisms. The jaas.config option is retained for backward
60+
// compatibility only.
61+
validatePlainLoginModule(jaasConfigStr);
62+
} else if (mechanism.equals(PlainSaslServer.PLAIN_MECHANISM)) {
5463
String username = configuration.get(CLIENT_SASL_JAAS_USERNAME);
5564
String password = configuration.get(CLIENT_SASL_JAAS_PASSWORD);
5665
if (username != null || password != null) {
@@ -68,6 +77,39 @@ public SaslClientAuthenticator(Configuration configuration) {
6877
this.pros = configuration.toMap();
6978
}
7079

80+
/**
81+
* Validates that the provided JAAS configuration string only uses {@link PlainLoginModule}.
82+
*
83+
* @param jaasConfigStr the JAAS configuration string to validate
84+
* @throws AuthenticationException if the JAAS config uses a login module other than
85+
* PlainLoginModule
86+
*/
87+
private static void validatePlainLoginModule(String jaasConfigStr) {
88+
JaasConfig jaasConfig = new JaasConfig("FlussClient", jaasConfigStr);
89+
AppConfigurationEntry[] entries = jaasConfig.getAppConfigurationEntry("FlussClient");
90+
if (entries == null || entries.length == 0) {
91+
throw new AuthenticationException(
92+
"JAAS config property does not contain any login modules");
93+
}
94+
if (entries.length != 1) {
95+
throw new AuthenticationException(
96+
"JAAS config property contains "
97+
+ entries.length
98+
+ " login modules, should be 1 module");
99+
}
100+
String loginModuleName = entries[0].getLoginModuleName();
101+
if (!PlainLoginModule.class.getName().equals(loginModuleName)) {
102+
throw new AuthenticationException(
103+
String.format(
104+
"Only '%s' is supported in '%s'. "
105+
+ "Fluss uses a plugin-based authentication system and does not support "
106+
+ "custom SASL mechanisms. Got: '%s'",
107+
PlainLoginModule.class.getName(),
108+
CLIENT_SASL_JAAS_CONFIG.key(),
109+
loginModuleName));
110+
}
111+
}
112+
71113
@Override
72114
public String protocol() {
73115
return mechanism;

fluss-rpc/src/test/java/org/apache/fluss/rpc/netty/authenticate/AuthenticationTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,25 @@ void testNormalAuthenticate() throws Exception {
7878
}
7979
}
8080

81+
@Test
82+
void testJaasConfigRejectsNonPlainLoginModule() throws Exception {
83+
Configuration clientConfig = new Configuration();
84+
clientConfig.set(ConfigOptions.CLIENT_SECURITY_PROTOCOL, "sasl");
85+
clientConfig.set(ConfigOptions.CLIENT_SASL_MECHANISM, "plain");
86+
clientConfig.setString(
87+
"client.security.sasl.jaas.config",
88+
"com.sun.security.auth.module.JndiLoginModule required username=\"root\" password=\"password\";");
89+
try (NettyClient nettyClient =
90+
new NettyClient(clientConfig, TestingClientMetricGroup.newInstance())) {
91+
assertThatThrownBy(
92+
() -> verifyGetTableNamesList(nettyClient, usernamePasswordServerNode))
93+
.isInstanceOf(AuthenticationException.class)
94+
.hasMessageContaining(
95+
"Only 'org.apache.fluss.security.auth.sasl.plain.PlainLoginModule' is supported")
96+
.hasMessageContaining("Got: 'com.sun.security.auth.module.JndiLoginModule'");
97+
}
98+
}
99+
81100
@Test
82101
void testMutualAuthenticate() throws Exception {
83102
Configuration clientConfig = new Configuration();

fluss-rpc/src/test/java/org/apache/fluss/rpc/netty/authenticate/SaslAuthenticationITCase.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ void testClientLackLoginModule() {
106106
clientConfig.setString("client.security.sasl.mechanism", "FAKE");
107107
clientConfig.setString("client.security.sasl.jaas.config", jaasClientInfo);
108108
assertThatThrownBy(() -> testAuthentication(clientConfig))
109-
.cause()
110109
.isExactlyInstanceOf(AuthenticationException.class)
111-
.hasMessage("Failed to load login manager");
110+
.hasMessageContaining(
111+
"Only 'org.apache.fluss.security.auth.sasl.plain.PlainLoginModule' is supported in 'client.security.sasl.jaas.config'.");
112112
}
113113

114114
@Test
@@ -120,9 +120,9 @@ void testClientMechanismNotMatchServer() {
120120
clientConfig.setString("client.security.sasl.mechanism", "DIGEST-MD5");
121121
clientConfig.setString("client.security.sasl.jaas.config", jaasClientInfo);
122122
assertThatThrownBy(() -> testAuthentication(clientConfig))
123-
.cause()
124123
.isExactlyInstanceOf(AuthenticationException.class)
125-
.hasMessage("SASL server enables [PLAIN] while protocol of client is 'DIGEST-MD5'");
124+
.hasMessageContaining(
125+
"Only 'org.apache.fluss.security.auth.sasl.plain.PlainLoginModule' is supported in 'client.security.sasl.jaas.config'.");
126126
}
127127

128128
@Test

0 commit comments

Comments
 (0)