Add groups scope/claim to OIDC/OAuth2 Provider (#17367)
* Add groups scope/claim to OICD/OAuth2 Add support for groups claim as part of the OIDC/OAuth2 flow. Groups is a list of "org" and "org:team" strings to allow clients to authorize based on the groups a user is part of. Signed-off-by: Nico Schieder <code@nico-schieder.de> Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
af96286f22
commit
870f5fbc41
|
@ -207,6 +207,17 @@ func newAccessTokenResponse(grant *login.OAuth2Grant, serverKey, clientKey oauth
|
|||
idToken.Email = user.Email
|
||||
idToken.EmailVerified = user.IsActive
|
||||
}
|
||||
if grant.ScopeContains("groups") {
|
||||
groups, err := getOAuthGroupsForUser(user)
|
||||
if err != nil {
|
||||
log.Error("Error getting groups: %v", err)
|
||||
return nil, &AccessTokenError{
|
||||
ErrorCode: AccessTokenErrorCodeInvalidRequest,
|
||||
ErrorDescription: "server error",
|
||||
}
|
||||
}
|
||||
idToken.Groups = groups
|
||||
}
|
||||
|
||||
signedIDToken, err = idToken.SignToken(clientKey)
|
||||
if err != nil {
|
||||
|
@ -232,6 +243,7 @@ type userInfoResponse struct {
|
|||
Username string `json:"preferred_username"`
|
||||
Email string `json:"email"`
|
||||
Picture string `json:"picture"`
|
||||
Groups []string `json:"groups"`
|
||||
}
|
||||
|
||||
// InfoOAuth manages request for userinfo endpoint
|
||||
|
@ -241,6 +253,7 @@ func InfoOAuth(ctx *context.Context) {
|
|||
ctx.HandleText(http.StatusUnauthorized, "no valid authorization")
|
||||
return
|
||||
}
|
||||
|
||||
response := &userInfoResponse{
|
||||
Sub: fmt.Sprint(ctx.User.ID),
|
||||
Name: ctx.User.FullName,
|
||||
|
@ -248,9 +261,41 @@ func InfoOAuth(ctx *context.Context) {
|
|||
Email: ctx.User.Email,
|
||||
Picture: ctx.User.AvatarLink(),
|
||||
}
|
||||
|
||||
groups, err := getOAuthGroupsForUser(ctx.User)
|
||||
if err != nil {
|
||||
ctx.ServerError("Oauth groups for user", err)
|
||||
return
|
||||
}
|
||||
response.Groups = groups
|
||||
|
||||
ctx.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
// returns a list of "org" and "org:team" strings,
|
||||
// that the given user is a part of.
|
||||
func getOAuthGroupsForUser(user *models.User) ([]string, error) {
|
||||
orgs, err := models.GetUserOrgsList(user)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetUserOrgList: %v", err)
|
||||
}
|
||||
|
||||
var groups []string
|
||||
for _, org := range orgs {
|
||||
groups = append(groups, org.Name)
|
||||
|
||||
if err := org.LoadTeams(); err != nil {
|
||||
return nil, fmt.Errorf("LoadTeams: %v", err)
|
||||
}
|
||||
for _, team := range org.Teams {
|
||||
if team.IsMember(user.ID) {
|
||||
groups = append(groups, org.Name+":"+team.LowerName)
|
||||
}
|
||||
}
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
// IntrospectOAuth introspects an oauth token
|
||||
func IntrospectOAuth(ctx *context.Context) {
|
||||
if ctx.User == nil {
|
||||
|
|
|
@ -83,6 +83,9 @@ type OIDCToken struct {
|
|||
// Scope email
|
||||
Email string `json:"email,omitempty"`
|
||||
EmailVerified bool `json:"email_verified,omitempty"`
|
||||
|
||||
// Groups are generated by organization and team names
|
||||
Groups []string `json:"groups,omitempty"`
|
||||
}
|
||||
|
||||
// SignToken signs an id_token with the (symmetric) client secret key
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
"scopes_supported": [
|
||||
"openid",
|
||||
"profile",
|
||||
"email"
|
||||
"email",
|
||||
"groups"
|
||||
],
|
||||
"claims_supported": [
|
||||
"aud",
|
||||
|
@ -34,7 +35,8 @@
|
|||
"locale",
|
||||
"updated_at",
|
||||
"email",
|
||||
"email_verified"
|
||||
"email_verified",
|
||||
"groups"
|
||||
],
|
||||
"code_challenge_methods_supported": [
|
||||
"plain",
|
||||
|
|
Loading…
Reference in a new issue