api_google_oauth.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package api
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. log "github.com/alecthomas/log4go"
  6. "github.com/gin-gonic/gin"
  7. "github.com/golang/oauth2"
  8. "github.com/torkelo/grafana-pro/pkg/models"
  9. "github.com/torkelo/grafana-pro/pkg/stores"
  10. )
  11. var oauthCfg *oauth2.Config
  12. func init() {
  13. addRoutes(func(self *HttpServer) {
  14. if !self.cfg.Http.GoogleOAuth.Enabled {
  15. return
  16. }
  17. self.router.GET("/login/google", self.loginGoogle)
  18. self.router.GET("/oauth2callback", self.oauthCallback)
  19. options := &oauth2.Options{
  20. ClientID: self.cfg.Http.GoogleOAuth.ClientId,
  21. ClientSecret: self.cfg.Http.GoogleOAuth.ClientSecret,
  22. RedirectURL: "http://localhost:3000/oauth2callback",
  23. Scopes: []string{
  24. "https://www.googleapis.com/auth/userinfo.profile",
  25. "https://www.googleapis.com/auth/userinfo.email",
  26. },
  27. }
  28. cfg, err := oauth2.NewConfig(options,
  29. "https://accounts.google.com/o/oauth2/auth",
  30. "https://accounts.google.com/o/oauth2/token")
  31. if err != nil {
  32. log.Error("Failed to init google auth %v", err)
  33. }
  34. oauthCfg = cfg
  35. })
  36. }
  37. func (self *HttpServer) loginGoogle(c *gin.Context) {
  38. url := oauthCfg.AuthCodeURL("", "online", "auto")
  39. c.Redirect(302, url)
  40. }
  41. type googleUserInfoDto struct {
  42. Email string `json:"email"`
  43. GivenName string `json:"givenName"`
  44. FamilyName string `json:"familyName"`
  45. Name string `json:"name"`
  46. }
  47. func (self *HttpServer) oauthCallback(c *gin.Context) {
  48. code := c.Request.URL.Query()["code"][0]
  49. log.Info("OAuth code: %v", code)
  50. transport, err := oauthCfg.NewTransportWithCode(code)
  51. if err != nil {
  52. c.String(500, "Failed to exchange oauth token: "+err.Error())
  53. return
  54. }
  55. client := http.Client{Transport: transport}
  56. resp, err := client.Get("https://www.googleapis.com/oauth2/v1/userinfo?alt=json")
  57. if err != nil {
  58. c.String(500, err.Error())
  59. return
  60. }
  61. var userInfo googleUserInfoDto
  62. decoder := json.NewDecoder(resp.Body)
  63. err = decoder.Decode(&userInfo)
  64. if err != nil {
  65. c.String(500, err.Error())
  66. return
  67. }
  68. if len(userInfo.Email) < 5 {
  69. c.String(500, "Invalid email")
  70. return
  71. }
  72. // try find existing account
  73. account, err := self.store.GetAccountByLogin(userInfo.Email)
  74. // create account if missing
  75. if err == stores.ErrAccountNotFound {
  76. account = &models.Account{
  77. Login: userInfo.Email,
  78. Email: userInfo.Email,
  79. Name: userInfo.Name,
  80. }
  81. if err = self.store.CreateAccount(account); err != nil {
  82. log.Error("Failed to create account %v", err)
  83. c.String(500, "Failed to create account")
  84. return
  85. }
  86. }
  87. // login
  88. loginUserWithAccount(account, c)
  89. c.Redirect(302, "/")
  90. }