social.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. package social
  2. import (
  3. "net/http"
  4. "strings"
  5. "context"
  6. "golang.org/x/oauth2"
  7. "github.com/grafana/grafana/pkg/infra/log"
  8. "github.com/grafana/grafana/pkg/setting"
  9. "github.com/grafana/grafana/pkg/util"
  10. )
  11. type BasicUserInfo struct {
  12. Id string
  13. Name string
  14. Email string
  15. Login string
  16. Company string
  17. Role string
  18. Groups []string
  19. }
  20. type SocialConnector interface {
  21. Type() int
  22. UserInfo(client *http.Client, token *oauth2.Token) (*BasicUserInfo, error)
  23. IsEmailAllowed(email string) bool
  24. IsSignupAllowed() bool
  25. AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) string
  26. Exchange(ctx context.Context, code string, authOptions ...oauth2.AuthCodeOption) (*oauth2.Token, error)
  27. Client(ctx context.Context, t *oauth2.Token) *http.Client
  28. TokenSource(ctx context.Context, t *oauth2.Token) oauth2.TokenSource
  29. }
  30. type SocialBase struct {
  31. *oauth2.Config
  32. log log.Logger
  33. }
  34. type Error struct {
  35. s string
  36. }
  37. func (e *Error) Error() string {
  38. return e.s
  39. }
  40. const (
  41. grafanaCom = "grafana_com"
  42. )
  43. var (
  44. SocialBaseUrl = "/login/"
  45. SocialMap = make(map[string]SocialConnector)
  46. allOauthes = []string{"github", "gitlab", "google", "generic_oauth", "grafananet", grafanaCom}
  47. )
  48. func NewOAuthService() {
  49. setting.OAuthService = &setting.OAuther{}
  50. setting.OAuthService.OAuthInfos = make(map[string]*setting.OAuthInfo)
  51. for _, name := range allOauthes {
  52. sec := setting.Raw.Section("auth." + name)
  53. info := &setting.OAuthInfo{
  54. ClientId: sec.Key("client_id").String(),
  55. ClientSecret: sec.Key("client_secret").String(),
  56. Scopes: util.SplitString(sec.Key("scopes").String()),
  57. AuthUrl: sec.Key("auth_url").String(),
  58. TokenUrl: sec.Key("token_url").String(),
  59. ApiUrl: sec.Key("api_url").String(),
  60. Enabled: sec.Key("enabled").MustBool(),
  61. EmailAttributeName: sec.Key("email_attribute_name").String(),
  62. EmailAttributePath: sec.Key("email_attribute_path").String(),
  63. AllowedDomains: util.SplitString(sec.Key("allowed_domains").String()),
  64. HostedDomain: sec.Key("hosted_domain").String(),
  65. AllowSignup: sec.Key("allow_sign_up").MustBool(),
  66. Name: sec.Key("name").MustString(name),
  67. TlsClientCert: sec.Key("tls_client_cert").String(),
  68. TlsClientKey: sec.Key("tls_client_key").String(),
  69. TlsClientCa: sec.Key("tls_client_ca").String(),
  70. TlsSkipVerify: sec.Key("tls_skip_verify_insecure").MustBool(),
  71. SendClientCredentialsViaPost: sec.Key("send_client_credentials_via_post").MustBool(),
  72. }
  73. if !info.Enabled {
  74. continue
  75. }
  76. // handle the clients that do not properly support Basic auth headers and require passing client_id/client_secret via POST payload
  77. if info.SendClientCredentialsViaPost {
  78. // TODO: Fix the staticcheck error
  79. oauth2.RegisterBrokenAuthHeaderProvider(info.TokenUrl) //nolint:staticcheck
  80. }
  81. if name == "grafananet" {
  82. name = grafanaCom
  83. }
  84. setting.OAuthService.OAuthInfos[name] = info
  85. config := oauth2.Config{
  86. ClientID: info.ClientId,
  87. ClientSecret: info.ClientSecret,
  88. Endpoint: oauth2.Endpoint{
  89. AuthURL: info.AuthUrl,
  90. TokenURL: info.TokenUrl,
  91. },
  92. RedirectURL: strings.TrimSuffix(setting.AppUrl, "/") + SocialBaseUrl + name,
  93. Scopes: info.Scopes,
  94. }
  95. logger := log.New("oauth." + name)
  96. // GitHub.
  97. if name == "github" {
  98. SocialMap["github"] = &SocialGithub{
  99. SocialBase: &SocialBase{
  100. Config: &config,
  101. log: logger,
  102. },
  103. allowedDomains: info.AllowedDomains,
  104. apiUrl: info.ApiUrl,
  105. allowSignup: info.AllowSignup,
  106. teamIds: sec.Key("team_ids").Ints(","),
  107. allowedOrganizations: util.SplitString(sec.Key("allowed_organizations").String()),
  108. }
  109. }
  110. // GitLab.
  111. if name == "gitlab" {
  112. SocialMap["gitlab"] = &SocialGitlab{
  113. SocialBase: &SocialBase{
  114. Config: &config,
  115. log: logger,
  116. },
  117. allowedDomains: info.AllowedDomains,
  118. apiUrl: info.ApiUrl,
  119. allowSignup: info.AllowSignup,
  120. allowedGroups: util.SplitString(sec.Key("allowed_groups").String()),
  121. }
  122. }
  123. // Google.
  124. if name == "google" {
  125. SocialMap["google"] = &SocialGoogle{
  126. SocialBase: &SocialBase{
  127. Config: &config,
  128. log: logger,
  129. },
  130. allowedDomains: info.AllowedDomains,
  131. hostedDomain: info.HostedDomain,
  132. apiUrl: info.ApiUrl,
  133. allowSignup: info.AllowSignup,
  134. }
  135. }
  136. // Generic - Uses the same scheme as Github.
  137. if name == "generic_oauth" {
  138. SocialMap["generic_oauth"] = &SocialGenericOAuth{
  139. SocialBase: &SocialBase{
  140. Config: &config,
  141. log: logger,
  142. },
  143. allowedDomains: info.AllowedDomains,
  144. apiUrl: info.ApiUrl,
  145. allowSignup: info.AllowSignup,
  146. emailAttributeName: info.EmailAttributeName,
  147. emailAttributePath: info.EmailAttributePath,
  148. teamIds: sec.Key("team_ids").Ints(","),
  149. allowedOrganizations: util.SplitString(sec.Key("allowed_organizations").String()),
  150. }
  151. }
  152. if name == grafanaCom {
  153. config = oauth2.Config{
  154. ClientID: info.ClientId,
  155. ClientSecret: info.ClientSecret,
  156. Endpoint: oauth2.Endpoint{
  157. AuthURL: setting.GrafanaComUrl + "/oauth2/authorize",
  158. TokenURL: setting.GrafanaComUrl + "/api/oauth2/token",
  159. },
  160. RedirectURL: strings.TrimSuffix(setting.AppUrl, "/") + SocialBaseUrl + name,
  161. Scopes: info.Scopes,
  162. }
  163. SocialMap[grafanaCom] = &SocialGrafanaCom{
  164. SocialBase: &SocialBase{
  165. Config: &config,
  166. log: logger,
  167. },
  168. url: setting.GrafanaComUrl,
  169. allowSignup: info.AllowSignup,
  170. allowedOrganizations: util.SplitString(sec.Key("allowed_organizations").String()),
  171. }
  172. }
  173. }
  174. }
  175. // GetOAuthProviders returns available oauth providers and if they're enabled or not
  176. var GetOAuthProviders = func(cfg *setting.Cfg) map[string]bool {
  177. result := map[string]bool{}
  178. if cfg == nil || cfg.Raw == nil {
  179. return result
  180. }
  181. for _, name := range allOauthes {
  182. if name == "grafananet" {
  183. name = grafanaCom
  184. }
  185. sec := cfg.Raw.Section("auth." + name)
  186. if sec == nil {
  187. continue
  188. }
  189. result[name] = sec.Key("enabled").MustBool()
  190. }
  191. return result
  192. }