You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2026/07/16 15:09:28 UTC

(camel) branch main updated: CAMEL-24112: camel-rest-openapi - Fix path parameters leaking into query string with multi-param operations

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

davsclaus 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 352344c3b969 CAMEL-24112: camel-rest-openapi - Fix path parameters leaking into query string with multi-param operations
352344c3b969 is described below

commit 352344c3b969dd4398dd467b85d0b84964f8a0b7
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Jul 16 17:09:21 2026 +0200

    CAMEL-24112: camel-rest-openapi - Fix path parameters leaking into query string with multi-param operations
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    
    Signed-off-by: Claus Ibsen <cl...@gmail.com>
    Co-authored-by: Claude Opus 4.6 <no...@anthropic.com>
---
 .../rest/openapi/RestOpenApiEndpoint.java          | 13 ++---
 .../rest/openapi/RestOpenApiEndpointV3Test.java    | 64 ++++++++++++++++++++++
 2 files changed, 70 insertions(+), 7 deletions(-)

diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
index 761ca925126c..9c856e06b48e 100644
--- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
+++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
@@ -683,13 +683,12 @@ public final class RestOpenApiEndpoint extends DefaultEndpoint {
         if (this.parameters != null) {
             if (operation.getParameters() != null) {
                 for (Map.Entry<String, Object> entry : this.parameters.entrySet()) {
-                    for (Parameter param : operation.getParameters()) {
-                        // skip parameters that are part of the operation as path as otherwise
-                        // it will be duplicated as query parameter as well
-                        boolean clash = "path".equals(param.getIn()) && entry.getKey().equals(param.getName());
-                        if (!clash) {
-                            nestedParameters.put(entry.getKey(), entry.getValue());
-                        }
+                    // skip parameters that are part of the operation as path as otherwise
+                    // it will be duplicated as query parameter as well
+                    boolean clash = operation.getParameters().stream()
+                            .anyMatch(p -> "path".equals(p.getIn()) && entry.getKey().equals(p.getName()));
+                    if (!clash) {
+                        nestedParameters.put(entry.getKey(), entry.getValue());
                     }
                 }
             } else {
diff --git a/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java
index 24ed458fb49f..f77769d89466 100644
--- a/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java
+++ b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java
@@ -287,6 +287,70 @@ public class RestOpenApiEndpointV3Test {
                 entry("queryParameters", "q={q}&o={o?}"));
     }
 
+    @Test
+    public void shouldNotLeakPathParametersAsQueryParameters() {
+        final CamelContext camelContext = mock(CamelContext.class);
+
+        final RestOpenApiComponent component = new RestOpenApiComponent();
+        component.setCamelContext(camelContext);
+
+        // endpoint parameters include two path params and one extra param
+        Map<String, Object> params = new HashMap<>();
+        params.put("userId", "1");
+        params.put("orderId", "2");
+        params.put("format", "json");
+
+        final RestOpenApiEndpoint endpoint = new RestOpenApiEndpoint(
+                "uri", "remaining", component, params);
+        endpoint.setHost("http://petstore.openapi.io");
+
+        final OpenAPI openapi = new OpenAPI();
+        final Operation operation = new Operation().operationId("getOrder");
+        operation.addParametersItem(new Parameter().name("userId").in("path").required(true));
+        operation.addParametersItem(new Parameter().name("orderId").in("path").required(true));
+
+        Map<String, Object> result = endpoint.determineEndpointParameters(openapi, operation);
+
+        @SuppressWarnings("unchecked")
+        Map<String, Object> nested = (Map<String, Object>) result.get("parameters");
+
+        // path params must not leak into nested parameters
+        assertThat(nested).doesNotContainKey("userId");
+        assertThat(nested).doesNotContainKey("orderId");
+        // non-path param must be preserved
+        assertThat(nested).containsEntry("format", "json");
+    }
+
+    @Test
+    public void shouldKeepEndpointParametersWhenNoPathParamClash() {
+        final CamelContext camelContext = mock(CamelContext.class);
+
+        final RestOpenApiComponent component = new RestOpenApiComponent();
+        component.setCamelContext(camelContext);
+
+        Map<String, Object> params = new HashMap<>();
+        params.put("verbose", "true");
+        params.put("timeout", "5000");
+
+        final RestOpenApiEndpoint endpoint = new RestOpenApiEndpoint(
+                "uri", "remaining", component, params);
+        endpoint.setHost("http://petstore.openapi.io");
+
+        final OpenAPI openapi = new OpenAPI();
+        final Operation operation = new Operation().operationId("listUsers");
+        operation.addParametersItem(new Parameter().name("page").in("query"));
+        operation.addParametersItem(new Parameter().name("limit").in("query"));
+
+        Map<String, Object> result = endpoint.determineEndpointParameters(openapi, operation);
+
+        @SuppressWarnings("unchecked")
+        Map<String, Object> nested = (Map<String, Object>) result.get("parameters");
+
+        // no path params in the operation, so all endpoint params should be preserved
+        assertThat(nested).containsEntry("verbose", "true");
+        assertThat(nested).containsEntry("timeout", "5000");
+    }
+
     @Test
     public void shouldDetermineHostFromRestConfiguration() {
         assertThat(RestOpenApiEndpoint.hostFrom(null)).isNull();