Repository navigation
fix(federation)!: keep static client keys, RP choices and empty values within policy - #697
Merged
Merged
Conversation
Resolving a Trust Chain fetches each authority hint's Entity Configuration and the Subordinate Statement from the federation_fetch_endpoint it names before any statement on the path is verified against a Trust Anchor, so the party controlling the subject chooses those URLs (host, port, path and query, with only "sub" added). On an authorization server with automatic registration this happens for any client_id an unauthenticated caller names, before client authentication. Document this on Resolver.Resolve, Dependencies.HTTP, AutomaticClientRepository, server.Dependencies.FederationHTTP and the OpenID Federation guide, and on fapihttp.Config.AllowedPrivateHosts: a host allow-listed there is reachable through this path by unauthenticated callers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s within policy AutomaticClientKeySource fell back to a client's federation-published keys whenever the underlying key source returned an error or no key, including for statically registered clients. A statically registered client whose client_id is also an Entity Identifier resolving under a configured Trust Anchor could therefore be authenticated with a key its federation metadata publishes, which any superior in its Trust Chain can set, and receive the static registration's scopes and grants. Keys now come from the same source as the registration: a client the underlying client repository resolves gets its keys from the underlying key source alone, a federation client from its openid_relying_party metadata alone, and an unavailable client store is an error. A superior's one_of or value policy on token_endpoint_auth_signing_alg or token_endpoint_auth_method only checked that parameter, and only when present (OpenID Federation 1.0 section 6.1.3.1.4), so an RP could leave it out and register a forbidden value through its OpenID Connect RP Metadata Choices 1.0 plural sibling, or take the OP's default algorithms. The resolver now keeps the merged metadata policy on the ResolvedEntity, and automatic registration limits the plural values and the defaults to what the policy permits for the singular parameter, refusing an RP left with none. An empty plural array, which subset_of can produce, is refused instead of being read as absent. Registering every mutually supported method stays as section 12.1.4 recommends. An empty string still counted as present to a metadata policy, so it met an essential policy, while automatic registration read it as unset for parameters other than the encryption algorithms. Automatic registration now refuses an empty string for every string parameter it reads. BREAKING CHANGE: a statically registered client is authenticated only with keys from Dependencies.ClientKeys, never with ones its federation metadata publishes, and a federation client only with its federation keys. Automatic registration no longer registers a client authentication method or assertion algorithm outside a superior's policy on token_endpoint_auth_method or token_endpoint_auth_signing_alg, refuses an empty token_endpoint_auth_methods_supported or token_endpoint_auth_signing_alg_values_supported, and refuses an empty string for any string parameter it reads. See UPGRADING.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…checks into helpers Keeps both tests' cognitive complexity within the analyzer's limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Three automatic-registration fixes, plus documentation of pre-trust fetching.
Static client keys (
AutomaticClientKeySource). Keys used to fall back to a client's federation-publishedjwkswheneverDependencies.ClientKeysreturned an error or no matching key, including for statically registered clients. A static client whoseclient_idis also an Entity Identifier resolving under a configured Trust Anchor could then be authenticated with a key its federation metadata publishes (which any superior in the chain can set), and get the static registration's scopes and grants. Keys now come from the same source as the registration:ClientRepositoryresolves gets its keys from the underlying key source only. An error or an empty set from that source is returned as is.openid_relying_partymetadata only.storage.ErrStoreUnavailablefrom the repository is returned, not read as "not static".RP Metadata Choices vs. a superior's policy. A
one_of/valuepolicy ontoken_endpoint_auth_signing_algortoken_endpoint_auth_methodis checked only on that parameter, and only when it is present (Federation 1.0 §6.1.3.1.4). An RP could leave the singular parameter out and register a forbidden value through*_values_supported/token_endpoint_auth_methods_supported, or name no algorithm and get all of the OP's defaults. The changes:Resolvernow keeps the merged metadata policy on theResolvedEntityin an unexported field. Resolved Metadata output is unchanged.subset_ofcan leave) is now refused. Before, it was read as absent, so the defaults applied.Registering every mutually supported method from
token_endpoint_auth_methods_supportedwhenAllowedClientAuthMethodsis empty is unchanged. Federation 1.0 §12.1.4 says OPs "SHOULD accept any client authentication method that is mutually supported", because the OP can't know which one the RP will use. The only narrowing added is the policy limit ontoken_endpoint_auth_methoddescribed above.Empty strings. cf067f6 made
nullcount as absent in the policy engine and refused""for the four encryption parameters. Everywhere else,""still counted as present toessential(§6.1.3.1.7 only requires presence), while registration read it as unset, sosubject_type: ""under an essential policy got the OP's default. Automatic registration now refuses""for every string parameter it reads. The list comes fromrelyingPartyMetadata's json tags, so a newly read parameter is covered automatically. The policy engine is unchanged and stays spec-literal.Docs only (pre-trust fetching). While a Trust Chain is being resolved, each untrusted superior's
federation_fetch_endpointis fetched before anything is verified against a Trust Anchor. On an AS, that happens for anyclient_idan unauthenticated caller names. This is now documented on:Resolver.Resolvefederation.Dependencies.HTTPAutomaticClientRepositoryserver.Dependencies.FederationHTTPfapihttp.Config.AllowedPrivateHosts: an allow-listed host is reachable through this path by unauthenticated callers.Breaking
This is
fix!, and UPGRADING.md has a v0.61.0 section for each behavior change:Dependencies.ClientKeys.""is refused for any string parameter registration reads.Tests
server/automatic_registration_static_keys_test.go: a static client also resolvable through federation still gets a token with its static key. An assertion signed with the federation-published key is now refused. This test fails onmain.federation: static and federation key-source separation (empty, error and unavailable-store cases); policy limits on plural algorithms and methods and on defaults, plus thesubset_of-emptied list;""refusal for several parameters underessential.internal/federation:PermittedStrings.GOTOOLCHAIN=go1.26.9 go test ./...,go vet ./...(includingGOARCH=arm),golangci-lint run ./...and the federated-union example tests all pass.🤖 Generated with Claude Code