CAMEL-24436/24450/24452/24456: CORS and credential scoping fixes, backport to camel-4.22.x - #25937
Conversation
…hat shapes the token (apache#25834) * CAMEL-24456: camel-http - key the OAuth2 token cache on every field that shapes the token The cache key was the record OAuth2URIAndCredentials(uri, clientId, clientSecret), while scope, tokenEndpoint and resourceIndicator all influence the token that getAccessTokenResponse() mints. The map is static, so it is shared by every OAuth2ClientConfigurer instance and every CamelContext in the JVM. A route configured with a narrow scope could therefore be handed a broad-scope token that another route had cached first for the same target and credentials, which defeats the scoping the operator configured and makes the audit trail misleading. Where several CamelContexts run in one JVM, a token minted for one could serve another's requests. Add tokenEndpoint, scope and resourceIndicator to the key. The map stays JVM wide, but a hit now requires every field of the token request to match, so it is the same token request by construction; scoping the cache per CamelContext is noted on the issue as a separate question. The added test follows the idiom of the tests around it: cache a token, close the token endpoint, then request the same target with a different scope. A cache hit succeeds, a miss cannot mint and fails - so without the fix the narrow-scope token is silently reused. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Andrea Cosentino <ancosen@gmail.com> * CAMEL-24456: Regenerate YAML DSL schema --------- Signed-off-by: Andrea Cosentino <ancosen@gmail.com> (cherry picked from commit 4e2ddab) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… the operator did not name (apache#25829) enableCORS=true added new CrossOriginFilter() with no init parameters, so Jetty's own defaults applied. Confirmed against jetty-ee10-servlets 12.1.12: DEFAULT_ALLOWED_ORIGINS is "*" and credentials default to true. The filter reflects the request's origin rather than sending "*", so that pairing is the credentialed any-origin configuration the fetch specification refuses to express - reflecting the origin being the usual way around that rule. An option named "enable CORS" should not mean "every origin, with credentials". Default allowCredentials to false when CORS is enabled. The origin is still reflected, so enabling CORS keeps working for requests that carry no credentials; an operator who needs credentialed cross-origin requests sets filterInit.allowCredentials=true and names the origins in filterInit.allowedOrigins. Asking for credentials while leaving the origins at "*" is logged as a warning, since that combination reproduces the original behaviour. The defaults are applied where the init parameter map is built, not where the filter is added: the map is handed to the endpoint earlier and only when it is non-empty, so applying them later would drop them in exactly the case that matters - enableCORS on its own, with no filterInit parameters at all. EnableCORSTest.testCORSenabled asserted that credentials are granted, so it encoded the previous behaviour; it now asserts the opposite, and a second test covers the opt-in. Matches the change made to camel-platform-http-vertx under CAMEL-24436. Signed-off-by: Andrea Cosentino <ancosen@gmail.com> (cherry picked from commit 6e3e4ec) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… endpoint was not configured with (apache#25830) CAMEL-24452: camel-http - do not send credentials to a host the endpoint was not configured with Two paths handed credentials to a redirect target, which is a host chosen by the remote server rather than by the route, once followRedirects=true. OAuth2ClientConfigurer registers its interceptor with addRequestInterceptorFirst, and HttpClient runs protocol-level request interceptors inside ProtocolExec, which sits below RedirectExec in the exec chain. The interceptor therefore ran again for every redirect hop and re-attached Authorization: Bearer <token> to whatever host the Location header named. It now attaches the token only for the endpoint's own host. HttpCredentialsHelper.getCredentialsProvider() was called with the endpoint's authHost, which is optional and null in the common basic-auth configuration, making the scope new AuthScope(null, -1) - any host, any port, any scheme. HttpClient then offered the credentials to whichever host issued a 401 challenge. The scope now falls back to the endpoint's host when authHost is not set; an explicit authHost still takes precedence. Both need to know the host the endpoint addresses, which createHttpClientConfigurer did not receive. Rather than change that protected signature, a three argument overload carries the target URI and the existing two argument form delegates to it with null, so any subclass overriding or calling it keeps the previous behaviour. The added test drives a real redirect from a server answering to localhost to a second one answering to 127.0.0.1 - a single server will not do, because the bootstrap sets a canonical host name and answers 421 to a mismatched Host. Without the fix the first case delivers "Bearer xxx.yyy.zzz" and the second "Basic c2NvdHQ6dGlnZXI=" to the redirect target. Signed-off-by: Andrea Cosentino <ancosen@gmail.com> Signed-off-by: Croway <federico.mariani.1990@gmail.com> (cherry picked from commit 3a6c27b) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…for a configured origin (apache#25820) createCorsHandler() set Access-Control-Allow-Credentials: true outside the origin check, so it went out on every response to a request carrying an Origin header - including responses to origins the handler had just decided not to allow. And when camel.server.cors.origins is unset, allowsOrigin is true for every origin and the caller's own Origin is echoed back as Access-Control-Allow-Origin. Together those produce the credentialed any-origin configuration the fetch specification refuses to express as "*", which is why reflecting the origin is the usual way around that rule. Send Access-Control-Allow-Credentials only when the request origin matched an origin the operator actually configured. With no origin list the origin is still reflected, as before, but credentials are not granted. Also add Vary: Origin whenever the origin is reflected, so a shared cache cannot serve one origin's response to another. Signed-off-by: Andrea Cosentino <ancosen@gmail.com> (cherry picked from commit 4b557e4) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 63 tested, 29 compile-only — current: 63 all testedMaveniverse Scalpel detected 92 affected modules (current approach: 63).
|
gnodet
left a comment
There was a problem hiding this comment.
Clean cherry-pick backport of four already-reviewed security fixes (CORS and credential scoping) to camel-4.22.x.
All four original PRs were previously reviewed:
- #25834 (CAMEL-24456, OAuth2 token cache) — APPROVE
- #25829 (CAMEL-24450, jetty CORS credentials) — APPROVE
- #25830 (CAMEL-24452, HTTP credential leakage) — COMMENT
- #25820 (CAMEL-24436, vertx CORS credentials) — APPROVE
Straight cherry-picks with no manual conflict resolution, matching the sibling backport to camel-4.18.x (#25938).
📋 PR Metadata
| Aspect | Current | Suggested |
|---|---|---|
| Labels | components |
+ bug |
| Milestone | (none) | 4.22.0 |
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
Backport to
camel-4.22.xof four fixes already reviewed and merged onmain. All four are about a credential or a CORS grant reaching a party the operator never named.4e2ddabd)6e3e4ec5)3a6c27bf)4b557e4e)Straight cherry-picks, applied in the order they merged on
main, with no manual conflict resolution. The upgrade-guide entries are not included: the guides for every line live onmain.Behaviour changes to be aware of when upgrading a patch release:
enableCORS=trueon jetty no longer installs Jetty's allow-allCrossOriginFilterdefaults. A deployment that relied on any origin being accepted must now name its origins.Access-Control-Allow-Credentialsonly when the request origin matched a configured origin. With no origin list the origin is still reflected as before, but credentials are not granted, andVary: Originis now set.Authorizationon cross-authority redirects whenfollowRedirects=true.Built and tested per module on this branch (
camel-http,camel-jetty-common,camel-jetty,camel-platform-http-vertx), including the new and touched tests:HttpOAuth2TokenCachingTest,HttpOAuth2RedirectTokenLeakTest,HttpClientConfigurerOverrideTest,EnableCORSTest,VertxPlatformHttpEngineTest.Claude Code on behalf of oscerd