api_oauth_google.go 2.8 KB

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