From cbbb3017e3479b6a8107eddd37e9813b66b7aabf Mon Sep 17 00:00:00 2001 From: Jiri Ondrusek Date: Mon, 20 Jul 2026 12:15:18 +0200 Subject: [PATCH] Fixes #8886. Add integration test coverage for CyberArk Vault alternative authentication methods Co-Authored-By: Claude Opus 4.6 --- integration-tests/cyberark-vault/README.adoc | 3 ++ .../vault/it/ConjurClientProducer.java | 49 +++++++++++++++++ .../cyberark/vault/it/CyberArkRoutes.java | 43 ++++++++++----- .../vault/it/CyberarkVaultResource.java | 21 ++++++++ .../src/main/resources/application.properties | 10 ++-- .../cyberark/vault/it/CyberarkVaultTest.java | 53 ++++++++++++++++++- .../vault/it/CyberarkVaultTestResource.java | 40 +++++++++++--- 7 files changed, 193 insertions(+), 26 deletions(-) create mode 100644 integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/ConjurClientProducer.java diff --git a/integration-tests/cyberark-vault/README.adoc b/integration-tests/cyberark-vault/README.adoc index 64d0c8eb5564..c6902b977593 100644 --- a/integration-tests/cyberark-vault/README.adoc +++ b/integration-tests/cyberark-vault/README.adoc @@ -22,6 +22,9 @@ export CQ_CONJUR_READ_USER=host/BotApp/myDemoApp export CQ_CONJUR_READ_USER_API_KEY=... export CQ_CONJUR_READ_WRITE_USER=user/Dave@BotApp export CQ_CONJUR_READ_WRITE_USER_API_KEY=... +# Optional: for alternative authentication method tests +export CQ_CONJUR_READ_USER_AUTH_TOKEN=... +export CQ_CONJUR_READ_WRITE_USER_PASSWORD=... # to avoid port conflict with quarkus (against opensource conjur) export QUARKUS_HTTP_PORT=0 export QUARKUS_HTTPS_PORT=0 diff --git a/integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/ConjurClientProducer.java b/integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/ConjurClientProducer.java new file mode 100644 index 000000000000..e38ce6965c9f --- /dev/null +++ b/integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/ConjurClientProducer.java @@ -0,0 +1,49 @@ +/* + * 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.cyberark.vault.it; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Disposes; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Named; +import org.apache.camel.component.cyberark.vault.client.ConjurClient; +import org.apache.camel.component.cyberark.vault.client.ConjurClientFactory; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +@ApplicationScoped +public class ConjurClientProducer { + + @ConfigProperty(name = "conjur.url") + String url; + @ConfigProperty(name = "conjur.account") + String account; + @ConfigProperty(name = "conjur.reader.username") + String readerUsername; + @ConfigProperty(name = "conjur.reader.apiKey") + String readerApiKey; + + @Produces + @ApplicationScoped + @Named("myConjurClient") + ConjurClient createConjurClient() { + return ConjurClientFactory.createWithApiKey(url, account, readerUsername, readerApiKey); + } + + void disposeConjurClient(@Disposes @Named("myConjurClient") ConjurClient client) throws Exception { + client.close(); + } +} diff --git a/integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberArkRoutes.java b/integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberArkRoutes.java index e6360adb1fbd..b706c73db0cf 100644 --- a/integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberArkRoutes.java +++ b/integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberArkRoutes.java @@ -16,6 +16,8 @@ */ package org.apache.camel.quarkus.component.cyberark.vault.it; +import java.util.Optional; + import jakarta.enterprise.context.ApplicationScoped; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.spi.PropertiesComponent; @@ -28,40 +30,44 @@ public class CyberArkRoutes extends RouteBuilder { String url; @ConfigProperty(name = "conjur.account") String account; - @ConfigProperty(name = "conjur.write.username") - String writeUsername; - @ConfigProperty(name = "conjur.write.apiKey") - String writeApiKey; - @ConfigProperty(name = "conjur.read.username") - String readUsername; - @ConfigProperty(name = "conjur.read.apiKey") - String readApiKey; + @ConfigProperty(name = "conjur.reader.username") + String readerUsername; + @ConfigProperty(name = "conjur.reader.apiKey") + String readerApiKey; + @ConfigProperty(name = "conjur.reader.authToken") + Optional readerAuthToken; + @ConfigProperty(name = "conjur.writer.password") + Optional writerPassword; + @ConfigProperty(name = "conjur.writer.username") + String writerUsername; + @ConfigProperty(name = "conjur.writer.apiKey") + String writerApiKey; @Override public void configure() throws Exception { from("direct:createSecret") .toF("cyberark-vault:secret?operation=createSecret&url=%s&account=%s&username=%s&apiKey=%s", - url, account, writeUsername, writeApiKey) + url, account, writerUsername, writerApiKey) .log("Secret created/updated"); from("direct:createSecretUnauthorized") .toF("cyberark-vault:secret?operation=createSecret&url=%s&account=%s&username=%s&apiKey=%s", - url, account, readUsername, readApiKey) + url, account, readerUsername, readerApiKey) .log("Secret created/updated"); from("direct:getSecret") .toF("cyberark-vault:secret?secretId=BotApp/secretVar&url=%s&account=%s&username=%s&apiKey=%s", - url, account, readUsername, readApiKey) + url, account, readerUsername, readerApiKey) .log("Retrieved secret: ${body}"); from("direct:getSecretByHeader") .toF("cyberark-vault:secret?url=%s&account=%s&username=%s&apiKey=%s", - url, account, readUsername, readApiKey); + url, account, readerUsername, readerApiKey); from("direct:getSecretVersion") .toF("cyberark-vault:secret?secretId=BotApp/versionVar&url=%s&account=%s&username=%s&apiKey=%s", - url, account, readUsername, readApiKey); + url, account, readerUsername, readerApiKey); // Programmatic equivalent of {{cyberark:BotApp/secretVar}} placeholder — resolved at runtime since the secret doesn't exist at route build time from("direct:propertyPlaceholder") @@ -72,5 +78,16 @@ public void configure() throws Exception { }); }); + writerPassword.ifPresent(password -> from("direct:getSecretByPassword") + .toF("cyberark-vault:secret?secretId=BotApp/secretVar&url=%s&account=%s&username=%s&password=%s", + url, account, writerUsername, password)); + + readerAuthToken.ifPresent(token -> from("direct:getSecretByToken") + .toF("cyberark-vault:secret?secretId=BotApp/secretVar&url=%s&account=%s&authToken=RAW(%s)", + url, account, token)); + + from("direct:getSecretByClient") + .to("cyberark-vault:secret?secretId=BotApp/secretVar&conjurClient=#myConjurClient"); + } } diff --git a/integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultResource.java b/integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultResource.java index 34b30aaf1854..4c7b97e85c7f 100644 --- a/integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultResource.java +++ b/integration-tests/cyberark-vault/src/main/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultResource.java @@ -87,4 +87,25 @@ public String getSecretVersion(@PathParam("version") int version) { public String propertyPlaceholder() { return producerTemplate.requestBody("direct:propertyPlaceholder", "", String.class); } + + @Path("/getSecretByPassword") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getSecretByPassword() { + return producerTemplate.requestBody("direct:getSecretByPassword", "", String.class); + } + + @Path("/getSecretByToken") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getSecretByToken() { + return producerTemplate.requestBody("direct:getSecretByToken", "", String.class); + } + + @Path("/getSecretByClient") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getSecretByClient() { + return producerTemplate.requestBody("direct:getSecretByClient", "", String.class); + } } diff --git a/integration-tests/cyberark-vault/src/main/resources/application.properties b/integration-tests/cyberark-vault/src/main/resources/application.properties index a40c06cb82e5..fed757ade96e 100644 --- a/integration-tests/cyberark-vault/src/main/resources/application.properties +++ b/integration-tests/cyberark-vault/src/main/resources/application.properties @@ -17,7 +17,9 @@ conjur.url={{env:CQ_CONJUR_URL}} conjur.account={{env:CQ_CONJUR_ACCOUNT}} -conjur.write.username={{env:CQ_CONJUR_READ_WRITE_USER}} -conjur.write.apiKey={{env:CQ_CONJUR_READ_WRITE_USER_API_KEY}} -conjur.read.username={{env:CQ_CONJUR_READ_USER}} -conjur.read.apiKey={{env:CQ_CONJUR_READ_USER_API_KEY}} \ No newline at end of file +conjur.reader.username={{env:CQ_CONJUR_READ_USER}} +conjur.reader.apiKey={{env:CQ_CONJUR_READ_USER_API_KEY}} +conjur.reader.authToken={{env:CQ_CONJUR_READ_USER_AUTH_TOKEN:}} +conjur.writer.username={{env:CQ_CONJUR_READ_WRITE_USER}} +conjur.writer.apiKey={{env:CQ_CONJUR_READ_WRITE_USER_API_KEY}} +conjur.writer.password={{env:CQ_CONJUR_READ_WRITE_USER_PASSWORD:}} diff --git a/integration-tests/cyberark-vault/src/test/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultTest.java b/integration-tests/cyberark-vault/src/test/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultTest.java index 96a06907cc06..d5a1f51a5430 100644 --- a/integration-tests/cyberark-vault/src/test/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultTest.java +++ b/integration-tests/cyberark-vault/src/test/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultTest.java @@ -36,7 +36,7 @@ @QuarkusTestResource(CyberarkVaultTestResource.class) class CyberarkVaultTest { @Test - void testRetrieveSecret() { + void testUnauthorizedFailure() { String secret = UUID.randomUUID().toString(); //create secret RestAssured.given() @@ -124,4 +124,55 @@ void testGetSecretVersion() { .statusCode(200) .body(is(secretV2)); } + + @Test + void testGetSecretByPassword() { + String secret = UUID.randomUUID().toString(); + + RestAssured.given() + .body(secret) + .post("/cyberark-vault/createSecret/true/BotApp/secretVar") + .then() + .statusCode(200); + + RestAssured + .get("/cyberark-vault/getSecretByPassword") + .then() + .statusCode(200) + .body(is(secret)); + } + + @Test + void testGetSecretByToken() { + String secret = UUID.randomUUID().toString(); + + RestAssured.given() + .body(secret) + .post("/cyberark-vault/createSecret/true/BotApp/secretVar") + .then() + .statusCode(200); + + RestAssured + .get("/cyberark-vault/getSecretByToken") + .then() + .statusCode(200) + .body(is(secret)); + } + + @Test + void testGetSecretByClient() { + String secret = UUID.randomUUID().toString(); + + RestAssured.given() + .body(secret) + .post("/cyberark-vault/createSecret/true/BotApp/secretVar") + .then() + .statusCode(200); + + RestAssured + .get("/cyberark-vault/getSecretByClient") + .then() + .statusCode(200) + .body(is(secret)); + } } diff --git a/integration-tests/cyberark-vault/src/test/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultTestResource.java b/integration-tests/cyberark-vault/src/test/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultTestResource.java index d17263c48347..cd67ffd1903a 100644 --- a/integration-tests/cyberark-vault/src/test/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultTestResource.java +++ b/integration-tests/cyberark-vault/src/test/java/org/apache/camel/quarkus/component/cyberark/vault/it/CyberarkVaultTestResource.java @@ -17,6 +17,12 @@ package org.apache.camel.quarkus.component.cyberark.vault.it; +import java.net.URI; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -129,8 +135,8 @@ public Map start() { result.put("camel.vault.cyberark.url", conjurUrl); result.put("camel.vault.cyberark.account", CONJUR_ACCOUNT); - result.put("camel.vault.cyberark.username", result.get("conjur.read.username")); - result.put("camel.vault.cyberark.apiKey", result.get("conjur.read.apiKey")); + result.put("camel.vault.cyberark.username", result.get("conjur.reader.username")); + result.put("camel.vault.cyberark.apiKey", result.get("conjur.reader.apiKey")); return result; } @@ -274,12 +280,30 @@ private void initializeConjur(Map result) throws Exception { ObjectMapper objectMapper = new ObjectMapper(); JsonNode jsonNode = objectMapper.readTree(er.getStdout()); - result.put("conjur.read.username", "host/BotApp/myDemoApp"); - result.put("conjur.read.apiKey", - jsonNode.get("created_roles").get(CONJUR_ACCOUNT + ":host:BotApp/myDemoApp").get("api_key").textValue()); - result.put("conjur.write.username", "user/Dave@BotApp"); - result.put("conjur.write.apiKey", - jsonNode.get("created_roles").get(CONJUR_ACCOUNT + ":user:Dave@BotApp").get("api_key").textValue()); + result.put("conjur.reader.username", "host/BotApp/myDemoApp"); + String readApiKey = jsonNode.get("created_roles").get(CONJUR_ACCOUNT + ":host:BotApp/myDemoApp").get("api_key") + .textValue(); + result.put("conjur.reader.apiKey", readApiKey); + result.put("conjur.writer.username", "user/Dave@BotApp"); + String writeApiKey = jsonNode.get("created_roles").get(CONJUR_ACCOUNT + ":user:Dave@BotApp").get("api_key") + .textValue(); + result.put("conjur.writer.apiKey", writeApiKey); + result.put("conjur.writer.password", writeApiKey); + + // Obtain a pre-authenticated token for token-based auth testing + String conjurUrl = "http://localhost:" + conjurContainer.getMappedPort(80); + String encodedLogin = URLEncoder.encode(result.get("conjur.reader.username"), StandardCharsets.UTF_8); + String authUrl = String.format("%s/authn/%s/%s/authenticate", conjurUrl, CONJUR_ACCOUNT, encodedLogin); + HttpClient httpClient = HttpClient.newHttpClient(); + HttpRequest authRequest = HttpRequest.newBuilder() + .uri(URI.create(authUrl)) + .header("Content-Type", "text/plain") + .POST(HttpRequest.BodyPublishers.ofString(readApiKey)) + .build(); + HttpResponse authResponse = httpClient.send(authRequest, HttpResponse.BodyHandlers.ofString()); + Assertions.assertEquals(200, authResponse.statusCode(), "Authentication failed: " + authResponse.body()); + result.put("conjur.reader.authToken", authResponse.body()); + LOGGER.info("Pre-authenticated token obtained for token-based auth test"); // Logout clientContainer.execInContainer("conjur", "logout");