For an existing application Im working on adding a functionality for being able to produce information on to a Kafka-topic. The application is based on SpringBoot:3.0.1 together with Java 17 and built using Gradle:7.6. To enable the kafka-functionality Ive also added Spring-kafka:3.0.1 as a dependency.
The code is pretty simple. I declare a configuration
public ProducerFactory<String, DeltaLogMessage> producerFactory() {
final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
// TRY AS SUGGESTED IN https://stackoverflow.com/questions/66261214/unable-to-find-loginmodule-class-org-apache-kafka-common-security-plain-plainlo
try {
Thread.currentThread().setContextClassLoader(null);
Thread.currentThread().setContextClassLoader(KafkaProducer.class.getClassLoader());
return new DefaultKafkaProducerFactory<>(
Map.of(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress,
ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class,
ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class,
CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, security_protocol,
SaslConfigs.SASL_MECHANISM, sasl_mechanism,
SaslConfigs.SASL_JAAS_CONFIG, String.format("%s required username=\"%s\" " + "password=\"%s\";", PlainLoginModule.class.getName(), "", ""),
"ssl.truststore.location", truststore_location,
"ssl.truststore.password", truststore_password
));
} finally {
Thread.currentThread().setContextClassLoader(currentClassLoader);
}
}
and then I use it like
kafkaTemplate.send(TOPIC_NAME, msg)
Here is the problem. While running the application through IntelliJ it works like a charm. However, when packaging into a fat-jar and run using something like
java -jar fatjar.jar
I get the error that the Jaas-moduel PlainLoginModule is missing and cant be loaded (ClassNotFoundException) resulting in LoginException.
Caused by: org.apache.kafka.common.KafkaException: javax.security.auth.login.LoginException: No LoginModule found for org.apache.kafka.common.security.plain.PlainLoginModule at org.apache.kafka.common.network.SaslChannelBuilder.configure(SaslChannelBuilder.java:184) ~[kafka-clients-3.3.1.jar!/:na] at org.apache.kafka.common.network.ChannelBuilders.create(ChannelBuilders.java:192) ~[kafka-clients-3.3.1.jar!/:na] at org.apache.kafka.common.network.ChannelBuilders.clientChannelBuilder(ChannelBuilders.java:81) ~[kafka-clients-3.3.1.jar!/:na] at org.apache.kafka.clients.ClientUtils.createChannelBuilder(ClientUtils.java:105) ~[kafka-clients-3.3.1.jar!/:na] at org.apache.kafka.clients.producer.KafkaProducer.newSender(KafkaProducer.java:514) ~[kafka-clients-3.3.1.jar!/:na] at org.apache.kafka.clients.producer.KafkaProducer.(KafkaProducer.java:457) ~[kafka-clients-3.3.1.jar!/:na] ... 17 common frames omitted Caused by: javax.security.auth.login.LoginException: No LoginModule found for org.apache.kafka.common.security.plain.PlainLoginModule at java.base/javax.security.auth.login.LoginContext.invoke(LoginContext.java:739) ~[na:na] at java.base/javax.security.auth.login.LoginContext$4.run(LoginContext.java:679) ~[na:na] at java.base/javax.security.auth.login.LoginContext$4.run(LoginContext.java:677) ~[na:na] at java.base/java.security.AccessController.doPrivileged(AccessController.java:712) ~[na:na] at java.base/javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:677) ~[na:na] at java.base/javax.security.auth.login.LoginContext.login(LoginContext.java:587) ~[na:na] at org.apache.kafka.common.security.authenticator.AbstractLogin.login(AbstractLogin.java:60) ~[kafka-clients-3.3.1.jar!/:na] at org.apache.kafka.common.security.authenticator.LoginManager.(LoginManager.java:62) ~[kafka-clients-3.3.1.jar!/:na] at org.apache.kafka.common.security.authenticator.LoginManager.acquireLoginManager(LoginManager.java:105) ~[kafka-clients-3.3.1.jar!/:na] at org.apache.kafka.common.network.SaslChannelBuilder.configure(SaslChannelBuilder.java:170) ~[kafka-clients-3.3.1.jar!/:na] ... 22 common frames omitted
I can see that the produced jar-file contains the required dependency (kafka-clients:3.3.1).
jar tvf build/libs/mitaka-0.0.1-SNAPSHOT.jar | grep kafka
BOOT-INF/lib/spring-kafka-3.0.1.jar
BOOT-INF/lib/kafka-clients-3.3.1.jar
If I connect intellij-debugger to the running jar-file and put a breakpoint in any of my own code I can do a Class.forName("org.apache.kafka.common.security.plain.PlainLoginModule") successfully.
But if I try to put the break point in javax.security.auth.login.LoginContext.invoke(LoginContext.java) where the error occures I get ClassNotFoundException. Im not skilled enough with regards to class-loading to be able to decide why this happens.
Ive looked at suggested solutions in unable to find LoginModule class: org.apache.kafka.common.security.plain.PlainLoginModule when the springboot app is run on docker container and Spring Kafka MSK : Unable to find LoginModule class: but none of them seem to make any difference for me.
Ive been been pulling my hair now on this for a couple of days and would very much appreciate some help. Please let me know if there is any additional information that I can provide
Regards
EDIT: No one that has any suggestions? What puzzles me is how there can be difference in running
./gradlew clean build && java -jar build/lib/fat.jar
vs
./gradlew bootRun