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.

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