Skip to content

Commit 870f5fb

Browse files
thetechnickzeripathwxiaoguang
authored
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>
1 parent af96286 commit 870f5fb

File tree

3 files changed

+57
-7
lines changed

3 files changed

+57
-7
lines changed

routers/web/user/oauth.go

+50-5
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,17 @@ func newAccessTokenResponse(grant *login.OAuth2Grant, serverKey, clientKey oauth
207207
idToken.Email = user.Email
208208
idToken.EmailVerified = user.IsActive
209209
}
210+
if grant.ScopeContains("groups") {
211+
groups, err := getOAuthGroupsForUser(user)
212+
if err != nil {
213+
log.Error("Error getting groups: %v", err)
214+
return nil, &AccessTokenError{
215+
ErrorCode: AccessTokenErrorCodeInvalidRequest,
216+
ErrorDescription: "server error",
217+
}
218+
}
219+
idToken.Groups = groups
220+
}
210221

211222
signedIDToken, err = idToken.SignToken(clientKey)
212223
if err != nil {
@@ -227,11 +238,12 @@ func newAccessTokenResponse(grant *login.OAuth2Grant, serverKey, clientKey oauth
227238
}
228239

229240
type userInfoResponse struct {
230-
Sub string `json:"sub"`
231-
Name string `json:"name"`
232-
Username string `json:"preferred_username"`
233-
Email string `json:"email"`
234-
Picture string `json:"picture"`
241+
Sub string `json:"sub"`
242+
Name string `json:"name"`
243+
Username string `json:"preferred_username"`
244+
Email string `json:"email"`
245+
Picture string `json:"picture"`
246+
Groups []string `json:"groups"`
235247
}
236248

237249
// InfoOAuth manages request for userinfo endpoint
@@ -241,16 +253,49 @@ func InfoOAuth(ctx *context.Context) {
241253
ctx.HandleText(http.StatusUnauthorized, "no valid authorization")
242254
return
243255
}
256+
244257
response := &userInfoResponse{
245258
Sub: fmt.Sprint(ctx.User.ID),
246259
Name: ctx.User.FullName,
247260
Username: ctx.User.Name,
248261
Email: ctx.User.Email,
249262
Picture: ctx.User.AvatarLink(),
250263
}
264+
265+
groups, err := getOAuthGroupsForUser(ctx.User)
266+
if err != nil {
267+
ctx.ServerError("Oauth groups for user", err)
268+
return
269+
}
270+
response.Groups = groups
271+
251272
ctx.JSON(http.StatusOK, response)
252273
}
253274

275+
// returns a list of "org" and "org:team" strings,
276+
// that the given user is a part of.
277+
func getOAuthGroupsForUser(user *models.User) ([]string, error) {
278+
orgs, err := models.GetUserOrgsList(user)
279+
if err != nil {
280+
return nil, fmt.Errorf("GetUserOrgList: %v", err)
281+
}
282+
283+
var groups []string
284+
for _, org := range orgs {
285+
groups = append(groups, org.Name)
286+
287+
if err := org.LoadTeams(); err != nil {
288+
return nil, fmt.Errorf("LoadTeams: %v", err)
289+
}
290+
for _, team := range org.Teams {
291+
if team.IsMember(user.ID) {
292+
groups = append(groups, org.Name+":"+team.LowerName)
293+
}
294+
}
295+
}
296+
return groups, nil
297+
}
298+
254299
// IntrospectOAuth introspects an oauth token
255300
func IntrospectOAuth(ctx *context.Context) {
256301
if ctx.User == nil {

services/auth/source/oauth2/token.go

+3
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ type OIDCToken struct {
8383
// Scope email
8484
Email string `json:"email,omitempty"`
8585
EmailVerified bool `json:"email_verified,omitempty"`
86+
87+
// Groups are generated by organization and team names
88+
Groups []string `json:"groups,omitempty"`
8689
}
8790

8891
// SignToken signs an id_token with the (symmetric) client secret key

templates/user/auth/oidc_wellknown.tmpl

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"scopes_supported": [
1919
"openid",
2020
"profile",
21-
"email"
21+
"email",
22+
"groups"
2223
],
2324
"claims_supported": [
2425
"aud",
@@ -34,7 +35,8 @@
3435
"locale",
3536
"updated_at",
3637
"email",
37-
"email_verified"
38+
"email_verified",
39+
"groups"
3840
],
3941
"code_challenge_methods_supported": [
4042
"plain",

0 commit comments

Comments
 (0)