AzureAD OAuth: Add optional strict parsing of role_attribute_path for Azure AD (#42157)

* AzureAD OAuth: Add optional strict parsing of role_attribute_path for Azure AD

Fix casting issues

modify unit tests

Unit test fix

Add proper test args

* Return empty role when using strict attribute mode

* Raise error on empty role

* Fix UT for latest case
This commit is contained in:
sivamu 2022-03-18 05:34:16 -05:00 committed by GitHub
parent ea7d5a6185
commit 6c468daabc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 13 deletions

View File

@ -508,6 +508,7 @@ auth_url = https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize
token_url = https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token
allowed_domains =
allowed_groups =
role_attribute_strict = false
#################################### Okta OAuth #######################
[auth.okta]

View File

@ -493,6 +493,7 @@
;token_url = https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token
;allowed_domains =
;allowed_groups =
;role_attribute_strict = false
#################################### Okta OAuth #######################
[auth.okta]

View File

@ -109,6 +109,7 @@ auth_url = https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/authorize
token_url = https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/token
allowed_domains =
allowed_groups =
role_attribute_strict = false
```
You can also use these environment variables to configure **client_id** and **client_secret**:

View File

@ -17,8 +17,9 @@ import (
type SocialAzureAD struct {
*SocialBase
allowedGroups []string
autoAssignOrgRole string
allowedGroups []string
autoAssignOrgRole string
roleAttributeStrict bool
}
type azureClaims struct {
@ -69,7 +70,10 @@ func (s *SocialAzureAD) UserInfo(client *http.Client, token *oauth2.Token) (*Bas
return nil, errors.New("error getting user info: no email found in access token")
}
role := extractRole(claims, s.autoAssignOrgRole)
role := extractRole(claims, s.autoAssignOrgRole, s.roleAttributeStrict)
if role == "" {
return nil, errors.New("user does not have a valid role")
}
logger.Debug("AzureAD OAuth: extracted role", "email", email, "role", role)
groups, err := extractGroups(client, claims, token)
@ -118,7 +122,7 @@ func extractEmail(claims azureClaims) string {
return claims.Email
}
func extractRole(claims azureClaims, autoAssignRole string) models.RoleType {
func extractRole(claims azureClaims, autoAssignRole string, strictMode bool) models.RoleType {
if len(claims.Roles) == 0 {
return models.RoleType(autoAssignRole)
}
@ -135,6 +139,10 @@ func extractRole(claims azureClaims, autoAssignRole string) models.RoleType {
}
}
if strictMode {
return models.RoleType("")
}
return models.ROLE_VIEWER
}

View File

@ -18,9 +18,10 @@ import (
func TestSocialAzureAD_UserInfo(t *testing.T) {
type fields struct {
SocialBase *SocialBase
allowedGroups []string
autoAssignOrgRole string
SocialBase *SocialBase
allowedGroups []string
autoAssignOrgRole string
roleAttributeStrict bool
}
type args struct {
client *http.Client
@ -279,13 +280,30 @@ func TestSocialAzureAD_UserInfo(t *testing.T) {
},
wantErr: false,
},
{
name: "Fetch empty role when strict attribute role is true and no match",
fields: fields{
roleAttributeStrict: true,
},
claims: &azureClaims{
Email: "me@example.com",
PreferredUsername: "",
Roles: []string{"foo"},
Groups: []string{},
Name: "My Name",
ID: "1234",
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &SocialAzureAD{
SocialBase: tt.fields.SocialBase,
allowedGroups: tt.fields.allowedGroups,
autoAssignOrgRole: tt.fields.autoAssignOrgRole,
SocialBase: tt.fields.SocialBase,
allowedGroups: tt.fields.allowedGroups,
autoAssignOrgRole: tt.fields.autoAssignOrgRole,
roleAttributeStrict: tt.fields.roleAttributeStrict,
}
key := []byte("secret")

View File

@ -149,9 +149,10 @@ func ProvideService(cfg *setting.Cfg) *SocialService {
// AzureAD.
if name == "azuread" {
ss.socialMap["azuread"] = &SocialAzureAD{
SocialBase: newSocialBase(name, &config, info),
allowedGroups: util.SplitString(sec.Key("allowed_groups").String()),
autoAssignOrgRole: cfg.AutoAssignOrgRole,
SocialBase: newSocialBase(name, &config, info),
allowedGroups: util.SplitString(sec.Key("allowed_groups").String()),
autoAssignOrgRole: cfg.AutoAssignOrgRole,
roleAttributeStrict: info.RoleAttributeStrict,
}
}