This is an automated email from the ASF dual-hosted git repository. jamesnetherton pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/main by this push: new 1de918f30a Kafka tests in fips 1de918f30a is described below commit 1de918f30a6a2f9e784b3face5c2956aa94ee02f Author: JiriOndrusek <ondrusek.j...@gmail.com> AuthorDate: Tue May 14 16:08:30 2024 +0200 Kafka tests in fips --- .../{kafka => certificate-generator}/pom.xml | 20 ++-- .../TestCertificateGenerationExtension.java | 127 +++++++++++++++++++++ .../test/support/certificate/TestCertificates.java | 55 +++++++++ integration-tests-support/kafka/pom.xml | 4 + .../test/support/kafka/KafkaTestResource.java | 78 ++++++++++++- .../test/support/kafka/KafkaTestSupport.java | 37 ------ .../kafka/src/main/resources/log4j.properties | 23 ++++ integration-tests-support/pom.xml | 1 + .../quarkus/test/DisabledIfFipsModeCondition.java | 2 +- .../quarkus/test/EnabledIfFipsModeCondition.java | 29 +---- ...dIfFipsModeCondition.java => FipsModeUtil.java} | 40 ++----- integration-tests/kafka-sasl-ssl/pom.xml | 5 + .../camel/quarkus/kafka/sasl/KafkaSaslSslTest.java | 7 ++ .../kafka/sasl/KafkaSaslSslTestResource.java | 76 ++++-------- .../test/resources/config/generate-certificates.sh | 39 ------- .../src/test/resources/config/kafka-keystore.p12 | Bin 2451 -> 0 bytes .../src/test/resources/config/kafka-truststore.p12 | Bin 1010 -> 0 bytes .../test/resources/config/kafka_server_jaas.conf | 5 +- .../quarkus/kafka/sasl/KafkaSaslBindingTest.java | 2 + integration-tests/kafka-ssl/pom.xml | 5 + .../camel/quarkus/kafka/ssl/KafkaSslTest.java | 10 ++ .../quarkus/kafka/ssl/KafkaSslTestResource.java | 74 +++--------- .../test/resources/config/generate-certificates.sh | 39 ------- .../src/test/resources/config/kafka-keystore.p12 | Bin 2451 -> 0 bytes .../src/test/resources/config/kafka-truststore.p12 | Bin 1010 -> 0 bytes pom.xml | 1 + poms/bom-test/pom.xml | 10 ++ 27 files changed, 385 insertions(+), 304 deletions(-) diff --git a/integration-tests-support/kafka/pom.xml b/integration-tests-support/certificate-generator/pom.xml similarity index 86% copy from integration-tests-support/kafka/pom.xml copy to integration-tests-support/certificate-generator/pom.xml index 736a0e369b..0bcbf9f57d 100644 --- a/integration-tests-support/kafka/pom.xml +++ b/integration-tests-support/certificate-generator/pom.xml @@ -26,21 +26,25 @@ </parent> <modelVersion>4.0.0</modelVersion> - <artifactId>camel-quarkus-integration-tests-support-kafka</artifactId> - <name>Camel Quarkus :: Integration Tests :: Support :: Kafka</name> + <artifactId>camel-quarkus-integration-tests-support-certificate-generator</artifactId> + <name>Camel Quarkus :: Integration Tests :: Support :: Certificate generator</name> <dependencies> <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-kafka-client</artifactId> + <groupId>me.escoffier.certs</groupId> + <artifactId>certificate-generator-junit5</artifactId> </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-integration-test-support</artifactId> </dependency> <dependency> - <groupId>io.strimzi</groupId> - <artifactId>strimzi-test-container</artifactId> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-junit4-mock</artifactId> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>testcontainers</artifactId> <exclusions> <exclusion> <groupId>junit</groupId> @@ -48,10 +52,6 @@ </exclusion> </exclusions> </dependency> - <dependency> - <groupId>io.quarkus</groupId> - <artifactId>quarkus-junit4-mock</artifactId> - </dependency> </dependencies> <build> diff --git a/integration-tests-support/certificate-generator/src/main/java/org/apache/camel/quarkus/test/support/certificate/TestCertificateGenerationExtension.java b/integration-tests-support/certificate-generator/src/main/java/org/apache/camel/quarkus/test/support/certificate/TestCertificateGenerationExtension.java new file mode 100644 index 0000000000..c695fdcaab --- /dev/null +++ b/integration-tests-support/certificate-generator/src/main/java/org/apache/camel/quarkus/test/support/certificate/TestCertificateGenerationExtension.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.test.support.certificate; + +import java.io.File; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +import me.escoffier.certs.AliasRequest; +import me.escoffier.certs.CertificateFiles; +import me.escoffier.certs.CertificateGenerator; +import me.escoffier.certs.CertificateRequest; +import me.escoffier.certs.junit5.Alias; +import me.escoffier.certs.junit5.Certificate; +import org.jboss.logging.Logger; +import org.junit.jupiter.api.extension.*; +import org.junit.platform.commons.util.AnnotationUtils; +import org.testcontainers.DockerClientFactory; + +/** + * Extension is based on + * https://github.com/cescoffier/certificate-generator/blob/main/certificate-generator-junit5/src/main/java/me/escoffier/certs/junit5/CertificateGenerationExtension.java + * + * Unfortunately there is no way of extending the original Extension with functionality of modifying CN and + * SubjectAlternativeName + * based on docker host (required for usage with external docker host) + * Therefore I created a new annotation 'TestCertificates' which would use this new extension. + */ +public class TestCertificateGenerationExtension implements BeforeAllCallback, ParameterResolver { + private static final Logger LOGGER = Logger.getLogger(TestCertificateGenerationExtension.class); + + public static TestCertificateGenerationExtension getInstance(ExtensionContext extensionContext) { + return extensionContext.getStore(ExtensionContext.Namespace.GLOBAL) + .get(TestCertificateGenerationExtension.class, TestCertificateGenerationExtension.class); + } + + List<CertificateFiles> certificateFiles = new ArrayList<>(); + + @Override + public void beforeAll(ExtensionContext extensionContext) throws Exception { + + extensionContext.getStore(ExtensionContext.Namespace.GLOBAL) + .getOrComputeIfAbsent(TestCertificateGenerationExtension.class, c -> this); + var maybe = AnnotationUtils.findAnnotation(extensionContext.getRequiredTestClass(), TestCertificates.class); + if (maybe.isEmpty()) { + return; + } + var annotation = maybe.get(); + + //cn and alternativeSubjectName might be different (to reflect docker host) + Optional<String> cn = resolveDockerHost(); + Optional<String> altSubName = cn.stream().map(h -> "IP:%s".formatted(h)).findAny(); + + for (Certificate certificate : annotation.certificates()) { + String baseDir = annotation.baseDir(); + File file = new File(baseDir); + file.mkdirs(); + CertificateGenerator generator = new CertificateGenerator(file.toPath(), annotation.replaceIfExists()); + + CertificateRequest request = new CertificateRequest() + .withName(certificate.name()) + .withClientCertificate(certificate.client()) + .withFormats(Arrays.asList(certificate.formats())) + .withCN(cn.orElse(certificate.cn())) + .withPassword(certificate.password().isEmpty() ? null : certificate.password()) + .withDuration(Duration.ofDays(certificate.duration())); + + if (altSubName.isPresent()) { + request.withSubjectAlternativeName(altSubName.get()); + } + + for (String san : certificate.subjectAlternativeNames()) { + request.withSubjectAlternativeName(san); + } + + for (Alias alias : certificate.aliases()) { + AliasRequest nested = new AliasRequest() + .withCN(alias.cn()) + .withPassword(alias.password()) + .withClientCertificate(alias.client()); + request.withAlias(alias.name(), nested); + for (String s : alias.subjectAlternativeNames()) { + nested.withSubjectAlternativeName(s); + } + } + + certificateFiles.addAll(generator.generate(request)); + } + } + + private Optional<String> resolveDockerHost() { + String dockerHost = DockerClientFactory.instance().dockerHostIpAddress(); + if (!dockerHost.equals("localhost") && !dockerHost.equals("127.0.0.1")) { + return Optional.of(dockerHost); + } + return Optional.empty(); + } + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + throw new IllegalArgumentException("Not supported!"); + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + throw new IllegalArgumentException("Not supported!"); + } +} diff --git a/integration-tests-support/certificate-generator/src/main/java/org/apache/camel/quarkus/test/support/certificate/TestCertificates.java b/integration-tests-support/certificate-generator/src/main/java/org/apache/camel/quarkus/test/support/certificate/TestCertificates.java new file mode 100644 index 0000000000..0d686dbc58 --- /dev/null +++ b/integration-tests-support/certificate-generator/src/main/java/org/apache/camel/quarkus/test/support/certificate/TestCertificates.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.test.support.certificate; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import me.escoffier.certs.junit5.Certificate; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Based on + * https://github.com/cescoffier/certificate-generator/blob/main/certificate-generator-junit5/src/main/java/me/escoffier/certs/junit5/Certificates.java + * Generates certificates before the tests via 'TestCertificateGenerationExtension' so the new certificates + * are customized to fullfill a remote docker host (if required). + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(TestCertificateGenerationExtension.class) +@Inherited +public @interface TestCertificates { + + /** + * The base directory in which certificates will be generated. + */ + String baseDir(); + + /** + * The certificates to generate. + * Must not be empty. + */ + Certificate[] certificates(); + + /** + * Whether to replace the certificates if they already exist. + */ + boolean replaceIfExists() default false; +} diff --git a/integration-tests-support/kafka/pom.xml b/integration-tests-support/kafka/pom.xml index 736a0e369b..2cc5a91e13 100644 --- a/integration-tests-support/kafka/pom.xml +++ b/integration-tests-support/kafka/pom.xml @@ -52,6 +52,10 @@ <groupId>io.quarkus</groupId> <artifactId>quarkus-junit4-mock</artifactId> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-integration-test-support</artifactId> + </dependency> </dependencies> <build> diff --git a/integration-tests-support/kafka/src/main/java/org/apache/camel/quarkus/test/support/kafka/KafkaTestResource.java b/integration-tests-support/kafka/src/main/java/org/apache/camel/quarkus/test/support/kafka/KafkaTestResource.java index 5e3fd138fa..a38e7c1f74 100644 --- a/integration-tests-support/kafka/src/main/java/org/apache/camel/quarkus/test/support/kafka/KafkaTestResource.java +++ b/integration-tests-support/kafka/src/main/java/org/apache/camel/quarkus/test/support/kafka/KafkaTestResource.java @@ -18,12 +18,18 @@ package org.apache.camel.quarkus.test.support.kafka; import java.util.Collections; import java.util.Map; +import java.util.function.Function; +import com.github.dockerjava.api.exception.NotFoundException; import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; import io.strimzi.test.container.StrimziKafkaContainer; +import org.apache.camel.quarkus.test.FipsModeUtil; import org.eclipse.microprofile.config.ConfigProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.testcontainers.containers.ContainerFetchException; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.images.builder.ImageFromDockerfile; import org.testcontainers.utility.TestcontainersConfiguration; public class KafkaTestResource implements QuarkusTestResourceLifecycleManager { @@ -31,18 +37,14 @@ public class KafkaTestResource implements QuarkusTestResourceLifecycleManager { private static final Logger LOGGER = LoggerFactory.getLogger(KafkaTestResource.class); private StrimziKafkaContainer container; + private GenericContainer j17container; @Override public Map<String, String> start() { LOGGER.info(TestcontainersConfiguration.getInstance().toString()); try { - container = new StrimziKafkaContainer(KAFKA_IMAGE_NAME) - /* Added container startup logging because of https://github.com/apache/camel-quarkus/issues/2461 */ - .withLogConsumer(frame -> System.out.print(frame.getUtf8String())) - .waitForRunning(); - - container.start(); + startContainer(KAFKA_IMAGE_NAME, name -> new StrimziKafkaContainer(name)); return Collections.singletonMap("camel.component.kafka.brokers", container.getBootstrapServers()); } catch (Exception e) { @@ -50,6 +52,62 @@ public class KafkaTestResource implements QuarkusTestResourceLifecycleManager { } } + public String start(Function<String, StrimziKafkaContainer> containerSupplier) { + LOGGER.info(TestcontainersConfiguration.getInstance().toString()); + + //if FIPS environment is present, custom container using J17 has to used because: + // Password-based encryption support in FIPs mode was implemented in the Red Hat build of OpenJDK 17 update 4 + if (FipsModeUtil.isFipsMode()) { + //custom image should be cached for the next usages with following id + String customImageName = "camel-quarkus-test-custom-" + KAFKA_IMAGE_NAME.replaceAll("[\\./]", "-"); + + try { + //in case that the image is not accessible, fetch exception is thrown + startContainer(customImageName, containerSupplier); + } catch (ContainerFetchException e) { + if (e.getCause() instanceof NotFoundException) { + LOGGER.info("Custom image for kafka (%s) does not exist. Has to be created.", customImageName); + + //start of the customized container will create the image + //it is not possible to customize existing StrimziKafkaContainer. Testcontainer API doe not allow + //to customize the image. + // This workaround can be removed once the strimzi container with openjdk 17 is released. + // According to https://strimzi.io/blog/2023/01/25/running-apache-kafka-on-fips-enabled-kubernetes-cluster/ + // image should exist + j17container = new GenericContainer( + new ImageFromDockerfile(customImageName, false) + .withDockerfileFromBuilder(builder -> builder + .from("quay.io/strimzi-test-container/test-container:latest-kafka-3.2.1") + .env("JAVA_HOME", "/usr/lib/jvm/jre-17") + .env("PATH", "/usr/lib/jvm/jre-17/bin:$PATH") + .user("root") + .run("microdnf install -y --nodocs java-17-openjdk-headless glibc-langpack-en && microdnf clean all"))); + j17container.start(); + + LOGGER.info("Custom image for kafka (%s) has been created.", customImageName); + + //start kafka container again + startContainer(customImageName, containerSupplier); + } + } + } else { + startContainer(KAFKA_IMAGE_NAME, containerSupplier); + } + + return container.getBootstrapServers(); + + } + + private void startContainer(String imageName, Function<String, StrimziKafkaContainer> containerSupplier) { + container = containerSupplier.apply(imageName); + + /* Added container startup logging because of https://github.com/apache/camel-quarkus/issues/2461 */ + container.withLogConsumer(frame -> System.out.print(frame.getUtf8String())) + // .withEnv("KAFKA_LOG4J_OPTS", "-Dlog4j.configuration=file:/log4j.properties") + .waitForRunning() + .start(); + } + @Override public void stop() { if (container != null) { @@ -59,6 +117,13 @@ public class KafkaTestResource implements QuarkusTestResourceLifecycleManager { // ignored } } + if (j17container != null) { + try { + j17container.stop(); + } catch (Exception e) { + // ignored + } + } } @Override @@ -66,4 +131,5 @@ public class KafkaTestResource implements QuarkusTestResourceLifecycleManager { testInjector.injectIntoFields(container, new TestInjector.AnnotatedAndMatchesType(InjectKafka.class, StrimziKafkaContainer.class)); } + } diff --git a/integration-tests-support/kafka/src/main/java/org/apache/camel/quarkus/test/support/kafka/KafkaTestSupport.java b/integration-tests-support/kafka/src/main/java/org/apache/camel/quarkus/test/support/kafka/KafkaTestSupport.java index 54170c5216..a62d6d475a 100644 --- a/integration-tests-support/kafka/src/main/java/org/apache/camel/quarkus/test/support/kafka/KafkaTestSupport.java +++ b/integration-tests-support/kafka/src/main/java/org/apache/camel/quarkus/test/support/kafka/KafkaTestSupport.java @@ -16,16 +16,12 @@ */ package org.apache.camel.quarkus.test.support.kafka; -import java.nio.file.Path; import java.util.Optional; import java.util.Properties; import org.apache.kafka.clients.CommonClientConfigs; import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; -import org.testcontainers.DockerClientFactory; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.utility.MountableFile; public final class KafkaTestSupport { @@ -59,37 +55,4 @@ public final class KafkaTestSupport { public static void setKafkaConfigFromProperty(Properties props, String key, String valueKey) { props.put(key, getKafkaConfigValue(valueKey)); } - - public static void regenerateCertificatesForDockerHost( - Path configDir, - String certificateScript, - String keyStoreFile, - String trustStoreFile) { - String dockerHost = DockerClientFactory.instance().dockerHostIpAddress(); - if (!dockerHost.equals("localhost") && !dockerHost.equals("127.0.0.1")) { - // Run certificate generation in a container in case the target platform does not have prerequisites like OpenSSL installed (E.g on Windows) - String imageName = ConfigProvider.getConfig().getValue("eclipse-temurin.container.image", String.class); - try (GenericContainer<?> container = new GenericContainer<>(imageName)) { - container.withCreateContainerCmdModifier(modifier -> { - modifier.withEntrypoint("/bin/bash"); - modifier.withStdinOpen(true); - }); - container.setWorkingDirectory("/"); - container.start(); - - String host = container.getHost(); - container.copyFileToContainer( - MountableFile.forClasspathResource("config/" + certificateScript), - "/" + certificateScript); - container.execInContainer("/bin/bash", "/" + certificateScript, host, - "DNS:%s,IP:%s".formatted(host, host)); - container.copyFileFromContainer("/" + keyStoreFile, - configDir.resolve(keyStoreFile).toString()); - container.copyFileFromContainer("/" + trustStoreFile, - configDir.resolve(trustStoreFile).toString()); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } } diff --git a/integration-tests-support/kafka/src/main/resources/log4j.properties b/integration-tests-support/kafka/src/main/resources/log4j.properties new file mode 100644 index 0000000000..061c5b6877 --- /dev/null +++ b/integration-tests-support/kafka/src/main/resources/log4j.properties @@ -0,0 +1,23 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- +# Set root logger level to DEBUG and its only appender to CONSOLE. +log4j.rootLogger=TRACE, CONSOLE + +# Console appender configuration +log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender +log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout +log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%-5p] %c{1}:%L - %m%n diff --git a/integration-tests-support/pom.xml b/integration-tests-support/pom.xml index 378254700c..d0d48a1886 100644 --- a/integration-tests-support/pom.xml +++ b/integration-tests-support/pom.xml @@ -50,6 +50,7 @@ <module>activemq</module> <module>aws2</module> <module>azure</module> + <module>certificate-generator</module> <module>custom-dataformat</module> <module>custom-log-component</module> <module>custom-routes-collector</module> diff --git a/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/DisabledIfFipsModeCondition.java b/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/DisabledIfFipsModeCondition.java index 984e8bde8a..f452be2c22 100644 --- a/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/DisabledIfFipsModeCondition.java +++ b/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/DisabledIfFipsModeCondition.java @@ -39,7 +39,7 @@ public class DisabledIfFipsModeCondition extends EnabledIfFipsModeCondition { private ConditionEvaluationResult map(DisabledIfFipsMode annotation) { List<String> providersToMatch = List.of(annotation.providers()); - Optional<String> fipsProviders = findFipsProvider(providersToMatch); + Optional<String> fipsProviders = FipsModeUtil.findFipsProvider(providersToMatch); if (fipsProviders == null) { return enabled("No FIPS security providers were detected"); diff --git a/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/EnabledIfFipsModeCondition.java b/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/EnabledIfFipsModeCondition.java index f858c2b835..89ca33ec01 100644 --- a/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/EnabledIfFipsModeCondition.java +++ b/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/EnabledIfFipsModeCondition.java @@ -16,8 +16,6 @@ */ package org.apache.camel.quarkus.test; -import java.security.Provider; -import java.security.Security; import java.util.List; import java.util.Optional; @@ -39,7 +37,7 @@ public class EnabledIfFipsModeCondition implements ExecutionCondition { private ConditionEvaluationResult map(EnabledIfFipsMode annotation) { List<String> providersToMatch = List.of(annotation.providers()); - Optional<String> fipsProviders = findFipsProvider(providersToMatch); + Optional<String> fipsProviders = FipsModeUtil.findFipsProvider(providersToMatch); if (fipsProviders == null) { return disabled("No FIPS security providers were detected"); @@ -51,29 +49,4 @@ public class EnabledIfFipsModeCondition implements ExecutionCondition { return enabled("Detected FIPS security provider " + fipsProviders.get()); } - /** - * Returns null if system is not in fips mode. - * Returns Optional.empty if system is in fips mode and there is some provider containing "fips" - * Returns Optional.name if system is in fips mode and there is a match with the provided providers - * (the last 2 options allows to differentiate reason of the enablement/disablement) - */ - Optional<String> findFipsProvider(List<String> providersToMatch) { - Provider[] jdkProviders = Security.getProviders(); - int matchCount = 0; - - for (Provider provider : jdkProviders) { - if (providersToMatch.isEmpty() && provider.getName().toLowerCase().contains("fips")) { - return Optional.of(provider.getName()); - } else if (providersToMatch.contains(provider.getName())) { - matchCount++; - } - } - - if (!providersToMatch.isEmpty() && matchCount == providersToMatch.size()) { - return Optional.empty(); - } - - return null; - - } } diff --git a/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/EnabledIfFipsModeCondition.java b/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/FipsModeUtil.java similarity index 54% copy from integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/EnabledIfFipsModeCondition.java copy to integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/FipsModeUtil.java index f858c2b835..6878576e5e 100644 --- a/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/EnabledIfFipsModeCondition.java +++ b/integration-tests-support/test-support/src/main/java/org/apache/camel/quarkus/test/FipsModeUtil.java @@ -18,46 +18,22 @@ package org.apache.camel.quarkus.test; import java.security.Provider; import java.security.Security; +import java.util.Collections; import java.util.List; import java.util.Optional; -import org.junit.jupiter.api.extension.ConditionEvaluationResult; -import org.junit.jupiter.api.extension.ExecutionCondition; -import org.junit.jupiter.api.extension.ExtensionContext; +public class FipsModeUtil { -import static org.junit.jupiter.api.extension.ConditionEvaluationResult.disabled; -import static org.junit.jupiter.api.extension.ConditionEvaluationResult.enabled; -import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation; - -public class EnabledIfFipsModeCondition implements ExecutionCondition { - private static final ConditionEvaluationResult ENABLED_BY_DEFAULT = enabled("@EnabledIfFipsMode is not present"); - - @Override - public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { - return findAnnotation(context.getElement(), EnabledIfFipsMode.class).map(this::map).orElse(ENABLED_BY_DEFAULT); - } - - private ConditionEvaluationResult map(EnabledIfFipsMode annotation) { - List<String> providersToMatch = List.of(annotation.providers()); - Optional<String> fipsProviders = findFipsProvider(providersToMatch); - - if (fipsProviders == null) { - return disabled("No FIPS security providers were detected"); - } - if (fipsProviders.isEmpty()) { - return enabled("Detected FIPS security providers"); - } - - return enabled("Detected FIPS security provider " + fipsProviders.get()); + private FipsModeUtil() { } /** * Returns null if system is not in fips mode. * Returns Optional.empty if system is in fips mode and there is some provider containing "fips" * Returns Optional.name if system is in fips mode and there is a match with the provided providers - * (the last 2 options allows to differentiate reason of the enablement/disablement) + * (the last 2 options allows differentiate reason of the enablement/disablement) */ - Optional<String> findFipsProvider(List<String> providersToMatch) { + static public Optional<String> findFipsProvider(List<String> providersToMatch) { Provider[] jdkProviders = Security.getProviders(); int matchCount = 0; @@ -74,6 +50,12 @@ public class EnabledIfFipsModeCondition implements ExecutionCondition { } return null; + } + /** + * Return true if system is in FIPS mode. + */ + static public boolean isFipsMode() { + return findFipsProvider(Collections.emptyList()) != null; } } diff --git a/integration-tests/kafka-sasl-ssl/pom.xml b/integration-tests/kafka-sasl-ssl/pom.xml index 347cb2e0f4..d54554c9c4 100644 --- a/integration-tests/kafka-sasl-ssl/pom.xml +++ b/integration-tests/kafka-sasl-ssl/pom.xml @@ -74,6 +74,11 @@ <artifactId>quarkus-junit4-mock</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-integration-tests-support-certificate-generator</artifactId> + <scope>test</scope> + </dependency> </dependencies> <profiles> diff --git a/integration-tests/kafka-sasl-ssl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslSslTest.java b/integration-tests/kafka-sasl-ssl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslSslTest.java index 947a7ee949..9c1fb307a0 100644 --- a/integration-tests/kafka-sasl-ssl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslSslTest.java +++ b/integration-tests/kafka-sasl-ssl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslSslTest.java @@ -22,10 +22,17 @@ import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; import io.restassured.path.json.JsonPath; +import me.escoffier.certs.Format; +import me.escoffier.certs.junit5.Certificate; +import org.apache.camel.quarkus.test.support.certificate.TestCertificates; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; +@TestCertificates(certificates = { + @Certificate(name = KafkaSaslSslTestResource.KAFKA_HOSTNAME, formats = { + Format.PKCS12 }, password = KafkaSaslSslTestResource.KAFKA_KEYSTORE_PASSWORD) +}, baseDir = KafkaSaslSslTestResource.CERTS_BASEDIR) @QuarkusTest @QuarkusTestResource(KafkaSaslSslTestResource.class) public class KafkaSaslSslTest { diff --git a/integration-tests/kafka-sasl-ssl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslSslTestResource.java b/integration-tests/kafka-sasl-ssl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslSslTestResource.java index 3366526b23..7de0728de2 100644 --- a/integration-tests/kafka-sasl-ssl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslSslTestResource.java +++ b/integration-tests/kafka-sasl-ssl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslSslTestResource.java @@ -16,10 +16,7 @@ */ package org.apache.camel.quarkus.kafka.sasl; -import java.io.IOException; -import java.io.InputStream; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import java.util.stream.Stream; @@ -27,77 +24,46 @@ import java.util.stream.Stream; import com.github.dockerjava.api.command.InspectContainerResponse; import io.strimzi.test.container.StrimziKafkaContainer; import org.apache.camel.quarkus.test.support.kafka.KafkaTestResource; -import org.apache.camel.quarkus.test.support.kafka.KafkaTestSupport; import org.apache.camel.util.CollectionHelper; -import org.apache.commons.io.FileUtils; import org.testcontainers.images.builder.Transferable; import org.testcontainers.utility.MountableFile; import static io.strimzi.test.container.StrimziZookeeperContainer.ZOOKEEPER_PORT; public class KafkaSaslSslTestResource extends KafkaTestResource { - private static final String KAFKA_KEYSTORE_FILE = "kafka-keystore.p12"; - private static final String KAFKA_KEYSTORE_PASSWORD = "kafkas3cret"; - private static final String KAFKA_KEYSTORE_TYPE = "PKCS12"; - private static final String KAFKA_TRUSTSTORE_FILE = "kafka-truststore.p12"; - private static final String KAFKA_CERTIFICATE_SCRIPT = "generate-certificates.sh"; - private static Path configDir; - private SaslSslKafkaContainer container; + static final String KAFKA_KEYSTORE_PASSWORD = "n7BfLSrdIKZSd2SJv8pUvVurrOW6q2Q3G"; + //min lengthe is 32 because of SCRAM-SHA-512 + static final String ALICE_PASSWORD = "IuepUrtaAXpwgTy6TPmInRAUinlK2acQL"; + static final String KAFKA_HOSTNAME = "localhost"; + static final String CERTS_BASEDIR = "target/certs"; + + static final String KAFKA_KEYSTORE_FILE = KAFKA_HOSTNAME + "-keystore.p12"; + static final String KAFKA_KEYSTORE_TYPE = "PKCS12"; + static final String KAFKA_TRUSTSTORE_FILE = KAFKA_HOSTNAME + "-truststore.p12"; @Override public Map<String, String> start() { - try { - configDir = Files.createTempDirectory("KafkaSaslSslTestResource-"); - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - Stream.of("kafka_server_jaas.conf", KAFKA_KEYSTORE_FILE, KAFKA_TRUSTSTORE_FILE) - .forEach(fileName -> { - try (InputStream in = classLoader.getResourceAsStream("config/" + fileName)) { - Files.copy(in, configDir.resolve(fileName)); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } catch (IOException e) { - throw new RuntimeException(e); - } - - KafkaTestSupport.regenerateCertificatesForDockerHost(configDir, KAFKA_CERTIFICATE_SCRIPT, KAFKA_KEYSTORE_FILE, - KAFKA_TRUSTSTORE_FILE); - - container = new SaslSslKafkaContainer(KAFKA_IMAGE_NAME); - container.waitForRunning(); - container.start(); + String bootstrapServers = start(name -> new SaslSslKafkaContainer(name)); String jaasConfig = "org.apache.kafka.common.security.scram.ScramLoginModule required " + "username=\"alice\" " - + "password=\"alice-secret\";"; + + "password=\"" + ALICE_PASSWORD + "\";"; return CollectionHelper.mapOf( - "camel.component.kafka.brokers", container.getBootstrapServers(), + "camel.component.kafka.brokers", bootstrapServers, "camel.component.kafka.sasl-mechanism", "SCRAM-SHA-512", "camel.component.kafka.sasl-jaas-config", jaasConfig, "camel.component.kafka.security-protocol", "SASL_SSL", "camel.component.kafka.ssl-key-password", KAFKA_KEYSTORE_PASSWORD, - "camel.component.kafka.ssl-keystore-location", configDir.resolve(KAFKA_KEYSTORE_FILE).toString(), + "camel.component.kafka.ssl-keystore-location", Path.of(CERTS_BASEDIR).resolve(KAFKA_KEYSTORE_FILE).toString(), "camel.component.kafka.ssl-keystore-password", KAFKA_KEYSTORE_PASSWORD, "camel.component.kafka.ssl-keystore-type", KAFKA_KEYSTORE_TYPE, - "camel.component.kafka.ssl-truststore-location", configDir.resolve(KAFKA_TRUSTSTORE_FILE).toString(), + "camel.component.kafka.ssl-truststore-location", + Path.of(CERTS_BASEDIR).resolve(KAFKA_TRUSTSTORE_FILE).toString(), "camel.component.kafka.ssl-truststore-password", KAFKA_KEYSTORE_PASSWORD, "camel.component.kafka.ssl-truststore-type", KAFKA_KEYSTORE_TYPE); } - @Override - public void stop() { - if (this.container != null) { - try { - this.container.stop(); - FileUtils.deleteDirectory(configDir.toFile()); - } catch (Exception e) { - // Ignored - } - } - } - // KafkaContainer does not support SASL SSL OOTB so we need some customizations static final class SaslSslKafkaContainer extends StrimziKafkaContainer { SaslSslKafkaContainer(final String dockerImageName) { @@ -143,17 +109,15 @@ public class KafkaSaslSslTestResource extends KafkaTestResource { Stream.of(KAFKA_KEYSTORE_FILE, KAFKA_TRUSTSTORE_FILE) .forEach(keyStoreFile -> { - try { - copyFileToContainer(Transferable.of(Files.readAllBytes(configDir.resolve(keyStoreFile))), - "/etc/kafka/secrets/" + keyStoreFile); - } catch (IOException e) { - throw new RuntimeException(e); - } + copyFileToContainer( + MountableFile.forHostPath(Path.of(CERTS_BASEDIR).resolve(keyStoreFile)), + "/etc/kafka/secrets/" + keyStoreFile); }); String setupUsersScript = "#!/bin/bash\n" + "KAFKA_OPTS= /opt/kafka/bin/kafka-configs.sh --zookeeper localhost:" + ZOOKEEPER_PORT - + " --alter --add-config 'SCRAM-SHA-512=[iterations=8192,password=alice-secret]' --entity-type users --entity-name alice"; + + " --alter --add-config 'SCRAM-SHA-512=[iterations=8192,password=" + ALICE_PASSWORD + + "]' --entity-type users --entity-name alice"; copyFileToContainer( Transferable.of(setupUsersScript.getBytes(StandardCharsets.UTF_8), 0775), diff --git a/integration-tests/kafka-sasl-ssl/src/test/resources/config/generate-certificates.sh b/integration-tests/kafka-sasl-ssl/src/test/resources/config/generate-certificates.sh deleted file mode 100755 index baabd055ab..0000000000 --- a/integration-tests/kafka-sasl-ssl/src/test/resources/config/generate-certificates.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -rm -f *.p12 - -export CN=${1:-localhost} -export SUBJECT_ALT_NAMES=${2:-"DNS:localhost,IP:127.0.0.1"} -export SECRET=kafkas3cret -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 3650 -ext "san=${SUBJECT_ALT_NAMES}" -dname CN=${CN} -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 -f *.crt *.jks diff --git a/integration-tests/kafka-sasl-ssl/src/test/resources/config/kafka-keystore.p12 b/integration-tests/kafka-sasl-ssl/src/test/resources/config/kafka-keystore.p12 deleted file mode 100644 index 2585d2eee3..0000000000 Binary files a/integration-tests/kafka-sasl-ssl/src/test/resources/config/kafka-keystore.p12 and /dev/null differ diff --git a/integration-tests/kafka-sasl-ssl/src/test/resources/config/kafka-truststore.p12 b/integration-tests/kafka-sasl-ssl/src/test/resources/config/kafka-truststore.p12 deleted file mode 100644 index c124e2113c..0000000000 Binary files a/integration-tests/kafka-sasl-ssl/src/test/resources/config/kafka-truststore.p12 and /dev/null differ diff --git a/integration-tests/kafka-sasl-ssl/src/test/resources/config/kafka_server_jaas.conf b/integration-tests/kafka-sasl-ssl/src/test/resources/config/kafka_server_jaas.conf index 4cd805f26a..1603da8ebc 100644 --- a/integration-tests/kafka-sasl-ssl/src/test/resources/config/kafka_server_jaas.conf +++ b/integration-tests/kafka-sasl-ssl/src/test/resources/config/kafka_server_jaas.conf @@ -1,7 +1,4 @@ KafkaServer { org.apache.kafka.common.security.scram.ScramLoginModule required - username="admin" - password="admin-secret" - user_admin="admin-secret" - user_alice="alice-secret"; + user_alice="IuepUrtaAXpwgTy6TPmInRAUinlK2acQL"; }; \ No newline at end of file diff --git a/integration-tests/kafka-sasl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslBindingTest.java b/integration-tests/kafka-sasl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslBindingTest.java index c4a246b13b..07c229427a 100644 --- a/integration-tests/kafka-sasl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslBindingTest.java +++ b/integration-tests/kafka-sasl/src/test/java/org/apache/camel/quarkus/kafka/sasl/KafkaSaslBindingTest.java @@ -22,10 +22,12 @@ import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; import io.restassured.path.json.JsonPath; +import org.apache.camel.quarkus.test.DisabledIfFipsMode; import org.junit.jupiter.api.Test; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +@DisabledIfFipsMode @QuarkusTest @QuarkusTestResource(KafkaSaslTestResource.class) public class KafkaSaslBindingTest { diff --git a/integration-tests/kafka-ssl/pom.xml b/integration-tests/kafka-ssl/pom.xml index b06b83ede8..b64451e28c 100644 --- a/integration-tests/kafka-ssl/pom.xml +++ b/integration-tests/kafka-ssl/pom.xml @@ -78,6 +78,11 @@ <artifactId>quarkus-junit4-mock</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-integration-tests-support-certificate-generator</artifactId> + <scope>test</scope> + </dependency> </dependencies> <profiles> diff --git a/integration-tests/kafka-ssl/src/test/java/org/apache/camel/quarkus/kafka/ssl/KafkaSslTest.java b/integration-tests/kafka-ssl/src/test/java/org/apache/camel/quarkus/kafka/ssl/KafkaSslTest.java index 8cc3a89696..0921d58d97 100644 --- a/integration-tests/kafka-ssl/src/test/java/org/apache/camel/quarkus/kafka/ssl/KafkaSslTest.java +++ b/integration-tests/kafka-ssl/src/test/java/org/apache/camel/quarkus/kafka/ssl/KafkaSslTest.java @@ -16,23 +16,33 @@ */ package org.apache.camel.quarkus.kafka.ssl; +import java.lang.reflect.AnnotatedElement; import java.util.UUID; import io.quarkus.test.common.QuarkusTestResource; import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; import io.restassured.path.json.JsonPath; +import me.escoffier.certs.Format; +import me.escoffier.certs.junit5.Certificate; +import org.apache.camel.quarkus.test.support.certificate.TestCertificates; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.is; +@TestCertificates(certificates = { + @Certificate(name = KafkaSslTestResource.KAFKA_HOSTNAME, formats = { + Format.PKCS12 }, password = KafkaSslTestResource.KAFKA_KEYSTORE_PASSWORD) +}, baseDir = KafkaSslTestResource.CERTS_BASEDIR) @QuarkusTest @QuarkusTestResource(KafkaSslTestResource.class) public class KafkaSslTest { @Test void testKafkaBridge() { + AnnotatedElement ae; + String body = UUID.randomUUID().toString(); RestAssured.given() diff --git a/integration-tests/kafka-ssl/src/test/java/org/apache/camel/quarkus/kafka/ssl/KafkaSslTestResource.java b/integration-tests/kafka-ssl/src/test/java/org/apache/camel/quarkus/kafka/ssl/KafkaSslTestResource.java index 01269fb7ad..2f7a767eb3 100644 --- a/integration-tests/kafka-ssl/src/test/java/org/apache/camel/quarkus/kafka/ssl/KafkaSslTestResource.java +++ b/integration-tests/kafka-ssl/src/test/java/org/apache/camel/quarkus/kafka/ssl/KafkaSslTestResource.java @@ -16,9 +16,6 @@ */ package org.apache.camel.quarkus.kafka.ssl; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import java.util.stream.Stream; @@ -26,70 +23,39 @@ import java.util.stream.Stream; import com.github.dockerjava.api.command.InspectContainerResponse; import io.strimzi.test.container.StrimziKafkaContainer; import org.apache.camel.quarkus.test.support.kafka.KafkaTestResource; -import org.apache.camel.quarkus.test.support.kafka.KafkaTestSupport; import org.apache.camel.util.CollectionHelper; -import org.apache.commons.io.FileUtils; import org.apache.kafka.clients.CommonClientConfigs; -import org.testcontainers.images.builder.Transferable; +import org.testcontainers.utility.MountableFile; public class KafkaSslTestResource extends KafkaTestResource { - private static final String KAFKA_KEYSTORE_FILE = "kafka-keystore.p12"; - private static final String KAFKA_KEYSTORE_PASSWORD = "kafkas3cret"; - private static final String KAFKA_KEYSTORE_TYPE = "PKCS12"; - private static final String KAFKA_TRUSTSTORE_FILE = "kafka-truststore.p12"; - private static final String KAFKA_CERTIFICATE_SCRIPT = "generate-certificates.sh"; - private static Path configDir; - private SSLKafkaContainer container; + + static final String KAFKA_KEYSTORE_PASSWORD = "PAG4i8511xp1lzVu585foRLjD4v62yBS"; + static final String KAFKA_HOSTNAME = "localhost"; + static final String CERTS_BASEDIR = "target/certs"; + + static final String KAFKA_KEYSTORE_FILE = KAFKA_HOSTNAME + "-keystore.p12"; + static final String KAFKA_KEYSTORE_TYPE = "PKCS12"; + static final String KAFKA_TRUSTSTORE_FILE = KAFKA_HOSTNAME + "-truststore.p12"; @Override public Map<String, String> start() { - try { - configDir = Files.createTempDirectory("KafkaSaslSslTestResource-"); - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - Stream.of(KAFKA_KEYSTORE_FILE, KAFKA_TRUSTSTORE_FILE) - .forEach(fileName -> { - try (InputStream in = classLoader.getResourceAsStream("config/" + fileName)) { - Files.copy(in, configDir.resolve(fileName)); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } catch (IOException e) { - throw new RuntimeException(e); - } - KafkaTestSupport.regenerateCertificatesForDockerHost(configDir, KAFKA_CERTIFICATE_SCRIPT, KAFKA_KEYSTORE_FILE, - KAFKA_TRUSTSTORE_FILE); - - container = new SSLKafkaContainer(KAFKA_IMAGE_NAME); - container.waitForRunning(); - container.start(); + String bootstrapServers = start(name -> new SSLKafkaContainer(name)); return CollectionHelper.mapOf( - "kafka." + CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, container.getBootstrapServers(), - "camel.component.kafka.brokers", container.getBootstrapServers(), + "kafka." + CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers, + "camel.component.kafka.brokers", bootstrapServers, "camel.component.kafka.security-protocol", "SSL", "camel.component.kafka.ssl-key-password", KAFKA_KEYSTORE_PASSWORD, - "camel.component.kafka.ssl-keystore-location", configDir.resolve(KAFKA_KEYSTORE_FILE).toString(), + "camel.component.kafka.ssl-keystore-location", Path.of(CERTS_BASEDIR).resolve(KAFKA_KEYSTORE_FILE).toString(), "camel.component.kafka.ssl-keystore-password", KAFKA_KEYSTORE_PASSWORD, "camel.component.kafka.ssl-keystore-type", KAFKA_KEYSTORE_TYPE, - "camel.component.kafka.ssl-truststore-location", configDir.resolve(KAFKA_TRUSTSTORE_FILE).toString(), + "camel.component.kafka.ssl-truststore-location", + Path.of(CERTS_BASEDIR).resolve(KAFKA_TRUSTSTORE_FILE).toString(), "camel.component.kafka.ssl-truststore-password", KAFKA_KEYSTORE_PASSWORD, "camel.component.kafka.ssl-truststore-type", KAFKA_KEYSTORE_TYPE); } - @Override - public void stop() { - if (this.container != null) { - try { - this.container.stop(); - FileUtils.deleteDirectory(configDir.toFile()); - } catch (Exception e) { - // Ignored - } - } - } - // KafkaContainer does not support SSL OOTB so we need some customizations static final class SSLKafkaContainer extends StrimziKafkaContainer { SSLKafkaContainer(final String dockerImageName) { @@ -117,6 +83,7 @@ public class KafkaSslTestResource extends KafkaTestResource { Map.entry("ssl.truststore.type", KAFKA_KEYSTORE_TYPE), Map.entry("ssl.endpoint.identification.algorithm", "")); + withEnv("STRIMZI_TEST_ROOT_LOG_LEVEL", "DEBUG"); withBrokerId(1); withKafkaConfigurationMap(config); withLogConsumer(frame -> System.out.print(frame.getUtf8String())); @@ -128,12 +95,9 @@ public class KafkaSslTestResource extends KafkaTestResource { Stream.of(KAFKA_KEYSTORE_FILE, KAFKA_TRUSTSTORE_FILE) .forEach(keyStoreFile -> { - try { - copyFileToContainer(Transferable.of(Files.readAllBytes(configDir.resolve(keyStoreFile))), - "/etc/kafka/secrets/" + keyStoreFile); - } catch (IOException e) { - throw new RuntimeException(e); - } + copyFileToContainer( + MountableFile.forHostPath(Path.of(CERTS_BASEDIR).resolve(keyStoreFile)), + "/etc/kafka/secrets/" + keyStoreFile); }); } } diff --git a/integration-tests/kafka-ssl/src/test/resources/config/generate-certificates.sh b/integration-tests/kafka-ssl/src/test/resources/config/generate-certificates.sh deleted file mode 100755 index baabd055ab..0000000000 --- a/integration-tests/kafka-ssl/src/test/resources/config/generate-certificates.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -rm -f *.p12 - -export CN=${1:-localhost} -export SUBJECT_ALT_NAMES=${2:-"DNS:localhost,IP:127.0.0.1"} -export SECRET=kafkas3cret -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 3650 -ext "san=${SUBJECT_ALT_NAMES}" -dname CN=${CN} -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 -f *.crt *.jks diff --git a/integration-tests/kafka-ssl/src/test/resources/config/kafka-keystore.p12 b/integration-tests/kafka-ssl/src/test/resources/config/kafka-keystore.p12 deleted file mode 100644 index 2585d2eee3..0000000000 Binary files a/integration-tests/kafka-ssl/src/test/resources/config/kafka-keystore.p12 and /dev/null differ diff --git a/integration-tests/kafka-ssl/src/test/resources/config/kafka-truststore.p12 b/integration-tests/kafka-ssl/src/test/resources/config/kafka-truststore.p12 deleted file mode 100644 index c124e2113c..0000000000 Binary files a/integration-tests/kafka-ssl/src/test/resources/config/kafka-truststore.p12 and /dev/null differ diff --git a/pom.xml b/pom.xml index 8bb4cc0adc..4021aa4687 100644 --- a/pom.xml +++ b/pom.xml @@ -169,6 +169,7 @@ <zookeeper.version>${zookeeper-version}</zookeeper.version> <!-- Test dependency versions (keep sorted alphabetically) --> + <certificate.generator.version>0.5.0</certificate.generator.version> <consul-client.version>${consul-client-version}</consul-client.version> <ftpserver.version>${ftpserver-version}</ftpserver.version> <hamcrest.version>2.2</hamcrest.version><!-- Awaitility and Wiremock --> diff --git a/poms/bom-test/pom.xml b/poms/bom-test/pom.xml index 1bdcfc59a1..908cbe12a0 100644 --- a/poms/bom-test/pom.xml +++ b/poms/bom-test/pom.xml @@ -81,6 +81,11 @@ <artifactId>quarkus-micrometer-registry-jmx</artifactId> <version>${quarkiverse-micrometer.version}</version> </dependency> + <dependency> + <groupId>me.escoffier.certs</groupId> + <artifactId>certificate-generator-junit5</artifactId> + <version>${certificate.generator.version}</version> + </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-integration-test-support-custom-dataformat</artifactId> @@ -149,6 +154,11 @@ <version>${camel-quarkus.version}</version> <type>test-jar</type> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-integration-tests-support-certificate-generator</artifactId> + <version>${camel-quarkus.version}</version> + </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-integration-tests-support-kafka</artifactId>