Skip to content

OIDC credential collision when multiple registries share a host #87

@kbukum1

Description

@kbukum1

Problem

When two or more private registries of the same ecosystem share the same hostname but use different URL paths (e.g., two Azure DevOps feeds on pkgs.dev.azure.com), the OIDC credential for the second registry silently overwrites the first.

This happens because each handler stores OIDC credentials in a map[string]*OIDCCredential keyed by hostname only. Since both registries resolve to the same hostname, the map key collides.

Impact

  • The first registry loses its OIDC credential and falls back to static auth (or fails)
  • Only the last-registered credential for a given host is used
  • Affects handlers that use cred.Host() as the OIDC map key: Python, Composer, Maven, Terraform, npm, NuGet

Reproduction

Configure two Azure DevOps feeds for the same ecosystem (e.g., two Python indexes):

[
  {"type": "python_index", "index-url": "https://pkgs.dev.azure.com/org/project/_packaging/feed-A/pypi/simple/", ...oidc config...},
  {"type": "python_index", "index-url": "https://pkgs.dev.azure.com/org/project/_packaging/feed-B/pypi/simple/", ...oidc config...}
]

Both resolve to hostname pkgs.dev.azure.com. The second credential overwrites the first in the OIDC map. Requests to feed-A use feed-B's token (or fail).

Fix

Introduce a shared OIDCRegistry type that stores credentials in a map[hostname][]entry structure, where each entry includes the parsed URL path. Lookup uses longest path-prefix matching to select the correct credential.

Acceptance Criteria

  • OIDCRegistry type exists with Register(), RegisterURL(), and TryAuth() methods (Add generalized OIDCRegistry for collision-free credential storage #78)
  • Multiple OIDC credentials on the same host with different paths do not collide
  • Longest path-prefix matching selects the most specific credential for a request
  • All 13 handlers migrated to use OIDCRegistry (Migrate cargo handler to OIDCRegistry #79-Migrate nuget handler to OIDCRegistry #92)
  • Handlers that previously used hostname-only keys now use full URL keys (Python, Composer, Maven, Terraform, npm, NuGet)
  • Handlers that already used full URL/registry keys have no behavior change (Cargo, Docker, Helm, Rubygems, Goproxy, Pub, Hex)
  • NuGet HTTP-discovered resource URLs registered via RegisterURL()
  • Cloudsmith X-Api-Key handling works through OIDCRegistry.TryAuth()
  • Case-insensitive hostname matching preserved
  • Port-aware matching preserved
  • Deprecated TryAuthOIDCRequestWithPrefix() removed after all handlers migrated
  • All existing tests pass; no regressions in static credential handling

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions