Auth: Add skip_org_role_sync setting for github (#61673)
* add: skip_org_role_sync setting for github * fix: frontend * rearranged tests * refactor: assignGrafanaAdmin skip also * Add: tests for allowGrafanaAdmin - both for the case when both settings are set and the setting for only allowGrafanaAdmin * Apply suggestions from code review Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> * Update docs/sources/setup-grafana/configure-grafana/_index.md Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> * Update pkg/login/social/github_oauth.go Co-authored-by: Ieva <ieva.vasiljeva@grafana.com> * added vairable inside scope * Update docs/sources/setup-grafana/configure-security/configure-authentication/github/index.md * Update docs/sources/setup-grafana/configure-security/configure-authentication/github/index.md Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
This commit is contained in:
co-authored by
Christopher Moyer
Ieva
parent
529e6c379f
commit
6bd11e0ebf
@@ -148,6 +148,7 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i
|
||||
"OAuthSkipOrgRoleUpdateSync": hs.Cfg.OAuthSkipOrgRoleUpdateSync,
|
||||
"SAMLSkipOrgRoleSync": hs.Cfg.SectionWithEnvOverrides("auth.saml").Key("skip_org_role_sync").MustBool(false),
|
||||
"LDAPSkipOrgRoleSync": hs.Cfg.LDAPSkipOrgRoleSync,
|
||||
"GithubSkipOrgRoleSync": hs.Cfg.GithubSkipOrgRoleSync,
|
||||
"GoogleSkipOrgRoleSync": hs.Cfg.GoogleSkipOrgRoleSync,
|
||||
"JWTAuthSkipOrgRoleSync": hs.Cfg.JWTAuthSkipOrgRoleSync,
|
||||
"GrafanaComSkipOrgRoleSync": hs.Cfg.GrafanaComSkipOrgRoleSync,
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"regexp"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models/roletype"
|
||||
)
|
||||
|
||||
type SocialGithub struct {
|
||||
@@ -15,6 +17,7 @@ type SocialGithub struct {
|
||||
allowedOrganizations []string
|
||||
apiUrl string
|
||||
teamIds []int
|
||||
skipOrgRoleSync bool
|
||||
}
|
||||
|
||||
type GithubTeam struct {
|
||||
@@ -201,14 +204,25 @@ func (s *SocialGithub) UserInfo(client *http.Client, token *oauth2.Token) (*Basi
|
||||
|
||||
teams := convertToGroupList(teamMemberships)
|
||||
|
||||
role, grafanaAdmin := s.extractRoleAndAdmin(response.Body, teams, true)
|
||||
if s.roleAttributeStrict && !role.IsValid() {
|
||||
return nil, &InvalidBasicRoleError{idP: "Github", assignedRole: string(role)}
|
||||
var role roletype.RoleType
|
||||
var isGrafanaAdmin *bool = nil
|
||||
|
||||
if !s.skipOrgRoleSync {
|
||||
var grafanaAdmin bool
|
||||
role, grafanaAdmin = s.extractRoleAndAdmin(response.Body, teams, true)
|
||||
|
||||
if s.roleAttributeStrict && !role.IsValid() {
|
||||
return nil, &InvalidBasicRoleError{idP: "Github", assignedRole: string(role)}
|
||||
}
|
||||
|
||||
if s.allowAssignGrafanaAdmin {
|
||||
isGrafanaAdmin = &grafanaAdmin
|
||||
}
|
||||
}
|
||||
|
||||
var isGrafanaAdmin *bool = nil
|
||||
if s.allowAssignGrafanaAdmin {
|
||||
isGrafanaAdmin = &grafanaAdmin
|
||||
// we skip allowing assignment of GrafanaAdmin if skipOrgRoleSync is present
|
||||
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{
|
||||
|
||||
@@ -112,11 +112,14 @@ const testGHUserJSON = `{
|
||||
}`
|
||||
|
||||
func TestSocialGitHub_UserInfo(t *testing.T) {
|
||||
var boolPointer *bool
|
||||
tests := []struct {
|
||||
name string
|
||||
userRawJSON string
|
||||
userTeamsRawJSON string
|
||||
settingAutoAssignOrgRole string
|
||||
settingAllowGrafanaAdmin bool
|
||||
settingSkipOrgRoleSync bool
|
||||
roleAttributePath string
|
||||
autoAssignOrgRole string
|
||||
want *BasicUserInfo
|
||||
@@ -167,6 +170,38 @@ func TestSocialGitHub_UserInfo(t *testing.T) {
|
||||
Groups: []string{"https://github.com/orgs/github/teams/justice-league", "@github/justice-league"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Should be empty role if setting skipOrgRoleSync is set to true",
|
||||
roleAttributePath: "contains(groups[*], '@github/justice-league') && 'Editor' || 'Viewer'",
|
||||
settingSkipOrgRoleSync: true,
|
||||
userRawJSON: testGHUserJSON,
|
||||
userTeamsRawJSON: testGHUserTeamsJSON,
|
||||
want: &BasicUserInfo{
|
||||
Id: "1",
|
||||
Name: "monalisa octocat",
|
||||
Email: "octocat@github.com",
|
||||
Login: "octocat",
|
||||
Role: "",
|
||||
Groups: []string{"https://github.com/orgs/github/teams/justice-league", "@github/justice-league"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Should return nil pointer if allowGrafanaAdmin and skipOrgRoleSync setting is set to true",
|
||||
roleAttributePath: "contains(groups[*], '@github/justice-league') && 'Editor' || 'Viewer'",
|
||||
settingSkipOrgRoleSync: true,
|
||||
settingAllowGrafanaAdmin: true,
|
||||
userRawJSON: testGHUserJSON,
|
||||
userTeamsRawJSON: testGHUserTeamsJSON,
|
||||
want: &BasicUserInfo{
|
||||
Id: "1",
|
||||
Name: "monalisa octocat",
|
||||
Email: "octocat@github.com",
|
||||
Login: "octocat",
|
||||
Role: "",
|
||||
Groups: []string{"https://github.com/orgs/github/teams/justice-league", "@github/justice-league"},
|
||||
IsGrafanaAdmin: boolPointer,
|
||||
},
|
||||
},
|
||||
{ // Case that's going to change with Grafana 10
|
||||
name: "No fallback to default org role (will change in Grafana 10)",
|
||||
roleAttributePath: "",
|
||||
@@ -208,6 +243,7 @@ func TestSocialGitHub_UserInfo(t *testing.T) {
|
||||
allowedOrganizations: []string{},
|
||||
apiUrl: server.URL + "/user",
|
||||
teamIds: []int{},
|
||||
skipOrgRoleSync: tt.settingSkipOrgRoleSync,
|
||||
}
|
||||
|
||||
token := &oauth2.Token{
|
||||
|
||||
@@ -146,6 +146,7 @@ func ProvideService(cfg *setting.Cfg, features *featuremgmt.FeatureManager) *Soc
|
||||
apiUrl: info.ApiUrl,
|
||||
teamIds: sec.Key("team_ids").Ints(","),
|
||||
allowedOrganizations: util.SplitString(sec.Key("allowed_organizations").String()),
|
||||
skipOrgRoleSync: cfg.GithubSkipOrgRoleSync,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -467,6 +467,9 @@ type Cfg struct {
|
||||
// then Live uses AppURL as the only allowed origin.
|
||||
LiveAllowedOrigins []string
|
||||
|
||||
// Github OAuth
|
||||
GithubSkipOrgRoleSync bool
|
||||
|
||||
// Grafana.com URL, used for OAuth redirect.
|
||||
GrafanaComURL string
|
||||
// Grafana.com API URL. Can be set separately to GrafanaComURL
|
||||
@@ -1375,6 +1378,11 @@ func readAuthGrafanaComSettings(iniFile *ini.File, cfg *Cfg) {
|
||||
cfg.GrafanaComSkipOrgRoleSync = sec.Key("skip_org_role_sync").MustBool(false)
|
||||
}
|
||||
|
||||
func readAuthGithubSettings(iniFile *ini.File, cfg *Cfg) {
|
||||
sec := iniFile.Section("auth.github")
|
||||
cfg.GithubSkipOrgRoleSync = sec.Key("skip_org_role_sync").MustBool(false)
|
||||
}
|
||||
|
||||
func readAuthGoogleSettings(iniFile *ini.File, cfg *Cfg) {
|
||||
sec := iniFile.Section("auth.google")
|
||||
cfg.GoogleSkipOrgRoleSync = sec.Key("skip_org_role_sync").MustBool(false)
|
||||
@@ -1501,7 +1509,11 @@ func readAuthSettings(iniFile *ini.File, cfg *Cfg) (err error) {
|
||||
|
||||
cfg.AuthProxyHeadersEncoded = authProxy.Key("headers_encoded").MustBool(false)
|
||||
|
||||
// GrafanaCom
|
||||
readAuthGrafanaComSettings(iniFile, cfg)
|
||||
|
||||
// Github
|
||||
readAuthGithubSettings(iniFile, cfg)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user