mirror of https://github.com/grafana/grafana
parent
2783196547
commit
450d242d5f
Binary file not shown.
@ -0,0 +1,9 @@ |
||||
package models |
||||
|
||||
type OAuthType int |
||||
|
||||
const ( |
||||
GITHUB OAuthType = iota + 1 |
||||
GOOGLE |
||||
TWITTER |
||||
) |
||||
@ -0,0 +1,71 @@ |
||||
package login |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
|
||||
"github.com/torkelo/grafana-pro/pkg/log" |
||||
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||
"github.com/torkelo/grafana-pro/pkg/models" |
||||
"github.com/torkelo/grafana-pro/pkg/setting" |
||||
"github.com/torkelo/grafana-pro/pkg/social" |
||||
) |
||||
|
||||
func OAuthLogin(ctx *middleware.Context) { |
||||
if setting.OAuthService == nil { |
||||
ctx.Handle(404, "social.SocialSignIn(oauth service not enabled)", nil) |
||||
return |
||||
} |
||||
|
||||
name := ctx.Params(":name") |
||||
connect, ok := social.SocialMap[name] |
||||
if !ok { |
||||
ctx.Handle(404, "social.SocialSignIn(social login not enabled)", errors.New(name)) |
||||
return |
||||
} |
||||
|
||||
code := ctx.Query("code") |
||||
if code == "" { |
||||
ctx.Redirect(connect.AuthCodeURL("", "online", "auto")) |
||||
return |
||||
} |
||||
|
||||
// handle call back
|
||||
transport, err := connect.NewTransportWithCode(code) |
||||
if err != nil { |
||||
ctx.Handle(500, "social.SocialSignIn(NewTransportWithCode)", err) |
||||
return |
||||
} |
||||
|
||||
log.Trace("social.SocialSignIn(Got token)") |
||||
|
||||
userInfo, err := connect.UserInfo(transport) |
||||
if err != nil { |
||||
ctx.Handle(500, fmt.Sprintf("social.SocialSignIn(get info from %s)", name), err) |
||||
return |
||||
} |
||||
|
||||
log.Info("social.SocialSignIn(social login): %s", userInfo) |
||||
|
||||
account, err := models.GetAccountByLogin(userInfo.Email) |
||||
|
||||
// create account if missing
|
||||
if err == models.ErrAccountNotFound { |
||||
account = &models.Account{ |
||||
Login: userInfo.Login, |
||||
Email: userInfo.Email, |
||||
Name: userInfo.Name, |
||||
Company: userInfo.Company, |
||||
} |
||||
|
||||
if err = models.CreateAccount(account); err != nil { |
||||
ctx.Handle(500, "Failed to create account", err) |
||||
return |
||||
} |
||||
} |
||||
|
||||
// login
|
||||
loginUserWithAccount(account, ctx) |
||||
|
||||
ctx.Redirect("/") |
||||
} |
||||
@ -0,0 +1,14 @@ |
||||
package setting |
||||
|
||||
type OAuthInfo struct { |
||||
ClientId, ClientSecret string |
||||
Scopes []string |
||||
AuthUrl, TokenUrl string |
||||
} |
||||
|
||||
type OAuther struct { |
||||
GitHub, Google, Twitter bool |
||||
OAuthInfos map[string]*OAuthInfo |
||||
} |
||||
|
||||
var OAuthService *OAuther |
||||
@ -0,0 +1,175 @@ |
||||
package social |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"net/http" |
||||
"strconv" |
||||
"strings" |
||||
|
||||
"github.com/gogits/gogs/models" |
||||
"github.com/golang/oauth2" |
||||
"github.com/torkelo/grafana-pro/pkg/log" |
||||
"github.com/torkelo/grafana-pro/pkg/setting" |
||||
) |
||||
|
||||
type BasicUserInfo struct { |
||||
Identity string |
||||
Name string |
||||
Email string |
||||
Login string |
||||
Company string |
||||
} |
||||
|
||||
type SocialConnector interface { |
||||
Type() int |
||||
UserInfo(transport *oauth2.Transport) (*BasicUserInfo, error) |
||||
|
||||
AuthCodeURL(state, accessType, prompt string) string |
||||
NewTransportWithCode(code string) (*oauth2.Transport, error) |
||||
} |
||||
|
||||
var ( |
||||
SocialBaseUrl = "/login" |
||||
SocialMap = make(map[string]SocialConnector) |
||||
) |
||||
|
||||
func NewOauthService() { |
||||
if !setting.Cfg.MustBool("oauth", "enabled") { |
||||
return |
||||
} |
||||
|
||||
var err error |
||||
setting.OAuthService = &setting.OAuther{} |
||||
setting.OAuthService.OAuthInfos = make(map[string]*setting.OAuthInfo) |
||||
|
||||
socialConfigs := make(map[string]*oauth2.Config) |
||||
|
||||
allOauthes := []string{"github", "google", "twitter"} |
||||
|
||||
// Load all OAuth config data.
|
||||
for _, name := range allOauthes { |
||||
info := &setting.OAuthInfo{ |
||||
ClientId: setting.Cfg.MustValue("oauth."+name, "client_id"), |
||||
ClientSecret: setting.Cfg.MustValue("oauth."+name, "client_secrect"), |
||||
Scopes: setting.Cfg.MustValueArray("oauth."+name, "scopes", " "), |
||||
AuthUrl: setting.Cfg.MustValue("oauth."+name, "auth_url"), |
||||
TokenUrl: setting.Cfg.MustValue("oauth."+name, "token_url"), |
||||
} |
||||
|
||||
opts := &oauth2.Options{ |
||||
ClientID: info.ClientId, |
||||
ClientSecret: info.ClientSecret, |
||||
RedirectURL: strings.TrimSuffix(setting.AppUrl, "/") + SocialBaseUrl + name, |
||||
Scopes: info.Scopes, |
||||
} |
||||
|
||||
setting.OAuthService.OAuthInfos[name] = info |
||||
socialConfigs[name], err = oauth2.NewConfig(opts, info.AuthUrl, info.TokenUrl) |
||||
if err != nil { |
||||
log.Error(4, "Failed to init oauth service", err) |
||||
} |
||||
} |
||||
|
||||
enabledOauths := make([]string, 0, 10) |
||||
|
||||
// GitHub.
|
||||
if setting.Cfg.MustBool("oauth.github", "enabled") { |
||||
setting.OAuthService.GitHub = true |
||||
newGitHubOAuth(socialConfigs["github"]) |
||||
enabledOauths = append(enabledOauths, "GitHub") |
||||
} |
||||
|
||||
// Google.
|
||||
if setting.Cfg.MustBool("oauth.google", "enabled") { |
||||
setting.OAuthService.Google = true |
||||
newGoogleOAuth(socialConfigs["google"]) |
||||
enabledOauths = append(enabledOauths, "Google") |
||||
} |
||||
} |
||||
|
||||
type SocialGithub struct { |
||||
*oauth2.Config |
||||
} |
||||
|
||||
func (s *SocialGithub) Type() int { |
||||
return int(models.GITHUB) |
||||
} |
||||
|
||||
func newGitHubOAuth(config *oauth2.Config) { |
||||
SocialMap["github"] = &SocialGithub{ |
||||
Config: config, |
||||
} |
||||
} |
||||
|
||||
func (s *SocialGithub) UserInfo(transport *oauth2.Transport) (*BasicUserInfo, error) { |
||||
var data struct { |
||||
Id int `json:"id"` |
||||
Name string `json:"login"` |
||||
Email string `json:"email"` |
||||
} |
||||
|
||||
var err error |
||||
client := http.Client{Transport: transport} |
||||
r, err := client.Get("https://api.github.com/user") |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
defer r.Body.Close() |
||||
|
||||
if err = json.NewDecoder(r.Body).Decode(&data); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return &BasicUserInfo{ |
||||
Identity: strconv.Itoa(data.Id), |
||||
Name: data.Name, |
||||
Email: data.Email, |
||||
}, nil |
||||
} |
||||
|
||||
// ________ .__
|
||||
// / _____/ ____ ____ ____ | | ____
|
||||
// / \ ___ / _ \ / _ \ / ___\| | _/ __ \
|
||||
// \ \_\ ( <_> | <_> ) /_/ > |_\ ___/
|
||||
// \______ /\____/ \____/\___ /|____/\___ >
|
||||
// \/ /_____/ \/
|
||||
|
||||
type SocialGoogle struct { |
||||
*oauth2.Config |
||||
} |
||||
|
||||
func (s *SocialGoogle) Type() int { |
||||
return int(models.GOOGLE) |
||||
} |
||||
|
||||
func newGoogleOAuth(config *oauth2.Config) { |
||||
SocialMap["google"] = &SocialGoogle{ |
||||
Config: config, |
||||
} |
||||
} |
||||
|
||||
func (s *SocialGoogle) UserInfo(transport *oauth2.Transport) (*BasicUserInfo, error) { |
||||
var data struct { |
||||
Id string `json:"id"` |
||||
Name string `json:"name"` |
||||
Email string `json:"email"` |
||||
} |
||||
var err error |
||||
|
||||
reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo" |
||||
client := http.Client{Transport: transport} |
||||
r, err := client.Get(reqUrl) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
defer r.Body.Close() |
||||
if err = json.NewDecoder(r.Body).Decode(&data); err != nil { |
||||
return nil, err |
||||
} |
||||
return &BasicUserInfo{ |
||||
Identity: data.Id, |
||||
Name: data.Name, |
||||
Email: data.Email, |
||||
}, nil |
||||
} |
||||
Loading…
Reference in new issue