social.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package social
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "strconv"
  6. "strings"
  7. "github.com/torkelo/grafana-pro/pkg/log"
  8. "github.com/torkelo/grafana-pro/pkg/models"
  9. "github.com/torkelo/grafana-pro/pkg/setting"
  10. "github.com/golang/oauth2"
  11. )
  12. type BasicUserInfo struct {
  13. Identity string
  14. Name string
  15. Email string
  16. Login string
  17. Company string
  18. }
  19. type SocialConnector interface {
  20. Type() int
  21. UserInfo(transport *oauth2.Transport) (*BasicUserInfo, error)
  22. AuthCodeURL(state, accessType, prompt string) string
  23. NewTransportFromCode(code string) (*oauth2.Transport, error)
  24. }
  25. var (
  26. SocialBaseUrl = "/login/"
  27. SocialMap = make(map[string]SocialConnector)
  28. )
  29. func NewOAuthService() {
  30. if !setting.Cfg.MustBool("oauth", "enabled") {
  31. return
  32. }
  33. setting.OAuthService = &setting.OAuther{}
  34. setting.OAuthService.OAuthInfos = make(map[string]*setting.OAuthInfo)
  35. allOauthes := []string{"github", "google", "twitter"}
  36. // Load all OAuth config data.
  37. for _, name := range allOauthes {
  38. info := &setting.OAuthInfo{
  39. ClientId: setting.Cfg.MustValue("oauth."+name, "client_id"),
  40. ClientSecret: setting.Cfg.MustValue("oauth."+name, "client_secret"),
  41. Scopes: setting.Cfg.MustValueArray("oauth."+name, "scopes", " "),
  42. AuthUrl: setting.Cfg.MustValue("oauth."+name, "auth_url"),
  43. TokenUrl: setting.Cfg.MustValue("oauth."+name, "token_url"),
  44. Enabled: setting.Cfg.MustBool("oauth."+name, "enabled"),
  45. }
  46. if !info.Enabled {
  47. continue
  48. }
  49. setting.OAuthService.OAuthInfos[name] = info
  50. options, err := oauth2.New(
  51. oauth2.Client(info.ClientId, info.ClientSecret),
  52. oauth2.Scope(info.Scopes...),
  53. oauth2.Endpoint(info.AuthUrl, info.TokenUrl),
  54. oauth2.RedirectURL(strings.TrimSuffix(setting.AppUrl, "/")+SocialBaseUrl+name),
  55. )
  56. if err != nil {
  57. log.Error(3, "Failed to init oauth service", err)
  58. continue
  59. }
  60. // GitHub.
  61. if name == "github" {
  62. setting.OAuthService.GitHub = true
  63. SocialMap["github"] = &SocialGithub{Options: options}
  64. }
  65. // Google.
  66. if name == "google" {
  67. setting.OAuthService.Google = true
  68. SocialMap["google"] = &SocialGoogle{Options: options}
  69. }
  70. }
  71. }
  72. type SocialGithub struct {
  73. *oauth2.Options
  74. }
  75. func (s *SocialGithub) Type() int {
  76. return int(models.GITHUB)
  77. }
  78. func (s *SocialGithub) UserInfo(transport *oauth2.Transport) (*BasicUserInfo, error) {
  79. var data struct {
  80. Id int `json:"id"`
  81. Name string `json:"login"`
  82. Email string `json:"email"`
  83. }
  84. var err error
  85. client := http.Client{Transport: transport}
  86. r, err := client.Get("https://api.github.com/user")
  87. if err != nil {
  88. return nil, err
  89. }
  90. defer r.Body.Close()
  91. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  92. return nil, err
  93. }
  94. return &BasicUserInfo{
  95. Identity: strconv.Itoa(data.Id),
  96. Name: data.Name,
  97. Email: data.Email,
  98. }, nil
  99. }
  100. // ________ .__
  101. // / _____/ ____ ____ ____ | | ____
  102. // / \ ___ / _ \ / _ \ / ___\| | _/ __ \
  103. // \ \_\ ( <_> | <_> ) /_/ > |_\ ___/
  104. // \______ /\____/ \____/\___ /|____/\___ >
  105. // \/ /_____/ \/
  106. type SocialGoogle struct {
  107. *oauth2.Options
  108. }
  109. func (s *SocialGoogle) Type() int {
  110. return int(models.GOOGLE)
  111. }
  112. func (s *SocialGoogle) UserInfo(transport *oauth2.Transport) (*BasicUserInfo, error) {
  113. var data struct {
  114. Id string `json:"id"`
  115. Name string `json:"name"`
  116. Email string `json:"email"`
  117. }
  118. var err error
  119. reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
  120. client := http.Client{Transport: transport}
  121. r, err := client.Get(reqUrl)
  122. if err != nil {
  123. return nil, err
  124. }
  125. defer r.Body.Close()
  126. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  127. return nil, err
  128. }
  129. return &BasicUserInfo{
  130. Identity: data.Id,
  131. Name: data.Name,
  132. Email: data.Email,
  133. }, nil
  134. }