mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Add github organizations support
This commit is contained in:
parent
57bacb339c
commit
b55d9350e7
@ -153,6 +153,7 @@ token_url = https://github.com/login/oauth/access_token
|
|||||||
api_url = https://api.github.com/user
|
api_url = https://api.github.com/user
|
||||||
team_ids =
|
team_ids =
|
||||||
allowed_domains =
|
allowed_domains =
|
||||||
|
allowed_organizations =
|
||||||
|
|
||||||
#################################### Google Auth ##########################
|
#################################### Google Auth ##########################
|
||||||
[auth.google]
|
[auth.google]
|
||||||
|
@ -146,12 +146,13 @@
|
|||||||
;allow_sign_up = false
|
;allow_sign_up = false
|
||||||
;client_id = some_id
|
;client_id = some_id
|
||||||
;client_secret = some_secret
|
;client_secret = some_secret
|
||||||
;scopes = user:email
|
;scopes = user:email,read:org
|
||||||
;auth_url = https://github.com/login/oauth/authorize
|
;auth_url = https://github.com/login/oauth/authorize
|
||||||
;token_url = https://github.com/login/oauth/access_token
|
;token_url = https://github.com/login/oauth/access_token
|
||||||
;api_url = https://api.github.com/user
|
;api_url = https://api.github.com/user
|
||||||
;team_ids =
|
;team_ids =
|
||||||
;allowed_domains =
|
;allowed_domains =
|
||||||
|
;allowed_organizations =
|
||||||
|
|
||||||
#################################### Google Auth ##########################
|
#################################### Google Auth ##########################
|
||||||
[auth.google]
|
[auth.google]
|
||||||
|
@ -48,6 +48,8 @@ func OAuthLogin(ctx *middleware.Context) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if err == social.ErrMissingTeamMembership {
|
if err == social.ErrMissingTeamMembership {
|
||||||
ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required Github team membership not fulfilled"))
|
ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required Github team membership not fulfilled"))
|
||||||
|
} else if err == social.ErrMissingOrganizationMembership {
|
||||||
|
ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required Github organization membership not fulfilled"))
|
||||||
} else {
|
} else {
|
||||||
ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err)
|
ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err)
|
||||||
}
|
}
|
||||||
|
@ -78,12 +78,14 @@ func NewOAuthService() {
|
|||||||
if name == "github" {
|
if name == "github" {
|
||||||
setting.OAuthService.GitHub = true
|
setting.OAuthService.GitHub = true
|
||||||
teamIds := sec.Key("team_ids").Ints(",")
|
teamIds := sec.Key("team_ids").Ints(",")
|
||||||
|
allowedOrganizations := sec.Key("allowed_organizations").Strings(" ")
|
||||||
SocialMap["github"] = &SocialGithub{
|
SocialMap["github"] = &SocialGithub{
|
||||||
Config: &config,
|
Config: &config,
|
||||||
allowedDomains: info.AllowedDomains,
|
allowedDomains: info.AllowedDomains,
|
||||||
apiUrl: info.ApiUrl,
|
apiUrl: info.ApiUrl,
|
||||||
allowSignup: info.AllowSignup,
|
allowSignup: info.AllowSignup,
|
||||||
teamIds: teamIds,
|
teamIds: teamIds,
|
||||||
|
allowedOrganizations: allowedOrganizations,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,16 +117,21 @@ func isEmailAllowed(email string, allowedDomains []string) bool {
|
|||||||
|
|
||||||
type SocialGithub struct {
|
type SocialGithub struct {
|
||||||
*oauth2.Config
|
*oauth2.Config
|
||||||
allowedDomains []string
|
allowedDomains []string
|
||||||
apiUrl string
|
allowedOrganizations []string
|
||||||
allowSignup bool
|
apiUrl string
|
||||||
teamIds []int
|
allowSignup bool
|
||||||
|
teamIds []int
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrMissingTeamMembership = errors.New("User not a member of one of the required teams")
|
ErrMissingTeamMembership = errors.New("User not a member of one of the required teams")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrMissingOrganizationMembership = errors.New("User not a member of one of the required organizations")
|
||||||
|
)
|
||||||
|
|
||||||
func (s *SocialGithub) Type() int {
|
func (s *SocialGithub) Type() int {
|
||||||
return int(models.GITHUB)
|
return int(models.GITHUB)
|
||||||
}
|
}
|
||||||
@ -137,26 +144,100 @@ func (s *SocialGithub) IsSignupAllowed() bool {
|
|||||||
return s.allowSignup
|
return s.allowSignup
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SocialGithub) IsTeamMember(client *http.Client, username string, teamId int) bool {
|
func (s *SocialGithub) IsTeamMember(client *http.Client) bool {
|
||||||
var data struct {
|
if len(s.teamIds) == 0 {
|
||||||
Url string `json:"url"`
|
return true
|
||||||
State string `json:"state"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
membershipUrl := fmt.Sprintf("https://api.github.com/teams/%d/memberships/%s", teamId, username)
|
teamMemberships, err := s.FetchTeamMemberships(client)
|
||||||
r, err := client.Get(membershipUrl)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
defer r.Body.Close()
|
for _, teamId := range s.teamIds {
|
||||||
|
for _, membershipId := range teamMemberships {
|
||||||
|
if teamId == membershipId {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocialGithub) IsOrganizationMember(client *http.Client) bool {
|
||||||
|
if len(s.allowedOrganizations) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
organizations, err := s.FetchOrganizations(client)
|
||||||
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
active := data.State == "active"
|
for _, allowedOrganization := range s.allowedOrganizations {
|
||||||
return active
|
for _, organization := range organizations {
|
||||||
|
if organization == allowedOrganization {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocialGithub) FetchTeamMemberships(client *http.Client) ([]int, error) {
|
||||||
|
type Record struct {
|
||||||
|
Id int `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
membershipUrl := fmt.Sprintf("https://api.github.com/user/teams")
|
||||||
|
r, err := client.Get(membershipUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
var records []Record
|
||||||
|
|
||||||
|
if err = json.NewDecoder(r.Body).Decode(&records); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ids = make([]int, len(records))
|
||||||
|
for i, record := range records {
|
||||||
|
ids[i] = record.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SocialGithub) FetchOrganizations(client *http.Client) ([]string, error) {
|
||||||
|
type Record struct {
|
||||||
|
Login string `json:"login"`
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("https://api.github.com/user/orgs")
|
||||||
|
r, err := client.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
var records []Record
|
||||||
|
|
||||||
|
if err = json.NewDecoder(r.Body).Decode(&records); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var logins = make([]string, len(records))
|
||||||
|
for i, record := range records {
|
||||||
|
logins[i] = record.Login
|
||||||
|
}
|
||||||
|
|
||||||
|
return logins, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) {
|
func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) {
|
||||||
@ -185,17 +266,15 @@ func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) {
|
|||||||
Email: data.Email,
|
Email: data.Email,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s.teamIds) > 0 {
|
if !s.IsTeamMember(client) {
|
||||||
for _, teamId := range s.teamIds {
|
|
||||||
if s.IsTeamMember(client, data.Name, teamId) {
|
|
||||||
return userInfo, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, ErrMissingTeamMembership
|
return nil, ErrMissingTeamMembership
|
||||||
} else {
|
|
||||||
return userInfo, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !s.IsOrganizationMember(client) {
|
||||||
|
return nil, ErrMissingOrganizationMembership
|
||||||
|
}
|
||||||
|
|
||||||
|
return userInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ________ .__
|
// ________ .__
|
||||||
|
Loading…
Reference in New Issue
Block a user