This is an automated email from the ASF dual-hosted git repository.
apupier 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 f745392821dc CAMEL-23592: camel-itest - update ShiroOverJmsTest for
renamed Shiro security headers
f745392821dc is described below
commit f745392821dc552a330ad558b25e9e842c39a783
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu May 28 10:19:53 2026 +0200
CAMEL-23592: camel-itest - update ShiroOverJmsTest for renamed Shiro
security headers
After CAMEL-23592 the three Shiro security headers (SHIRO_SECURITY_TOKEN,
SHIRO_SECURITY_USERNAME, SHIRO_SECURITY_PASSWORD) carry their value in 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 demonstrates the Shiro-over-JMS pattern and started
failing because the consumer-side policy could no longer read the token
from the message: the failed message went to the dead-letter mock
(expected 0, was 1). The test was passing on main only because its
incremental-build scope did not exercise camel-itest after the rename;
the regression is latent on main too.
- 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 and delegates to super
for everything else). This is the pattern end-users will need.
- 4.21 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) <[email protected]>
Signed-off-by: Andrea Cosentino <[email protected]>
---
.../ROOT/pages/camel-4x-upgrade-guide-4_21.adoc | 38 ++++++++++++++++++++++
.../apache/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_21.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
index c4127f531c2e..919a78f78fdb 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
@@ -910,6 +910,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 65f4db919560..12e104127932 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 @@ package org.apache.camel.itest.shiro;
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;
@@ -63,9 +65,42 @@ public class ShiroOverJmsTest extends CamelTestSupport {
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() {