mirror of
https://github.com/grafana/grafana.git
synced 2024-11-24 09:50:29 -06:00
Auth: Add org to role mappings support to Okta integration (#88770)
* Add org mapping support to Okta * Update docs and configs * Prettier docs * Apply suggestions from code review Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> * Improve tests --------- Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com>
This commit is contained in:
parent
50b3269ef0
commit
4f2a9a47f3
@ -783,6 +783,8 @@ allowed_domains =
|
||||
allowed_groups =
|
||||
role_attribute_path =
|
||||
role_attribute_strict = false
|
||||
org_attribute_path =
|
||||
org_mapping =
|
||||
allow_assign_grafana_admin = false
|
||||
skip_org_role_sync = false
|
||||
tls_skip_verify_insecure = false
|
||||
|
@ -715,6 +715,8 @@
|
||||
;allowed_groups =
|
||||
;role_attribute_path =
|
||||
;role_attribute_strict = false
|
||||
; org_attribute_path =
|
||||
; org_mapping =
|
||||
;allow_assign_grafana_admin = false
|
||||
;skip_org_role_sync = false
|
||||
;use_pkce = true
|
||||
|
@ -116,7 +116,7 @@ Refer to [configuration options]({{< relref "#configuration-options" >}}) for mo
|
||||
If no valid role is found, the user is assigned the role specified by [the `auto_assign_org_role` option]({{< relref "../../../configure-grafana#auto_assign_org_role" >}}).
|
||||
You can disable this default role assignment by setting `role_attribute_strict = true`. This setting denies user access if no role or an invalid role is returned after evaluating the `role_attribute_path` and the `org_mapping` expressions.
|
||||
|
||||
You can use the `org_attribute_path` and `org_mapping` configuration options to assign the user to organizations and specify their role. For more information, refer to [Org roles mapping example](#org-roles-mapping-example). If both org role mapping (`org_mapping`) and the regular role mapping (`role_attribute_path`) are specified, then the user will get the highest of the two mapped roles.
|
||||
You can use the `org_mapping` configuration options to assign the user to organizations and specify their role based on their GitHub team membership. For more information, refer to [Org roles mapping example](#org-roles-mapping-example). If both org role mapping (`org_mapping`) and the regular role mapping (`role_attribute_path`) are specified, then the user will get the highest of the two mapped roles.
|
||||
|
||||
To ease configuration of a proper JMESPath expression, go to [JMESPath](http://jmespath.org/) to test and evaluate expressions with custom payloads.
|
||||
|
||||
@ -231,7 +231,7 @@ The table below describes all GitHub OAuth configuration options. Like any other
|
||||
| `allow_sign_up` | No | Whether to allow new Grafana user creation through GitHub login. If set to `false`, then only existing Grafana users can log in with GitHub OAuth. | `true` |
|
||||
| `auto_login` | No | Set to `true` to enable users to bypass the login screen and automatically log in. This setting is ignored if you configure multiple auth providers to use auto-login. | `false` |
|
||||
| `role_attribute_path` | No | [JMESPath](http://jmespath.org/examples.html) expression to use for Grafana role lookup. Grafana will first evaluate the expression using the user information obtained from the UserInfo endpoint. If no role is found, Grafana creates a JSON data with `groups` key that maps to GitHub teams obtained from GitHub's [`/api/user/teams`](https://docs.github.com/en/rest/teams/teams#list-teams-for-the-authenticated-user) endpoint, and evaluates the expression using this data. The result of the evaluation should be a valid Grafana role (`None`, `Viewer`, `Editor`, `Admin` or `GrafanaAdmin`). For more information on user role mapping, refer to [Configure role mapping](#org-roles-mapping-example). | |
|
||||
| `role_attribute_strict` | No | et to `true` to deny user login if the Grafana org role cannot be extracted using `role_attribute_path` or `org_mapping`. For more information on user role mapping, refer to [Configure role mapping](#org-roles-mapping-example). | `false` |
|
||||
| `role_attribute_strict` | No | Set to `true` to deny user login if the Grafana org role cannot be extracted using `role_attribute_path` or `org_mapping`. For more information on user role mapping, refer to [Configure role mapping](#org-roles-mapping-example). | `false` |
|
||||
| `org_mapping` | No | List of comma- or space-separated `<ExternalGitHubTeamName>:<OrgIdOrName>:<Role>` mappings. Value can be `*` meaning "All users". Role is optional and can have the following values: `None`, `Viewer`, `Editor` or `Admin`. For more information on external organization to role mapping, refer to [Org roles mapping example](#org-roles-mapping-example). | |
|
||||
| `allow_assign_grafana_admin` | No | Set to `true` to enable automatic sync of the Grafana server administrator role. If this option is set to `true` and the result of evaluating `role_attribute_path` for a user is `GrafanaAdmin`, Grafana grants the user the server administrator privileges and organization administrator role. If this option is set to `false` and the result of evaluating `role_attribute_path` for a user is `GrafanaAdmin`, Grafana grants the user only organization administrator role. For more information on user role mapping, refer to [Configure role mapping]({{< relref "#configure-role-mapping" >}}). | `false` |
|
||||
| `skip_org_role_sync` | No | Set to `true` to stop automatically syncing user roles. | `false` |
|
||||
|
@ -212,7 +212,9 @@ At the configuration file, extend the `scopes` in `[auth.okta]` section with `of
|
||||
The user's role is retrieved using a [JMESPath](http://jmespath.org/examples.html) expression from the `role_attribute_path` configuration option against the `api_url` (`/userinfo` OIDC endpoint) endpoint payload.
|
||||
|
||||
If no valid role is found, the user is assigned the role specified by [the `auto_assign_org_role` option]({{< relref "../../../configure-grafana#auto_assign_org_role" >}}).
|
||||
You can disable this default role assignment by setting `role_attribute_strict = true`. This setting denies user access if no role or an invalid role is returned.
|
||||
You can disable this default role assignment by setting `role_attribute_strict = true`. This setting denies user access if no role or an invalid role is returned after evaluating the `role_attribute_path` and the `org_mapping` expressions.
|
||||
|
||||
You can use the `org_attribute_path` and `org_mapping` configuration options to assign the user to organizations and specify their role. For more information, refer to [Org roles mapping example](#org-roles-mapping-example). If both org role mapping (`org_mapping`) and the regular role mapping (`role_attribute_path`) are specified, then the user will get the highest of the two mapped roles.
|
||||
|
||||
To allow mapping Grafana server administrator role, use the `allow_assign_grafana_admin` configuration option.
|
||||
Refer to [configuration options]({{< relref "../generic-oauth/index.md#configuration-options" >}}) for more information.
|
||||
@ -223,6 +225,17 @@ If you want to map the role based on the user's group, you can use the `groups`
|
||||
|
||||
To learn about adding custom claims to the user info in Okta, refer to [add custom claims](https://developer.okta.com/docs/guides/customize-tokens-returned-from-okta/main/#add-a-custom-claim-to-a-token).
|
||||
|
||||
#### Org roles mapping example
|
||||
|
||||
In this example, the `org_mapping` uses the `groups` attribute as the source (`org_attribute_path`) to map the current user to different organizations and roles. The user has been granted the role of a `Viewer` in the `org_foo` org if they are a member of the `Group 1` group, the role of an `Editor` in the `org_bar` org if they are a member of the `Group 2` group, and the role of an `Editor` in the `org_baz`(OrgID=3) org.
|
||||
|
||||
Config:
|
||||
|
||||
```ini
|
||||
org_attribute_path = groups
|
||||
org_mapping = ["Group 1:org_foo:Viewer", "Group 2:org_bar:Editor", "*:3:Editor"]
|
||||
```
|
||||
|
||||
### Configure team synchronization (Enterprise only)
|
||||
|
||||
> **Note:** Available in [Grafana Enterprise]({{< relref "../../../../introduction/grafana-enterprise" >}}) and [Grafana Cloud]({{< relref "../../../../introduction/grafana-cloud" >}}).
|
||||
@ -254,7 +267,9 @@ The following table outlines the various Okta OIDC configuration options. You ca
|
||||
| `allow_sign_up` | No | Controls Grafana user creation through the Okta OIDC login. Only existing Grafana users can log in with Okta OIDC if set to `false`. | `true` |
|
||||
| `auto_login` | No | Set to `true` to enable users to bypass the login screen and automatically log in. This setting is ignored if you configure multiple auth providers to use auto-login. | `false` |
|
||||
| `role_attribute_path` | No | [JMESPath](http://jmespath.org/examples.html) expression to use for Grafana role lookup. Grafana will first evaluate the expression using the Okta OIDC ID token. If no role is found, the expression will be evaluated using the user information obtained from the UserInfo endpoint. The result of the evaluation should be a valid Grafana role (`None`, `Viewer`, `Editor`, `Admin` or `GrafanaAdmin`). For more information on user role mapping, refer to [Configure role mapping]({{< relref "#configure-role-mapping" >}}). | |
|
||||
| `role_attribute_strict` | No | Set to `true` to deny user login if the Grafana role cannot be extracted using `role_attribute_path`. For more information on user role mapping, refer to [Configure role mapping]({{< relref "#configure-role-mapping" >}}). | `false` |
|
||||
| `role_attribute_strict` | No | Set to `true` to deny user login if the Grafana org role cannot be extracted using `role_attribute_path` or `org_mapping`. For more information on user role mapping, refer to [Configure role mapping]({{< relref "#configure-role-mapping" >}}). | `false` |
|
||||
| `org_attribute_path` | No | [JMESPath](http://jmespath.org/examples.html) expression to use for Grafana org to role lookup. The result of the evaluation will be mapped to org roles based on `org_mapping`. For more information on org to role mapping, refer to [Org roles mapping example](#org-roles-mapping-example). | |
|
||||
| `org_mapping` | No | List of comma- or space-separated `<ExternalOrgName>:<OrgIdOrName>:<Role>` mappings. Value can be `*` meaning "All users". Role is optional and can have the following values: `None`, `Viewer`, `Editor` or `Admin`. For more information on external organization to role mapping, refer to [Org roles mapping example](#org-roles-mapping-example). | |
|
||||
| `skip_org_role_sync` | No | Set to `true` to stop automatically syncing user roles. This will allow you to set organization roles for your users from within Grafana manually. | `false` |
|
||||
| `allowed_groups` | No | List of comma- or space-separated groups. The user should be a member of at least one group to log in. | |
|
||||
| `allowed_domains` | No | List comma- or space-separated domains. The user should belong to at least one domain to log in. | |
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/login/social"
|
||||
"github.com/grafana/grafana/pkg/models/roletype"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/ssosettings"
|
||||
@ -139,32 +138,41 @@ func (s *SocialOkta) UserInfo(ctx context.Context, client *http.Client, token *o
|
||||
return nil, errMissingGroupMembership
|
||||
}
|
||||
|
||||
var role roletype.RoleType
|
||||
var isGrafanaAdmin *bool
|
||||
userInfo := &social.BasicUserInfo{
|
||||
Id: claims.ID,
|
||||
Name: claims.Name,
|
||||
Email: email,
|
||||
Login: email,
|
||||
Groups: groups,
|
||||
}
|
||||
|
||||
if !s.info.SkipOrgRoleSync {
|
||||
var grafanaAdmin bool
|
||||
role, grafanaAdmin, err = s.extractRoleAndAdmin(data.rawJSON, groups)
|
||||
directlyMappedRole, grafanaAdmin, err := s.extractRoleAndAdminOptional(data.rawJSON, groups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
s.log.Warn("Failed to extract role", "err", err)
|
||||
}
|
||||
|
||||
if s.info.AllowAssignGrafanaAdmin {
|
||||
isGrafanaAdmin = &grafanaAdmin
|
||||
userInfo.IsGrafanaAdmin = &grafanaAdmin
|
||||
}
|
||||
|
||||
externalOrgs, err := s.extractOrgs(data.rawJSON)
|
||||
if err != nil {
|
||||
s.log.Warn("Failed to extract orgs", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userInfo.OrgRoles = s.orgRoleMapper.MapOrgRoles(s.orgMappingCfg, externalOrgs, directlyMappedRole)
|
||||
if s.info.RoleAttributeStrict && len(userInfo.OrgRoles) == 0 {
|
||||
return nil, errRoleAttributeStrictViolation.Errorf("could not evaluate any valid roles using IdP provided data")
|
||||
}
|
||||
}
|
||||
|
||||
if s.info.AllowAssignGrafanaAdmin && s.info.SkipOrgRoleSync {
|
||||
s.log.Debug("AllowAssignGrafanaAdmin and skipOrgRoleSync are both set, Grafana Admin role will not be synced, consider setting one or the other")
|
||||
}
|
||||
|
||||
return &social.BasicUserInfo{
|
||||
Id: claims.ID,
|
||||
Name: claims.Name,
|
||||
Email: email,
|
||||
Login: email,
|
||||
Role: role,
|
||||
IsGrafanaAdmin: isGrafanaAdmin,
|
||||
Groups: groups,
|
||||
}, nil
|
||||
return userInfo, nil
|
||||
}
|
||||
|
||||
func (s *SocialOkta) extractAPI(ctx context.Context, data *OktaUserInfoJson, client *http.Client) error {
|
||||
|
@ -13,9 +13,10 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/login/social"
|
||||
"github.com/grafana/grafana/pkg/models/roletype"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
||||
"github.com/grafana/grafana/pkg/services/ssosettings"
|
||||
ssoModels "github.com/grafana/grafana/pkg/services/ssosettings/models"
|
||||
"github.com/grafana/grafana/pkg/services/ssosettings/ssosettingstests"
|
||||
@ -29,63 +30,142 @@ func TestSocialOkta_UserInfo(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
userRawJSON string
|
||||
OAuth2Extra any
|
||||
autoAssignOrgRole string
|
||||
settingSkipOrgRoleSync bool
|
||||
oAuth2Extra any
|
||||
skipOrgRoleSync bool
|
||||
allowAssignGrafanaAdmin bool
|
||||
RoleAttributePath string
|
||||
ExpectedEmail string
|
||||
ExpectedRole roletype.RoleType
|
||||
ExpectedGrafanaAdmin *bool
|
||||
ExpectedErr error
|
||||
wantErr bool
|
||||
roleAttributePath string
|
||||
roleAttributeStrict bool
|
||||
orgMapping []string
|
||||
orgAttributePath string
|
||||
expectedEmail string
|
||||
expectedOrgRoles map[int64]org.RoleType
|
||||
expectedGrafanaAdmin *bool
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "Should give role from JSON and email from id token",
|
||||
name: "should give role from JSON and email from id token",
|
||||
userRawJSON: `{ "email": "okta-octopus@grafana.com", "role": "Admin" }`,
|
||||
RoleAttributePath: "role",
|
||||
OAuth2Extra: map[string]any{
|
||||
roleAttributePath: "role",
|
||||
oAuth2Extra: map[string]any{
|
||||
// {
|
||||
// "email": "okto.octopus@test.com"
|
||||
// },
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiQWRtaW4iLCJlbWFpbCI6Im9rdG8ub2N0b3B1c0B0ZXN0LmNvbSJ9.yhg0nvYCpMVCVrRvwtmHzhF0RJqid_YFbjJ_xuBCyHs",
|
||||
},
|
||||
ExpectedEmail: "okto.octopus@test.com",
|
||||
ExpectedRole: "Admin",
|
||||
ExpectedGrafanaAdmin: boolPointer,
|
||||
wantErr: false,
|
||||
expectedEmail: "okto.octopus@test.com",
|
||||
expectedOrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
|
||||
expectedGrafanaAdmin: boolPointer,
|
||||
},
|
||||
{
|
||||
name: "Should give empty role and nil pointer for GrafanaAdmin when skip org role sync enable",
|
||||
userRawJSON: `{ "email": "okta-octopus@grafana.com", "role": "Admin" }`,
|
||||
RoleAttributePath: "role",
|
||||
settingSkipOrgRoleSync: true,
|
||||
OAuth2Extra: map[string]any{
|
||||
name: "should give empty role and nil pointer for GrafanaAdmin when skip org role sync enable",
|
||||
userRawJSON: `{ "email": "okta-octopus@grafana.com", "role": "Admin" }`,
|
||||
roleAttributePath: "role",
|
||||
skipOrgRoleSync: true,
|
||||
oAuth2Extra: map[string]any{
|
||||
// {
|
||||
// "email": "okto.octopus@test.com"
|
||||
// },
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiQWRtaW4iLCJlbWFpbCI6Im9rdG8ub2N0b3B1c0B0ZXN0LmNvbSJ9.yhg0nvYCpMVCVrRvwtmHzhF0RJqid_YFbjJ_xuBCyHs",
|
||||
},
|
||||
ExpectedEmail: "okto.octopus@test.com",
|
||||
ExpectedRole: "",
|
||||
ExpectedGrafanaAdmin: boolPointer,
|
||||
wantErr: false,
|
||||
expectedEmail: "okto.octopus@test.com",
|
||||
expectedOrgRoles: nil,
|
||||
expectedGrafanaAdmin: boolPointer,
|
||||
},
|
||||
{
|
||||
name: "Should give grafanaAdmin role for specific GrafanaAdmin in the role assignement",
|
||||
name: "should give grafanaAdmin role for specific GrafanaAdmin in the role assignement",
|
||||
userRawJSON: fmt.Sprintf(`{ "email": "okta-octopus@grafana.com", "role": "%s" }`, social.RoleGrafanaAdmin),
|
||||
RoleAttributePath: "role",
|
||||
roleAttributePath: "role",
|
||||
allowAssignGrafanaAdmin: true,
|
||||
OAuth2Extra: map[string]any{
|
||||
oAuth2Extra: map[string]any{
|
||||
// {
|
||||
// "email": "okto.octopus@test.com"
|
||||
// },
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiQWRtaW4iLCJlbWFpbCI6Im9rdG8ub2N0b3B1c0B0ZXN0LmNvbSJ9.yhg0nvYCpMVCVrRvwtmHzhF0RJqid_YFbjJ_xuBCyHs",
|
||||
},
|
||||
ExpectedEmail: "okto.octopus@test.com",
|
||||
ExpectedRole: "Admin",
|
||||
ExpectedGrafanaAdmin: trueBoolPtr(),
|
||||
wantErr: false,
|
||||
expectedEmail: "okto.octopus@test.com",
|
||||
expectedOrgRoles: map[int64]org.RoleType{1: org.RoleAdmin},
|
||||
expectedGrafanaAdmin: trueBoolPtr(),
|
||||
},
|
||||
{
|
||||
name: "should fallback to default org role when role attribute path is empty",
|
||||
userRawJSON: fmt.Sprintf(`{ "email": "okta-octopus@grafana.com", "groups": ["Group 1"], "role": "%s" }`, org.RoleEditor),
|
||||
oAuth2Extra: map[string]any{
|
||||
// {
|
||||
// "email": "okto.octopus@test.com"
|
||||
// },
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiQWRtaW4iLCJlbWFpbCI6Im9rdG8ub2N0b3B1c0B0ZXN0LmNvbSJ9.yhg0nvYCpMVCVrRvwtmHzhF0RJqid_YFbjJ_xuBCyHs",
|
||||
},
|
||||
expectedEmail: "okto.octopus@test.com",
|
||||
expectedOrgRoles: map[int64]org.RoleType{1: org.RoleViewer},
|
||||
},
|
||||
{
|
||||
name: "should map role when only org mapping is set",
|
||||
userRawJSON: fmt.Sprintf(`{ "email": "okta-octopus@grafana.com", "groups": ["Group 1"], "role": "%s" }`, org.RoleEditor),
|
||||
orgAttributePath: "groups",
|
||||
orgMapping: []string{"Group 1:Org4:Editor", "*:Org5:Viewer"},
|
||||
roleAttributeStrict: false,
|
||||
oAuth2Extra: map[string]any{
|
||||
// {
|
||||
// "email": "okto.octopus@test.com"
|
||||
// },
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiQWRtaW4iLCJlbWFpbCI6Im9rdG8ub2N0b3B1c0B0ZXN0LmNvbSJ9.yhg0nvYCpMVCVrRvwtmHzhF0RJqid_YFbjJ_xuBCyHs",
|
||||
},
|
||||
expectedEmail: "okto.octopus@test.com",
|
||||
expectedOrgRoles: map[int64]org.RoleType{4: org.RoleEditor, 5: org.RoleViewer},
|
||||
},
|
||||
{
|
||||
name: "should map role when only org mapping is set and role attribute strict is enabled",
|
||||
userRawJSON: fmt.Sprintf(`{ "email": "okta-octopus@grafana.com", "groups": ["Group 1"], "role": "%s" }`, org.RoleEditor),
|
||||
orgAttributePath: "groups",
|
||||
orgMapping: []string{"Group 1:Org4:Editor", "*:Org5:Viewer"},
|
||||
roleAttributeStrict: true,
|
||||
oAuth2Extra: map[string]any{
|
||||
// {
|
||||
// "email": "okto.octopus@test.com"
|
||||
// },
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiQWRtaW4iLCJlbWFpbCI6Im9rdG8ub2N0b3B1c0B0ZXN0LmNvbSJ9.yhg0nvYCpMVCVrRvwtmHzhF0RJqid_YFbjJ_xuBCyHs",
|
||||
},
|
||||
expectedEmail: "okto.octopus@test.com",
|
||||
expectedOrgRoles: map[int64]org.RoleType{4: org.RoleEditor, 5: org.RoleViewer},
|
||||
},
|
||||
{
|
||||
name: "should return nil OrgRoles when SkipOrgRoleSync is enabled",
|
||||
userRawJSON: fmt.Sprintf(`{ "email": "okta-octopus@grafana.com", "role": "%s" }`, org.RoleEditor),
|
||||
roleAttributePath: "role",
|
||||
skipOrgRoleSync: true,
|
||||
oAuth2Extra: map[string]any{
|
||||
// {
|
||||
// "email": "okto.octopus@test.com"
|
||||
// },
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiQWRtaW4iLCJlbWFpbCI6Im9rdG8ub2N0b3B1c0B0ZXN0LmNvbSJ9.yhg0nvYCpMVCVrRvwtmHzhF0RJqid_YFbjJ_xuBCyHs",
|
||||
},
|
||||
expectedOrgRoles: nil,
|
||||
expectedEmail: "okto.octopus@test.com",
|
||||
},
|
||||
{
|
||||
name: "should return error when neither role attribute path nor org mapping evaluates to a role and role attribute strict is enabled",
|
||||
userRawJSON: fmt.Sprintf(`{ "email": "okta-octopus@grafana.com", "role": "%s" }`, org.RoleEditor),
|
||||
roleAttributePath: "invalid_role_path",
|
||||
roleAttributeStrict: true,
|
||||
oAuth2Extra: map[string]any{
|
||||
// {
|
||||
// "email": "okto.octopus@test.com"
|
||||
// },
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiQWRtaW4iLCJlbWFpbCI6Im9rdG8ub2N0b3B1c0B0ZXN0LmNvbSJ9.yhg0nvYCpMVCVrRvwtmHzhF0RJqid_YFbjJ_xuBCyHs",
|
||||
},
|
||||
expectedErr: errRoleAttributeStrictViolation,
|
||||
},
|
||||
{
|
||||
name: "should return error when neither role attribute path nor org mapping is set and role attribute strict is enabled",
|
||||
userRawJSON: fmt.Sprintf(`{ "email": "okta-octopus@grafana.com", "role": "%s" }`, org.RoleEditor),
|
||||
roleAttributeStrict: true,
|
||||
oAuth2Extra: map[string]any{
|
||||
// {
|
||||
// "email": "okto.octopus@test.com"
|
||||
// },
|
||||
"id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiQWRtaW4iLCJlbWFpbCI6Im9rdG8ub2N0b3B1c0B0ZXN0LmNvbSJ9.yhg0nvYCpMVCVrRvwtmHzhF0RJqid_YFbjJ_xuBCyHs",
|
||||
},
|
||||
expectedErr: errRoleAttributeStrictViolation,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@ -103,17 +183,23 @@ func TestSocialOkta_UserInfo(t *testing.T) {
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
cfg := &setting.Cfg{
|
||||
AutoAssignOrgRole: "Viewer", // default role
|
||||
}
|
||||
|
||||
provider := NewOktaProvider(
|
||||
&social.OAuthInfo{
|
||||
ApiUrl: server.URL + "/user",
|
||||
RoleAttributePath: tt.RoleAttributePath,
|
||||
RoleAttributePath: tt.roleAttributePath,
|
||||
RoleAttributeStrict: tt.roleAttributeStrict,
|
||||
OrgMapping: tt.orgMapping,
|
||||
OrgAttributePath: tt.orgAttributePath,
|
||||
AllowAssignGrafanaAdmin: tt.allowAssignGrafanaAdmin,
|
||||
SkipOrgRoleSync: tt.settingSkipOrgRoleSync,
|
||||
SkipOrgRoleSync: tt.skipOrgRoleSync,
|
||||
},
|
||||
&setting.Cfg{
|
||||
AutoAssignOrgRole: tt.autoAssignOrgRole,
|
||||
},
|
||||
nil,
|
||||
cfg,
|
||||
ProvideOrgRoleMapper(cfg,
|
||||
&orgtest.FakeOrgService{ExpectedOrgs: []*org.OrgDTO{{ID: 4, Name: "Org4"}, {ID: 5, Name: "Org5"}}}),
|
||||
&ssosettingstests.MockService{},
|
||||
featuremgmt.WithFeatures())
|
||||
|
||||
@ -124,15 +210,19 @@ func TestSocialOkta_UserInfo(t *testing.T) {
|
||||
RefreshToken: "",
|
||||
Expiry: time.Now(),
|
||||
}
|
||||
token := staticToken.WithExtra(tt.OAuth2Extra)
|
||||
got, err := provider.UserInfo(context.Background(), server.Client(), token)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("UserInfo() error = %v, wantErr %v", err, tt.wantErr)
|
||||
|
||||
token := staticToken.WithExtra(tt.oAuth2Extra)
|
||||
actual, err := provider.UserInfo(context.Background(), server.Client(), token)
|
||||
|
||||
if tt.expectedErr != nil {
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, tt.expectedErr)
|
||||
return
|
||||
}
|
||||
require.Equal(t, tt.ExpectedEmail, got.Email)
|
||||
require.Equal(t, tt.ExpectedRole, got.Role)
|
||||
require.Equal(t, tt.ExpectedGrafanaAdmin, got.IsGrafanaAdmin)
|
||||
|
||||
require.Equal(t, tt.expectedEmail, actual.Email)
|
||||
require.Equal(t, tt.expectedOrgRoles, actual.OrgRoles)
|
||||
require.Equal(t, tt.expectedGrafanaAdmin, actual.IsGrafanaAdmin)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ func (c *OAuth) Authenticate(ctx context.Context, r *authn.Request) (*authn.Iden
|
||||
|
||||
// This is required to implement OrgRole mapping for OAuth providers step by step
|
||||
switch c.providerName {
|
||||
case social.GenericOAuthProviderName, social.GitHubProviderName, social.GitlabProviderName:
|
||||
case social.GenericOAuthProviderName, social.GitHubProviderName, social.GitlabProviderName, social.OktaProviderName:
|
||||
// Do nothing, these providers already supports OrgRole mapping
|
||||
default:
|
||||
userInfo.OrgRoles, userInfo.IsGrafanaAdmin, _ = getRoles(c.cfg, func() (org.RoleType, *bool, error) {
|
||||
|
Loading…
Reference in New Issue
Block a user