Skip to content

[OIDC 16] Add IFederatedCredentialValidator for additional token validation#10306

Merged
joelverhagen merged 8 commits into
devfrom
jver-oidc-ship-16
Dec 24, 2024
Merged

[OIDC 16] Add IFederatedCredentialValidator for additional token validation#10306
joelverhagen merged 8 commits into
devfrom
jver-oidc-ship-16

Conversation

@joelverhagen
Copy link
Copy Markdown
Member

Progress on https://github.com/NuGet/Engineering/issues/5911.
Depends on #10305.

This adds a new abstraction called IFederatedCredentialValidator which allows us to inject custom token validation code (i.e. closed source, "shim" code) into the token validation pipeline.

0 or more IFederatedCredentialValidator implementations can be used by the policy evaluator to perform additional validations on bearer tokens. These additional implementations come from the add-ins directory via MEF, much like existing shims.

The flow of validation BEFORE the change is like this:

  1. Parse the JWT
  2. Identify the issuer
  3. Perform an OSS issuer-specific validation, such as EntraIdTokenValidator
  4. If the issuer says the token is good, then compare it to the given list of trust policies.

This PR adds a new step between 3 and 4 where the request headers (in particular the Authorization header) is passed to each IFederatedCredentialValidator to get additional token validation results. If either the built-in token validation or any additional IFederatedCredentialValidator says the token is bad, it will be rejected.

We pass all request headers, the detected issuer type (e.g. Entra ID vs. GitHub Actions), and unvalidated claims to the IFederatedCredentialValidator. This essentially provides all the context we have to the shim at the time so it can make the most informed decision.

At no point will as "valid" result from an IFederatedCredentialValidator override a "bad" result from the built-in token validation. In other words, if there is an inconsistency between various validation flows, we fail close and reject the token. We will log a warning if any of the validators disagree on valid vs. invalid.

A IFederatedCredentialValidator can return NotApplicable if the validator is only meant for a specific issuer. For example, IFederatedCredentialValidator might only know how to validate GitHub Actions tokens, not Entra ID tokens. The GitHub Actions example is for the future of course. Right now, the only supported issuer is Entra ID.

I chose to plumb the request headers in from the service layer (and eventually from the controller action) instead of using the current HttpContext so that the flow of data was clearer. I would have preferred to only provide the bearer token to IFederatedCredentialValidator instead of all headers, but our internal token validation library expects all request headers, not just the bearer token.

Our internal token validation shim uses a newer version of Microsoft.Extensions.Caching.Memory so I had to bump up the version to avoid runtime issues.

@joelverhagen joelverhagen requested a review from a team as a code owner December 11, 2024 22:23
erdembayar
erdembayar previously approved these changes Dec 20, 2024
@joelverhagen joelverhagen changed the base branch from jver-oidc-ship-15 to dev December 23, 2024 18:56
@joelverhagen joelverhagen dismissed erdembayar’s stale review December 23, 2024 18:56

The base branch was changed.

@joelverhagen joelverhagen merged commit 1abc175 into dev Dec 24, 2024
@joelverhagen joelverhagen deleted the jver-oidc-ship-16 branch January 14, 2025 15:37
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