diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 8ee8609c13092..2ea68c8b6b08b 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -3593,11 +3593,6 @@ hamcrest ${hamcrest.version} - - me.escoffier.certs - certificate-generator-junit5 - 0.3.0 - org.antlr diff --git a/build-parent/pom.xml b/build-parent/pom.xml index 12ef10026f472..f35d317404593 100644 --- a/build-parent/pom.xml +++ b/build-parent/pom.xml @@ -371,6 +371,13 @@ + + me.escoffier.certs + certificate-generator-junit5 + 0.4.0 + test + + diff --git a/integration-tests/kafka-ssl/pom.xml b/integration-tests/kafka-ssl/pom.xml index fed5b581d11ba..0b912f72f02fc 100644 --- a/integration-tests/kafka-ssl/pom.xml +++ b/integration-tests/kafka-ssl/pom.xml @@ -83,6 +83,11 @@ testcontainers test + + me.escoffier.certs + certificate-generator-junit5 + test + diff --git a/integration-tests/kafka-ssl/src/main/java/io/quarkus/it/kafka/ssl/CertificateFormat.java b/integration-tests/kafka-ssl/src/main/java/io/quarkus/it/kafka/ssl/CertificateFormat.java new file mode 100644 index 0000000000000..77102121ce606 --- /dev/null +++ b/integration-tests/kafka-ssl/src/main/java/io/quarkus/it/kafka/ssl/CertificateFormat.java @@ -0,0 +1,7 @@ +package io.quarkus.it.kafka.ssl; + +public enum CertificateFormat { + PKCS12, + JKS, + PEM +} diff --git a/integration-tests/kafka-ssl/src/main/java/io/quarkus/it/kafka/ssl/SslKafkaEndpoint.java b/integration-tests/kafka-ssl/src/main/java/io/quarkus/it/kafka/ssl/SslKafkaEndpoint.java index 773fd8681bb51..ab872e9ee0ac0 100644 --- a/integration-tests/kafka-ssl/src/main/java/io/quarkus/it/kafka/ssl/SslKafkaEndpoint.java +++ b/integration-tests/kafka-ssl/src/main/java/io/quarkus/it/kafka/ssl/SslKafkaEndpoint.java @@ -5,10 +5,10 @@ import java.util.Collections; import java.util.Properties; -import jakarta.annotation.PostConstruct; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; +import jakarta.ws.rs.QueryParam; import org.apache.kafka.clients.CommonClientConfigs; import org.apache.kafka.clients.consumer.Consumer; @@ -26,26 +26,21 @@ @Path("/ssl") public class SslKafkaEndpoint { - private Consumer consumer; - @Inject Config config; - @PostConstruct - public void create() { - consumer = createConsumer(); - } - @GET - public String get() { + public String get(@QueryParam("format") CertificateFormat format) { + Consumer consumer = createConsumer(format); final ConsumerRecords records = consumer.poll(Duration.ofMillis(60000)); if (records.isEmpty()) { return null; } + consumer.close(); return records.iterator().next().value(); } - public KafkaConsumer createConsumer() { + public KafkaConsumer createConsumer(CertificateFormat format) { Properties props = new Properties(); props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, config.getValue("kafka.bootstrap.servers", String.class)); props.put(ConsumerConfig.GROUP_ID_CONFIG, "test-consumer"); @@ -53,11 +48,20 @@ public KafkaConsumer createConsumer() { props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true"); props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); - File tsFile = new File(config.getValue("ssl-dir", String.class), "kafka-truststore.p12"); + + String truststore = switch (format) { + case PKCS12 -> "kafka-truststore.p12"; + case JKS -> "kafka-truststore.jks"; + case PEM -> "kafka-ca.crt"; + }; + + File tsFile = new File(config.getValue("ssl-dir", String.class), truststore); props.setProperty(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SSL"); props.setProperty(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, tsFile.getPath()); - props.setProperty(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, "Z_pkTh9xgZovK4t34cGB2o6afT4zZg0L"); - props.setProperty(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG, "PKCS12"); + if (format != CertificateFormat.PEM) { + props.setProperty(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, "Z_pkTh9xgZovK4t34cGB2o6afT4zZg0L"); + } + props.setProperty(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG, format.name()); props.setProperty(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, ""); KafkaConsumer consumer = new KafkaConsumer<>(props); diff --git a/integration-tests/kafka-ssl/src/test/java/io/quarkus/it/kafka/KafkaSSLTestResource.java b/integration-tests/kafka-ssl/src/test/java/io/quarkus/it/kafka/KafkaSSLTestResource.java index ad140e14fce63..429c927722cc2 100644 --- a/integration-tests/kafka-ssl/src/test/java/io/quarkus/it/kafka/KafkaSSLTestResource.java +++ b/integration-tests/kafka-ssl/src/test/java/io/quarkus/it/kafka/KafkaSSLTestResource.java @@ -16,9 +16,9 @@ public class KafkaSSLTestResource implements QuarkusTestResourceLifecycleManager private final StrimziKafkaContainer kafka = new StrimziKafkaContainer() .withBootstrapServers(c -> String.format("SSL://%s:%s", c.getHost(), c.getMappedPort(KAFKA_PORT))) .withServerProperties(MountableFile.forClasspathResource("server.properties")) - .withCopyFileToContainer(MountableFile.forClasspathResource("kafka-keystore.p12"), + .withCopyFileToContainer(MountableFile.forHostPath("target/certs/kafka-keystore.p12"), "/opt/kafka/config/kafka-keystore.p12") - .withCopyFileToContainer(MountableFile.forClasspathResource("kafka-truststore.p12"), + .withCopyFileToContainer(MountableFile.forHostPath("target/certs/kafka-truststore.p12"), "/opt/kafka/config/kafka-truststore.p12"); @Override @@ -29,7 +29,7 @@ public Map start() { // Used by the application Map properties = new HashMap<>(); properties.put("kafka.bootstrap.servers", kafka.getBootstrapServers()); - properties.put("ssl-dir", new File("src/test/resources").getAbsolutePath()); + properties.put("ssl-dir", new File("target/certs").getAbsolutePath()); return properties; } diff --git a/integration-tests/kafka-ssl/src/test/java/io/quarkus/it/kafka/SslKafkaConsumerTest.java b/integration-tests/kafka-ssl/src/test/java/io/quarkus/it/kafka/SslKafkaConsumerTest.java index 443fd19106c11..aa33c97a8b676 100644 --- a/integration-tests/kafka-ssl/src/test/java/io/quarkus/it/kafka/SslKafkaConsumerTest.java +++ b/integration-tests/kafka-ssl/src/test/java/io/quarkus/it/kafka/SslKafkaConsumerTest.java @@ -12,38 +12,65 @@ import org.apache.kafka.common.serialization.IntegerSerializer; import org.apache.kafka.common.serialization.StringSerializer; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import io.quarkus.it.kafka.ssl.CertificateFormat; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; +import me.escoffier.certs.Format; +import me.escoffier.certs.junit5.Certificate; +import me.escoffier.certs.junit5.Certificates; +@Certificates(certificates = { + @Certificate(name = "kafka", formats = { Format.PKCS12, Format.JKS, + Format.PEM }, alias = "kafka-test-store", password = "Z_pkTh9xgZovK4t34cGB2o6afT4zZg0L") +}, baseDir = "target/certs") @QuarkusTest @QuarkusTestResource(KafkaSSLTestResource.class) public class SslKafkaConsumerTest { - public static Producer createProducer() { + public static Producer createProducer(CertificateFormat format) { Properties props = new Properties(); props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, System.getProperty("bootstrap.servers")); props.put(ProducerConfig.CLIENT_ID_CONFIG, "test-ssl-producer"); props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class.getName()); props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); - File tsFile = new File("src/test/resources/kafka-truststore.p12"); + + String truststore = switch (format) { + case PKCS12 -> "kafka-truststore.p12"; + case JKS -> "kafka-truststore.jks"; + case PEM -> "kafka-ca.crt"; + }; + + File tsFile = new File("target/certs/" + truststore); props.setProperty(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SSL"); props.setProperty(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, tsFile.getPath()); - props.setProperty(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, "Z_pkTh9xgZovK4t34cGB2o6afT4zZg0L"); - props.setProperty(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG, "PKCS12"); + if (format != CertificateFormat.PEM) { + props.setProperty(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, "Z_pkTh9xgZovK4t34cGB2o6afT4zZg0L"); + } + props.setProperty(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG, format.name()); props.setProperty(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG, ""); return new KafkaProducer<>(props); } - @Test - public void testReception() { - Producer consumer = createProducer(); - consumer.send(new ProducerRecord<>("test-ssl-consumer", 1, "hi world")); - String string = RestAssured.when().get("/ssl").andReturn().asString(); - Assertions.assertEquals("hi world", string); + @ParameterizedTest + @CsvSource({ + "PKCS12", + "JKS", + "PEM" + }) + public void testReception(String format) { + try (Producer producer = createProducer(CertificateFormat.valueOf(format))) { + producer.send(new ProducerRecord<>("test-ssl-consumer", 1, "hi world")); + String string = RestAssured + .given().queryParam("format", format) + .when().get("/ssl") + .andReturn().asString(); + Assertions.assertEquals("hi world", string); + } } } diff --git a/integration-tests/kafka-ssl/src/test/resources/README.md b/integration-tests/kafka-ssl/src/test/resources/README.md deleted file mode 100644 index ab3ac1cbc7e1c..0000000000000 --- a/integration-tests/kafka-ssl/src/test/resources/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# How to generate the key and trust stores - -Run: - -```shell script -cd src/test/resources -rm -Rf *.p12 -export SECRET=Z_pkTh9xgZovK4t34cGB2o6afT4zZg0L -export JKS_FILE=kafka-keystore.jks -export JKS_TRUST_FILE=kafka-truststore.jks -export CERT_FILE=localhost.crt -export PKCS_FILE=kafka-keystore.p12 -export PKCS_TRUST_FILE=kafka-truststore.p12 -export PEM_FILE_CERT=kafka-cert.pem -export PEM_FILE_KEY=kafka-key.pem -keytool -genkey -alias kafka-test-store -keyalg RSA -keystore ${JKS_FILE} -keysize 2048 -validity 1095 -dname CN=localhost -keypass ${SECRET} -storepass ${SECRET} -keytool -export -alias kafka-test-store -file ${CERT_FILE} -keystore ${JKS_FILE} -keypass ${SECRET} -storepass ${SECRET} -keytool -importkeystore -srckeystore ${JKS_FILE} -srcstorepass ${SECRET} -destkeystore ${PKCS_FILE} -deststoretype PKCS12 -deststorepass ${SECRET} -keytool -keystore ${JKS_TRUST_FILE} -import -file ${CERT_FILE} -keypass ${SECRET} -storepass ${SECRET} -noprompt -keytool -importkeystore -srckeystore ${JKS_TRUST_FILE} -srcstorepass ${SECRET} -destkeystore ${PKCS_TRUST_FILE} -deststoretype PKCS12 -deststorepass ${SECRET} -rm -Rf localhost.crt *.jks -cd ../../.. || exit -1 -``` \ No newline at end of file diff --git a/integration-tests/kafka-ssl/src/test/resources/kafka-keystore.p12 b/integration-tests/kafka-ssl/src/test/resources/kafka-keystore.p12 deleted file mode 100644 index 04b1592caeb08..0000000000000 Binary files a/integration-tests/kafka-ssl/src/test/resources/kafka-keystore.p12 and /dev/null differ diff --git a/integration-tests/kafka-ssl/src/test/resources/kafka-truststore.p12 b/integration-tests/kafka-ssl/src/test/resources/kafka-truststore.p12 deleted file mode 100644 index 3fc21188bfebc..0000000000000 Binary files a/integration-tests/kafka-ssl/src/test/resources/kafka-truststore.p12 and /dev/null differ