You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
8.5 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. // Copyright 2014 Google Inc. All Rights Reserved.
  2. // Copyright 2014 The Gogs Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package social
  6. import (
  7. "encoding/json"
  8. "io/ioutil"
  9. "net/http"
  10. "net/url"
  11. "strconv"
  12. "github.com/macaron-contrib/oauth2"
  13. "github.com/gogits/gogs/models"
  14. "github.com/gogits/gogs/modules/log"
  15. "github.com/gogits/gogs/modules/setting"
  16. )
  17. type BasicUserInfo struct {
  18. Identity string
  19. Name string
  20. Email string
  21. }
  22. type SocialConnector interface {
  23. Type() int
  24. UserInfo(*oauth2.Token, *url.URL) (*BasicUserInfo, error)
  25. }
  26. var (
  27. SocialMap = make(map[string]SocialConnector)
  28. )
  29. func NewOauthService() {
  30. if !setting.Cfg.Section("oauth").Key("ENABLED").MustBool() {
  31. return
  32. }
  33. oauth2.AppSubUrl = setting.AppSubUrl
  34. setting.OauthService = &setting.Oauther{}
  35. setting.OauthService.OauthInfos = make(map[string]*setting.OauthInfo)
  36. socialConfigs := make(map[string]*oauth2.Options)
  37. allOauthes := []string{"github", "google", "qq", "twitter", "weibo"}
  38. // Load all OAuth config data.
  39. for _, name := range allOauthes {
  40. sec := setting.Cfg.Section("oauth." + name)
  41. if !sec.Key("ENABLED").MustBool() {
  42. continue
  43. }
  44. setting.OauthService.OauthInfos[name] = &setting.OauthInfo{
  45. Options: oauth2.Options{
  46. ClientID: sec.Key("CLIENT_ID").String(),
  47. ClientSecret: sec.Key("CLIENT_SECRET").String(),
  48. Scopes: sec.Key("SCOPES").Strings(" "),
  49. PathLogin: "/user/login/oauth2/" + name,
  50. PathCallback: setting.AppSubUrl + "/user/login/" + name,
  51. RedirectURL: setting.AppUrl + "user/login/" + name,
  52. },
  53. AuthUrl: sec.Key("AUTH_URL").String(),
  54. TokenUrl: sec.Key("TOKEN_URL").String(),
  55. }
  56. socialConfigs[name] = &oauth2.Options{
  57. ClientID: setting.OauthService.OauthInfos[name].ClientID,
  58. ClientSecret: setting.OauthService.OauthInfos[name].ClientSecret,
  59. Scopes: setting.OauthService.OauthInfos[name].Scopes,
  60. }
  61. }
  62. enabledOauths := make([]string, 0, 10)
  63. // GitHub.
  64. if setting.Cfg.Section("oauth.github").Key("ENABLED").MustBool() {
  65. setting.OauthService.GitHub = true
  66. newGitHubOauth(socialConfigs["github"])
  67. enabledOauths = append(enabledOauths, "GitHub")
  68. }
  69. // Google.
  70. if setting.Cfg.Section("oauth.google").Key("ENABLED").MustBool() {
  71. setting.OauthService.Google = true
  72. newGoogleOauth(socialConfigs["google"])
  73. enabledOauths = append(enabledOauths, "Google")
  74. }
  75. // QQ.
  76. if setting.Cfg.Section("oauth.qq").Key("ENABLED").MustBool() {
  77. setting.OauthService.Tencent = true
  78. newTencentOauth(socialConfigs["qq"])
  79. enabledOauths = append(enabledOauths, "QQ")
  80. }
  81. // Twitter.
  82. // if setting.Cfg.Section("oauth.twitter").Key( "ENABLED").MustBool() {
  83. // setting.OauthService.Twitter = true
  84. // newTwitterOauth(socialConfigs["twitter"])
  85. // enabledOauths = append(enabledOauths, "Twitter")
  86. // }
  87. // Weibo.
  88. if setting.Cfg.Section("oauth.weibo").Key("ENABLED").MustBool() {
  89. setting.OauthService.Weibo = true
  90. newWeiboOauth(socialConfigs["weibo"])
  91. enabledOauths = append(enabledOauths, "Weibo")
  92. }
  93. log.Info("Oauth Service Enabled %s", enabledOauths)
  94. }
  95. // ________.__ __ ___ ___ ___.
  96. // / _____/|__|/ |_ / | \ __ _\_ |__
  97. // / \ ___| \ __\/ ~ \ | \ __ \
  98. // \ \_\ \ || | \ Y / | / \_\ \
  99. // \______ /__||__| \___|_ /|____/|___ /
  100. // \/ \/ \/
  101. type SocialGithub struct {
  102. opts *oauth2.Options
  103. }
  104. func newGitHubOauth(opts *oauth2.Options) {
  105. SocialMap["github"] = &SocialGithub{opts}
  106. }
  107. func (s *SocialGithub) Type() int {
  108. return int(models.GITHUB)
  109. }
  110. func (s *SocialGithub) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
  111. transport := s.opts.NewTransportFromToken(token)
  112. var data struct {
  113. Id int `json:"id"`
  114. Name string `json:"login"`
  115. Email string `json:"email"`
  116. }
  117. r, err := transport.Client().Get("https://api.github.com/user")
  118. if err != nil {
  119. return nil, err
  120. }
  121. defer r.Body.Close()
  122. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  123. return nil, err
  124. }
  125. return &BasicUserInfo{
  126. Identity: strconv.Itoa(data.Id),
  127. Name: data.Name,
  128. Email: data.Email,
  129. }, nil
  130. }
  131. // ________ .__
  132. // / _____/ ____ ____ ____ | | ____
  133. // / \ ___ / _ \ / _ \ / ___\| | _/ __ \
  134. // \ \_\ ( <_> | <_> ) /_/ > |_\ ___/
  135. // \______ /\____/ \____/\___ /|____/\___ >
  136. // \/ /_____/ \/
  137. type SocialGoogle struct {
  138. opts *oauth2.Options
  139. }
  140. func (s *SocialGoogle) Type() int {
  141. return int(models.GOOGLE)
  142. }
  143. func newGoogleOauth(opts *oauth2.Options) {
  144. SocialMap["google"] = &SocialGoogle{opts}
  145. }
  146. func (s *SocialGoogle) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
  147. transport := s.opts.NewTransportFromToken(token)
  148. var data struct {
  149. Id string `json:"id"`
  150. Name string `json:"name"`
  151. Email string `json:"email"`
  152. }
  153. r, err := transport.Client().Get("https://www.googleapis.com/userinfo/v2/me")
  154. if err != nil {
  155. return nil, err
  156. }
  157. defer r.Body.Close()
  158. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  159. return nil, err
  160. }
  161. return &BasicUserInfo{
  162. Identity: data.Id,
  163. Name: data.Name,
  164. Email: data.Email,
  165. }, nil
  166. }
  167. // ________ ________
  168. // \_____ \ \_____ \
  169. // / / \ \ / / \ \
  170. // / \_/. \/ \_/. \
  171. // \_____\ \_/\_____\ \_/
  172. // \__> \__>
  173. type SocialTencent struct {
  174. opts *oauth2.Options
  175. }
  176. func newTencentOauth(opts *oauth2.Options) {
  177. SocialMap["qq"] = &SocialTencent{opts}
  178. }
  179. func (s *SocialTencent) Type() int {
  180. return int(models.QQ)
  181. }
  182. func (s *SocialTencent) UserInfo(token *oauth2.Token, URL *url.URL) (*BasicUserInfo, error) {
  183. r, err := http.Get("https://graph.z.qq.com/moc2/me?access_token=" + url.QueryEscape(token.AccessToken))
  184. if err != nil {
  185. return nil, err
  186. }
  187. defer r.Body.Close()
  188. body, err := ioutil.ReadAll(r.Body)
  189. if err != nil {
  190. return nil, err
  191. }
  192. vals, err := url.ParseQuery(string(body))
  193. if err != nil {
  194. return nil, err
  195. }
  196. return &BasicUserInfo{
  197. Identity: vals.Get("openid"),
  198. }, nil
  199. }
  200. // ___________ .__ __ __
  201. // \__ ___/_ _ _|__|/ |__/ |_ ___________
  202. // | | \ \/ \/ / \ __\ __\/ __ \_ __ \
  203. // | | \ /| || | | | \ ___/| | \/
  204. // |____| \/\_/ |__||__| |__| \___ >__|
  205. // \/
  206. // type SocialTwitter struct {
  207. // Token *oauth2.Token
  208. // *oauth2.Transport
  209. // }
  210. // func (s *SocialTwitter) Type() int {
  211. // return int(models.TWITTER)
  212. // }
  213. // func newTwitterOauth(config *oauth2.Config) {
  214. // SocialMap["twitter"] = &SocialTwitter{
  215. // Transport: &oauth.Transport{
  216. // Config: config,
  217. // Transport: http.DefaultTransport,
  218. // },
  219. // }
  220. // }
  221. // func (s *SocialTwitter) SetRedirectUrl(url string) {
  222. // s.Transport.Config.RedirectURL = url
  223. // }
  224. // //https://github.com/mrjones/oauth
  225. // func (s *SocialTwitter) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
  226. // // transport := &oauth.Transport{Token: token}
  227. // // var data struct {
  228. // // Id string `json:"id"`
  229. // // Name string `json:"name"`
  230. // // Email string `json:"email"`
  231. // // }
  232. // // var err error
  233. // // reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
  234. // // r, err := transport.Client().Get(reqUrl)
  235. // // if err != nil {
  236. // // return nil, err
  237. // // }
  238. // // defer r.Body.Close()
  239. // // if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  240. // // return nil, err
  241. // // }
  242. // // return &BasicUserInfo{
  243. // // Identity: data.Id,
  244. // // Name: data.Name,
  245. // // Email: data.Email,
  246. // // }, nil
  247. // return nil, nil
  248. // }
  249. // __ __ ._____.
  250. // / \ / \ ____ |__\_ |__ ____
  251. // \ \/\/ // __ \| || __ \ / _ \
  252. // \ /\ ___/| || \_\ ( <_> )
  253. // \__/\ / \___ >__||___ /\____/
  254. // \/ \/ \/
  255. type SocialWeibo struct {
  256. opts *oauth2.Options
  257. }
  258. func newWeiboOauth(opts *oauth2.Options) {
  259. SocialMap["weibo"] = &SocialWeibo{opts}
  260. }
  261. func (s *SocialWeibo) Type() int {
  262. return int(models.WEIBO)
  263. }
  264. func (s *SocialWeibo) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
  265. transport := s.opts.NewTransportFromToken(token)
  266. var data struct {
  267. Name string `json:"name"`
  268. }
  269. var urls = url.Values{
  270. "access_token": {token.AccessToken},
  271. "uid": {token.Extra("uid")},
  272. }
  273. reqUrl := "https://api.weibo.com/2/users/show.json"
  274. r, err := transport.Client().Get(reqUrl + "?" + urls.Encode())
  275. if err != nil {
  276. return nil, err
  277. }
  278. defer r.Body.Close()
  279. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  280. return nil, err
  281. }
  282. return &BasicUserInfo{
  283. Identity: token.Extra("uid"),
  284. Name: data.Name,
  285. }, nil
  286. }