oscerd opened a new pull request, #27781:
URL: https://github.com/apache/camel/pull/27781

   ## Backport of #27716
   
   Backport of #27716 (CAMEL-25564, merged on `main` as 60104cd3a195) onto 
`camel-4.22.x`.
   
   **Original PR:** #27716 - CAMEL-25564: camel-telegram - verify the Bot API 
secret token on webhook updates
   **Original author:** @oscerd
   **Target branch:** `camel-4.22.x`
   
   ### Differences from #27716
   
   This is not a straight cherry-pick, so it needs a review:
   
   - `TelegramAsyncHandler`: #27716 sits on CAMEL-25577 (#27761), which is on 
`main` only and removed the
     `AsyncCallback` from the handler. `camel-4.22.x` still has the 
five-argument constructor and the
     `finally { callback.done(false); }`. The change of #27716 (the HTTP method 
and the method of the Bot API instead of
     the request URI, in the TRACE log and in the exception messages) is 
applied to that version of the handler, and
     `TelegramServiceRestBotAPIAdapterErrorTest` passes a callback to it.
   - The upgrade-guide note is not part of the backport: it is on `main` 
already, in `camel-4x-upgrade-guide-4_22.adoc`
     ("Upgrading from 4.22.1 to 4.22.2").
   - The generated files are regenerated on this branch.
   
   The options, the endpoint, the webhook processor, the adapter, the component 
page and the other tests are identical
   to #27716.
   
   ### Tests
   
   - `camel-telegram` on `camel-4.22.x`: 105 tests, 0 failures (1 skipped, as 
before).
   - Full reactor `mvn clean install -DskipTests -DskipITs` on `camel-4.22.x`: 
green. Regenerated: the component JSON,
     configurer and URI factory, the catalog JSON and component page mirror, 
the endpoint DSL, and the `SecurityUtils`
     entry for `webhookSecretTokenEnabled`.
   
   ### Original description
   
   ## Description
   
   [CAMEL-25564](https://issues.apache.org/jira/browse/CAMEL-25564)
   
   In webhook mode, camel-telegram registered the webhook with the `url` 
parameter only. The Bot API's `setWebhook` also
   accepts a `secret_token`, which Telegram sends back in the 
`X-Telegram-Bot-Api-Secret-Token` header of every webhook
   request. This PR uses it:
   
   - New endpoint option `webhookSecretToken` (label `consumer,security`, 
marked as a secret). When it is not set, the
     token is derived from the authorization token: HMAC-SHA256, base64url 
without padding, so 43 characters from the set
     Telegram allows. A derived value, rather than a random one, stays the same 
across restarts and across replicas that
     serve the same webhook URL. It also lets the two sides of the 
`WebhookRoutePolicy` flow (a registration run and the
     serving instances, both with `webhookAutoRegister=false`) agree on the 
token without extra configuration. A
     configured value is checked against Telegram's rules: 1 to 256 characters, 
only `A-Z`, `a-z`, `0-9`, `_` and `-`.
   - New endpoint option `webhookSecretTokenEnabled` (default `true`, marked 
`insecure:dev` with insecure value `false`).
     Setting it to `false` restores the previous behaviour: the webhook is 
registered without a secret token, and webhook
     requests are not verified. The endpoint logs a WARN at startup in that 
case.
   - `TelegramEndpoint.registerWebhook()` passes the token to `setWebhook`, 
through a new
     `TelegramService.setWebhook(url, secretToken)` overload. The existing 
one-argument method is kept, and is used when
     the secret token is disabled.
   - `TelegramWebhookProcessor` compares the header with the token in constant 
time, before it parses the body. A
     request without the header, or with a different value, gets HTTP 403, is 
logged at WARN, and does not reach the
     route. The header is removed from the message, so the token is not passed 
on to the route.
   - The errors and TRACE logs of the Bot API requests no longer show the 
request URI, which contains the authorization
     token (and now the secret token of `setWebhook`). They show the HTTP 
method and the method of the Bot API instead,
     such as `Could not GET setWebhook: 401 ...` or `POST sendMessage 
responded: 400...`. This applies to
     `TelegramServiceRestBotAPIAdapter.sendSyncRequest` (`getUpdates`, 
`setWebhook`, `deleteWebhook`) and to the
     producer's `TelegramAsyncHandler`.
   - Docs: the webhook mode section of the component page, and upgrade-guide 
notes for 4.24, 4.22.2 and 4.18.6. The
     backports to `camel-4.22.x` and `camel-4.18.x` will follow once this is 
merged.
   
   ### Behaviour change
   
   - When Camel registers the webhook at startup (the default 
`webhookAutoRegister=true`), nothing needs to change:
     each upgraded instance registers the webhook with the token, and the 
instances that are not upgraded yet ignore the
     header.
   - When the webhook is registered in another way, through the 
`WebhookRoutePolicy` or outside Camel, the registration
     made with the previous version has no secret token, so the upgraded 
instances reject every update until the webhook
     is registered again with it. The upgrade notes give the safe order: 
register again first (the instances of the
     previous version ignore the header), then upgrade the instances that 
receive the updates. Outside Camel,
     `webhookSecretToken` must be set and passed as `secret_token`.
   - The default webhook path is a hash of the endpoint URI, so adding an 
option to the URI, such as
     `webhookSecretToken` or `webhookSecretTokenEnabled`, changes the path. 
When the webhook is not registered by Camel
     at startup, `webhookPath` keeps the registered path. The upgrade notes and 
the component page say so.
   - `webhookSecretTokenEnabled=false` restores the previous behaviour.
   - A client that calls the webhook endpoint directly must send the header. 
That includes two downstream tests:
     `TelegramWebhookCallTest` in camel-spring-boot (`camel-telegram-starter`), 
and `TelegramTest#testWebhookEndpoint`
     in the camel-quarkus telegram integration tests. As 
`deriveWebhookSecretToken` is package-private, they need to set
     `webhookSecretToken` and send the same value.
   
   ## Tests
   
   - `TelegramWebhookCallTest`: a request is accepted with the derived token 
and with a configured token, and the route
     does not see the header. A request without the header, or with a wrong 
value, gets 403, and the route is not invoked.
     With `webhookSecretTokenEnabled=false`, a request without the header 
reaches the route.
   - `TelegramWebhookSecretTokenTest`: the derived token is stable, differs for 
another authorization token and uses only
     the allowed characters. An invalid configured token is refused. 
Registration sends the derived token, or the
     configured one, as `secret_token`, and no `secret_token` when the secret 
token is disabled; this is checked against
     a mock Telegram API.
   - `TelegramServiceRestBotAPIAdapterErrorTest`: the error of a failed 
`setWebhook` (sync) and of a failed
     `sendMessage` (async) shows the HTTP method and the method of the Bot API, 
and neither the authorization token nor
     the secret token.
   - `camel-telegram`: 111 tests, 0 failures (1 skipped, as before), including 
`TelegramProducerFailureTest` from CAMEL-25577, which this branch is rebased on.
   - Full reactor `mvn clean install -DskipTests -DskipITs`: green; the 
regenerated files are included.
   
   
   _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