Przeglądaj źródła

Github oauth login works

Torkel Ödegaard 11 lat temu
rodzic
commit
3bba8b2c26

+ 1 - 1
grafana

@@ -1 +1 @@
-Subproject commit 071ac0dc85e48be546315dde196f90f01ad7b274
+Subproject commit d584076b93b4ebfb33e5a5f375feb6d6ff7f9bfc

+ 1 - 0
pkg/api/api_oauth.go

@@ -0,0 +1 @@
+package api

+ 112 - 0
pkg/api/api_oauth_github.go

@@ -0,0 +1,112 @@
+package api
+
+import (
+	"encoding/json"
+	"net/http"
+
+	log "github.com/alecthomas/log4go"
+	"github.com/gin-gonic/gin"
+	"github.com/golang/oauth2"
+	"github.com/torkelo/grafana-pro/pkg/models"
+	"github.com/torkelo/grafana-pro/pkg/stores"
+)
+
+var (
+	githubOAuthConfig *oauth2.Config
+	githubRedirectUrl string = "http://localhost:3000/oauth2/github/callback"
+	githubAuthUrl     string = "https://github.com/login/oauth/authorize"
+	githubTokenUrl    string = "https://github.com/login/oauth/access_token"
+)
+
+func init() {
+	addRoutes(func(self *HttpServer) {
+		if !self.cfg.Http.GithubOAuth.Enabled {
+			return
+		}
+
+		self.router.GET("/oauth2/github", self.oauthGithub)
+		self.router.GET("/oauth2/github/callback", self.oauthGithubCallback)
+
+		options := &oauth2.Options{
+			ClientID:     self.cfg.Http.GithubOAuth.ClientId,
+			ClientSecret: self.cfg.Http.GithubOAuth.ClientSecret,
+			RedirectURL:  githubRedirectUrl,
+			Scopes:       []string{"user:email"},
+		}
+
+		cfg, err := oauth2.NewConfig(options, githubAuthUrl, githubTokenUrl)
+
+		if err != nil {
+			log.Error("Failed to init github auth %v", err)
+		}
+
+		githubOAuthConfig = cfg
+	})
+}
+
+func (self *HttpServer) oauthGithub(c *gin.Context) {
+	url := githubOAuthConfig.AuthCodeURL("", "online", "auto")
+	c.Redirect(302, url)
+}
+
+type githubUserInfoDto struct {
+	Login   string `json:"login"`
+	Name    string `json:"name"`
+	Email   string `json:"email"`
+	Company string `json:"company"`
+}
+
+func (self *HttpServer) oauthGithubCallback(c *gin.Context) {
+	code := c.Request.URL.Query()["code"][0]
+	log.Info("OAuth code: %v", code)
+
+	transport, err := githubOAuthConfig.NewTransportWithCode(code)
+	if err != nil {
+		c.String(500, "Failed to exchange oauth token: "+err.Error())
+		return
+	}
+
+	client := http.Client{Transport: transport}
+	resp, err := client.Get("https://api.github.com/user")
+	if err != nil {
+		c.String(500, err.Error())
+		return
+	}
+
+	var userInfo githubUserInfoDto
+	decoder := json.NewDecoder(resp.Body)
+	err = decoder.Decode(&userInfo)
+	if err != nil {
+		c.String(500, err.Error())
+		return
+	}
+
+	if len(userInfo.Email) < 5 {
+		c.String(500, "Invalid email")
+		return
+	}
+
+	// try find existing account
+	account, err := self.store.GetAccountByLogin(userInfo.Email)
+
+	// create account if missing
+	if err == stores.ErrAccountNotFound {
+		account = &models.Account{
+			Login:   userInfo.Login,
+			Email:   userInfo.Email,
+			Name:    userInfo.Name,
+			Company: userInfo.Company,
+		}
+
+		if err = self.store.CreateAccount(account); err != nil {
+			log.Error("Failed to create account %v", err)
+			c.String(500, "Failed to create account")
+			return
+		}
+	}
+
+	// login
+	loginUserWithAccount(account, c)
+
+	c.Redirect(302, "/")
+}

+ 18 - 16
pkg/api/api_google_oauth.go → pkg/api/api_oauth_google.go

@@ -11,7 +11,14 @@ import (
 	"github.com/torkelo/grafana-pro/pkg/stores"
 )
 
-var oauthCfg *oauth2.Config
+var (
+	googleOAuthConfig  *oauth2.Config
+	googleRedirectUrl  string = "http://localhost:3000/oauth2/google/callback"
+	googleAuthUrl      string = "https://accounts.google.com/o/oauth2/auth"
+	googleTokenUrl     string = "https://accounts.google.com/o/oauth2/token"
+	googleScopeProfile string = "https://www.googleapis.com/auth/userinfo.profile"
+	googleScopeEmail   string = "https://www.googleapis.com/auth/userinfo.email"
+)
 
 func init() {
 	addRoutes(func(self *HttpServer) {
@@ -19,33 +26,28 @@ func init() {
 			return
 		}
 
-		self.router.GET("/login/google", self.loginGoogle)
-		self.router.GET("/oauth2callback", self.oauthCallback)
+		self.router.GET("/oauth2/google", self.oauthGoogle)
+		self.router.GET("/oauth2/google/callback", self.oauthGoogleCallback)
 
 		options := &oauth2.Options{
 			ClientID:     self.cfg.Http.GoogleOAuth.ClientId,
 			ClientSecret: self.cfg.Http.GoogleOAuth.ClientSecret,
-			RedirectURL:  "http://localhost:3000/oauth2callback",
-			Scopes: []string{
-				"https://www.googleapis.com/auth/userinfo.profile",
-				"https://www.googleapis.com/auth/userinfo.email",
-			},
+			RedirectURL:  googleRedirectUrl,
+			Scopes:       []string{googleScopeEmail, googleScopeProfile},
 		}
 
-		cfg, err := oauth2.NewConfig(options,
-			"https://accounts.google.com/o/oauth2/auth",
-			"https://accounts.google.com/o/oauth2/token")
+		cfg, err := oauth2.NewConfig(options, googleAuthUrl, googleTokenUrl)
 
 		if err != nil {
 			log.Error("Failed to init google auth %v", err)
 		}
 
-		oauthCfg = cfg
+		googleOAuthConfig = cfg
 	})
 }
 
-func (self *HttpServer) loginGoogle(c *gin.Context) {
-	url := oauthCfg.AuthCodeURL("", "online", "auto")
+func (self *HttpServer) oauthGoogle(c *gin.Context) {
+	url := googleOAuthConfig.AuthCodeURL("", "online", "auto")
 	c.Redirect(302, url)
 }
 
@@ -56,11 +58,11 @@ type googleUserInfoDto struct {
 	Name       string `json:"name"`
 }
 
-func (self *HttpServer) oauthCallback(c *gin.Context) {
+func (self *HttpServer) oauthGoogleCallback(c *gin.Context) {
 	code := c.Request.URL.Query()["code"][0]
 	log.Info("OAuth code: %v", code)
 
-	transport, err := oauthCfg.NewTransportWithCode(code)
+	transport, err := googleOAuthConfig.NewTransportWithCode(code)
 	if err != nil {
 		c.String(500, "Failed to exchange oauth token: "+err.Error())
 		return

+ 9 - 3
pkg/configuration/configuration.go

@@ -6,10 +6,11 @@ type Cfg struct {
 
 type HttpCfg struct {
 	Port        string
-	GoogleOAuth GoogleOAuthCfg
+	GoogleOAuth OAuthCfg
+	GithubOAuth OAuthCfg
 }
 
-type GoogleOAuthCfg struct {
+type OAuthCfg struct {
 	Enabled      bool
 	ClientId     string
 	ClientSecret string
@@ -24,11 +25,16 @@ func NewCfg(port string) *Cfg {
 	return &Cfg{
 		Http: HttpCfg{
 			Port: port,
-			GoogleOAuth: GoogleOAuthCfg{
+			GoogleOAuth: OAuthCfg{
 				Enabled:      true,
 				ClientId:     "106011922963-4pvl05e9urtrm8bbqr0vouosj3e8p8kb.apps.googleusercontent.com",
 				ClientSecret: "K2evIa4QhfbhhAm3SO72t2Zv",
 			},
+			GithubOAuth: OAuthCfg{
+				Enabled:      true,
+				ClientId:     "de054205006b9baa2e17",
+				ClientSecret: "72b7ea52d9f1096fdf36cea95e95362a307e0322",
+			},
 		},
 	}
 }

+ 1 - 0
pkg/models/account.go

@@ -27,6 +27,7 @@ type Account struct {
 	AccountName     string
 	Password        string
 	Name            string
+	Company         string
 	NextDashboardId int
 	UsingAccountId  int
 	Collaborators   []CollaboratorLink