-
Notifications
You must be signed in to change notification settings - Fork 928
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
Conversation
… are present in id_token
} | ||
|
||
api.Logger.Debug(ctx, "got oidc claims", | ||
slog.F("user_info", userInfo), |
There was a problem hiding this comment.
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), |
There was a problem hiding this comment.
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
// 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") |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
@@ -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", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops
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 requiresresource=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
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 withallatclaims
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 theCODER_
prefix, so updated that for consistency. This is technically a breaking change.Still TODO: