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 48f499f5e991 CAMEL-25705: camel-netty-http - reject an ambiguous 
request path when a security constraint is configured (#27945)
48f499f5e991 is described below

commit 48f499f5e99166b05752a1f3a68a206560866d9a
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Oct 23 07:24:46 2026 +0200

    CAMEL-25705: camel-netty-http - reject an ambiguous request path when a 
security constraint is configured (#27945)
    
    Co-authored-by: Claus Ibsen <[email protected]>
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Andrea Cosentino <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../http/handlers/HttpServerChannelHandler.java    | 101 ++++++++++++++-
 ...NettyHttpBasicAuthConstraintDotSegmentTest.java | 141 +++++++++++++++++++++
 ...ettyHttpBasicAuthConstraintRootContextTest.java | 114 +++++++++++++++++
 .../HttpServerChannelHandlerDotSegmentTest.java    |  71 +++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |  19 +++
 5 files changed, 445 insertions(+), 1 deletion(-)

diff --git 
a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
 
b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
index b846213a6ebd..109098640dab 100644
--- 
a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
+++ 
b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
@@ -163,6 +163,27 @@ public class HttpServerChannelHandler extends 
ServerChannelHandler {
 
             // we need the relative path without the hostname and port
             URI uri = new URI(request.uri());
+
+            // a request path with . or .. segments is ambiguous: the security 
constraint, the consumer dispatch
+            // and the route may each interpret it differently, so a path such 
as /foo/../admin/x (or its percent-encoded
+            // /foo/%2e%2e/admin/x form) could be matched against the 
constraint inclusions/exclusions in a different
+            // form than the one the route handles. Reject it up front when a 
security constraint is configured; a
+            // well-behaved HTTP client normalizes dot-segments before sending 
(CAMEL-25705). The same applies to a path
+            // with an empty segment, a ; path parameter or a \ (also in their 
percent-encoded forms), which a backend
+            // the route forwards to may collapse, strip or treat as a / 
respectively. A request target that starts with
+            // // is parsed as a host followed by a path, so its first segment 
never reaches uri.getPath(); check the
+            // request target for that empty segment.
+            if (security.getSecurityConstraint() != null
+                    && (request.uri().startsWith("//") || 
isAmbiguousPath(uri.getPath()))) {
+                LOG.debug("Rejecting request with an ambiguous path for 
resource: {}", url);
+                HttpResponse response = new DefaultHttpResponse(HTTP_1_1, 
BAD_REQUEST);
+                response.headers().set(NettyHttpConstants.CONTENT_TYPE, 
"text/plain");
+                response.headers().set(Exchange.CONTENT_LENGTH, 0);
+                ctx.writeAndFlush(response);
+                ctx.channel().close();
+                return;
+            }
+
             final String target = extractTarget(uri);
 
             // is it a restricted resource?
@@ -223,7 +244,7 @@ public class HttpServerChannelHandler extends 
ServerChannelHandler {
         // strip the starting endpoint path so the target is relative to the 
endpoint uri.
         // the comparison must ignore case on the context-path, the same way 
consumer dispatch does
         // (RestConsumerContextPathMatcher), so the security constraint is 
evaluated against the same
-        // normalized target the request is actually routed to
+        // target the request is actually routed to
         String path = consumer.getConfiguration().getPath();
         if (path != null && 
target.toLowerCase(Locale.US).startsWith(path.toLowerCase(Locale.US))) {
             target = target.substring(path.length());
@@ -231,6 +252,84 @@ public class HttpServerChannelHandler extends 
ServerChannelHandler {
         return target;
     }
 
+    /**
+     * Whether the (decoded) path may be interpreted differently by the 
security constraint, the consumer dispatch, the
+     * route or a backend the route forwards to: it contains a {@code .} or 
{@code ..} segment, an empty segment
+     * ({@code //}), a {@code ;} path parameter or a {@code \}. Such a path is 
rejected up front when a security
+     * constraint is configured (see {@link #channelRead0}).
+     */
+    static boolean isAmbiguousPath(String path) {
+        if (path == null) {
+            return false;
+        }
+        return path.indexOf(';') != -1 || path.indexOf('\\') != -1 || 
path.contains("//") || containsDotSegments(path);
+    }
+
+    /**
+     * Whether the path contains a {@code .} or {@code ..} segment that path 
normalization would resolve. Such a path
+     * may be interpreted differently by the security constraint, the consumer 
dispatch and the route, so it is rejected
+     * up front when a security constraint is configured (see {@link 
#channelRead0}).
+     */
+    private static boolean containsDotSegments(String path) {
+        return path != null && !path.equals(removeDotSegments(path));
+    }
+
+    /**
+     * Removes {@code .} and {@code ..} segments from the given path, as 
specified by the {@code remove_dot_segments}
+     * algorithm in RFC 3986 section 5.2.4. Used to detect whether a request 
path carries dot-segments. Excess
+     * {@code ..} segments cannot climb above the root, so the returned path 
never contains a {@code ..} segment.
+     */
+    static String removeDotSegments(String path) {
+        // fast path: nothing to resolve unless there is a dot segment to 
begin with
+        if (path == null || path.isEmpty() || path.indexOf('.') == -1) {
+            return path;
+        }
+
+        String in = path;
+        StringBuilder out = new StringBuilder(path.length());
+        while (!in.isEmpty()) {
+            if (in.startsWith("../")) {
+                in = in.substring(3);
+            } else if (in.startsWith("./")) {
+                in = in.substring(2);
+            } else if (in.startsWith("/./")) {
+                in = in.substring(2);
+            } else if (in.equals("/.")) {
+                in = "/";
+            } else if (in.startsWith("/../")) {
+                in = in.substring(3);
+                removeLastSegment(out);
+            } else if (in.equals("/..")) {
+                in = "/";
+                removeLastSegment(out);
+            } else if (in.equals(".") || in.equals("..")) {
+                in = "";
+            } else {
+                // move the first path segment (including any leading slash, 
up to but not including the
+                // next slash) from the input to the output
+                int start = in.charAt(0) == '/' ? 1 : 0;
+                int next = in.indexOf('/', start);
+                if (next < 0) {
+                    out.append(in);
+                    in = "";
+                } else {
+                    out.append(in, 0, next);
+                    in = in.substring(next);
+                }
+            }
+        }
+        return out.toString();
+    }
+
+    private static void removeLastSegment(StringBuilder out) {
+        int lastSlash = out.lastIndexOf("/");
+        if (lastSlash >= 0) {
+            out.setLength(lastSlash);
+        } else {
+            out.setLength(0);
+        }
+    }
+
     protected boolean matchesRoles(String roles, String userRoles) {
         // matches if no role restrictions or any role is accepted
         if (roles.equals("*")) {
diff --git 
a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpBasicAuthConstraintDotSegmentTest.java
 
b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpBasicAuthConstraintDotSegmentTest.java
new file mode 100644
index 000000000000..eb9f655f93ff
--- /dev/null
+++ 
b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpBasicAuthConstraintDotSegmentTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.netty.http;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.camel.test.junit6.TestSupport.assertIsInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * A request path containing {@code .} or {@code ..} segments may be 
interpreted differently by the security constraint,
+ * the consumer dispatch and the route, so with a {@code securityConstraint} 
configured such a request is rejected with
+ * HTTP 400. This closes both directions of the mismatch: a dot-segment path 
can neither reach a restricted inclusion
+ * (for example {@code /admin/*}) unchallenged, nor be treated as an excluded 
(public) path when its raw form targets a
+ * restricted one.
+ */
+class NettyHttpBasicAuthConstraintDotSegmentTest extends BaseNettyTestSupport {
+
+    @Override
+    public void doPreSetup() {
+        System.setProperty("java.security.auth.login.config", 
"src/test/resources/myjaas.config");
+    }
+
+    @Override
+    public void doPostTearDown() {
+        System.clearProperty("java.security.auth.login.config");
+    }
+
+    @BindToRegistry("mySecurityConfig")
+    public NettyHttpSecurityConfiguration loadSecConf() {
+        NettyHttpSecurityConfiguration security = new 
NettyHttpSecurityConfiguration();
+        security.setRealm("karaf");
+        SecurityAuthenticator auth = new JAASSecurityAuthenticator();
+        auth.setName("karaf");
+        security.setSecurityAuthenticator(auth);
+
+        // a specific inclusion and a public exclusion, both below the 
endpoint path
+        SecurityConstraintMapping matcher = new SecurityConstraintMapping();
+        matcher.addInclusion("/admin/*");
+        matcher.addExclusion("/public/*");
+        security.setSecurityConstraint(matcher);
+
+        return security;
+    }
+
+    @Test
+    void restrictedPathIsChallenged() {
+        assertStatus("netty-http:http://localhost:{{port}}/foo/admin/x";, 401);
+    }
+
+    @Test
+    void excludedPathIsPublic() {
+        assertEquals("Bye World",
+                
template.requestBody("netty-http:http://localhost:{{port}}/foo/public/x";, 
"Hello", String.class));
+    }
+
+    @Test
+    void literalDotSegmentIsRejected() {
+        // a leading .. reaches /admin/x as the raw target evades /admin/*
+        assertStatus("netty-http:http://localhost:{{port}}/foo/../admin/x";, 
400);
+    }
+
+    @Test
+    void encodedDotSegmentIsRejected() {
+        
assertStatus("netty-http:http://localhost:{{port}}/foo/%2e%2e/admin/x";, 400);
+    }
+
+    @Test
+    void inContextDotSegmentIsRejected() {
+        // resolves to /foo/admin/y, which stays below the endpoint context
+        assertStatus("netty-http:http://localhost:{{port}}/foo/x/../admin/y";, 
400);
+    }
+
+    @Test
+    void reverseDotSegmentIsRejected() {
+        // raw /admin/../public/x matches the /admin/* inclusion, but resolves 
to the excluded /public/x; rejecting it
+        // prevents the restricted raw target from being treated as public
+        
assertStatus("netty-http:http://localhost:{{port}}/foo/admin/../public/x";, 400);
+    }
+
+    @Test
+    void pathParameterIsRejected() {
+        // raw /admin;x/y evades /admin/*, but a backend that strips path 
parameters sees /admin/y
+        assertStatus("netty-http:http://localhost:{{port}}/foo/admin;x/y";, 
400);
+        assertStatus("netty-http:http://localhost:{{port}}/foo/admin%3bx/y";, 
400);
+    }
+
+    @Test
+    void dotSegmentWithPathParameterIsRejected() {
+        // raw /public/..;/admin/x matches the /public/* exclusion, but a 
backend that treats ..; as .. sees /admin/x
+        
assertStatus("netty-http:http://localhost:{{port}}/foo/public/..;/admin/x";, 
400);
+    }
+
+    @Test
+    void backslashIsRejected() {
+        // raw /public/\..\..\admin matches the /public/* exclusion, but a 
backend that treats \ as / sees /admin
+        
assertStatus("netty-http:http://localhost:{{port}}/foo/public/%5c..%5c..%5cadmin";,
 400);
+    }
+
+    @Test
+    void emptySegmentIsRejected() {
+        // raw //admin/x evades /admin/*, but a backend that collapses empty 
segments sees /admin/x
+        assertStatus("netty-http:http://localhost:{{port}}/foo//admin/x";, 400);
+    }
+
+    private void assertStatus(String uri, int expected) {
+        CamelExecutionException e = assertThrows(CamelExecutionException.class,
+                () -> template.requestBody(uri, "Hello", String.class));
+        NettyHttpOperationFailedException cause = 
assertIsInstanceOf(NettyHttpOperationFailedException.class, e.getCause());
+        assertEquals(expected, cause.getStatusCode());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                
from("netty-http:http://0.0.0.0:{{port}}/foo?matchOnUriPrefix=true&securityConfiguration=#mySecurityConfig";)
+                        .transform().constant("Bye World");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpBasicAuthConstraintRootContextTest.java
 
b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpBasicAuthConstraintRootContextTest.java
new file mode 100644
index 000000000000..5255e6f4b6eb
--- /dev/null
+++ 
b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpBasicAuthConstraintRootContextTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.netty.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * A consumer at the root context with a {@code securityConstraint} rejects 
with HTTP 400 a request target that starts
+ * with {@code //}. Such a target is parsed as a host followed by a path, so 
the empty segment is not in the decoded
+ * path. The requests are written on a plain socket, so the request target 
reaches the consumer as written.
+ */
+class NettyHttpBasicAuthConstraintRootContextTest extends BaseNettyTestSupport 
{
+
+    @Override
+    public void doPreSetup() {
+        System.setProperty("java.security.auth.login.config", 
"src/test/resources/myjaas.config");
+    }
+
+    @Override
+    public void doPostTearDown() {
+        System.clearProperty("java.security.auth.login.config");
+    }
+
+    @BindToRegistry("mySecurityConfig")
+    public NettyHttpSecurityConfiguration loadSecConf() {
+        NettyHttpSecurityConfiguration security = new 
NettyHttpSecurityConfiguration();
+        security.setRealm("karaf");
+        SecurityAuthenticator auth = new JAASSecurityAuthenticator();
+        auth.setName("karaf");
+        security.setSecurityAuthenticator(auth);
+
+        SecurityConstraintMapping matcher = new SecurityConstraintMapping();
+        matcher.addInclusion("/admin/*");
+        security.setSecurityConstraint(matcher);
+
+        return security;
+    }
+
+    @Test
+    void restrictedPathIsChallenged() throws IOException {
+        assertEquals(401, statusOf("/admin/x"));
+    }
+
+    @Test
+    void otherPathIsPublic() throws IOException {
+        assertEquals(200, statusOf("/x"));
+    }
+
+    @Test
+    void leadingEmptySegmentIsRejected() throws IOException {
+        assertEquals(400, statusOf("//admin/x"));
+    }
+
+    @Test
+    void leadingEmptySegmentInAbsoluteFormIsRejected() throws IOException {
+        assertEquals(400, statusOf("http://localhost:"; + getPort() + 
"//admin/x"));
+    }
+
+    private int statusOf(String requestTarget) throws IOException {
+        try (Socket socket = new Socket()) {
+            socket.connect(new InetSocketAddress("localhost", getPort()), 
5000);
+            socket.setSoTimeout(5000);
+            String request = "GET " + requestTarget + " HTTP/1.1\r\nHost: 
localhost:" + getPort()
+                             + "\r\nConnection: close\r\n\r\n";
+            
socket.getOutputStream().write(request.getBytes(StandardCharsets.US_ASCII));
+            socket.getOutputStream().flush();
+
+            // the status line is HTTP/1.1 <code> <reason>
+            InputStream in = socket.getInputStream();
+            StringBuilder statusLine = new StringBuilder();
+            int b = in.read();
+            while (b != -1 && b != '\r') {
+                statusLine.append((char) b);
+                b = in.read();
+            }
+            return Integer.parseInt(statusLine.toString().split(" ")[1]);
+        }
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                
from("netty-http:http://0.0.0.0:{{port}}?matchOnUriPrefix=true&securityConfiguration=#mySecurityConfig";)
+                        .transform().constant("Bye World");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandlerDotSegmentTest.java
 
b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandlerDotSegmentTest.java
new file mode 100644
index 000000000000..573817c376c9
--- /dev/null
+++ 
b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandlerDotSegmentTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.netty.http.handlers;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * A request path carrying {@code .} or {@code ..} segments is rejected when a 
security constraint is configured;
+ * {@code removeDotSegments} (RFC 3986 section 5.2.4) resolves the path so 
those segments can be detected (the result
+ * differs from the input). A path without dot-segments, including a 
leading-dot file name, is returned unchanged.
+ * Excess {@code ..} segments cannot climb above the root, so the result never 
contains a {@code ..} segment.
+ */
+class HttpServerChannelHandlerDotSegmentTest {
+
+    @ParameterizedTest
+    @CsvSource(delimiter = '|', textBlock = """
+            # input                 | expected
+            /foo/admin/x            | /foo/admin/x
+            /foo/./admin/x          | /foo/admin/x
+            /foo/../admin/x         | /admin/x
+            /app/../admin/x         | /admin/x
+            /foo/../../admin/x      | /admin/x
+            /foo/sub/../admin/x     | /foo/admin/x
+            /foo/a/../../../admin   | /admin
+            /foo/admin/.            | /foo/admin/
+            /foo/admin/..           | /foo/
+            /..                     | /
+            /admin/file.txt         | /admin/file.txt
+            /admin/.hidden/secret   | /admin/.hidden/secret
+            /                       | /
+            """)
+    void resolvesDotSegments(String input, String expected) {
+        assertEquals(expected, 
HttpServerChannelHandler.removeDotSegments(input), () -> "input " + input);
+    }
+
+    @ParameterizedTest
+    @CsvSource(delimiter = '|', textBlock = """
+            # input                 | expected
+            /foo/admin/x            | false
+            /admin/file.txt         | false
+            /admin/.hidden/secret   | false
+            /foo/admin/x/           | false
+            /                       | false
+            /foo/../admin/x         | true
+            /foo/admin/.            | true
+            /foo//admin/x           | true
+            /foo/admin;x/y          | true
+            /foo/public/..;/admin   | true
+            /foo/public/\\..\\admin | true
+            """)
+    void detectsAmbiguousPath(String input, boolean expected) {
+        assertEquals(expected, 
HttpServerChannelHandler.isAmbiguousPath(input), () -> "input " + input);
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 78e56e371433..0ecb5e9d4a4e 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -1161,6 +1161,25 @@ On Jira Cloud the Jira consumers now read the pages of a 
search with the next pa
 start index: with `maxResults` above 50, a search with more than 50 results 
failed on the second page with
 `UnsupportedOperationException`.
 
+=== camel-netty-http - an ambiguous request path is rejected when a security 
constraint is configured
+
+A `netty-http` consumer configured with a `securityConstraint` now rejects, 
with HTTP 400, a request whose path
+contains `.` or `..` segments (including their percent-encoded `%2e` form). 
Such a path is ambiguous: the security
+constraint, the consumer dispatch and the route may each interpret it 
differently, so with `matchOnUriPrefix=true` and a
+specific inclusion such as `/admin/*`, a request like `/foo/../admin/x` (or 
its encoded `/foo/%2e%2e/admin/x` form)
+could be matched against the inclusions and exclusions in a different form 
than the one the route handles. Rejecting
+it up front keeps the constraint decision and the routed path consistent. A 
well-behaved HTTP client normalizes
+dot-segments before sending, so normal traffic is unaffected.
+
+For the same reason, such a consumer also rejects with HTTP 400 a request 
whose path contains an empty segment (`//`),
+a `;` path parameter (also as `%3b`) or a `\` (also as `%5c`). A backend the 
route forwards the request to may collapse
+the empty segment, strip the path parameter or treat the backslash as a `/`, 
and so act on a different path than the one
+the constraint was checked against. A route that needs matrix parameters (`;`) 
must not configure a
+`securityConstraint` on the same consumer.
+
+This applies only when a `securityConstraint` is configured; a consumer 
without one is unchanged, and continues to
+receive the request path as sent.
+
 === camel-hashicorp-vault - properties without engine use the `secret` engine
 
 A `hashicorp:` property without an engine, such as `{{hashicorp:mysecret}}` or 
`{{hashicorp:mysecret#field}}`, now

Reply via email to