OAuth: Make generic teams URL and JMES path configurable (#37233)
OAuth: Make generic teams URL and JMES path configurable
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"net/http"
|
||||
"net/mail"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
@@ -21,6 +22,7 @@ type SocialGenericOAuth struct {
|
||||
*SocialBase
|
||||
allowedOrganizations []string
|
||||
apiUrl string
|
||||
teamsUrl string
|
||||
emailAttributeName string
|
||||
emailAttributePath string
|
||||
loginAttributePath string
|
||||
@@ -29,7 +31,8 @@ type SocialGenericOAuth struct {
|
||||
roleAttributeStrict bool
|
||||
groupsAttributePath string
|
||||
idTokenAttributeName string
|
||||
teamIds []int
|
||||
teamIdsAttributePath string
|
||||
teamIds []string
|
||||
}
|
||||
|
||||
func (s *SocialGenericOAuth) Type() int {
|
||||
@@ -41,8 +44,8 @@ func (s *SocialGenericOAuth) IsTeamMember(client *http.Client) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
teamMemberships, ok := s.FetchTeamMemberships(client)
|
||||
if !ok {
|
||||
teamMemberships, err := s.FetchTeamMemberships(client)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -412,15 +415,36 @@ func (s *SocialGenericOAuth) FetchPrivateEmail(client *http.Client) (string, err
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (s *SocialGenericOAuth) FetchTeamMemberships(client *http.Client) ([]int, bool) {
|
||||
func (s *SocialGenericOAuth) FetchTeamMemberships(client *http.Client) ([]string, error) {
|
||||
var err error
|
||||
var ids []string
|
||||
|
||||
if s.teamsUrl == "" {
|
||||
ids, err = s.fetchTeamMembershipsFromDeprecatedTeamsUrl(client)
|
||||
} else {
|
||||
ids, err = s.fetchTeamMembershipsFromTeamsUrl(client)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
s.log.Debug("Received team memberships", "ids", ids)
|
||||
}
|
||||
|
||||
return ids, err
|
||||
}
|
||||
|
||||
func (s *SocialGenericOAuth) fetchTeamMembershipsFromDeprecatedTeamsUrl(client *http.Client) ([]string, error) {
|
||||
var response httpGetResponse
|
||||
var err error
|
||||
var ids []string
|
||||
|
||||
type Record struct {
|
||||
Id int `json:"id"`
|
||||
}
|
||||
|
||||
response, err := s.httpGet(client, fmt.Sprintf(s.apiUrl+"/teams"))
|
||||
response, err = s.httpGet(client, fmt.Sprintf(s.apiUrl+"/teams"))
|
||||
if err != nil {
|
||||
s.log.Error("Error getting team memberships", "url", s.apiUrl+"/teams", "error", err)
|
||||
return nil, false
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
var records []Record
|
||||
@@ -428,17 +452,32 @@ func (s *SocialGenericOAuth) FetchTeamMemberships(client *http.Client) ([]int, b
|
||||
err = json.Unmarshal(response.Body, &records)
|
||||
if err != nil {
|
||||
s.log.Error("Error decoding team memberships response", "raw_json", string(response.Body), "error", err)
|
||||
return nil, false
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
var ids = make([]int, len(records))
|
||||
ids = make([]string, len(records))
|
||||
for i, record := range records {
|
||||
ids[i] = record.Id
|
||||
ids[i] = strconv.Itoa(record.Id)
|
||||
}
|
||||
|
||||
s.log.Debug("Received team memberships", "ids", ids)
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
return ids, true
|
||||
func (s *SocialGenericOAuth) fetchTeamMembershipsFromTeamsUrl(client *http.Client) ([]string, error) {
|
||||
if s.teamIdsAttributePath == "" {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
var response httpGetResponse
|
||||
var err error
|
||||
|
||||
response, err = s.httpGet(client, fmt.Sprintf(s.teamsUrl))
|
||||
if err != nil {
|
||||
s.log.Error("Error getting team memberships", "url", s.teamsUrl, "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.searchJSONForStringArrayAttr(s.teamIdsAttributePath, response.Body)
|
||||
}
|
||||
|
||||
func (s *SocialGenericOAuth) FetchOrganizations(client *http.Client) ([]string, bool) {
|
||||
|
||||
+27
-21
@@ -38,9 +38,11 @@ type OAuthInfo struct {
|
||||
RoleAttributePath string
|
||||
RoleAttributeStrict bool
|
||||
GroupsAttributePath string
|
||||
TeamIdsAttributePath string
|
||||
AllowedDomains []string
|
||||
HostedDomain string
|
||||
ApiUrl string
|
||||
TeamsUrl string
|
||||
AllowSignup bool
|
||||
Name string
|
||||
TlsClientCert string
|
||||
@@ -60,26 +62,28 @@ func ProvideService(cfg *setting.Cfg) *SocialService {
|
||||
sec := cfg.Raw.Section("auth." + name)
|
||||
|
||||
info := &OAuthInfo{
|
||||
ClientId: sec.Key("client_id").String(),
|
||||
ClientSecret: sec.Key("client_secret").String(),
|
||||
Scopes: util.SplitString(sec.Key("scopes").String()),
|
||||
AuthUrl: sec.Key("auth_url").String(),
|
||||
TokenUrl: sec.Key("token_url").String(),
|
||||
ApiUrl: sec.Key("api_url").String(),
|
||||
Enabled: sec.Key("enabled").MustBool(),
|
||||
EmailAttributeName: sec.Key("email_attribute_name").String(),
|
||||
EmailAttributePath: sec.Key("email_attribute_path").String(),
|
||||
RoleAttributePath: sec.Key("role_attribute_path").String(),
|
||||
RoleAttributeStrict: sec.Key("role_attribute_strict").MustBool(),
|
||||
GroupsAttributePath: sec.Key("groups_attribute_path").String(),
|
||||
AllowedDomains: util.SplitString(sec.Key("allowed_domains").String()),
|
||||
HostedDomain: sec.Key("hosted_domain").String(),
|
||||
AllowSignup: sec.Key("allow_sign_up").MustBool(),
|
||||
Name: sec.Key("name").MustString(name),
|
||||
TlsClientCert: sec.Key("tls_client_cert").String(),
|
||||
TlsClientKey: sec.Key("tls_client_key").String(),
|
||||
TlsClientCa: sec.Key("tls_client_ca").String(),
|
||||
TlsSkipVerify: sec.Key("tls_skip_verify_insecure").MustBool(),
|
||||
ClientId: sec.Key("client_id").String(),
|
||||
ClientSecret: sec.Key("client_secret").String(),
|
||||
Scopes: util.SplitString(sec.Key("scopes").String()),
|
||||
AuthUrl: sec.Key("auth_url").String(),
|
||||
TokenUrl: sec.Key("token_url").String(),
|
||||
ApiUrl: sec.Key("api_url").String(),
|
||||
TeamsUrl: sec.Key("teams_url").String(),
|
||||
Enabled: sec.Key("enabled").MustBool(),
|
||||
EmailAttributeName: sec.Key("email_attribute_name").String(),
|
||||
EmailAttributePath: sec.Key("email_attribute_path").String(),
|
||||
RoleAttributePath: sec.Key("role_attribute_path").String(),
|
||||
RoleAttributeStrict: sec.Key("role_attribute_strict").MustBool(),
|
||||
GroupsAttributePath: sec.Key("groups_attribute_path").String(),
|
||||
TeamIdsAttributePath: sec.Key("team_ids_attribute_path").String(),
|
||||
AllowedDomains: util.SplitString(sec.Key("allowed_domains").String()),
|
||||
HostedDomain: sec.Key("hosted_domain").String(),
|
||||
AllowSignup: sec.Key("allow_sign_up").MustBool(),
|
||||
Name: sec.Key("name").MustString(name),
|
||||
TlsClientCert: sec.Key("tls_client_cert").String(),
|
||||
TlsClientKey: sec.Key("tls_client_key").String(),
|
||||
TlsClientCa: sec.Key("tls_client_ca").String(),
|
||||
TlsSkipVerify: sec.Key("tls_skip_verify_insecure").MustBool(),
|
||||
}
|
||||
|
||||
// when empty_scopes parameter exists and is true, overwrite scope with empty value
|
||||
@@ -162,6 +166,7 @@ func ProvideService(cfg *setting.Cfg) *SocialService {
|
||||
ss.socialMap["generic_oauth"] = &SocialGenericOAuth{
|
||||
SocialBase: newSocialBase(name, &config, info),
|
||||
apiUrl: info.ApiUrl,
|
||||
teamsUrl: info.TeamsUrl,
|
||||
emailAttributeName: info.EmailAttributeName,
|
||||
emailAttributePath: info.EmailAttributePath,
|
||||
nameAttributePath: sec.Key("name_attribute_path").String(),
|
||||
@@ -170,7 +175,8 @@ func ProvideService(cfg *setting.Cfg) *SocialService {
|
||||
groupsAttributePath: info.GroupsAttributePath,
|
||||
loginAttributePath: sec.Key("login_attribute_path").String(),
|
||||
idTokenAttributeName: sec.Key("id_token_attribute_name").String(),
|
||||
teamIds: sec.Key("team_ids").Ints(","),
|
||||
teamIdsAttributePath: sec.Key("team_ids_attribute_path").String(),
|
||||
teamIds: sec.Key("team_ids").Strings(","),
|
||||
allowedOrganizations: util.SplitString(sec.Key("allowed_organizations").String()),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user