Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(coderd)!: add CODER_OIDC_IGNORE_USERINFO configuration option #6922

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 5, 2023

Conversation

johnstcn
Copy link
Member

@johnstcn johnstcn commented Mar 31, 2023

Previously, we would always hit the Userinfo endpoint when performing OIDC logins, and would merge the claims returned by UserInfo with the claims from the ID token.

Unfortunately, certain identity providers require different URL parameters when requesting UserInfo versus requesting an ID token. For example, ADFS requires specifying the relying party identifier as the resource parameter when requesting an ID token, but requires resource=urn:microsoft:userinfo when requesting the resource parameter.

As far as I can tell, this is a proposed standard (RFC8707) but I'm not sure it has been ratified yet. To make matters more complicated, the proposed standard also says that

Multiple resource parameters MAY be used to indicate that the requested token is intended
to be used at multiple resources.

So, we can't guarantee that simply specifying multiple resources in the resource parameter will work for all IDPs.

To work around this, I propose changing the OIDC login logic such that we only request UserInfo if we lack the required claims from the ID token itself. This allows folks using identity providers like ADFS to stuff everything they need into the ID Token with allatclaims and not have to worry about UserInfo.

Update: to minimise the level of magic in the product, I elected instead to add an extra option OIDC_IGNORE_USERINFO. This will allow an operator to cause Coder to never hit the UserInfo endpoint of the upstream identity provider, and instead take all information from the ID token. This also eliminates the possibility of introducing breaking behaviour into the product in the case where the upstream OIDC provider returns inconsistent information from the ID token versus from the UserInfo endpoint.

Also, I noted that the environment variable OIDC_GROUP_MAPPING was missing the CODER_ prefix, so updated that for consistency. This is technically a breaking change.

Still TODO:

  • Update documentation

@johnstcn johnstcn self-assigned this Mar 31, 2023
@johnstcn johnstcn marked this pull request as ready for review March 31, 2023 15:16
}

api.Logger.Debug(ctx, "got oidc claims",
slog.F("user_info", userInfo),
Copy link
Member Author

@johnstcn johnstcn Mar 31, 2023

Choose a reason for hiding this comment

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

NOTE: we were previously logging all of the userinfo claims here; this could contain sensitive user information. I modified this to instead log the claim fields, and which of these claim fields are an empty string.

@@ -657,7 +674,7 @@ func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) {
group, ok := groupInterface.(string)
if !ok {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: fmt.Sprintf("Invalid group type. Expected string, got: %t", emailRaw),
Message: fmt.Sprintf("Invalid group type. Expected string, got: %T", groupInterface),
Copy link
Member Author

Choose a reason for hiding this comment

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

NOTE: I'm assuming this was what the original author intended here

Comment on lines +606 to +609
// The OIDC provider does not support the UserInfo endpoint.
// This is not an error, but we should log it as it may mean
// that some claims are missing.
api.Logger.Warn(ctx, "OIDC provider does not support the user info endpoint, ensure that all required claims are present in the id_token")
Copy link
Member

Choose a reason for hiding this comment

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

Should we be printing an error here too? We don't have the required claims at this point, so it seems odd to just warn with logs but proceed.

Copy link
Member Author

Choose a reason for hiding this comment

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

If we're going to error, I'd say we should just fail the request outright.
However, we could still theoretically successfully login a user if we're just missing something like the preferred_username field (i.e. we generate it from the email).

I could remove the check for the username field as a "required" claim, WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

Ahh, I see.

Up to you, I'm really not sure. Kinda uncharted territory for me.

Copy link
Member Author

@johnstcn johnstcn Apr 4, 2023

Choose a reason for hiding this comment

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

Instead of making the logic "magical", maybe a better choice is adding an option CODER_OIDC_IGNORE_USERINFO and keep the existing behaviour of always hitting UserInfo unless this option is set. This way, we keep the existing behaviour but allow folks who can't or don't want to use the UserInfo endpoint to just rely on what's in the id_token.

@johnstcn johnstcn changed the title fix(coderd): do not hit oidc userinfo endpoint if not required fix!(coderd): do not hit oidc userinfo endpoint if not required Mar 31, 2023
@johnstcn johnstcn changed the title fix!(coderd): do not hit oidc userinfo endpoint if not required fix(coderd)!: do not hit oidc userinfo endpoint if not required Mar 31, 2023
@github-actions github-actions bot added the release/breaking This label is applied to PRs to detect breaking changes as part of the release process label Mar 31, 2023
@@ -900,7 +900,7 @@ when required by your organization's security policy.`,
Name: "OIDC Group Mapping",
Description: "A map of OIDC group IDs and the group in Coder it should map to. This is useful for when OIDC providers only return group IDs.",
Flag: "oidc-group-mapping",
Env: "OIDC_GROUP_MAPPING",
Env: "CODER_OIDC_GROUP_MAPPING",
Copy link
Contributor

Choose a reason for hiding this comment

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

Oops

@johnstcn johnstcn changed the title fix(coderd)!: do not hit oidc userinfo endpoint if not required fix(coderd): add CODER_OIDC_IGNORE_USERINFO configuration option Apr 4, 2023
@github-actions github-actions bot removed the release/breaking This label is applied to PRs to detect breaking changes as part of the release process label Apr 4, 2023
@johnstcn johnstcn requested review from kylecarbs and coadler April 4, 2023 13:45
@johnstcn johnstcn changed the title fix(coderd): add CODER_OIDC_IGNORE_USERINFO configuration option fix(coderd)!: add CODER_OIDC_IGNORE_USERINFO configuration option Apr 4, 2023
@github-actions github-actions bot added the release/breaking This label is applied to PRs to detect breaking changes as part of the release process label Apr 4, 2023
@johnstcn johnstcn merged commit 9c4ccd7 into main Apr 5, 2023
@johnstcn johnstcn deleted the cj/oidc-skip-userinfo branch April 5, 2023 08:07
@github-actions github-actions bot locked and limited conversation to collaborators Apr 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
release/breaking This label is applied to PRs to detect breaking changes as part of the release process
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants