Skip to content

Commit 138cf15

Browse files
edanidzerdagaryrussell
authored andcommitted
GH-2709: Preserve existing JAAS configuration
Resolves #2709 The existing JAAS configuration at the time the KafkaJaasLoginModuleInitializer's afterSingletonsInstantiated() is now saved. The InternalConfiguration class will now search the saved JAAS Configuration first before returning its own stored configurationEntries. This mimics the approach used by Microsoft's SQL Server JDBC driver, which preserves any existing Configuration while still being able to return its own default JAAS Configuration. Added a unit test to KafkaJaasLoginModuleInitializerTests.java to ensure that an existing configuration can be found.
1 parent 4401f96 commit 138cf15

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

spring-kafka/src/main/java/org/springframework/kafka/security/jaas/KafkaJaasLoginModuleInitializer.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2019 the original author or authors.
2+
* Copyright 2017-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@
3636
*
3737
* @author Marius Bogoevici
3838
* @author Gary Russell
39+
* @author Edan Idzerda
3940
*
4041
* @since 1.3
4142
*/
@@ -143,7 +144,8 @@ public void afterSingletonsInstantiated() {
143144
this.options);
144145
configurationEntries.put(KAFKA_CLIENT_CONTEXT_NAME,
145146
new AppConfigurationEntry[] { kafkaClientConfigurationEntry });
146-
Configuration.setConfiguration(new InternalConfiguration(configurationEntries));
147+
Configuration.setConfiguration(new InternalConfiguration(configurationEntries,
148+
Configuration.getConfiguration()));
147149
// Workaround for a 0.9 client issue where even if the Configuration is
148150
// set
149151
// a system property check is performed.
@@ -166,15 +168,19 @@ private static class InternalConfiguration extends Configuration {
166168

167169
private final Map<String, AppConfigurationEntry[]> configurationEntries;
168170

169-
InternalConfiguration(Map<String, AppConfigurationEntry[]> configurationEntries) {
171+
private final Configuration delegate;
172+
173+
InternalConfiguration(Map<String, AppConfigurationEntry[]> configurationEntries, Configuration delegate) {
170174
Assert.notNull(configurationEntries, " cannot be null");
171175
Assert.notEmpty(configurationEntries, " cannot be empty");
172176
this.configurationEntries = configurationEntries;
177+
this.delegate = delegate;
173178
}
174179

175180
@Override
176181
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
177-
return this.configurationEntries.get(name);
182+
AppConfigurationEntry[] conf = this.delegate == null ? null : this.delegate.getAppConfigurationEntry(name);
183+
return conf != null ? conf : this.configurationEntries.get(name);
178184
}
179185

180186
}

spring-kafka/src/test/java/org/springframework/kafka/security/jaas/KafkaJaasLoginModuleInitializerTests.java

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2019 the original author or authors.
2+
* Copyright 2017-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,8 +27,11 @@
2727
import javax.security.auth.login.AppConfigurationEntry;
2828

2929
import org.apache.kafka.common.security.JaasContext;
30+
import org.jetbrains.annotations.NotNull;
3031
import org.junit.jupiter.api.Test;
3132

33+
import org.springframework.beans.BeansException;
34+
import org.springframework.beans.factory.config.BeanPostProcessor;
3235
import org.springframework.context.annotation.Bean;
3336
import org.springframework.context.annotation.Configuration;
3437
import org.springframework.core.io.ClassPathResource;
@@ -40,6 +43,7 @@
4043
/**
4144
* @author Marius Bogoevici
4245
* @author Gary Russell
46+
* @author Edan Idzerda
4347
*
4448
* @since 1.3
4549
*/
@@ -68,6 +72,16 @@ public void testConfigurationParsedCorrectlyWithKafkaClient() throws Exception {
6872
assertThat(appConfigurationEntries.get(0).getOptions()).isEqualTo(kafkaConfigurationArray[0].getOptions());
6973
}
7074

75+
@Test
76+
public void testOtherConfigurationFound() {
77+
javax.security.auth.login.Configuration configuration = javax.security.auth.login.Configuration
78+
.getConfiguration();
79+
80+
final AppConfigurationEntry[] otherConfiguration = configuration
81+
.getAppConfigurationEntry(PreConfiguredJaasConfig.OtherJaasConfigurationName);
82+
assertThat(otherConfiguration).hasSize(1);
83+
}
84+
7185
@Configuration
7286
public static class Config {
7387

@@ -86,4 +100,39 @@ public KafkaJaasLoginModuleInitializer jaasConfig() throws IOException {
86100

87101
}
88102

103+
@Configuration
104+
public static class PreConfiguredJaasConfig implements BeanPostProcessor {
105+
106+
private boolean initialized = false;
107+
108+
public static String OtherJaasConfigurationName = "other-jaas-configuration-name";
109+
110+
@Override
111+
public Object postProcessBeforeInitialization(@NotNull Object bean, @NotNull String beanName)
112+
throws BeansException {
113+
114+
// Install our "other" configuration before the KAFKA_CLIENT_CONTEXT_NAME is installed
115+
if (!initialized) {
116+
javax.security.auth.login.Configuration.setConfiguration(new OtherJaasConfiguration());
117+
initialized = true;
118+
}
119+
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
120+
}
121+
122+
public static class OtherJaasConfiguration extends javax.security.auth.login.Configuration {
123+
@Override
124+
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
125+
if (name.equals(OtherJaasConfigurationName)) {
126+
AppConfigurationEntry dummyAppConfigurationEntry = new AppConfigurationEntry("loginModuleName",
127+
AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL, new HashMap<>());
128+
return new AppConfigurationEntry[] { dummyAppConfigurationEntry };
129+
}
130+
else {
131+
return null;
132+
}
133+
}
134+
}
135+
136+
}
137+
89138
}

0 commit comments

Comments
 (0)