OAuth: clarify role & group paths prefer id_token over userinfo api (#39066)
* OAuth: clarify role & group paths prefer id_token over userinfo api (#39066) Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Co-authored-by: Kevin Minehart <kmineh0151@gmail.com>
This commit is contained in:
co-authored by
achatterjee-grafana
Kevin Minehart
parent
ae4900e76f
commit
89878dae1b
@@ -149,19 +149,21 @@ func (s *SocialGenericOAuth) UserInfo(client *http.Client, token *oauth2.Token)
|
||||
if userInfo.Role == "" {
|
||||
role, err := s.extractRole(data)
|
||||
if err != nil {
|
||||
s.log.Error("Failed to extract role", "error", err)
|
||||
s.log.Warn("Failed to extract role", "error", err)
|
||||
} else if role != "" {
|
||||
s.log.Debug("Setting user info role from extracted role")
|
||||
userInfo.Role = role
|
||||
}
|
||||
}
|
||||
|
||||
groups, err := s.extractGroups(data)
|
||||
if err != nil {
|
||||
s.log.Error("Failed to extract groups", "error", err)
|
||||
} else if len(groups) > 0 {
|
||||
s.log.Debug("Setting user info groups from extracted groups")
|
||||
userInfo.Groups = groups
|
||||
if userInfo.Groups != nil && len(userInfo.Groups) == 0 {
|
||||
groups, err := s.extractGroups(data)
|
||||
if err != nil {
|
||||
s.log.Warn("Failed to extract groups", "err", err)
|
||||
} else if len(groups) > 0 {
|
||||
s.log.Debug("Setting user info groups from extracted groups")
|
||||
userInfo.Groups = groups
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -379,6 +379,48 @@ func TestUserInfoSearchesForEmailAndRole(t *testing.T) {
|
||||
ExpectedEmail: "john.doe@example.com",
|
||||
ExpectedRole: "FromResponse",
|
||||
},
|
||||
{
|
||||
Name: "Given a valid id_token, a valid advanced JMESPath role path, derive the role",
|
||||
OAuth2Extra: map[string]interface{}{
|
||||
// { "email": "john.doe@example.com",
|
||||
// "info": { "roles": [ "dev", "engineering" ] }}
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4uZG9lQGV4YW1wbGUuY29tIiwiaW5mbyI6eyJyb2xlcyI6WyJkZXYiLCJlbmdpbmVlcmluZyJdfX0.RmmQfv25eXb4p3wMrJsvXfGQ6EXhGtwRXo6SlCFHRNg",
|
||||
},
|
||||
RoleAttributePath: "contains(info.roles[*], 'dev') && 'Editor'",
|
||||
ExpectedEmail: "john.doe@example.com",
|
||||
ExpectedRole: "Editor",
|
||||
},
|
||||
{
|
||||
Name: "Given a valid id_token without role info, a valid advanced JMESPath role path, a valid API response, derive the correct role using the userinfo API response (JMESPath warning on id_token)",
|
||||
OAuth2Extra: map[string]interface{}{
|
||||
// { "email": "john.doe@example.com" }
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4uZG9lQGV4YW1wbGUuY29tIn0.k5GwPcZvGe2BE_jgwN0ntz0nz4KlYhEd0hRRLApkTJ4",
|
||||
},
|
||||
ResponseBody: map[string]interface{}{
|
||||
"info": map[string]interface{}{
|
||||
"roles": []string{"engineering", "SRE"},
|
||||
},
|
||||
},
|
||||
RoleAttributePath: "contains(info.roles[*], 'SRE') && 'Admin'",
|
||||
ExpectedEmail: "john.doe@example.com",
|
||||
ExpectedRole: "Admin",
|
||||
},
|
||||
{
|
||||
Name: "Given a valid id_token, a valid advanced JMESPath role path, a valid API response, prefer ID token",
|
||||
OAuth2Extra: map[string]interface{}{
|
||||
// { "email": "john.doe@example.com",
|
||||
// "info": { "roles": [ "dev", "engineering" ] }}
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvaG4uZG9lQGV4YW1wbGUuY29tIiwiaW5mbyI6eyJyb2xlcyI6WyJkZXYiLCJlbmdpbmVlcmluZyJdfX0.RmmQfv25eXb4p3wMrJsvXfGQ6EXhGtwRXo6SlCFHRNg",
|
||||
},
|
||||
ResponseBody: map[string]interface{}{
|
||||
"info": map[string]interface{}{
|
||||
"roles": []string{"engineering", "SRE"},
|
||||
},
|
||||
},
|
||||
RoleAttributePath: "contains(info.roles[*], 'SRE') && 'Admin' || contains(info.roles[*], 'dev') && 'Editor' || 'Viewer'",
|
||||
ExpectedEmail: "john.doe@example.com",
|
||||
ExpectedRole: "Editor",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
Reference in New Issue
Block a user