Skip to content

CAMEL-25918: camel-as2 - consumers sharing a port use their own asynchronous MDN settings - #28274

Merged
davsclaus merged 2 commits into
apache:mainfrom
oscerd:fix/CAMEL-25918
Oct 23, 2026
Merged

davsclaus merged 2 commits into
apache:mainfrom
oscerd:fix/CAMEL-25918

Conversation

@oscerd

@oscerd oscerd commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Jira: https://issues.apache.org/jira/browse/CAMEL-25918

Problem

AS2ConnectionHelper keeps one AS2ServerConnection per serverPortNumber, built from the first endpoint created on that port. Since CAMEL-22557 the signing and decrypting material is selected per request path (AS2ServerConnection.AS2ConsumerConfiguration, registered by AS2Consumer.doStart for the consumer's requestUriPattern), but the asynchronous MDN settings (mdnUserName, mdnPassword and mdnAccessToken, added by CAMEL-21875, and asyncMdnAllowedHosts) stayed connection-wide fields taken from the first endpoint only.

When several as2://server/listen consumers share a port with different requestUriPattern values:

  • the asynchronous MDN for a message received on a second consumer's path was delivered with the first consumer's MDN settings, and the second consumer's own values were ignored without anything being logged;
  • a consumer with the default / pattern never registered its own configuration when another endpoint had created the connection (doStart only registered when no configuration matched, and the constructor's / fallback always matched);
  • the first consumer's MDN settings stayed in use for the other consumers after the first consumer's route was stopped, because unlisten removes only the path's handler and configuration.

A single consumer per port is not affected. The four options are documented as endpoint options, so each consumer is expected to apply its own values.

Change

  • camel-as2-api, AS2ServerConnection: AS2ConsumerConfiguration carries mdnUserName, mdnPassword, mdnAccessToken and asyncMdnAllowedHosts through a new constructor; the existing five-argument constructor stays and delegates with null values. handleAsynchronousMDN builds the AS2AsynchronousMDNManager from the matched path's configuration instead of the connection-level fields, which are removed. The / fallback registered by the constructor carries the constructor's values, so direct users of AS2ServerConnection and single-consumer deployments behave as before. The javadoc of registerConsumerConfiguration states that each consumer registers its own configuration for its own pattern.
  • camel-as2-component, AS2Consumer.doStart: registers the consumer's own configuration (keys, certificates and MDN settings) for its own requestUriPattern, replacing the / fallback when the pattern is /.
  • AS2Configuration: the javadoc of the four options states that they apply to the consumer endpoint they are set on; as2.json, the catalog mirror and AS2EndpointBuilderFactory are regenerated.
  • as2-component.adoc: a note under Usage that consumers sharing a serverPortNumber each apply their own keys and asynchronous MDN settings.
  • Upgrade guide 4.24: consumers that share a port now use their own settings; a consumer that relied on inheriting the first consumer's values has to set them itself. The backports will add the same note to the 4.22 and 4.18 guides on main.

Tests

  • AS2ServerTwoConsumerAsyncMdnSettingsTest (camel-as2-component): four consumers on one port (a first consumer with basic authentication and an allowed-host list, a second with a bearer token and its own list, one without settings, one on the default / pattern) and local receipt endpoints. The asynchronous MDN for the second consumer carries its own bearer token and follows its own allowed-host list; a consumer without settings sends no Authorization header; the consumer on / uses its own token; the first consumer is unchanged; after the first consumer's route stops, the remaining consumer's settings are used. Without the change, the five tests about the other consumers fail (the MDN carried the first consumer's basic authentication, or followed its allowed-host list).
  • AS2ConsumerConfigurationMdnSettingsTest (camel-as2-api): the per-path configuration carries the settings, the / fallback carries the constructor's values, and registering a path again replaces its configuration.
  • Existing tests kept green: AS2AsyncMdnBasicAuthHeaderTest, AS2AsyncMdnTokenAuthHeaderTest, AS2AsyncMdnContextReuseTest, AS2AsynchronousMDNManagerDeliveryAddressTest, the camel-as2-api and camel-as2-component unit tests, and AS2ServerTwoConsumerSecEncryptedIT.

Claude Code on behalf of oscerd

🤖 Generated with Claude Code

…hronous MDN settings

AS2 consumers that share a serverPortNumber delivered their asynchronous
MDNs with the mdnUserName, mdnPassword, mdnAccessToken and
asyncMdnAllowedHosts of the first endpoint created on the port: the
shared AS2ServerConnection kept those values as connection-wide fields,
while the signing material was already selected per request path. The
MDN settings are now part of the per-path AS2ConsumerConfiguration. Each
consumer registers its own values for its own requestUriPattern, also
for the default "/" pattern, which no longer inherits the fallback, and
the asynchronous MDN of a request uses the settings of the matched path.
The fallback configuration of the root path carries the values given to
the connection's constructor, so direct users of AS2ServerConnection
behave as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Clean, well-scoped fix. The move of async MDN settings (username, password, access token, allowed hosts) from connection-level fields into AS2ConsumerConfiguration is the right design — it allows consumers sharing a port to each have their own async MDN configuration.

Implementation looks correct:

  • doStop properly cleans up via unlisten → consumerConfigurations.remove
  • doStart unconditionally re-registers, which is correct for restart scenarios
  • synchronizedMap provides adequate per-operation thread safety for the ConcurrentHashMap-backed structure
  • All 6 integration tests are confirmed to cover the multi-consumer scenarios this fixes

💡 Minor nit: The new 9-arg AS2ConsumerConfiguration constructor (with mdnUserName, mdnPassword, mdnAccessToken, asyncMdnAllowedHosts) is missing a Javadoc comment, while the 5-arg constructor has one. Consider adding a /** ... */ block to keep the API documented consistently.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@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.

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks Andrea,

The change looks good to me. The asynchronous MDN settings are now picked from the configuration matched for the request path, the same way the signing material already is. AS2Consumer.doStart now always registers the consumer's own configuration, and that also covers the consumer on / that used to keep the fallback built from the first endpoint. Registering the same pattern again also keeps the configuration in step with the handler: listen already used the last consumer, while the configuration used to stay with the first one. The old 5-argument AS2ConsumerConfiguration constructor is kept, so direct users of camel-as2-api are not affected. The tests cover each case from the JIRA.

Two optional doc points inline: the settings that are still per port (shared AS2ServerConnection), and the asyncMdnAllowedHosts change in the upgrade guide.

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

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • catalog/camel-catalog
  • components/camel-as2/camel-as2-api
  • components/camel-as2/camel-as2-component
  • docs
  • dsl/camel-endpointdsl

🔁 1 test passed only after a retry on JDK 21 (1 retried attempt)

Recovered flaky tests on JDK 21 (1)
Module Test Failed attempts First failure
dsl/camel-jbang/camel-jbang-plugin-tui LaunchManagerOutcomeTest.startedWhenTheStatusFileSaysSo 1 expected: null but was: LaunchOutcome[ok=false, log=null]

ℹ️ These tests did not fail the build. Surefire retried them and they passed.
Retries are enabled project-wide by surefire.rerunFailingTestsCount in parent/pom.xml.


🔬 Scalpel shadow comparison — Scalpel: 9 of 707 tested, 24 compile-only — current: 9 all tested

Maveniverse Scalpel detected 9 affected modules (current approach: 9).

Skip-tests mode would test 9 modules (5 direct + 7 downstream), skip tests for 24 (generated code, meta-modules)

Modules Scalpel would test (9)
  • camel-as2 ← components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json, components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc, components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java, components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Consumer.java, components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerTwoConsumerAsyncMdnSettingsTest.java
  • camel-as2-api ← components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java, components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2ConsumerConfigurationMdnSettingsTest.java
  • camel-jbang-mcp ← downstream of org.apache.camel:camel-catalog
  • camel-jbang-plugin-mcp ← downstream of org.apache.camel:camel-jbang-core
  • camel-jbang-plugin-tui ← downstream of org.apache.camel:camel-catalog
  • camel-jbang-plugin-validate ← downstream of org.apache.camel:camel-yaml-dsl-validator
  • camel-launcher-container ← downstream of org.apache.camel:camel-launcher
  • camel-yaml-dsl-validator ← downstream of org.apache.camel:camel-catalog
  • camel-yaml-dsl-validator-maven-plugin ← downstream of org.apache.camel:camel-yaml-dsl-validator
Modules with tests skipped (24)
  • apache-camel
  • camel-allcomponents
  • camel-catalog-console
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • dummy-component

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

All tested modules (36 modules, 6m 10s total)

Total reactor time: 6m 10s

Module Duration Status
Camel :: JBang :: Plugin :: TUI 57.5s SUCCESS
Camel :: AS2 :: Component 40.3s SUCCESS
Camel :: Launcher 33.2s SUCCESS
Camel :: JBang :: MCP 28.9s SUCCESS
Camel :: JBang :: Plugin :: Validate 26.2s SUCCESS
Camel :: Component DSL 25.4s SUCCESS
Camel :: YAML DSL 21.5s SUCCESS
Camel :: Catalog :: Camel Catalog 17.5s SUCCESS
Camel :: YAML DSL :: Validator 17.1s SUCCESS
Camel :: AS2 :: API 14.2s SUCCESS
Camel :: Kamelet Main 11.8s SUCCESS
Camel :: Docs 9.8s SUCCESS
Camel :: JBang :: Plugin :: Kubernetes 9.0s SUCCESS
Camel :: YAML DSL :: Validator Maven Plugin 8.9s SUCCESS
Camel :: JBang :: Plugin :: Testing 7.7s SUCCESS
Camel :: YAML DSL :: Deserializers 6.5s SUCCESS
Camel :: Catalog :: Camel Route Parser 6.3s SUCCESS
Camel :: Catalog :: Camel Report Maven Plugin 6.0s SUCCESS
Camel :: All Components Sync point 4.7s SUCCESS
Camel :: YAML DSL :: Maven Plugins 2.6s SUCCESS
Camel :: Catalog :: Suggest (deprecated) 2.3s SUCCESS
Camel :: Catalog :: Maven 2.2s SUCCESS
Camel :: Assembly 2.0s SUCCESS
Camel :: Coverage 1.3s SUCCESS
Camel :: JBang :: Integration tests 1.3s SUCCESS
Camel :: JBang :: Plugin :: Edit 1.2s SUCCESS
Camel :: JBang :: Plugin :: Generate 1.0s SUCCESS
Camel :: Catalog :: Console 0.9s SUCCESS
Camel :: Catalog :: Dummy Component 0.8s SUCCESS
Camel :: Endpoint DSL :: Support 0.6s SUCCESS
Camel :: Launcher :: Container 0.6s SUCCESS
Camel :: JBang :: Main 0.6s SUCCESS
Camel :: JBang :: Plugin :: MCP 0.4s SUCCESS
Camel :: Endpoint DSL n/a
Camel :: Integration Tests n/a
Camel :: JBang :: Core n/a

Top 20 slowest modules:

  • Camel :: JBang :: Plugin :: TUI (57.5s)
  • Camel :: AS2 :: Component (40.3s)
  • Camel :: Launcher (33.2s)
  • Camel :: JBang :: MCP (28.9s)
  • Camel :: JBang :: Plugin :: Validate (26.2s)
  • Camel :: Component DSL (25.4s)
  • Camel :: YAML DSL (21.5s)
  • Camel :: Catalog :: Camel Catalog (17.5s)
  • Camel :: YAML DSL :: Validator (17.1s)
  • Camel :: AS2 :: API (14.2s)
  • Camel :: Kamelet Main (11.8s)
  • Camel :: Docs (9.8s)
  • Camel :: JBang :: Plugin :: Kubernetes (9.0s)
  • Camel :: YAML DSL :: Validator Maven Plugin (8.9s)
  • Camel :: JBang :: Plugin :: Testing (7.7s)
  • Camel :: YAML DSL :: Deserializers (6.5s)
  • Camel :: Catalog :: Camel Route Parser (6.3s)
  • Camel :: Catalog :: Camel Report Maven Plugin (6.0s)
  • Camel :: All Components Sync point (4.7s)
  • Camel :: YAML DSL :: Maven Plugins (2.6s)

⚙️ View full build and test results

… and the asyncMdnAllowedHosts change, javadoc for the MDN constructor

The component page says which settings still come from the first endpoint created on a shared port (the TLS context, mdnMessageTemplate, server, serverFqdn and as2Version), the upgrade-guide note says what changes for a consumer without its own asyncMdnAllowedHosts, and the AS2ConsumerConfiguration constructor that carries the asynchronous MDN settings has a javadoc like the one without them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
@oscerd

oscerd commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

Pushed one more commit for the review: "CAMEL-25918: Address review feedback - document the per-port settings and the asyncMdnAllowedHosts change, javadoc for the MDN constructor".

  • Component page (and its catalog copy): the settings that still belong to the shared server connection and come from the first endpoint created on the port — sslContextParameters/sslContext, mdnMessageTemplate, server, serverFqdn, as2Version — are now named as per-port settings, next to the paragraph on the per-consumer ones.
  • Upgrade guide: the asyncMdnAllowedHosts change is stated explicitly (inherited list before, delivery to the sender's address without credentials now, set the list on each consumer).
  • The nine-argument AS2ConsumerConfiguration constructor has a javadoc like the five-argument one (gnodet-bot's nit).

Documentation and javadoc only; no code change. Re-requested the review since the approval was given on the previous head.

Claude Code on behalf of oscerd

@oscerd
oscerd requested a review from davsclaus October 23, 2026 07:28

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Previous finding addressed. LGTM.

The only finding from my prior review — the missing Javadoc on the 9-argument AS2ConsumerConfiguration constructor — is now documented with a clear description of what the MDN credentials and asyncMdnAllowedHosts do. The 5-argument constructor got a matching doc block too. The component page now explicitly calls out which settings are per-consumer vs per-port, and the upgrade guide documents the asyncMdnAllowedHosts behavior change that davsclaus flagged.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks Andrea, the new commit addresses both doc points:

  • The component page (and its catalog copy, which is identical) lists the settings that still come from the first endpoint on the port.
  • The upgrade guide covers asyncMdnAllowedHosts. The text matches AS2AsynchronousMDNManager: isAllowedHost returns false when no list is set, so the MDN goes to the address the sender gives, without the Authorization header.

The new constructor javadoc also covers gnodet-bot's nit. This commit only changes docs and javadoc.

One heads-up: #28265 (AS2 HTTP proxy) changes the same parts of AS2Configuration.java, as2.json, the endpoint DSL and the end of as2-component.adoc. Whichever PR merges second will need a rebase and the generated files regenerated.

LGTM once CI is green.

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

@davsclaus davsclaus added this to the 4.24.0 milestone Oct 23, 2026
@davsclaus davsclaus added the bug Something isn't working label Oct 23, 2026
@davsclaus
davsclaus merged commit cb73720 into apache:main Oct 23, 2026
7 checks passed
@davsclaus davsclaus added port/camel-4.18.x Bug needs porting to camel-4.18.x port/camel-4.22.x Bug needs porting to camel-4.22.x labels Oct 23, 2026
@davsclaus

Copy link
Copy Markdown
Contributor

/port

@gnodet

gnodet commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

🔄 Backport Bot

Conflicts (🤖 agent dispatched to resolve):

  • ⚠️ camel-4.22.x — Cherry-pick conflict in: catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/as2-component.adoc, components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java, components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc, docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
  • ⚠️ camel-4.18.x — Cherry-pick conflict in: catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json, catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/as2-component.adoc, components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java, components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json, components/camel-as2/camel-as2-component/src/main/docs/as2-component.adoc

ℹ️ If you push additional commits after /port, use /port again to update the port PRs.

@gnodet

gnodet commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

✅ Backport to camel-4.22.x created: #28347

@gnodet

gnodet commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

✅ Backport to camel-4.18.x created: #28348

@gnodet gnodet removed the port/camel-4.18.x Bug needs porting to camel-4.18.x label Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants