mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
OAuth: Support role mapping for GitLab OAuth (#30025)
* Support `role_attribute_path` for GitLab OAuth Allow role mapping for GitLab accounts. Example: [auth.gitlab] role_attribute_path = is_admin && 'Admin' || 'Viewer' * Support `role_attribute_path` for GitLab OAuth Allow role mapping for GitLab accounts. Example: [auth.gitlab] role_attribute_path = is_admin && 'Admin' || 'Viewer' * docs: add docs for role_attribute_path * Apply suggestions from code review Co-authored-by: Peter Leitzen <splattael@users.noreply.github.com> * docs: update example example should suggest a full configuration * Apply suggestions from code review Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> * Apply suggestions from code review Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com> * docs: add suggestions from tech writers Co-authored-by: Henry Sachs <Henry.Sachs@deutschebahn.com> Co-authored-by: Henry Sachs <henrysachs@gmail.com> Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> Co-authored-by: Fiona Artiaga <89225282+GrafanaWriter@users.noreply.github.com>
This commit is contained in:
@@ -26,10 +26,10 @@ instance, if you access Grafana at `http://203.0.113.31:3000`, you should use
|
|||||||
http://203.0.113.31:3000/login/gitlab
|
http://203.0.113.31:3000/login/gitlab
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, select _read_api_ as the _Scope_ and submit the form. Note that if you're
|
Finally, select _read_api_as the_Scope_and submit the form. Note that if you're
|
||||||
not going to use GitLab groups for authorization (i.e. not setting
|
not going to use GitLab groups for authorization (i.e. not setting
|
||||||
`allowed_groups`, see below), you can select _read_user_ instead of _read_api_ as
|
`allowed_groups`, see below), you can select_read_user_ instead of _read_api_as
|
||||||
the _Scope_, thus giving a more restricted access to your GitLab API.
|
the_Scope_, thus giving a more restricted access to your GitLab API.
|
||||||
|
|
||||||
You'll get an _Application Id_ and a _Secret_ in return; we'll call them
|
You'll get an _Application Id_ and a _Secret_ in return; we'll call them
|
||||||
`GITLAB_APPLICATION_ID` and `GITLAB_SECRET` respectively for the rest of this
|
`GITLAB_APPLICATION_ID` and `GITLAB_SECRET` respectively for the rest of this
|
||||||
@@ -94,8 +94,8 @@ display name, especially if the display name contains spaces or special
|
|||||||
characters. Make sure you always use the group or subgroup name as it appears
|
characters. Make sure you always use the group or subgroup name as it appears
|
||||||
in the URL of the group or subgroup.
|
in the URL of the group or subgroup.
|
||||||
|
|
||||||
Here's a complete example with `allow_sign_up` enabled, and access limited to
|
Here's a complete example with `allow_sign_up` enabled, with access limited to
|
||||||
the `example` and `foo/bar` groups:
|
the `example` and `foo/bar` groups. The example also promotes all GitLab Admins to Grafana Admins:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[auth.gitlab]
|
[auth.gitlab]
|
||||||
@@ -103,13 +103,28 @@ enabled = true
|
|||||||
allow_sign_up = true
|
allow_sign_up = true
|
||||||
client_id = GITLAB_APPLICATION_ID
|
client_id = GITLAB_APPLICATION_ID
|
||||||
client_secret = GITLAB_SECRET
|
client_secret = GITLAB_SECRET
|
||||||
scopes = api
|
scopes = read_api
|
||||||
auth_url = https://gitlab.com/oauth/authorize
|
auth_url = https://gitlab.com/oauth/authorize
|
||||||
token_url = https://gitlab.com/oauth/token
|
token_url = https://gitlab.com/oauth/token
|
||||||
api_url = https://gitlab.com/api/v4
|
api_url = https://gitlab.com/api/v4
|
||||||
allowed_groups = example, foo/bar
|
allowed_groups = example, foo/bar
|
||||||
|
role_attribute_path = is_admin && 'Admin' || 'Viewer'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Map roles
|
||||||
|
|
||||||
|
You can use GitLab OAuth to map roles. During mapping, Grafana checks for the presence of a role using the [JMESPath](http://jmespath.org/examples.html) specified via the `role_attribute_path` configuration option.
|
||||||
|
|
||||||
|
For the path lookup, Grafana uses JSON obtained from querying GitLab's API [`/api/v4/user`](https://docs.gitlab.com/ee/api/users.html#list-current-user-for-normal-users) endpoint. The result of evaluating the `role_attribute_path` JMESPath expression must be a valid Grafana role, for example, `Viewer`, `Editor` or `Admin`. For more information about roles and permissions in Grafana, refer to [Organization roles]({{< relref "../permissions/organization_roles.md" >}}).
|
||||||
|
|
||||||
|
An example Query could look like the following:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
role_attribute_path = is_admin && 'Admin' || 'Viewer'
|
||||||
|
```
|
||||||
|
|
||||||
|
This allows every GitLab Admin to be an Admin in Grafana.
|
||||||
|
|
||||||
### Team Sync (Enterprise only)
|
### Team Sync (Enterprise only)
|
||||||
|
|
||||||
> Only available in Grafana Enterprise v6.4+
|
> Only available in Grafana Enterprise v6.4+
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type SocialGitlab struct {
|
|||||||
*SocialBase
|
*SocialBase
|
||||||
allowedGroups []string
|
allowedGroups []string
|
||||||
apiUrl string
|
apiUrl string
|
||||||
|
roleAttributePath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SocialGitlab) Type() int {
|
func (s *SocialGitlab) Type() int {
|
||||||
@@ -114,12 +115,18 @@ func (s *SocialGitlab) UserInfo(client *http.Client, token *oauth2.Token) (*Basi
|
|||||||
|
|
||||||
groups := s.GetGroups(client)
|
groups := s.GetGroups(client)
|
||||||
|
|
||||||
|
role, err := s.extractRole(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
s.log.Error("Failed to extract role", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
userInfo := &BasicUserInfo{
|
userInfo := &BasicUserInfo{
|
||||||
Id: fmt.Sprintf("%d", data.Id),
|
Id: fmt.Sprintf("%d", data.Id),
|
||||||
Name: data.Name,
|
Name: data.Name,
|
||||||
Login: data.Username,
|
Login: data.Username,
|
||||||
Email: data.Email,
|
Email: data.Email,
|
||||||
Groups: groups,
|
Groups: groups,
|
||||||
|
Role: role,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !s.IsGroupMember(groups) {
|
if !s.IsGroupMember(groups) {
|
||||||
@@ -128,3 +135,16 @@ func (s *SocialGitlab) UserInfo(client *http.Client, token *oauth2.Token) (*Basi
|
|||||||
|
|
||||||
return userInfo, nil
|
return userInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SocialGitlab) extractRole(rawJSON []byte) (string, error) {
|
||||||
|
if s.roleAttributePath == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
role, err := s.searchJSONForStringAttr(s.roleAttributePath, rawJSON)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return role, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ func ProvideService(cfg *setting.Cfg) *SocialService {
|
|||||||
SocialBase: newSocialBase(name, &config, info),
|
SocialBase: newSocialBase(name, &config, info),
|
||||||
apiUrl: info.ApiUrl,
|
apiUrl: info.ApiUrl,
|
||||||
allowedGroups: util.SplitString(sec.Key("allowed_groups").String()),
|
allowedGroups: util.SplitString(sec.Key("allowed_groups").String()),
|
||||||
|
roleAttributePath: info.RoleAttributePath,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user