Просмотр исходного кода

Merge branch 'github-team-membership-requirement' of https://github.com/dewski/grafana into dewski-github-team-membership-requirement

Torkel Ödegaard 10 лет назад
Родитель
Сommit
d812414621
4 измененных файлов с 67 добавлено и 6 удалено
  1. 1 0
      conf/defaults.ini
  2. 16 2
      docs/sources/installation/configuration.md
  3. 5 1
      pkg/api/login_oauth.go
  4. 45 3
      pkg/social/social.go

+ 1 - 0
conf/defaults.ini

@@ -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

+ 16 - 2
docs/sources/installation/configuration.md

@@ -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.
 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`.
 ### 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.
-
-

+ 5 - 1
pkg/api/login_oauth.go

@@ -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
 	}
 	}
 
 

+ 45 - 3
pkg/social/social.go

@@ -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() {
 		// 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 {
 	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 {
 	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) {
 		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
+	}
 }
 }
 
 
 //   ________                     .__
 //   ________                     .__