mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Auth: Add skip_org_role_sync to GitLab OAuth (#62055)
* Auth: Add skip_org_role_sync to GitLab OAuth - add: tests - docs added * Update pkg/login/social/gitlab_oauth.go Co-authored-by: Karl Persson <kalle.persson@grafana.com> * fix: for import Co-authored-by: Karl Persson <kalle.persson@grafana.com>
This commit is contained in:
parent
5f6616ff3e
commit
143ee0c49f
@ -546,6 +546,7 @@ allowed_groups =
|
||||
role_attribute_path =
|
||||
role_attribute_strict = false
|
||||
allow_assign_grafana_admin = false
|
||||
skip_org_role_sync = false
|
||||
|
||||
#################################### Google Auth #########################
|
||||
[auth.google]
|
||||
|
@ -550,6 +550,7 @@
|
||||
;role_attribute_path =
|
||||
;role_attribute_strict = false
|
||||
;allow_assign_grafana_admin = false
|
||||
;skip_org_role_sync = false
|
||||
|
||||
#################################### Google Auth ##########################
|
||||
[auth.google]
|
||||
|
@ -904,6 +904,21 @@ The following table shows the OAuth provider's setting with the default value an
|
||||
| Google | false | true | User organization roles are set with `defaultRole` and the org role can be changed for Google synced users. |
|
||||
| Google | true | true | User organization roles are set with `defaultRole` for Google. For other providers, the synchronization will be skipped, and the org role can be changed, along with other OAuth provider users' org roles. |
|
||||
|
||||
### [auth.gitlab] skip_org_role_sync
|
||||
|
||||
When a user logs in the first time, Grafana sets the organization role based on the value specified in `AutoAssignOrgRole`. If you want to manage organization roles, set the `skip_org_role_sync` option to `true`. GitLab syncs organization roles and sets Grafana Admins.
|
||||
This also impacts `allow_assign_grafana_admin` setting, by not syncing the grafana admin role from GitLab.
|
||||
|
||||
> **Note:** There is a separate setting called `oauth_skip_org_role_update_sync` which has a different scope. While `skip_org_role_sync` only applies to the specific OAuth provider, `oauth_skip_org_role_update_sync` is a generic setting that affects all configured OAuth providers.
|
||||
|
||||
The following table shows the OAuth provider's setting with the default value and the skip org role sync setting.
|
||||
| OAuth Provider | `oauth_skip_org_role_sync_update` | `skip_org_role_sync` | Behavior |
|
||||
| --- | --- | --- | --- |
|
||||
| GitLab | false | false | User organization roles are set with `defaultRole` and cannot be changed |
|
||||
| Github | true | false | User organization roles are set with `defaultRole` for GitLab, and Grafana Admins are set. For other providers, the synchronization is skipped, and the org role can be changed, along with other OAuth provider users' org roles. |
|
||||
| GitLab | false | true | User organization roles are set with `defaultRole`, and the organization role can be changed for GitLab synced users. |
|
||||
| GitLab | true | true | User organization roles are set with `defaultRole` for GitLab. For other providers, the synchronization is skipped, and the org role can be changed, along with other OAuth provider users' org roles. |
|
||||
|
||||
### api_key_max_seconds_to_live
|
||||
|
||||
Limit of API key seconds to live before expiration. Default is -1 (unlimited).
|
||||
|
@ -223,3 +223,16 @@ the correct teams.
|
||||
Your GitLab groups can be referenced in the same way as `allowed_groups`, like `example` or `foo/bar`.
|
||||
|
||||
[Learn more about Team Sync]({{< relref "../../configure-team-sync/" >}})
|
||||
|
||||
## Skip organization role sync
|
||||
|
||||
To prevent the sync of organization roles from GitLab, set `skip_org_role_sync` to `true`. This is useful if you want to manage the organization roles for your users from within Grafana.
|
||||
This also impacts the `allow_assign_grafana_admin` setting by not syncing the Grafana admin role from GitLab.
|
||||
|
||||
```ini
|
||||
[auth.gitlab]
|
||||
# ..
|
||||
# prevents the sync of org roles from Github
|
||||
skip_org_role_sync = true
|
||||
``
|
||||
```
|
||||
|
@ -226,6 +226,7 @@ export interface AuthSettings {
|
||||
LDAPSkipOrgRoleSync?: boolean;
|
||||
JWTAuthSkipOrgRoleSync?: boolean;
|
||||
GrafanaComSkipOrgRoleSync?: boolean;
|
||||
GitLabSkipOrgRoleSync?: boolean;
|
||||
AzureADSkipOrgRoleSync?: boolean;
|
||||
GoogleSkipOrgRoleSync?: boolean;
|
||||
DisableSyncLock?: boolean;
|
||||
|
@ -151,6 +151,7 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i
|
||||
"GoogleSkipOrgRoleSync": hs.Cfg.GoogleSkipOrgRoleSync,
|
||||
"JWTAuthSkipOrgRoleSync": hs.Cfg.JWTAuthSkipOrgRoleSync,
|
||||
"GrafanaComSkipOrgRoleSync": hs.Cfg.GrafanaComSkipOrgRoleSync,
|
||||
"GitLabSkipOrgRoleSync": hs.Cfg.GitLabSkipOrgRoleSync,
|
||||
"AzureADSkipOrgRoleSync": hs.Cfg.AzureADSkipOrgRoleSync,
|
||||
"DisableSyncLock": hs.Cfg.DisableSyncLock,
|
||||
},
|
||||
|
@ -7,12 +7,15 @@ import (
|
||||
"regexp"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models/roletype"
|
||||
)
|
||||
|
||||
type SocialGitlab struct {
|
||||
*SocialBase
|
||||
allowedGroups []string
|
||||
apiUrl string
|
||||
allowedGroups []string
|
||||
apiUrl string
|
||||
skipOrgRoleSync bool
|
||||
}
|
||||
|
||||
func (s *SocialGitlab) IsGroupMember(groups []string) bool {
|
||||
@ -107,14 +110,21 @@ func (s *SocialGitlab) UserInfo(client *http.Client, _ *oauth2.Token) (*BasicUse
|
||||
|
||||
groups := s.GetGroups(client)
|
||||
|
||||
role, grafanaAdmin := s.extractRoleAndAdmin(response.Body, groups, true)
|
||||
if s.roleAttributeStrict && !role.IsValid() {
|
||||
return nil, &InvalidBasicRoleError{idP: "Gitlab", assignedRole: string(role)}
|
||||
}
|
||||
|
||||
var role roletype.RoleType
|
||||
var isGrafanaAdmin *bool = nil
|
||||
if s.allowAssignGrafanaAdmin {
|
||||
isGrafanaAdmin = &grafanaAdmin
|
||||
if !s.skipOrgRoleSync {
|
||||
var grafanaAdmin bool
|
||||
role, grafanaAdmin = s.extractRoleAndAdmin(response.Body, groups, true)
|
||||
if s.roleAttributeStrict && !role.IsValid() {
|
||||
return nil, &InvalidBasicRoleError{idP: "Gitlab", assignedRole: string(role)}
|
||||
}
|
||||
|
||||
if s.allowAssignGrafanaAdmin {
|
||||
isGrafanaAdmin = &grafanaAdmin
|
||||
}
|
||||
}
|
||||
if s.allowAssignGrafanaAdmin && s.skipOrgRoleSync {
|
||||
s.log.Debug("allowAssignGrafanaAdmin and skipOrgRoleSync are both set, Grafana Admin role will not be synced, consider setting one or the other")
|
||||
}
|
||||
|
||||
userInfo := &BasicUserInfo{
|
||||
|
@ -27,16 +27,19 @@ const (
|
||||
)
|
||||
|
||||
func TestSocialGitlab_UserInfo(t *testing.T) {
|
||||
var nilPointer *bool
|
||||
provider := SocialGitlab{
|
||||
SocialBase: &SocialBase{
|
||||
log: newLogger("gitlab_oauth_test", "debug"),
|
||||
},
|
||||
skipOrgRoleSync: false,
|
||||
}
|
||||
|
||||
type conf struct {
|
||||
AllowAssignGrafanaAdmin bool
|
||||
RoleAttributeStrict bool
|
||||
AutoAssignOrgRole org.RoleType
|
||||
SkipOrgRoleSync bool
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
@ -83,6 +86,17 @@ func TestSocialGitlab_UserInfo(t *testing.T) {
|
||||
ExpectedRole: "Editor",
|
||||
ExpectedGrafanaAdmin: falseBoolPtr(),
|
||||
},
|
||||
{
|
||||
Name: "Should not sync role, return empty role and nil pointer for GrafanaAdmin for skip org role sync set to true",
|
||||
Cfg: conf{SkipOrgRoleSync: true},
|
||||
UserRespBody: editorUserRespBody,
|
||||
GroupsRespBody: "[" + strings.Join([]string{viewerGroup, editorGroup}, ",") + "]",
|
||||
RoleAttributePath: gitlabAttrPath,
|
||||
ExpectedLogin: "gitlab-editor",
|
||||
ExpectedEmail: "gitlab-editor@example.org",
|
||||
ExpectedRole: "",
|
||||
ExpectedGrafanaAdmin: nilPointer,
|
||||
},
|
||||
{ // Case that's going to change with Grafana 10
|
||||
Name: "No fallback to default org role (will change in Grafana 10)",
|
||||
Cfg: conf{AutoAssignOrgRole: org.RoleViewer},
|
||||
@ -126,6 +140,7 @@ func TestSocialGitlab_UserInfo(t *testing.T) {
|
||||
provider.allowAssignGrafanaAdmin = test.Cfg.AllowAssignGrafanaAdmin
|
||||
provider.autoAssignOrgRole = string(test.Cfg.AutoAssignOrgRole)
|
||||
provider.roleAttributeStrict = test.Cfg.RoleAttributeStrict
|
||||
provider.skipOrgRoleSync = test.Cfg.SkipOrgRoleSync
|
||||
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -152,9 +152,10 @@ func ProvideService(cfg *setting.Cfg, features *featuremgmt.FeatureManager) *Soc
|
||||
// GitLab.
|
||||
if name == "gitlab" {
|
||||
ss.socialMap["gitlab"] = &SocialGitlab{
|
||||
SocialBase: newSocialBase(name, &config, info, cfg.AutoAssignOrgRole, cfg.OAuthSkipOrgRoleUpdateSync, *features),
|
||||
apiUrl: info.ApiUrl,
|
||||
allowedGroups: util.SplitString(sec.Key("allowed_groups").String()),
|
||||
SocialBase: newSocialBase(name, &config, info, cfg.AutoAssignOrgRole, cfg.OAuthSkipOrgRoleUpdateSync, *features),
|
||||
apiUrl: info.ApiUrl,
|
||||
allowedGroups: util.SplitString(sec.Key("allowed_groups").String()),
|
||||
skipOrgRoleSync: cfg.GitLabSkipOrgRoleSync,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -430,6 +430,9 @@ type Cfg struct {
|
||||
// Google
|
||||
GoogleSkipOrgRoleSync bool
|
||||
|
||||
// Gitlab
|
||||
GitLabSkipOrgRoleSync bool
|
||||
|
||||
// LDAP
|
||||
LDAPEnabled bool
|
||||
LDAPSkipOrgRoleSync bool
|
||||
@ -1377,6 +1380,11 @@ func readAuthGoogleSettings(iniFile *ini.File, cfg *Cfg) {
|
||||
cfg.GoogleSkipOrgRoleSync = sec.Key("skip_org_role_sync").MustBool(false)
|
||||
}
|
||||
|
||||
func readAuthGitlabSettings(iniFile *ini.File, cfg *Cfg) {
|
||||
sec := iniFile.Section("auth.gitlab")
|
||||
cfg.GitLabSkipOrgRoleSync = sec.Key("skip_org_role_sync").MustBool(false)
|
||||
}
|
||||
|
||||
func readAuthSettings(iniFile *ini.File, cfg *Cfg) (err error) {
|
||||
auth := iniFile.Section("auth")
|
||||
|
||||
@ -1434,6 +1442,9 @@ func readAuthSettings(iniFile *ini.File, cfg *Cfg) (err error) {
|
||||
// Google Auth
|
||||
readAuthGoogleSettings(iniFile, cfg)
|
||||
|
||||
// GitLab Auth
|
||||
readAuthGitlabSettings(iniFile, cfg)
|
||||
|
||||
// anonymous access
|
||||
AnonymousEnabled = iniFile.Section("auth.anonymous").Key("enabled").MustBool(false)
|
||||
cfg.AnonymousEnabled = AnonymousEnabled
|
||||
|
@ -39,7 +39,7 @@ interface OwnProps extends GrafanaRouteComponentProps<{ id: string }> {
|
||||
error?: UserAdminError;
|
||||
}
|
||||
|
||||
const SyncedOAuthLabels: string[] = ['GitHub', 'GitLab', 'OAuth'];
|
||||
const SyncedOAuthLabels: string[] = ['GitHub', 'OAuth'];
|
||||
|
||||
export class UserAdminPage extends PureComponent<Props> {
|
||||
async componentDidMount() {
|
||||
@ -113,6 +113,7 @@ export class UserAdminPage extends PureComponent<Props> {
|
||||
user?.isExternal && user?.authLabels?.some((r) => SyncedOAuthLabels.includes(r));
|
||||
const isSAMLUser = user?.isExternal && user?.authLabels?.includes('SAML');
|
||||
const isGoogleUser = user?.isExternal && user?.authLabels?.includes('Google');
|
||||
const isGitLabUser = user?.isExternal && user?.authLabels?.includes('GitLab');
|
||||
const isAuthProxyUser = user?.isExternal && user?.authLabels?.includes('Auth Proxy');
|
||||
const isAzureADUser = user?.isExternal && user?.authLabels?.includes('AzureAD');
|
||||
const isGrafanaComUser = user?.isExternal && user?.authLabels?.includes('grafana.com');
|
||||
@ -122,6 +123,7 @@ export class UserAdminPage extends PureComponent<Props> {
|
||||
!(
|
||||
isAuthProxyUser ||
|
||||
isGoogleUser ||
|
||||
isGitLabUser ||
|
||||
isOAuthUserWithSkippableSync ||
|
||||
isSAMLUser ||
|
||||
isLDAPUser ||
|
||||
@ -136,6 +138,7 @@ export class UserAdminPage extends PureComponent<Props> {
|
||||
// both OAuthSkipOrgRoleUpdateSync and specific provider settings needs to be false for a user to be synced
|
||||
(!config.auth.OAuthSkipOrgRoleUpdateSync && !config.auth.GrafanaComSkipOrgRoleSync && isGrafanaComUser) ||
|
||||
(!config.auth.OAuthSkipOrgRoleUpdateSync && !config.auth.AzureADSkipOrgRoleSync && isAzureADUser) ||
|
||||
(!config.auth.OAuthSkipOrgRoleUpdateSync && !config.auth.GitLabSkipOrgRoleSync && isGitLabUser) ||
|
||||
(!config.auth.OAuthSkipOrgRoleUpdateSync && !config.auth.GoogleSkipOrgRoleSync && isGoogleUser));
|
||||
|
||||
const pageNav: NavModelItem = {
|
||||
|
Loading…
Reference in New Issue
Block a user