fix(auth): require audience when introspecting via Google tokeninfo - #6236
fix(auth): require audience when introspecting via Google tokeninfo#6236SashaMIT wants to merge 2 commits into
Conversation
Google's tokeninfo response carries no iss claim; the GoogleProvider synthesises iss locally, so a configured-issuer check against it is self-satisfying and proves nothing about which OAuth client the token was minted for. The only real binding to the deployment is the audience check - which is skipped when audience is empty. A deployment pointed at https://oauth2.googleapis.com/tokeninfo with no audience accepted ANY valid Google access token, including one minted for an unrelated attacker-controlled OAuth client. NewTokenValidator now refuses that combination at startup instead of silently accepting cross-client tokens at runtime.
jhrozek
left a comment
There was a problem hiding this comment.
Nice fix, this closes a real gap — tokeninfo doesn't give you a verifiable iss so audience was the only thing actually binding the token to this deployment. Two small optional nits below, neither blocking.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6236 +/- ##
==========================================
+ Coverage 72.54% 72.87% +0.32%
==========================================
Files 739 742 +3
Lines 76851 77786 +935
==========================================
+ Hits 55755 56688 +933
+ Misses 17113 17107 -6
- Partials 3983 3991 +8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Extract JWKS-discovery resolution and the Google tokeninfo audience check into their own functions so NewTokenValidator's cyclomatic complexity drops back under the gocyclo threshold, which CI was failing on. Also apply the two open review nits: trim whitespace on the audience check and make the new test table-driven.
|
Thanks for landing the nits yourself. Trim on audience and the table-driven test are the right shape, and pulling the Google tokeninfo check out of NewTokenValidator is cleaner than fighting gocyclo. Happy to leave the rest with you. |
jhrozek
left a comment
There was a problem hiding this comment.
Both nits addressed (helper extraction fixes the gocyclo lint failure too). CI green aside from the pre-existing, unrelated GitHub Actions Static Analysis failure that's also failing on main.
Problem
The Google tokeninfo path has a validation hole:
issclaim.GoogleProvider.parseGoogleResponse(token.go) compensates by settingclaims["iss"] = "https://accounts.google.com"locally.validateClaimsthen compares that fabricated value against the configured issuer — a check that is self-satisfying: it passes for every token tokeninfo accepts and proves nothing about which OAuth client the token was minted for.if v.audience != "". Audience is optional everywhere —NewTokenValidatordoesn't require it,--oidc-audiencedefaults to empty, the operator CRD marks it Optional.Net effect: a deployment configured with issuer
https://accounts.google.com+ introspection URLhttps://oauth2.googleapis.com/tokeninfo+ no audience accepts any valid Google OAuth access token — including one minted for an unrelated attacker-registered OAuth client. That token passesValidateToken, becomes anauth.Identity, and lands in the request context.Fix
NewTokenValidatorrefusesIntrospectionURL == GoogleTokeninfoURLwith an empty audience at startup, with an error explaining why. Fail-closed beats a silently-accepting runtime.Tests
New
TestNewTokenValidator_GoogleTokeninfoRequiresAudience: tokeninfo-without-audience is rejected with the explanatory error; the same config with an audience is accepted. Fullpkg/authsuite passes.Made with Cursor
Made with Cursor