From 2acebd9616426a58dde4d755909b4e18460c8985 Mon Sep 17 00:00:00 2001 From: Andrea Cosentino Date: Wed, 27 May 2026 10:08:11 +0200 Subject: [PATCH 1/2] CAMEL-23592: camel-shiro - align Exchange header constant names with Camel naming convention (#23506) Renames the three Exchange header string values in ShiroSecurityConstants that drive Shiro authentication (SHIRO_SECURITY_TOKEN, SHIRO_SECURITY_USERNAME, SHIRO_SECURITY_PASSWORD) to CamelShiroSecurity, following the convention used across the rest of the Camel component catalog and matching the pattern established in CAMEL-23526 (camel-cxf), CAMEL-23522 (camel-mail), CAMEL-23461 (camel-aws-bedrock), CAMEL-23532 (camel-vertx-websocket / camel-atmosphere-websocket / camel-iggy), and CAMEL-23576 (camel-jira). - SHIRO_SECURITY_TOKEN: "SHIRO_SECURITY_TOKEN" -> "CamelShiroSecurityToken" - SHIRO_SECURITY_USERNAME: "SHIRO_SECURITY_USERNAME" -> "CamelShiroSecurityUsername" - SHIRO_SECURITY_PASSWORD: "SHIRO_SECURITY_PASSWORD" -> "CamelShiroSecurityPassword" These headers carry credentials and a serialized authentication token, so filtering them at transport boundaries by default is particularly important. The Java field names are unchanged so routes referencing the constants symbolically continue to work; routes using the literal string values must be updated (documented in the 4.21 upgrade guide). No tests reference the literal values, and the shiro adoc documentation references the constants symbolically. Tracker: CAMEL-23577 Reported by Claude Code on behalf of Andrea Cosentino Signed-off-by: Andrea Cosentino --- .../security/ShiroSecurityConstants.java | 6 ++--- .../pages/camel-4x-upgrade-guide-4_18.adoc | 27 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityConstants.java b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityConstants.java index b3b30e800efac..4f8e7d21e5adf 100644 --- a/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityConstants.java +++ b/components/camel-shiro/src/main/java/org/apache/camel/component/shiro/security/ShiroSecurityConstants.java @@ -21,9 +21,9 @@ */ public final class ShiroSecurityConstants { - public static final String SHIRO_SECURITY_TOKEN = "SHIRO_SECURITY_TOKEN"; - public static final String SHIRO_SECURITY_USERNAME = "SHIRO_SECURITY_USERNAME"; - public static final String SHIRO_SECURITY_PASSWORD = "SHIRO_SECURITY_PASSWORD"; + public static final String SHIRO_SECURITY_TOKEN = "CamelShiroSecurityToken"; + public static final String SHIRO_SECURITY_USERNAME = "CamelShiroSecurityUsername"; + public static final String SHIRO_SECURITY_PASSWORD = "CamelShiroSecurityPassword"; private ShiroSecurityConstants() { } diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc index 78a7434455898..43ea2812e68af 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc @@ -656,6 +656,33 @@ The generated Endpoint DSL header accessors on each component's +=== camel-shiro - potential breaking change + +The three Exchange header constants in `ShiroSecurityConstants` that drive +Shiro authentication used header values outside the `Camel` namespace +(`SHIRO_SECURITY_TOKEN`, `SHIRO_SECURITY_USERNAME`, `SHIRO_SECURITY_PASSWORD`) +and were therefore not filtered by the default `HeaderFilterStrategy`. They +have been renamed to follow the Camel naming convention. The Java field names +are unchanged; only the header string values have changed: + +[options="header"] +|=== +| Constant | Previous value | New value +| `ShiroSecurityConstants.SHIRO_SECURITY_TOKEN` | `SHIRO_SECURITY_TOKEN` | `CamelShiroSecurityToken` +| `ShiroSecurityConstants.SHIRO_SECURITY_USERNAME` | `SHIRO_SECURITY_USERNAME` | `CamelShiroSecurityUsername` +| `ShiroSecurityConstants.SHIRO_SECURITY_PASSWORD` | `SHIRO_SECURITY_PASSWORD` | `CamelShiroSecurityPassword` +|=== + +These headers carry credentials and a serialized authentication token, so +filtering them at transport boundaries by default is particularly important. + +Routes that reference the constants symbolically (for example +`setHeader(ShiroSecurityConstants.SHIRO_SECURITY_USERNAME, ...)`) continue to +work without changes. Routes that set the header by its literal string value +(for example `setHeader("SHIRO_SECURITY_USERNAME", ...)`) must be updated to +use the new value (`setHeader("CamelShiroSecurityUsername", ...)`). + + === camel-web3j - potential breaking change The Exchange header constants in `Web3jConstants` have been renamed to follow the From ec8917288f2bb61f0e131b364b5464d6f8715320 Mon Sep 17 00:00:00 2001 From: Andrea Cosentino Date: Thu, 28 May 2026 10:34:01 +0200 Subject: [PATCH 2/2] CAMEL-23592: camel-itest - update ShiroOverJmsTest for renamed Shiro security headers After CAMEL-23592 the three Shiro security header values move into the Camel* namespace (CamelShiroSecurityToken etc.). The default JmsHeaderFilterStrategy filters every Camel* header at the transport boundary, which is the intended behavior for untrusted producers but strips the serialized authentication token from trusted Shiro-over-JMS routes that previously relied on the old non-Camel-prefixed value surviving the JMS round-trip. ShiroOverJmsTest is exactly such a trusted Shiro-over-JMS route and started failing on this backport branch's CI: mock://ShiroOverJmsTestError Received message count. Expected: <0> but was: <1> (the consumer-side ShiroSecurityPolicy could no longer read the token and the message ended up at the dead-letter mock). The same regression exists latently on main; the matching fix is in PR #23592. - ShiroOverJmsTest: configure a small subclass of JmsHeaderFilterStrategy on the JMS component that opts the three Shiro security headers back in (returns false from applyFilterToCamelHeaders / applyFilterToExternalHeaders for those headers, delegates to super for everything else). This is the pattern end-users will need. - 4.18 upgrade guide: extend the camel-shiro entry to document the new required HeaderFilterStrategy opt-in for trusted Shiro-over-transport routes, with a worked code example mirroring the one used in the test. Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: Andrea Cosentino --- .../pages/camel-4x-upgrade-guide-4_18.adoc | 38 +++++++++++++++++++ .../camel/itest/shiro/ShiroOverJmsTest.java | 35 +++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc index 43ea2812e68af..75b7aa87622b7 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc @@ -682,6 +682,44 @@ work without changes. Routes that set the header by its literal string value (for example `setHeader("SHIRO_SECURITY_USERNAME", ...)`) must be updated to use the new value (`setHeader("CamelShiroSecurityUsername", ...)`). +Because the three header values are now in the `Camel*` namespace, transports +that filter Camel-internal headers by default (JMS, CXF, HTTP, etc.) will +strip the serialized Shiro authentication token before publishing. This is +the intended behavior for untrusted producers. Trusted Shiro-over-transport +routes that previously relied on the token surviving the boundary must opt +those three headers back in via a custom `HeaderFilterStrategy`, for example: + +[source,java] +---- +public class ShiroFriendlyJmsHeaderFilterStrategy extends JmsHeaderFilterStrategy { + @Override + public boolean applyFilterToCamelHeaders(String name, Object value, Exchange ex) { + if (isShiroSecurityHeader(name)) { + return false; + } + return super.applyFilterToCamelHeaders(name, value, ex); + } + + @Override + public boolean applyFilterToExternalHeaders(String name, Object value, Exchange ex) { + if (isShiroSecurityHeader(name)) { + return false; + } + return super.applyFilterToExternalHeaders(name, value, ex); + } + + private static boolean isShiroSecurityHeader(String name) { + return ShiroSecurityConstants.SHIRO_SECURITY_TOKEN.equalsIgnoreCase(name) + || ShiroSecurityConstants.SHIRO_SECURITY_USERNAME.equalsIgnoreCase(name) + || ShiroSecurityConstants.SHIRO_SECURITY_PASSWORD.equalsIgnoreCase(name); + } +} + +jmsComponent.setHeaderFilterStrategy(new ShiroFriendlyJmsHeaderFilterStrategy()); +---- + +A worked example is in `ShiroOverJmsTest` in the `camel-itest` module. + === camel-web3j - potential breaking change diff --git a/tests/camel-itest/src/test/java/org/apache/camel/itest/shiro/ShiroOverJmsTest.java b/tests/camel-itest/src/test/java/org/apache/camel/itest/shiro/ShiroOverJmsTest.java index ccd5e8b2661f6..5a702f8e9da8d 100644 --- a/tests/camel-itest/src/test/java/org/apache/camel/itest/shiro/ShiroOverJmsTest.java +++ b/tests/camel-itest/src/test/java/org/apache/camel/itest/shiro/ShiroOverJmsTest.java @@ -19,8 +19,10 @@ import java.util.HashMap; import java.util.Map; +import org.apache.camel.Exchange; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.jms.JmsComponent; +import org.apache.camel.component.jms.JmsHeaderFilterStrategy; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.component.shiro.security.ShiroSecurityConstants; import org.apache.camel.component.shiro.security.ShiroSecurityPolicy; @@ -61,9 +63,42 @@ protected void bindToRegistry(Registry registry) { amq.setCamelContext(context); + // After CAMEL-23592 the Shiro security headers live in the CamelShiroSecurity* namespace, + // which the default JmsHeaderFilterStrategy filters at the transport boundary. For a + // trusted Shiro-over-JMS route, the operator must opt those three headers back in. + amq.setHeaderFilterStrategy(new ShiroFriendlyJmsHeaderFilterStrategy()); + registry.bind("jms", amq); } + /** + * Allows the three Shiro security headers (token, username, password) to cross the JMS transport boundary while + * still filtering every other Camel-internal header. + */ + private static final class ShiroFriendlyJmsHeaderFilterStrategy extends JmsHeaderFilterStrategy { + @Override + public boolean applyFilterToCamelHeaders(String headerName, Object headerValue, Exchange exchange) { + if (isShiroSecurityHeader(headerName)) { + return false; + } + return super.applyFilterToCamelHeaders(headerName, headerValue, exchange); + } + + @Override + public boolean applyFilterToExternalHeaders(String headerName, Object headerValue, Exchange exchange) { + if (isShiroSecurityHeader(headerName)) { + return false; + } + return super.applyFilterToExternalHeaders(headerName, headerValue, exchange); + } + + private static boolean isShiroSecurityHeader(String headerName) { + return ShiroSecurityConstants.SHIRO_SECURITY_TOKEN.equalsIgnoreCase(headerName) + || ShiroSecurityConstants.SHIRO_SECURITY_USERNAME.equalsIgnoreCase(headerName) + || ShiroSecurityConstants.SHIRO_SECURITY_PASSWORD.equalsIgnoreCase(headerName); + } + } + @Override protected RouteBuilder createRouteBuilder() { return new RouteBuilder() {