Skip to content

Commit df2c5a3

Browse files
k-wallrobobario
andauthored
Fix for kroxylicious#3035 and new ITs demonstrating the virtual cluster/sasl inspection subject builder working end-to-end (kroxylicious#3036)
* fix(sasl inspection): add missing annotations that cause kroxylicious#3035 * Add unit tests for sasl inspector config deserialization Signed-off-by: Keith Wall <[email protected]> Signed-off-by: Robert Young <[email protected]> Co-authored-by: Robert Young <[email protected]>
1 parent 7c5904a commit df2c5a3

File tree

15 files changed

+607
-193
lines changed

15 files changed

+607
-193
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ For changes that effect a public API, the [deprecation policy](./DEV_GUIDE.md#de
66
Format `<github issue/pr number>: <short description>`.
77

88
## SNAPSHOT
9+
10+
* [#3035](https://github.com/kroxylicious/kroxylicious/issues/3035): fix(sasl inspector): Fix config parsing error if SaslInspector with subject builder
11+
912
## 0.18.0
1013

1114
* [#2922](https://github.com/kroxylicious/kroxylicious/pull/2922): build(deps): bump kafka.version from 4.1.0 to 4.1.1

kroxylicious-filters/kroxylicious-sasl-inspection/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@
8181
<artifactId>logcaptor</artifactId>
8282
<scope>test</scope>
8383
</dependency>
84+
<dependency>
85+
<groupId>com.fasterxml.jackson.core</groupId>
86+
<artifactId>jackson-databind</artifactId>
87+
<scope>test</scope>
88+
</dependency>
8489
</dependencies>
8590

8691
</project>

kroxylicious-filters/kroxylicious-sasl-inspection/src/main/java/io/kroxylicious/filters/sasl/inspection/Config.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
import java.util.Set;
1010

11+
import io.kroxylicious.proxy.authentication.SaslSubjectBuilderService;
12+
import io.kroxylicious.proxy.plugin.PluginImplConfig;
13+
import io.kroxylicious.proxy.plugin.PluginImplName;
14+
1115
import edu.umd.cs.findbugs.annotations.Nullable;
1216

1317
/**
@@ -25,6 +29,6 @@
2529
* SASL authentication has been attempted or was successful. Defaults to false.
2630
*/
2731
public record Config(@Nullable Set<String> enabledMechanisms,
28-
@Nullable String subjectBuilder,
29-
@Nullable Object subjectBuilderConfig,
32+
@Nullable @PluginImplName(SaslSubjectBuilderService.class) String subjectBuilder,
33+
@Nullable @PluginImplConfig(implNameProperty = "subjectBuilder") Object subjectBuilderConfig,
3034
@Nullable Boolean requireAuthentication) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright Kroxylicious Authors.
3+
*
4+
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
7+
package io.kroxylicious.filters.sasl.inspection;
8+
9+
import java.io.IOException;
10+
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.params.ParameterizedTest;
13+
import org.junit.jupiter.params.provider.CsvSource;
14+
15+
import io.kroxylicious.proxy.config.ConfigParser;
16+
17+
import static org.assertj.core.api.Assertions.assertThat;
18+
19+
class ConfigurationSerializationTest {
20+
21+
@Test
22+
void deserializeEmpty() throws IOException {
23+
Config config = parseConfig("{}");
24+
assertThat(config.enabledMechanisms()).isNull();
25+
assertThat(config.requireAuthentication()).isNull();
26+
assertThat(config.subjectBuilderConfig()).isNull();
27+
assertThat(config.subjectBuilder()).isNull();
28+
}
29+
30+
@Test
31+
void deserializeEnabledMechanisms() throws IOException {
32+
String configYaml = """
33+
enabledMechanisms:
34+
- PLAIN
35+
""";
36+
Config config = parseConfig(configYaml);
37+
assertThat(config.enabledMechanisms()).containsExactly("PLAIN");
38+
}
39+
40+
@CsvSource({ "true", "false" })
41+
@ParameterizedTest
42+
void deserializeRequireAuthentication(boolean requireAuthentication) throws IOException {
43+
String configYaml = """
44+
requireAuthentication: %s
45+
""".formatted(requireAuthentication);
46+
Config config = parseConfig(configYaml);
47+
assertThat(config.requireAuthentication()).isEqualTo(requireAuthentication);
48+
}
49+
50+
@Test
51+
void deserializeSubjectBuilder() throws IOException {
52+
String configYaml = """
53+
subjectBuilder: MockSubjectBuilderService
54+
""";
55+
Config config = parseConfig(configYaml);
56+
assertThat(config.subjectBuilder()).isEqualTo("MockSubjectBuilderService");
57+
}
58+
59+
// covers the plugin annotations on io.kroxylicious.filters.sasl.inspection.Config
60+
@Test
61+
void deserializeSubjectBuilderConfig() throws IOException {
62+
String configYaml = """
63+
subjectBuilder: MockSubjectBuilderService
64+
subjectBuilderConfig:
65+
arbitraryProperty: foo
66+
""";
67+
Config config = parseConfig(configYaml);
68+
assertThat(config.subjectBuilderConfig()).isInstanceOf(MockSubjectBuilderService.Config.class);
69+
}
70+
71+
private static Config parseConfig(String input) throws IOException {
72+
return ConfigParser.createObjectMapper().reader().readValue(input, Config.class);
73+
}
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright Kroxylicious Authors.
3+
*
4+
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
7+
package io.kroxylicious.filters.sasl.inspection;
8+
9+
import io.kroxylicious.proxy.authentication.SaslSubjectBuilder;
10+
import io.kroxylicious.proxy.authentication.SaslSubjectBuilderService;
11+
import io.kroxylicious.proxy.plugin.Plugin;
12+
13+
import edu.umd.cs.findbugs.annotations.NonNull;
14+
15+
@Plugin(configType = MockSubjectBuilderService.Config.class)
16+
public class MockSubjectBuilderService implements SaslSubjectBuilderService<MockSubjectBuilderService.Config> {
17+
@Override
18+
public void initialize(@NonNull Config config) {
19+
throw new IllegalStateException("not implemented");
20+
}
21+
22+
@Override
23+
public SaslSubjectBuilder build() {
24+
throw new IllegalStateException("not implemented");
25+
}
26+
27+
public record Config(String arbitraryProperty) {}
28+
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#
2+
# Copyright Kroxylicious Authors.
3+
#
4+
# Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
#
6+
io.kroxylicious.filters.sasl.inspection.MockSubjectBuilderService

kroxylicious-integration-test-support/src/main/java/io/kroxylicious/proxy/config/BuilderConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"io.kroxylicious.proxy.config.VirtualClusterGateway",
1919
"io.kroxylicious.proxy.config.PortIdentifiesNodeIdentificationStrategy",
2020
"io.kroxylicious.proxy.config.SniHostIdentifiesNodeIdentificationStrategy",
21+
"io.kroxylicious.proxy.config.TransportSubjectBuilderConfig",
2122
"io.kroxylicious.proxy.config.NamedRange",
2223
"io.kroxylicious.proxy.config.admin.ManagementConfiguration",
2324
"io.kroxylicious.proxy.config.admin.EndpointsConfiguration",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright Kroxylicious Authors.
3+
*
4+
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
7+
package io.kroxylicious.proxy.config;
8+
9+
import java.util.Map;
10+
11+
import io.kroxylicious.proxy.authentication.TransportSubjectBuilderService;
12+
13+
public class TransportSubjectBuilderDefinitionBuilder extends AbstractDefinitionBuilder<TransportSubjectBuilderConfig> {
14+
public TransportSubjectBuilderDefinitionBuilder(String type) {
15+
super(type);
16+
}
17+
18+
@Override
19+
protected TransportSubjectBuilderConfig buildInternal(String type, Map<String, Object> config) {
20+
ServiceBasedPluginFactoryRegistry registry = new ServiceBasedPluginFactoryRegistry();
21+
PluginFactory<TransportSubjectBuilderService> factory = registry.pluginFactory(TransportSubjectBuilderService.class);
22+
Class<?> configType = factory.configType(type);
23+
return new TransportSubjectBuilderConfig(type, mapper.convertValue(config, configType));
24+
}
25+
}

kroxylicious-integration-tests/src/test/java/io/kroxylicious/proxy/BaseIT.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,32 @@
66

77
package io.kroxylicious.proxy;
88

9+
import java.time.Duration;
910
import java.util.HashMap;
1011
import java.util.List;
1112
import java.util.Map;
1213
import java.util.Optional;
14+
import java.util.Set;
1315
import java.util.concurrent.TimeUnit;
16+
import java.util.function.BiConsumer;
1417

1518
import org.apache.kafka.clients.admin.Admin;
1619
import org.apache.kafka.clients.admin.CreateTopicsResult;
1720
import org.apache.kafka.clients.admin.DeleteTopicsResult;
1821
import org.apache.kafka.clients.admin.NewTopic;
1922
import org.apache.kafka.clients.consumer.Consumer;
23+
import org.apache.kafka.clients.consumer.ConsumerRecords;
2024
import org.apache.kafka.clients.producer.Producer;
25+
import org.apache.kafka.clients.producer.ProducerRecord;
2126
import org.apache.kafka.common.TopicCollection;
27+
import org.apache.kafka.common.serialization.Serdes;
2228
import org.junit.jupiter.api.extension.ExtendWith;
2329

2430
import io.github.nettyplus.leakdetector.junit.NettyLeakDetectorExtension;
2531

2632
import io.kroxylicious.test.tester.KroxyliciousTester;
2733
import io.kroxylicious.testing.kafka.junit5ext.KafkaClusterExtension;
34+
import io.kroxylicious.testing.kafka.junit5ext.Topic;
2835

2936
import static org.assertj.core.api.Assertions.assertThat;
3037

@@ -78,4 +85,28 @@ protected final Producer<String, String> getProducerWithConfig(KroxyliciousTeste
7885
}
7986
return tester.producer(producerConfig);
8087
}
88+
89+
public static void sendReceiveBatches(KroxyliciousTester tester,
90+
Topic topic,
91+
Map<String, Object> producerConfig,
92+
Map<String, Object> consumerConfig,
93+
int numBatches,
94+
BiConsumer<Integer, ConsumerRecords<String, byte[]>> recordConsumer) {
95+
try (var producer = tester.producer(producerConfig);
96+
var consumer = tester
97+
.consumer(Serdes.String(), Serdes.ByteArray(), consumerConfig)) {
98+
int batchNumOneBased = 1;
99+
while (batchNumOneBased <= numBatches) {
100+
assertThat(producer.send(new ProducerRecord<>(topic.name(), "my-key", "my-value")))
101+
.succeedsWithin(Duration.ofSeconds(5));
102+
103+
consumer.subscribe(Set.of(topic.name()));
104+
var records = consumer.poll(Duration.ofSeconds(10));
105+
106+
assertThat(records).hasSize(1);
107+
recordConsumer.accept(batchNumOneBased, records);
108+
batchNumOneBased += 1;
109+
}
110+
}
111+
}
81112
}

kroxylicious-integration-tests/src/test/java/io/kroxylicious/proxy/BaseOauthBearerIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
@ExtendWith(NettyLeakDetectorExtension.class)
3838
@EnabledIf(value = "isDockerAvailable", disabledReason = "docker unavailable")
3939
@RestoreSystemProperties
40-
public class BaseOauthBearerIT {
40+
public class BaseOauthBearerIT extends BaseIT {
4141
private static final int OAUTH_SERVER_PORT = 28089;
4242

4343
// This token is expired

0 commit comments

Comments
 (0)