forked from gitea/gitea
		
	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 { | ||||
| @ -227,11 +238,12 @@ func newAccessTokenResponse(grant *login.OAuth2Grant, serverKey, clientKey oauth | ||||
| } | ||||
| 
 | ||||
| type userInfoResponse struct { | ||||
| 	Sub      string `json:"sub"` | ||||
| 	Name     string `json:"name"` | ||||
| 	Username string `json:"preferred_username"` | ||||
| 	Email    string `json:"email"` | ||||
| 	Picture  string `json:"picture"` | ||||
| 	Sub      string   `json:"sub"` | ||||
| 	Name     string   `json:"name"` | ||||
| 	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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nico Schieder
						Nico Schieder