Skip to content

Commit

Permalink
Fix hashicorp-vault extension
Browse files Browse the repository at this point in the history
Fixes #6254

* Depend on camel-quarkus-support-spring
* Unban spring-web
* Add integration tests
  • Loading branch information
jamesnetherton committed Aug 27, 2024
1 parent d24a036 commit 464000d
Show file tree
Hide file tree
Showing 13 changed files with 357 additions and 35 deletions.
4 changes: 4 additions & 0 deletions extensions-jvm/hashicorp-vault/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-core-deployment</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-support-spring-deployment</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-hashicorp-vault</artifactId>
Expand Down
4 changes: 4 additions & 0 deletions extensions-jvm/hashicorp-vault/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-support-spring</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-hashicorp-vault</artifactId>
Expand Down
44 changes: 44 additions & 0 deletions integration-tests-jvm/hashicorp-vault/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
<description>Integration tests for Camel Quarkus Hashicorp Vault extension</description>

<dependencies>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-direct</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-hashicorp-vault</artifactId>
Expand All @@ -51,6 +55,22 @@
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit4-mock</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<profiles>
Expand All @@ -63,6 +83,19 @@
</activation>
<dependencies>
<!-- The following dependencies guarantee that this module is built after them. You can update them by running `mvn process-resources -Pformat -N` from the source tree root directory -->
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-direct-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-hashicorp-vault-deployment</artifactId>
Expand All @@ -78,5 +111,16 @@
</dependency>
</dependencies>
</profile>
<profile>
<id>skip-testcontainers-tests</id>
<activation>
<property>
<name>skip-testcontainers-tests</name>
</property>
</activation>
<properties>
<skipTests>true</skipTests>
</properties>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,75 @@
*/
package org.apache.camel.quarkus.component.hashicorp.vault.it;

import java.net.URI;
import java.util.List;
import java.util.Map;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.apache.camel.CamelContext;
import org.jboss.logging.Logger;
import org.apache.camel.ProducerTemplate;

@Path("/hashicorp-vault")
@ApplicationScoped
public class HashicorpVaultResource {
@Inject
ProducerTemplate producerTemplate;

private static final Logger LOG = Logger.getLogger(HashicorpVaultResource.class);
@Path("/secret")
@POST
public Response createSecret(@QueryParam("key") String key, @QueryParam("value") String value) throws Exception {
producerTemplate.sendBody("direct:createSecret", Map.of(key, value));
return Response.created(new URI("https://camel.apache.org/")).build();
}

private static final String COMPONENT_HASHICORP_VAULT = "hashicorp-vault";
@Inject
CamelContext context;
@SuppressWarnings("unchecked")
@Path("/secret")
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response getSecret(@QueryParam("key") String key) {
try {
Map<String, Map<String, String>> map = producerTemplate.requestBody("direct:getSecret", null, Map.class);
if (map.containsKey("data")) {
Map<String, String> data = map.get("data");
if (data.containsKey(key)) {
return Response.ok(data.get(key)).build();
}
}
return Response.status(404).build();
} catch (Exception e) {
return Response.status(404).build();
}
}

@Path("/load/component/hashicorp-vault")
@Path("/secret/placeholder")
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response loadComponentHashicorpVault() throws Exception {
/* This is an autogenerated test */
if (context.getComponent(COMPONENT_HASHICORP_VAULT) != null) {
return Response.ok().build();
public String getSecretFromPropertyPlaceholder() {
return producerTemplate.requestBody("direct:propertyPlaceholder", null, String.class);
}

@Path("/secret")
@DELETE
public void deleteSecret() {
producerTemplate.sendBody("direct:deleteSecret", null);
}

@SuppressWarnings("unchecked")
@Path("/secret/list/all")
@GET
public String listSecrets() {
List<String> secrets = producerTemplate.requestBody("direct:listSecrets", null, List.class);
if (secrets.size() == 1) {
return secrets.get(0);
}
LOG.warnf("Could not load [%s] from the Camel context", COMPONENT_HASHICORP_VAULT);
return Response.status(500, COMPONENT_HASHICORP_VAULT + " could not be loaded from the Camel context").build();
throw new IllegalStateException("Expected a list containing 1 secret, but found " + secrets.size());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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.component.hashicorp.vault.it;

import jakarta.enterprise.context.ApplicationScoped;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.hashicorp.vault.HashicorpVaultConstants;
import org.apache.camel.spi.PropertiesComponent;
import org.eclipse.microprofile.config.inject.ConfigProperty;

@ApplicationScoped
public class HashicorpVaultRoutes extends RouteBuilder {
public static final String TEST_SECRET_NAME = "my-secret";
public static final String TEST_SECRET_PATH = "camel-quarkus-secret";

@ConfigProperty(name = "camel.vault.hashicorp.host")
String host;

@ConfigProperty(name = "camel.vault.hashicorp.port")
int port;

@ConfigProperty(name = "camel.vault.hashicorp.token")
String token;

@Override
public void configure() throws Exception {
from("direct:createSecret")
.toF("hashicorp-vault:secret?operation=createSecret&scheme=http&host=%s&port=%d&token=%s&secretPath=%s", host,
port, token, TEST_SECRET_PATH);

from("direct:getSecret")
.setHeader(HashicorpVaultConstants.SECRET_PATH).constant(TEST_SECRET_PATH)
.toF("hashicorp-vault:secret?operation=getSecret&scheme=http&host=%s&port=%d&token=%s", host, port, token);

from("direct:deleteSecret")
.toF("hashicorp-vault:secret?operation=deleteSecret&scheme=http&host=%s&port=%d&token=%s&secretPath=%s", host,
port, token, TEST_SECRET_PATH);

from("direct:listSecrets")
.toF("hashicorp-vault:secret?operation=listSecrets&scheme=http&host=%s&port=%d&token=%s&secretPath=%s", host,
port, token, TEST_SECRET_PATH);

from("direct:propertyPlaceholder")
.process(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
Message message = exchange.getMessage();
PropertiesComponent component = exchange.getContext().getPropertiesComponent();
component.resolveProperty("hashicorp:secret:" + TEST_SECRET_PATH).ifPresent(value -> {
message.setBody(value.replaceAll("[{}]", "").split("=")[1]);
});
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,57 @@
*/
package org.apache.camel.quarkus.component.hashicorp.vault.it;

import io.quarkus.test.common.WithTestResource;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;

import static org.apache.camel.quarkus.component.hashicorp.vault.it.HashicorpVaultRoutes.TEST_SECRET_NAME;
import static org.apache.camel.quarkus.component.hashicorp.vault.it.HashicorpVaultRoutes.TEST_SECRET_PATH;
import static org.hamcrest.Matchers.is;

@QuarkusTest
@WithTestResource(HashicorpVaultTestResource.class)
class HashicorpVaultTest {

@Test
public void loadComponentHashicorpVault() {
/* A simple autogenerated test */
RestAssured.get("/hashicorp-vault/load/component/hashicorp-vault")
void secretCRUD() {
String secretValue = "2s3cr3t";

RestAssured.given()
.queryParam("key", TEST_SECRET_NAME)
.queryParam("value", secretValue)
.post("/hashicorp-vault/secret")
.then()
.statusCode(200);
}
.statusCode(201);

RestAssured.given()
.queryParam("key", TEST_SECRET_NAME)
.get("/hashicorp-vault/secret")
.then()
.statusCode(200)
.body(is(secretValue));

RestAssured.given()
.get("/hashicorp-vault/secret/placeholder")
.then()
.statusCode(200)
.body(is(secretValue));

RestAssured.given()
.get("/hashicorp-vault/secret/list/all")
.then()
.statusCode(200)
.body(is(TEST_SECRET_PATH));

RestAssured.given()
.delete("/hashicorp-vault/secret")
.then()
.statusCode(204);

RestAssured.given()
.queryParam("key", TEST_SECRET_NAME)
.get("/hashicorp-vault/secret")
.then()
.statusCode(404);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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.component.hashicorp.vault.it;

import java.util.Map;
import java.util.UUID;

import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import org.eclipse.microprofile.config.ConfigProvider;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.DockerImageName;

public class HashicorpVaultTestResource implements QuarkusTestResourceLifecycleManager {
private static final String DOCKER_IMAGE_NAME = ConfigProvider.getConfig().getValue("hashicorp-vault.container.image",
String.class);
private static final String VAULT_TOKEN = UUID.randomUUID().toString();
private static final int VAULT_PORT = 8200;
private GenericContainer<?> container;

@Override
public Map<String, String> start() {
container = new GenericContainer<>(DockerImageName.parse(DOCKER_IMAGE_NAME));
container.withEnv("VAULT_DEV_ROOT_TOKEN_ID", VAULT_TOKEN);
container.addExposedPort(VAULT_PORT);
container.waitingFor(Wait.forListeningPort());
container.waitingFor(Wait.forLogMessage(".*Development.*mode.*should.*", 1));

container.start();

return Map.of(
"camel.vault.hashicorp.token", VAULT_TOKEN,
"camel.vault.hashicorp.host", container.getHost(),
"camel.vault.hashicorp.port", String.valueOf(container.getMappedPort(VAULT_PORT)),
"camel.vault.hashicorp.scheme", "http");
}

@Override
public void stop() {
if (container != null) {
container.stop();
}
}
}
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@
<google-cloud-sdk.container.image>gcr.io/google.com/cloudsdktool/cloud-sdk:441.0.0-emulators</google-cloud-sdk.container.image>
<google-storage.container.image>docker.io/fsouza/fake-gcs-server:1.47.3</google-storage.container.image>
<greenmail.container.image>docker.io/greenmail/standalone:2.0.0</greenmail.container.image>
<hashicorp-vault.container.image>docker.io/hashicorp/vault:1.17</hashicorp-vault.container.image>
<ibm-mq.container.image>icr.io/ibm-messaging/mq:9.3.2.1-r1</ibm-mq.container.image>
<influxdb.container.image>docker.io/influxdb:1.8.10</influxdb.container.image>
<kafka.container.image>quay.io/strimzi-test-container/test-container:latest-kafka-3.2.1</kafka.container.image>
Expand Down
Loading

0 comments on commit 464000d

Please sign in to comment.