mirror of
https://github.com/juanfont/headscale.git
synced 2025-08-10 13:46:46 +02:00
Merge 9b32bbcd85
into efc6974017
This commit is contained in:
commit
92407e3a89
@ -14,6 +14,10 @@
|
|||||||
[#2614](https://github.com/juanfont/headscale/pull/2614)
|
[#2614](https://github.com/juanfont/headscale/pull/2614)
|
||||||
- Support client verify for DERP
|
- Support client verify for DERP
|
||||||
[#2046](https://github.com/juanfont/headscale/pull/2046)
|
[#2046](https://github.com/juanfont/headscale/pull/2046)
|
||||||
|
- OIDC: Update user with claims from UserInfo *before* comparing with allowed
|
||||||
|
groups, email and domain [#2663](https://github.com/juanfont/headscale/pull/2663)
|
||||||
|
- OIDC: Use group claim from UserInfo
|
||||||
|
[#2663](https://github.com/juanfont/headscale/pull/2663)
|
||||||
|
|
||||||
## 0.26.1 (2025-06-06)
|
## 0.26.1 (2025-06-06)
|
||||||
|
|
||||||
|
@ -262,6 +262,35 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch user information (email, groups, name, etc) from the userinfo endpoint
|
||||||
|
// https://openid.net/specs/openid-connect-core-1_0.html#UserInfo
|
||||||
|
var userinfo *oidc.UserInfo
|
||||||
|
userinfo, err = a.oidcProvider.UserInfo(req.Context(), oauth2.StaticTokenSource(oauth2Token))
|
||||||
|
if err != nil {
|
||||||
|
util.LogErr(err, "could not get userinfo; only using claims from id token")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The oidc.UserInfo type only decodes some fields (Subject, Profile, Email, EmailVerified).
|
||||||
|
// We are interested in other fields too (e.g. groups are required for allowedGroups) so we
|
||||||
|
// decode into our own OIDCUserInfo type using the underlying claims struct.
|
||||||
|
var userinfo2 types.OIDCUserInfo
|
||||||
|
if userinfo != nil && userinfo.Claims(&userinfo2) == nil && userinfo2.Sub == claims.Sub {
|
||||||
|
// Update the user with the userinfo claims (with id token claims as fallback).
|
||||||
|
// TODO(kradalby): there might be more interesting fields here that we have not found yet.
|
||||||
|
claims.Email = cmp.Or(userinfo2.Email, claims.Email)
|
||||||
|
claims.EmailVerified = cmp.Or(userinfo2.EmailVerified, claims.EmailVerified)
|
||||||
|
claims.Username = cmp.Or(userinfo2.PreferredUsername, claims.Username)
|
||||||
|
claims.Name = cmp.Or(userinfo2.Name, claims.Name)
|
||||||
|
claims.ProfilePictureURL = cmp.Or(userinfo2.Picture, claims.ProfilePictureURL)
|
||||||
|
if userinfo2.Groups != nil {
|
||||||
|
claims.Groups = userinfo2.Groups
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
util.LogErr(err, "could not get userinfo; only using claims from id token")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The user claims are now updated from the the userinfo endpoint so we can verify the user a
|
||||||
|
// against allowed emails, email domains, and groups.
|
||||||
if err := validateOIDCAllowedDomains(a.cfg.AllowedDomains, &claims); err != nil {
|
if err := validateOIDCAllowedDomains(a.cfg.AllowedDomains, &claims); err != nil {
|
||||||
httpError(writer, err)
|
httpError(writer, err)
|
||||||
return
|
return
|
||||||
@ -277,30 +306,6 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var userinfo *oidc.UserInfo
|
|
||||||
userinfo, err = a.oidcProvider.UserInfo(req.Context(), oauth2.StaticTokenSource(oauth2Token))
|
|
||||||
if err != nil {
|
|
||||||
util.LogErr(err, "could not get userinfo; only checking claim")
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the userinfo is available, we can check if the subject matches the
|
|
||||||
// claims, then use some of the userinfo fields to update the user.
|
|
||||||
// https://openid.net/specs/openid-connect-core-1_0.html#UserInfo
|
|
||||||
if userinfo != nil && userinfo.Subject == claims.Sub {
|
|
||||||
claims.Email = cmp.Or(claims.Email, userinfo.Email)
|
|
||||||
claims.EmailVerified = cmp.Or(claims.EmailVerified, types.FlexibleBoolean(userinfo.EmailVerified))
|
|
||||||
|
|
||||||
// The userinfo has some extra fields that we can use to update the user but they are only
|
|
||||||
// available in the underlying claims struct.
|
|
||||||
// TODO(kradalby): there might be more interesting fields here that we have not found yet.
|
|
||||||
var userinfo2 types.OIDCUserInfo
|
|
||||||
if err := userinfo.Claims(&userinfo2); err == nil {
|
|
||||||
claims.Username = cmp.Or(claims.Username, userinfo2.PreferredUsername)
|
|
||||||
claims.Name = cmp.Or(claims.Name, userinfo2.Name)
|
|
||||||
claims.ProfilePictureURL = cmp.Or(claims.ProfilePictureURL, userinfo2.Picture)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
user, policyChanged, err := a.createOrUpdateUserFromClaim(&claims)
|
user, policyChanged, err := a.createOrUpdateUserFromClaim(&claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
|
@ -308,6 +308,7 @@ type OIDCUserInfo struct {
|
|||||||
PreferredUsername string `json:"preferred_username"`
|
PreferredUsername string `json:"preferred_username"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
EmailVerified FlexibleBoolean `json:"email_verified,omitempty"`
|
EmailVerified FlexibleBoolean `json:"email_verified,omitempty"`
|
||||||
|
Groups []string `json:"groups"`
|
||||||
Picture string `json:"picture"`
|
Picture string `json:"picture"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user