This is an automated email from the ASF dual-hosted git repository.

oscerd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new caf68b54f26e CAMEL-24717: camel-opa - do not publish the bearerToken 
in the health-check id (#26415)
caf68b54f26e is described below

commit caf68b54f26e2a732664db75099fe7ac52564dd6
Author: Andrea Cosentino <[email protected]>
AuthorDate: Mon Sep 14 17:23:13 2026 +0200

    CAMEL-24717: camel-opa - do not publish the bearerToken in the health-check 
id (#26415)
    
    The camel-opa producer health check embedded the configured bearerToken in 
its health-check id,
    exposing the credential in health-check output. The id no longer includes 
the token.
    
    Co-authored-by: Claude Opus 4.8 <[email protected]>
---
 .../component/opa/OpaProducerHealthCheck.java      |  7 +-
 .../opa/OpaHealthCheckRegistrationTest.java        | 77 ++++++++++++++++++++++
 .../component/opa/OpaProducerHealthCheckTest.java  | 25 +++++++
 3 files changed, 107 insertions(+), 2 deletions(-)

diff --git 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducerHealthCheck.java
 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducerHealthCheck.java
index c2479d9e4ab9..31d754769dfd 100644
--- 
a/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducerHealthCheck.java
+++ 
b/components/camel-opa/src/main/java/org/apache/camel/component/opa/OpaProducerHealthCheck.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import org.apache.camel.health.HealthCheckResultBuilder;
 import org.apache.camel.impl.health.AbstractHealthCheck;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.URISupport;
 
 /**
  * Readiness check for the OPA server a producer sends its decisions to.
@@ -49,7 +50,9 @@ public class OpaProducerHealthCheck extends 
AbstractHealthCheck {
     private final String policyPath;
 
     public OpaProducerHealthCheck(String serverUrl, String bearerToken, String 
policyPath, String id) {
-        super("camel", "producer:opa-" + id);
+        // the id is built from the endpoint URI so that two endpoints sharing 
a policy path stay distinct, but that
+        // URI carries the bearerToken in the clear and the id is published in 
the health output, so sanitize it
+        super("camel", "producer:opa-" + URISupport.sanitizeUri(id));
         this.serverUrl = serverUrl;
         this.bearerToken = bearerToken;
         this.policyPath = policyPath;
@@ -57,7 +60,7 @@ public class OpaProducerHealthCheck extends 
AbstractHealthCheck {
 
     @Override
     protected void doCall(HealthCheckResultBuilder builder, Map<String, 
Object> options) {
-        builder.detail("opa.serverUrl", serverUrl);
+        builder.detail("opa.serverUrl", URISupport.sanitizeUri(serverUrl));
         builder.detail("opa.policyPath", policyPath);
 
         HttpRequest.Builder request = HttpRequest.newBuilder()
diff --git 
a/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaHealthCheckRegistrationTest.java
 
b/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaHealthCheckRegistrationTest.java
new file mode 100644
index 000000000000..e62274016043
--- /dev/null
+++ 
b/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaHealthCheckRegistrationTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.component.opa;
+
+import java.util.List;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.health.HealthCheck;
+import org.apache.camel.health.HealthCheckHelper;
+import org.apache.camel.health.WritableHealthCheckRepository;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Checks what the producer actually registers in the health registry.
+ * <p/>
+ * {@link OpaProducerHealthCheckTest} covers the check in isolation; this one 
goes through the route so that the id the
+ * producer hands it is covered too, which is where the token used to leak 
from.
+ */
+public class OpaHealthCheckRegistrationTest extends CamelTestSupport {
+
+    private static final String TOKEN = "s3cr3t-token";
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:primary")
+                        
.to("opa:authz/allow?serverUrl=http://opa-primary:8181&bearerToken="; + TOKEN);
+                from("direct:secondary")
+                        
.to("opa:authz/allow?serverUrl=http://opa-secondary:8181";);
+            }
+        };
+    }
+
+    private List<HealthCheck> registeredChecks() {
+        WritableHealthCheckRepository repository = 
HealthCheckHelper.getHealthCheckRepository(
+                context, "producers", WritableHealthCheckRepository.class);
+        assertThat(repository).isNotNull();
+        // producer health checks are disabled globally by default, so enable 
the repository to read them back
+        repository.setEnabled(true);
+        return repository.stream().toList();
+    }
+
+    @Test
+    void neverPublishesTheBearerTokenInAnyRegisteredId() {
+        assertThat(registeredChecks())
+                .isNotEmpty()
+                .allSatisfy(check -> 
assertThat(check.getId()).doesNotContain(TOKEN));
+    }
+
+    @Test
+    void keepsEndpointsOnDifferentServersDistinct() {
+        List<String> ids = 
registeredChecks().stream().map(HealthCheck::getId).toList();
+
+        assertThat(ids).hasSize(2).doesNotHaveDuplicates();
+        assertThat(ids).anySatisfy(id -> 
assertThat(id).contains("opa-primary"));
+        assertThat(ids).anySatisfy(id -> 
assertThat(id).contains("opa-secondary"));
+    }
+}
diff --git 
a/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaProducerHealthCheckTest.java
 
b/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaProducerHealthCheckTest.java
index 0797c491c393..649c373ac548 100644
--- 
a/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaProducerHealthCheckTest.java
+++ 
b/components/camel-opa/src/test/java/org/apache/camel/component/opa/OpaProducerHealthCheckTest.java
@@ -57,6 +57,31 @@ class OpaProducerHealthCheckTest {
         return check.call(Map.of());
     }
 
+    @Test
+    void neverPublishesTheBearerTokenInTheHealthCheckId() {
+        // the id is derived from the endpoint URI, which carries the token in 
the clear; the id reaches the
+        // health output, so the token must not survive into it
+        OpaProducerHealthCheck check = new OpaProducerHealthCheck(
+                "http://localhost:8181";, "s3cr3t-token", "authz/allow",
+                
"opa://authz/allow?bearerToken=s3cr3t-token&serverUrl=http://localhost:8181";);
+
+        assertThat(check.getId()).doesNotContain("s3cr3t-token");
+        assertThat(check.getId()).contains("serverUrl=http://localhost:8181";);
+    }
+
+    @Test
+    void givesEndpointsOnDifferentServersDistinctIds() {
+        OpaProducerHealthCheck primary = new OpaProducerHealthCheck(
+                "http://opa-primary:8181";, null, "authz/allow",
+                "opa://authz/allow?serverUrl=http://opa-primary:8181";);
+        OpaProducerHealthCheck secondary = new OpaProducerHealthCheck(
+                "http://opa-secondary:8181";, null, "authz/allow",
+                "opa://authz/allow?serverUrl=http://opa-secondary:8181";);
+
+        assertThat(primary.getId()).isNotEqualTo(secondary.getId());
+        assertThat(primary).isNotEqualTo(secondary);
+    }
+
     @Test
     void isUpWhenTheServerIsHealthy() throws Exception {
         HealthCheck.Result result = call(startServer(200));

Reply via email to