|
|
|
@ -78,12 +78,14 @@ func NewOAuthService() { |
|
|
|
|
if name == "github" { |
|
|
|
|
setting.OAuthService.GitHub = true |
|
|
|
|
teamIds := sec.Key("team_ids").Ints(",") |
|
|
|
|
allowedOrganizations := sec.Key("allowed_organizations").Strings(" ") |
|
|
|
|
SocialMap["github"] = &SocialGithub{ |
|
|
|
|
Config: &config, |
|
|
|
|
allowedDomains: info.AllowedDomains, |
|
|
|
|
apiUrl: info.ApiUrl, |
|
|
|
|
allowSignup: info.AllowSignup, |
|
|
|
|
teamIds: teamIds, |
|
|
|
|
Config: &config, |
|
|
|
|
allowedDomains: info.AllowedDomains, |
|
|
|
|
apiUrl: info.ApiUrl, |
|
|
|
|
allowSignup: info.AllowSignup, |
|
|
|
|
teamIds: teamIds, |
|
|
|
|
allowedOrganizations: allowedOrganizations, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -115,16 +117,21 @@ func isEmailAllowed(email string, allowedDomains []string) bool { |
|
|
|
|
|
|
|
|
|
type SocialGithub struct { |
|
|
|
|
*oauth2.Config |
|
|
|
|
allowedDomains []string |
|
|
|
|
apiUrl string |
|
|
|
|
allowSignup bool |
|
|
|
|
teamIds []int |
|
|
|
|
allowedDomains []string |
|
|
|
|
allowedOrganizations []string |
|
|
|
|
apiUrl string |
|
|
|
|
allowSignup bool |
|
|
|
|
teamIds []int |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
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 { |
|
|
|
|
return int(models.GITHUB) |
|
|
|
|
} |
|
|
|
@ -137,26 +144,100 @@ func (s *SocialGithub) IsSignupAllowed() bool { |
|
|
|
|
return s.allowSignup |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *SocialGithub) IsTeamMember(client *http.Client, username string, teamId int) bool { |
|
|
|
|
var data struct { |
|
|
|
|
Url string `json:"url"` |
|
|
|
|
State string `json:"state"` |
|
|
|
|
func (s *SocialGithub) IsTeamMember(client *http.Client) bool { |
|
|
|
|
if len(s.teamIds) == 0 { |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
membershipUrl := fmt.Sprintf("https://api.github.com/teams/%d/memberships/%s", teamId, username) |
|
|
|
|
r, err := client.Get(membershipUrl) |
|
|
|
|
teamMemberships, err := s.FetchTeamMemberships(client) |
|
|
|
|
if err != nil { |
|
|
|
|
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 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
active := data.State == "active" |
|
|
|
|
return active |
|
|
|
|
for _, allowedOrganization := range s.allowedOrganizations { |
|
|
|
|
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) { |
|
|
|
@ -185,17 +266,15 @@ func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) { |
|
|
|
|
Email: data.Email, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if len(s.teamIds) > 0 { |
|
|
|
|
for _, teamId := range s.teamIds { |
|
|
|
|
if s.IsTeamMember(client, data.Name, teamId) { |
|
|
|
|
return userInfo, nil |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !s.IsTeamMember(client) { |
|
|
|
|
return nil, ErrMissingTeamMembership |
|
|
|
|
} else { |
|
|
|
|
return userInfo, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !s.IsOrganizationMember(client) { |
|
|
|
|
return nil, ErrMissingOrganizationMembership |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return userInfo, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ________ .__
|
|
|
|
|