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]

Reply via email to