Commit d8124146 by Torkel Ödegaard

Merge branch 'github-team-membership-requirement' of…

Merge branch 'github-team-membership-requirement' of https://github.com/dewski/grafana into dewski-github-team-membership-requirement
parents 52c32d8b 1fdc5277
...@@ -140,6 +140,7 @@ enabled = false ...@@ -140,6 +140,7 @@ enabled = false
client_id = some_id client_id = some_id
client_secret = some_secret client_secret = some_secret
scopes = user:email scopes = user:email
team_ids =
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
......
...@@ -179,6 +179,7 @@ Client ID and a Client Secret. Specify these in the grafana config file. Example ...@@ -179,6 +179,7 @@ Client ID and a Client Secret. Specify these in the grafana config file. Example
client_id = YOUR_GITHUB_APP_CLIENT_ID client_id = YOUR_GITHUB_APP_CLIENT_ID
client_secret = YOUR_GITHUB_APP_CLIENT_SECRET client_secret = YOUR_GITHUB_APP_CLIENT_SECRET
scopes = user:email scopes = user:email
team_ids =
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
allow_sign_up = false allow_sign_up = false
...@@ -189,6 +190,21 @@ now login or signup with your github accounts. ...@@ -189,6 +190,21 @@ now login or signup with your github accounts.
You may allow users to sign-up via github auth by setting allow_sign_up to true. When this option is You may allow users to sign-up via github auth by setting allow_sign_up to true. When this option is
set to true, any user successfully authenticating via github auth will be automatically signed up. set to true, any user successfully authenticating via github auth will be automatically signed up.
### team_ids
Require an active team membership for at least one of the given teams on GitHub.
If the authenticated user isn't a member of at least one the teams they will not
be able to register or authenticate with your Grafana instance. Example:
[auth.github]
enabled = true
client_id = YOUR_GITHUB_APP_CLIENT_ID
client_secret = YOUR_GITHUB_APP_CLIENT_SECRET
scopes = user:email
team_ids = 150,300
auth_url = https://github.com/login/oauth/authorize
token_url = https://github.com/login/oauth/access_token
allow_sign_up = false
## [auth.google] ## [auth.google]
You need to create a google project. You can do this in the [Google Developer Console](https://console.developers.google.com/project). You need to create a google project. You can do this in the [Google Developer Console](https://console.developers.google.com/project).
When you create the project you will need to specify a callback URL. Specify this as callback: When you create the project you will need to specify a callback URL. Specify this as callback:
...@@ -257,5 +273,3 @@ enabled. Counters are sent every 24 hours. Default value is `true`. ...@@ -257,5 +273,3 @@ enabled. Counters are sent every 24 hours. Default value is `true`.
### google_analytics_ua_id ### google_analytics_ua_id
If you want to track Grafana usage via Google analytics specify *your* Univeral Analytics ID If you want to track Grafana usage via Google analytics specify *your* Univeral Analytics ID
here. By defualt this feature is disabled. here. By defualt this feature is disabled.
...@@ -45,7 +45,11 @@ func OAuthLogin(ctx *middleware.Context) { ...@@ -45,7 +45,11 @@ func OAuthLogin(ctx *middleware.Context) {
userInfo, err := connect.UserInfo(token) userInfo, err := connect.UserInfo(token)
if err != nil { if err != nil {
ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err) if err == social.ErrMissingTeamMembership {
ctx.Redirect(setting.AppSubUrl + "/login?missing_team_membership=1")
} else {
ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err)
}
return return
} }
......
...@@ -5,6 +5,8 @@ import ( ...@@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
"errors"
"net/http"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
...@@ -75,7 +77,8 @@ func NewOAuthService() { ...@@ -75,7 +77,8 @@ func NewOAuthService() {
// GitHub. // GitHub.
if name == "github" { if name == "github" {
setting.OAuthService.GitHub = true setting.OAuthService.GitHub = true
SocialMap["github"] = &SocialGithub{Config: &config, allowedDomains: info.AllowedDomains, ApiUrl: info.ApiUrl, allowSignup: info.AllowSignup} teamIds := sec.Key("team_ids").Ints(",")
SocialMap["github"] = &SocialGithub{Config: &config, allowedDomains: info.AllowedDomains, ApiUrl: info.ApiUrl, allowSignup: info.AllowSignup, teamIds: teamIds}
} }
// Google. // Google.
...@@ -105,8 +108,13 @@ type SocialGithub struct { ...@@ -105,8 +108,13 @@ type SocialGithub struct {
allowedDomains []string allowedDomains []string
ApiUrl string ApiUrl string
allowSignup bool allowSignup bool
teamIds []int
} }
var (
ErrMissingTeamMembership = errors.New("User not a member of one of the required teams")
)
func (s *SocialGithub) Type() int { func (s *SocialGithub) Type() int {
return int(models.GITHUB) return int(models.GITHUB)
} }
...@@ -119,6 +127,28 @@ func (s *SocialGithub) IsSignupAllowed() bool { ...@@ -119,6 +127,28 @@ func (s *SocialGithub) IsSignupAllowed() bool {
return s.allowSignup 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"`
}
membershipUrl := fmt.Sprintf("https://api.github.com/teams/%d/memberships/%s", teamId, username)
r, err := client.Get(membershipUrl)
if err != nil {
return false
}
defer r.Body.Close()
if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
return false
}
active := data.State == "active"
return active
}
func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) { func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) {
var data struct { var data struct {
Id int `json:"id"` Id int `json:"id"`
...@@ -139,11 +169,23 @@ func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) { ...@@ -139,11 +169,23 @@ func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) {
return nil, err return nil, err
} }
return &BasicUserInfo{ userInfo := &BasicUserInfo{
Identity: strconv.Itoa(data.Id), Identity: strconv.Itoa(data.Id),
Name: data.Name, Name: data.Name,
Email: data.Email, Email: data.Email,
}, nil }
if len(s.teamIds) > 0 {
for _, teamId := range s.teamIds {
if s.IsTeamMember(client, data.Name, teamId) {
return userInfo, nil
}
}
return nil, ErrMissingTeamMembership
} else {
return userInfo, nil
}
} }
// ________ .__ // ________ .__
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment