Skip to content

CAMEL-23543: Centralize and harden Camel* header filtering in DefaultHeaderFilterStrategy#23652

Open
ammachado wants to merge 7 commits into
apache:mainfrom
ammachado:CAMEL-23543
Open

CAMEL-23543: Centralize and harden Camel* header filtering in DefaultHeaderFilterStrategy#23652
ammachado wants to merge 7 commits into
apache:mainfrom
ammachado:CAMEL-23543

Conversation

@ammachado
Copy link
Copy Markdown
Contributor

@ammachado ammachado commented May 30, 2026

Description

Centralises Camel-internal header filtering in DefaultHeaderFilterStrategy so every component gets secure defaults without having to call setInFilterStartsWith/setOutFilterStartsWith explicitly.

  • DefaultHeaderFilterStrategy now initializes inFilterStartsWith and outFilterStartsWith to CAMEL_FILTER_STARTS_WITH by default (previously null).
  • All component-specific strategies that duplicated this setup have had the now-redundant calls removed.
  • ClassicJmsHeaderFilterStrategy explicitly opts out via setInFilterStartsWith((String[]) null) to preserve legacy Camel-header-passthrough behaviour.
  • Upgrade guide updated (camel-4x-upgrade-guide-4_21.adoc).
  • Redundant setLowerCase(true) calls: removed from camel-http-base and camel-http-common HTTP strategies; lowerCase=true is already the field-initialiser default.
  • Added ClassicJmsHeaderFilterStrategyTest directly asserting that Camel headers pass through in both directions.
  • Six no-op subclasses removed: CoAPHeaderFilterStrategy, CometdHeaderFilterStrategy, IggyHeaderFilterStrategy, NatsHeaderFilterStrategy, VertxWebsocketHeaderFilterStrategy, and XmppHeaderFilterStrategy. All six classes and their test files have been deleted; callers instantiate DefaultHeaderFilterStrategy directly.

Target

  • I checked that the commit is targeting the correct branch (Camel 4 uses the main branch)

Tracking

  • If this is a large change, bug fix, or code improvement, I checked there is a JIRA issue filed for the change (usually before you start working on it).

Apache Camel coding standards and style

  • I checked that each commit in the pull request has a meaningful subject line and body.
  • I have run mvn clean install -DskipTests locally from root folder and I have committed all auto-generated changes.

Claude Code on behalf of Adriano Machado

@ammachado ammachado marked this pull request as ready for review May 30, 2026 21:38
Copy link
Copy Markdown
Contributor

@davsclaus davsclaus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well-executed security hardening — the change aligns with design/headers.adoc which states that DefaultHeaderFilterStrategy should strip Camel* and org.apache.camel.* by default. Making that the actual default rather than requiring each component to opt in is the right move.

All 6 deleted strategy classes were verified as pure no-ops, callers are properly updated, the .clone() on field initializers prevents shared mutable state, and the JMS opt-out is correctly implemented with good test coverage.

One minor suggestion on the upgrade guide below.

This review covers project conventions and correctness. It does not replace specialized review tools such as CodeRabbit, Sourcery, or SonarCloud.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

@davsclaus
Copy link
Copy Markdown
Contributor

Note that org.apache.camel.* is only a Camel 1.x feature. In Camel v2 onwards its changed to Camel* syntax, so essentially this is obsolete to filter.

@github-actions
Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

🧪 CI tested the following changed modules:

  • components/camel-aws/camel-aws2-sns
  • components/camel-aws/camel-aws2-sqs
  • components/camel-azure/camel-azure-servicebus
  • components/camel-coap
  • components/camel-cometd
  • components/camel-cxf/camel-cxf-rest
  • components/camel-cxf/camel-cxf-transport
  • components/camel-google/camel-google-pubsub
  • components/camel-http-base
  • components/camel-http-common
  • components/camel-http
  • components/camel-iggy
  • components/camel-jetty
  • components/camel-jms
  • components/camel-kafka
  • components/camel-knative/camel-knative-http
  • components/camel-mail
  • components/camel-nats
  • components/camel-netty-http
  • components/camel-sjms
  • components/camel-spring-parent/camel-spring-rabbitmq
  • components/camel-vertx/camel-vertx-http
  • components/camel-vertx/camel-vertx-websocket
  • components/camel-xmpp
  • core/camel-core
  • core/camel-support
  • docs

ℹ️ Dependent modules were not tested because the total number of affected modules exceeded the threshold (50). Use the test-dependents label to force testing all dependents.

⚠️ Some tests are disabled on GitHub Actions (@DisabledIfSystemProperty(named = "ci.env.name")) and require manual verification:

  • components/camel-iggy: 4 test(s) disabled on GitHub Actions
  • components/camel-jetty: 1 test(s) disabled on GitHub Actions
  • components/camel-jms: 1 test(s) disabled on GitHub Actions
  • components/camel-kafka: 2 test(s) disabled on GitHub Actions
  • components/camel-xmpp: 6 test(s) disabled on GitHub Actions
  • core/camel-core: 2 test(s) disabled on GitHub Actions
Build reactor — dependencies compiled but only changed modules were tested (27 modules)
  • Camel :: AWS2 SNS
  • Camel :: AWS2 SQS
  • Camel :: Azure :: ServiceBus
  • Camel :: CXF :: REST
  • Camel :: CXF :: Transport
  • Camel :: CoAP
  • Camel :: Cometd
  • Camel :: Core
  • Camel :: Docs
  • Camel :: Google :: PubSub
  • Camel :: HTTP
  • Camel :: HTTP :: Base
  • Camel :: HTTP :: Common
  • Camel :: Iggy
  • Camel :: JMS
  • Camel :: Jetty
  • Camel :: Kafka
  • Camel :: Knative HTTP
  • Camel :: Mail
  • Camel :: Nats
  • Camel :: Netty HTTP
  • Camel :: Simple JMS
  • Camel :: Spring RabbitMQ
  • Camel :: Support
  • Camel :: Vert.x :: HTTP
  • Camel :: Vert.x :: WebSocket
  • Camel :: XMPP

⚙️ View full build and test results

@ammachado ammachado marked this pull request as draft June 1, 2026 15:03
@ammachado ammachado marked this pull request as ready for review June 1, 2026 15:32
Copy link
Copy Markdown
Contributor

@davsclaus davsclaus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convention & Correctness Review

Well-structured security hardening PR that centralizes header filtering from 20+ component-specific strategies into DefaultHeaderFilterStrategy. The approach is sound, the .clone() on field initializers prevents shared mutable state, the JMS opt-out is correctly implemented with good test coverage, and all existing subclasses are touched — no unintentional inheritance gaps.

Findings

1. PR description claims CAMEL_FILTER_STARTS_WITH extended — but it wasn't

The description states CAMEL_FILTER_STARTS_WITH was extended to ["Camel", "camel", "org.apache.camel"]. The code does not change this constant — it remains ["Camel", "camel"]. The new core tests correctly assert that org.apache.camel.* headers pass through (which aligns with the committer's comment that this prefix is a Camel 1.x artifact). The PR description should be corrected to avoid misleading future readers.

2. Dead/inconsistent org.apache.camel code in CAMEL_FILTER_PATTERN and tryPattern

The deprecated CAMEL_FILTER_PATTERN regex and the tryPattern optimization were updated to also match org.apache.camel, but CAMEL_FILTER_STARTS_WITH (the active mechanism) does not include it, and no code in the codebase references CAMEL_FILTER_PATTERN anymore. This creates an inconsistency — the deprecated pattern matches org.apache.camel, the startsWith doesn't, and the tryPattern optimization handles it but never executes. Consider reverting these changes for consistency.

3. HttpProtocolHeaderFilterStrategy asymmetric opt-out

Only setInFilterStartsWith((String[]) null) is added. The outbound direction now inherits the default Camel filter via the field initializer. While this strategy is primarily used for inbound filtering in HttpProducer.copyHeaders(), the asymmetry could surprise someone using it for outbound. Consider also nulling outbound for symmetry, or adding a comment explaining the inbound-only intent.

4. Minor: regex bug fix in deprecated CAMEL_FILTER_PATTERN not called out

The original pattern had A-z (which accidentally includes ASCII chars [\]^_\``) — the PR fixes this to A-Z`. Genuine bug fix but not mentioned in the description or upgrade guide.

No Issues Found

  • All 6 deleted subclasses verified as pure no-ops — correct to remove
  • ClassicJmsHeaderFilterStrategy opt-out properly implemented and well-tested
  • setLowerCase(true) removal safe — default already true on main
  • Upgrade guide is comprehensive with opt-out guidance
  • evalFilterMatch refactoring is logically equivalent

This review covers project conventions and correctness. It does not replace specialized review tools such as CodeRabbit, Sourcery, or SonarCloud.

This review was generated by an AI agent (Claude Code on behalf of Claus Ibsen) and may contain inaccuracies. Please verify all suggestions before applying.

ammachado and others added 7 commits June 6, 2026 17:27
…efaultHeaderFilterStrategy

- Default `inFilterStartsWith` and `outFilterStartsWith` to `CAMEL_FILTER_STARTS_WITH` in
  `DefaultHeaderFilterStrategy`, so all consumers and producers block `Camel*`, `camel*`, and
  `org.apache.camel.*` headers by default without per-component boilerplate
- Extend `CAMEL_FILTER_STARTS_WITH` to include `org.apache.camel.` alongside `Camel` and `camel`
- Remove now-redundant `setInFilterStartsWith` / `setOutFilterStartsWith(CAMEL_FILTER_STARTS_WITH)`
  calls from 20+ component-specific strategies
- `ClassicJmsHeaderFilterStrategy` explicitly opts out (null) to preserve legacy pass-through behavior
- `KafkaHeaderFilterStrategy` builds its array from the constant + `kafka.` via `Arrays.copyOf`
- `Sns2` / `Sqs2` / `KnativeHttp` replace redundant regex patterns with a `getOutFilter().add("breadcrumbId")`
  set entry (SNS/SQS) or no extra filtering (Knative), relying on the default startsWith
- Add tests verifying both directions filter by default; update 4.21 upgrade guide

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
…trategy subclasses

- DefaultHeaderFilterStrategy: use .clone() on field initializers so each
  instance gets its own array copy; mutating the public CAMEL_FILTER_STARTS_WITH
  constant no longer corrupts all instances
- Change CAMEL_FILTER_STARTS_WITH from "org.apache.camel." to "org.apache.camel"
  (no trailing dot) so the bare prefix "org.apache.camel" is also blocked
- Update deprecated CAMEL_FILTER_PATTERN regex and its fast-path in tryPattern
  to cover the org.apache.camel namespace consistently
- Remove redundant setLowerCase(true) calls from HTTP strategies (lowerCase=true
  is already the field-initializer default)
- Fix HttpBridgeMultipartRouteTest inner strategy: remove setLowerCase(true) and
  the now-redundant setOutFilterStartsWith(CAMEL_FILTER_STARTS_WITH) call
- Add ClassicJmsHeaderFilterStrategyTest to directly assert Camel headers pass
  through in both directions in legacy mode (opt-out via null startsWith)
- Expand upgrade guide to cover subclass authors, not just direct instantiators;
  add pointer to ClassicJmsHeaderFilterStrategy as a worked opt-out example
- Remove six no-op header filter strategy subclasses whose only body was
  setLowerCase(true), which is now the default: CoAPHeaderFilterStrategy,
  CometdHeaderFilterStrategy, IggyHeaderFilterStrategy, NatsHeaderFilterStrategy,
  VertxWebsocketHeaderFilterStrategy, XmppHeaderFilterStrategy. Update all
  callers to instantiate DefaultHeaderFilterStrategy directly. Delete associated
  test files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
- Remove org.apache.camel from CAMEL_FILTER_STARTS_WITH: this prefix
  was a Camel 1.x artifact; Camel 2+ uses Camel* syntax only
- Add upgrade guide note listing the 6 removed header filter strategy
  classes and directing users to use DefaultHeaderFilterStrategy instead

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Signed-off-by: Adriano Machado <60320+ammachado@users.noreply.github.com>

Signed-off-by: Adriano Machado <60320+ammachado@users.noreply.github.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
…pt-out

DefaultHeaderFilterStrategy already defaults lowerCase to true; remove
the redundant setLowerCase(true) calls from all subclasses. Also add
upgrade guide note on setLowerCase(false) for users who need case-sensitive
header matching.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
…eaders in copyHeaders

HttpProtocolHeaderFilterStrategy inherited the new default inFilterStartsWith
(["Camel", "camel"]) from DefaultHeaderFilterStrategy, causing MessageHelper.copyHeaders
in HttpProducer to silently drop Camel-prefixed headers (e.g. CamelFileName) from the
request exchange when building the response message. Reset inFilterStartsWith to null in
initialize() since this strategy only filters HTTP protocol headers, not Camel internals.

Also: switch HttpProducer to import from camel-http-base directly, deprecate the empty
camel-http-common wrapper class, and document both in the 4.21 upgrade guide.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
- Revert CAMEL_FILTER_PATTERN and tryPattern to their original state;
  the org.apache.camel prefix is a Camel 1.x artifact and adding it to
  the deprecated constant created inconsistency with CAMEL_FILTER_STARTS_WITH.
- Add setOutFilterStartsWith(null) to HttpProtocolHeaderFilterStrategy for
  symmetry with the inbound opt-out already present.
- Clarify upgrade guide: deleted strategy classes should be replaced with
  `new DefaultHeaderFilterStrategy()` (not just the class name).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ammachado
Copy link
Copy Markdown
Contributor Author

Root cause analysis for NatsProducerReplyToIT and NatsConsumerWithRedeliveryIT failures

Claude Code on behalf of Adriano Machado

Both tests were broken by commit 76479634bf35(CAMEL-23676: camel-nats - Only send reply when exchange pattern is InOut), which is in the common ancestor of this branch and main. That commit changed NatsConsumer to only publish a reply to msg.getReplyTo() when exchange.getPattern().isOutCapable(). Since NatsEndpoint defaults to InOnly, consumer exchanges are InOnly by default and the reply is never published unless the endpoint URI explicitly sets exchangePattern=InOut.

Both failing tests use template.requestBody(...), which creates an InOut exchange on the producer side. The NATS producer therefore calls connection.request(), attaching a reply-to inbox to the message. The consumer receives the message, but because its exchange is InOnly, the isOutCapable() check fails and the reply is never sent. The producer then blocks until the 20-second requestTimeout fires, causing the test to fail with an ExchangeTimedOutException.

These issues are addressed by PR #23811.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants