Skip to content

Commit 5b5d5fe

Browse files
Auth: fix role_attribute_path when using ID tokens in Gitlab OAuth (#107634)
1 parent ab676ce commit 5b5d5fe

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

pkg/login/social/connectors/gitlab_oauth.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ func (s *SocialGitlab) extractFromToken(ctx context.Context, client *http.Client
302302
data.Groups = userInfo.Groups
303303
}
304304

305+
data.raw = rawJSON
306+
305307
s.log.Debug("Resolved user data", "data", fmt.Sprintf("%+v", data))
306308
return &data, nil
307309
}

pkg/login/social/connectors/gitlab_oauth_test.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ const (
3737
rootUserRespBody = `{"id":1,"username":"root","name":"Administrator","state":"active","email":"[email protected]", "confirmed_at":"2022-09-13T19:38:04.891Z","is_admin":true,"namespace_id":1}`
3838
editorUserRespBody = `{"id":3,"username":"gitlab-editor","name":"Gitlab Editor","state":"active","email":"[email protected]", "confirmed_at":"2022-09-13T19:38:04.891Z","is_admin":false,"namespace_id":1}`
3939

40+
editorUserIDToken = `{"sub":"3","preferred_username":"gitlab-editor","name":"Gitlab Editor","email":"[email protected]","email_verified":true,"groups_direct":["editors", "viewers"]}` // #nosec G101 not a hardcoded credential
41+
4042
adminGroup = `{"id":4,"web_url":"http://grafana-gitlab.local/groups/admins","name":"Admins","path":"admins","project_creation_level":"developer","full_name":"Admins","full_path":"admins","created_at":"2022-09-13T19:38:04.891Z"}`
4143
editorGroup = `{"id":5,"web_url":"http://grafana-gitlab.local/groups/editors","name":"Editors","path":"editors","project_creation_level":"developer","full_name":"Editors","full_path":"editors","created_at":"2022-09-13T19:38:15.074Z"}`
4244
viewerGroup = `{"id":6,"web_url":"http://grafana-gitlab.local/groups/viewers","name":"Viewers","path":"viewers","project_creation_level":"developer","full_name":"Viewers","full_path":"viewers","created_at":"2022-09-13T19:38:25.777Z"}`
@@ -61,6 +63,7 @@ func TestSocialGitlab_UserInfo(t *testing.T) {
6163
GroupsRespBody string
6264
GroupHeaders map[string]string
6365
RoleAttributePath string
66+
IDToken string
6467
ExpectedLogin string
6568
ExpectedEmail string
6669
ExpectedRoles map[int64]org.RoleType
@@ -180,6 +183,24 @@ func TestSocialGitlab_UserInfo(t *testing.T) {
180183
ExpectedEmail: "[email protected]",
181184
ExpectedRoles: map[int64]org.RoleType{4: "Editor", 5: "Viewer"},
182185
},
186+
{
187+
Name: "Maps roles from ID token attributes if available",
188+
RoleAttributePath: `email=='[email protected]' && 'Editor' || 'Viewer'`,
189+
IDToken: editorUserIDToken,
190+
ExpectedLogin: "gitlab-editor",
191+
ExpectedEmail: "[email protected]",
192+
ExpectedRoles: map[int64]org.RoleType{1: "Editor"},
193+
ExpectedGrafanaAdmin: nilPointer,
194+
},
195+
{
196+
Name: "Maps groups from ID token groups if available",
197+
RoleAttributePath: gitlabAttrPath,
198+
IDToken: editorUserIDToken,
199+
ExpectedLogin: "gitlab-editor",
200+
ExpectedEmail: "[email protected]",
201+
ExpectedRoles: map[int64]org.RoleType{1: "Editor"},
202+
ExpectedGrafanaAdmin: nilPointer,
203+
},
183204
{
184205
Name: "Should return error when neither role attribute path nor org mapping evaluates to a role and role attribute strict is enabled",
185206
Cfg: conf{RoleAttributeStrict: true, OrgMapping: []string{"other:Org4:Editor"}},
@@ -230,8 +251,17 @@ func TestSocialGitlab_UserInfo(t *testing.T) {
230251
require.Fail(t, "unexpected request URI: "+r.RequestURI)
231252
}
232253
}))
254+
255+
token := &oauth2.Token{}
256+
if tt.IDToken != "" {
257+
emptyJWTHeader := base64.RawURLEncoding.EncodeToString([]byte("{}"))
258+
JWTBody := base64.RawURLEncoding.EncodeToString([]byte(tt.IDToken))
259+
idToken := fmt.Sprintf("%s.%s.signature", emptyJWTHeader, JWTBody)
260+
token = token.WithExtra(map[string]any{"id_token": idToken})
261+
}
262+
233263
provider.info.ApiUrl = ts.URL + apiURI
234-
actualResult, err := provider.UserInfo(context.Background(), ts.Client(), &oauth2.Token{})
264+
actualResult, err := provider.UserInfo(context.Background(), ts.Client(), token)
235265
if tt.ExpectedError != nil {
236266
require.ErrorIs(t, err, tt.ExpectedError)
237267
return
@@ -382,6 +412,9 @@ func TestSocialGitlab_extractFromToken(t *testing.T) {
382412
}
383413

384414
for _, tc := range testCases {
415+
if tc.wantUser != nil {
416+
tc.wantUser.raw = []byte(tc.payload)
417+
}
385418
t.Run(tc.name, func(t *testing.T) {
386419
// Create a test client with a dummy token
387420
client := oauth2.NewClient(context.Background(), &tokenSource{accessToken: "dummy_access_token"})

0 commit comments

Comments
 (0)