oscerd opened a new pull request, #27719: URL: https://github.com/apache/camel/pull/27719
## Description [CAMEL-25578](https://issues.apache.org/jira/browse/CAMEL-25578) The LRA participant routes (`PUT <localParticipantContextPath>/compensate` and `/complete`) take the saga step endpoint and the saga options from the callback URL that the participant enlisted with the LRA coordinator. This adds an optional shared secret to the LRA saga service, so the participant can sign those callback URLs and verify them when the coordinator calls back. - New `callbackSecret` option on `LRASagaService`, also available as `camel.lra.callbackSecret` in camel-main (`security = "secret"`). - When it is set, `LRAClient.join()` adds a `Camel-Saga-Signature` query parameter to the compensate and complete URLs. It is an HMAC-SHA256 over the callback path and every query parameter (step URIs and saga options), sorted and encoded one by one, so it does not depend on how the coordinator orders or re-encodes the URL. Each URL is signed for its own path, so a compensate URL is not accepted on `/complete`. - `LRASagaRoutes` verifies the signature, in constant time, against the raw query (`CamelHttpQuery`) before the existing allowlist check. A missing or invalid signature gets HTTP 403 and is not routed any further. When it is valid, the step URIs and the saga options are set from the signed parameters, so a request header with the same name as an option does not reach the step endpoint. - Without a secret the behaviour is unchanged, and the service logs a warning at startup that the callbacks are not signed. - `callbacksecret` is added to the extra sensitive keys of `UpdateSensitizeHelper` (the option is not in a component JSON, so the scan cannot find it), so camel-main masks the value when it logs its configuration. `SensitiveUtils` is regenerated. - Docs: a "Signing the participant callbacks" section in the Saga EIP page, with a pointer from the LRA page. It also says that, without a secret, the participant endpoints are meant to be reachable by the LRA coordinator only. ## Tests - `LRACallbackSignerTest`: the signature is bound to the parameters, the callback path and the secret; it does not depend on the parameter order; a null option value signs as an empty one. - `LRAClientTest`: `join()` signs both callback URLs when a secret is set, and leaves them unsigned otherwise. - `LRASagaRoutesCallbackSignatureTest` (HTTP, camel-undertow): signed callbacks are routed with the signed values; a missing or changed signature, and a compensate signature used on `/complete`, get 403 and do not reach the step endpoint; signed values take precedence over request headers; the URI allowlist still applies. - `LRASignedCallbacksIT`: runs the `LRAOptionsIT` tests with a secret, against the LRA coordinator container, so the coordinator calls back signed URLs. Run locally together with `LRAOptionsIT`: 6 tests, all green. ## Follow-ups - camel-spring-boot: `camel-lra-starter` sets the LRA service options one by one in `LraServiceAutoConfiguration`, so it needs the new option. - Backports to `camel-4.22.x` and `camel-4.18.x` after this is merged. On 4.18.x the port needs adapting (`@Metadata(secret = true)`, and the LRA code there predates the URL-encoding of the callback parameters). _Claude Code on behalf of oscerd_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
