Skip to content

Add ext.cattle.io/v1 token support#632

Draft
pmatseykanets wants to merge 8 commits into
rancher:mainfrom
pmatseykanets:ext-cattle-token-support
Draft

Add ext.cattle.io/v1 token support#632
pmatseykanets wants to merge 8 commits into
rancher:mainfrom
pmatseykanets:ext-cattle-token-support

Conversation

@pmatseykanets

@pmatseykanets pmatseykanets commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Issue: rancher/rancher#55988

Problem

Rancher will migrate session tokens from management.cattle.io/v3 to ext.cattle.io/v1. When this lands, /v1-public/login will begin returning ext.cattle.io/v1 Token objects. Current CLI versions parse the login response as a v3.Token and would fail to extract the bearer from an ext.Token-shaped response.

The kubectl command also looks up the current user and validates the kubeconfig token via the v3.Token API only, so looking up an ext.Token would return 404 and stale-kubeconfig detection would surface the error instead of regenerating the config.

Solution

Accept both response shapes from /v1-public/login and route token lookups through v3 with an ext.cattle.io/v1 fallback.

  • A parser detects v3 vs ext.cattle.io/v1 response shape via apiVersion and kind, then unmarshals into a single internal type.
  • Basic and OAuth login paths return that shared type.
  • User-id resolution and token validation try v3 first and fall back to the ext.cattle.io/v1. Tokens whose id carries the ext/ prefix skip the v3 attempt.
  • The kubectl subcommand uses the new lookup helpers.
  • 401 and 403 from the ext.cattle.io/v1 API are treated the same as 404 so kubeconfig regeneration still runs for v3-tokened users whose credentials the ext authenticator does not accept.

The SAML login path is unchanged. The SamlToken CRD used for the poll response is a transport envelope that carries an encrypted bearer string, and that encryption is agnostic to the underlying token shape (v3 name:value or ext ext/name:value). Once SAML login code path starts issuing ext tokens, the existing decrypt path forwards the bearer through unchanged.

The basic and OAuth login paths returned a v3 Norman Token directly. With session tokens about to migrate to ext.cattle.io/v1 server-side, the CLI needs to accept both response shapes from /v1-public/login.

A parser detects the shape via apiVersion and kind, then unmarshals into a single internal type that carries the bearer token, expires-at, and user id.
The basic and OAuth login paths returned a v3 Norman Token, mixing the protocol shape into the cred-building code.

These paths now return the shared internal type, and the cred builder reads only its bearer token, expires-at, and user id. The SAML path stays on v3 because the corresponding server endpoint stays on v3.
The OAuth login tests asserted only the v3 token shape and did not exercise the new ext-token branch in the response parser.

The existing table-driven test gains an ext-shaped case with the corresponding bearer-token assertion, and a new test exercises the parser plus cred-building pipeline for both shapes with and without an expires-at field.
Token lookups hit only the v3 Management API. Once session tokens start being issued by the ext.cattle.io/v1 API, those lookups would 404.

An HTTP helper now fetches tokens from the ext.cattle.io/v1 API. The user-id resolution and token-validation helpers try v3 first and fall back to the ext API; tokens whose id carries the ext/ prefix skip the v3 attempt entirely. Test stubs use function types so the mocks stay minimal.
…command

The kubectl command resolved the current user and validated the kubeconfig token by calling the v3 Token API directly, with no fallback for ext-issued tokens.

Both lookups now route through the shared helpers that try v3 first and fall back to the ext.cattle.io/v1 API. The local v3-only validation function and its dependent imports are removed.
A stale or deleted v3 token id surfaced a raw 404 from the ext API after fallback. A v3-tokened user with a stale kubeconfig also saw a hard 401 or 403 from the ext authenticator instead of getting the kubeconfig regenerated.

The user-id lookup now wraps the underlying error with the failing token id so the failure is debuggable. Token validation treats 401 and 403 from the ext API the same as 404 and falls through to kubeconfig regeneration. Two new comments explain why the bearer token keeps any ext/ prefix and why a second HTTP client is needed alongside Norman's master client.
Comment thread cmd/token.go
// getTokenUserID returns the user id associated with the given token id.
// It tries the v3 Management API first and falls back to ext.cattle.io/v1.
// Ids prefixed with "ext/" skip the v3 attempt entirely. The prefix is stripped
// before the ext lookup so callers receive a clean token name.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// before the ext lookup so callers receive a clean token name.
// before the ext lookup so callees receive a clean token name.

Comment thread cmd/token.go
// validateToken reports whether the token with the given id exists and is not expired.
// It tries the v3 Management API first and falls back to ext.cattle.io/v1.
// Ids prefixed with "ext/" skip the v3 attempt entirely. The prefix is stripped
// before the ext lookup so callers receive a clean token name.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// before the ext lookup so callers receive a clean token name.
// before the ext lookup so callees receive a clean token name.

@andreas-kupries andreas-kupries left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment nits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants