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.

188 lines
5.8 KiB

Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
7 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
7 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
7 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
7 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
7 years ago
Oauth2 consumer (#679) * initial stuff for oauth2 login, fails on: * login button on the signIn page to start the OAuth2 flow and a callback for each provider Only GitHub is implemented for now * show login button only when the OAuth2 consumer is configured (and activated) * create macaron group for oauth2 urls * prevent net/http in modules (other then oauth2) * use a new data sessions oauth2 folder for storing the oauth2 session data * add missing 2FA when this is enabled on the user * add password option for OAuth2 user , for use with git over http and login to the GUI * add tip for registering a GitHub OAuth application * at startup of Gitea register all configured providers and also on adding/deleting of new providers * custom handling of errors in oauth2 request init + show better tip * add ExternalLoginUser model and migration script to add it to database * link a external account to an existing account (still need to handle wrong login and signup) and remove if user is removed * remove the linked external account from the user his settings * if user is unknown we allow him to register a new account or link it to some existing account * sign up with button on signin page (als change OAuth2Provider structure so we can store basic stuff about providers) * from gorilla/sessions docs: "Important Note: If you aren't using gorilla/mux, you need to wrap your handlers with context.ClearHandler as or else you will leak memory!" (we're using gorilla/sessions for storing oauth2 sessions) * use updated goth lib that now supports getting the OAuth2 user if the AccessToken is still valid instead of re-authenticating (prevent flooding the OAuth2 provider)
7 years ago
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "time"
  7. "code.gitea.io/gitea/modules/structs"
  8. "github.com/markbates/goth"
  9. "xorm.io/builder"
  10. )
  11. // ExternalLoginUser makes the connecting between some existing user and additional external login sources
  12. type ExternalLoginUser struct {
  13. ExternalID string `xorm:"pk NOT NULL"`
  14. UserID int64 `xorm:"INDEX NOT NULL"`
  15. LoginSourceID int64 `xorm:"pk NOT NULL"`
  16. RawData map[string]interface{} `xorm:"TEXT JSON"`
  17. Provider string `xorm:"index VARCHAR(25)"`
  18. Email string
  19. Name string
  20. FirstName string
  21. LastName string
  22. NickName string
  23. Description string
  24. AvatarURL string
  25. Location string
  26. AccessToken string `xorm:"TEXT"`
  27. AccessTokenSecret string `xorm:"TEXT"`
  28. RefreshToken string `xorm:"TEXT"`
  29. ExpiresAt time.Time
  30. }
  31. // GetExternalLogin checks if a externalID in loginSourceID scope already exists
  32. func GetExternalLogin(externalLoginUser *ExternalLoginUser) (bool, error) {
  33. return x.Get(externalLoginUser)
  34. }
  35. // ListAccountLinks returns a map with the ExternalLoginUser and its LoginSource
  36. func ListAccountLinks(user *User) ([]*ExternalLoginUser, error) {
  37. externalAccounts := make([]*ExternalLoginUser, 0, 5)
  38. err := x.Where("user_id=?", user.ID).
  39. Desc("login_source_id").
  40. Find(&externalAccounts)
  41. if err != nil {
  42. return nil, err
  43. }
  44. return externalAccounts, nil
  45. }
  46. // LinkExternalToUser link the external user to the user
  47. func LinkExternalToUser(user *User, externalLoginUser *ExternalLoginUser) error {
  48. has, err := x.Where("external_id=? AND login_source_id=?", externalLoginUser.ExternalID, externalLoginUser.LoginSourceID).
  49. NoAutoCondition().
  50. Exist(externalLoginUser)
  51. if err != nil {
  52. return err
  53. } else if has {
  54. return ErrExternalLoginUserAlreadyExist{externalLoginUser.ExternalID, user.ID, externalLoginUser.LoginSourceID}
  55. }
  56. _, err = x.Insert(externalLoginUser)
  57. return err
  58. }
  59. // RemoveAccountLink will remove all external login sources for the given user
  60. func RemoveAccountLink(user *User, loginSourceID int64) (int64, error) {
  61. deleted, err := x.Delete(&ExternalLoginUser{UserID: user.ID, LoginSourceID: loginSourceID})
  62. if err != nil {
  63. return deleted, err
  64. }
  65. if deleted < 1 {
  66. return deleted, ErrExternalLoginUserNotExist{user.ID, loginSourceID}
  67. }
  68. return deleted, err
  69. }
  70. // removeAllAccountLinks will remove all external login sources for the given user
  71. func removeAllAccountLinks(e Engine, user *User) error {
  72. _, err := e.Delete(&ExternalLoginUser{UserID: user.ID})
  73. return err
  74. }
  75. // GetUserIDByExternalUserID get user id according to provider and userID
  76. func GetUserIDByExternalUserID(provider string, userID string) (int64, error) {
  77. var id int64
  78. _, err := x.Table("external_login_user").
  79. Select("user_id").
  80. Where("provider=?", provider).
  81. And("external_id=?", userID).
  82. Get(&id)
  83. if err != nil {
  84. return 0, err
  85. }
  86. return id, nil
  87. }
  88. // UpdateExternalUser updates external user's information
  89. func UpdateExternalUser(user *User, gothUser goth.User) error {
  90. loginSource, err := GetActiveOAuth2LoginSourceByName(gothUser.Provider)
  91. if err != nil {
  92. return err
  93. }
  94. externalLoginUser := &ExternalLoginUser{
  95. ExternalID: gothUser.UserID,
  96. UserID: user.ID,
  97. LoginSourceID: loginSource.ID,
  98. RawData: gothUser.RawData,
  99. Provider: gothUser.Provider,
  100. Email: gothUser.Email,
  101. Name: gothUser.Name,
  102. FirstName: gothUser.FirstName,
  103. LastName: gothUser.LastName,
  104. NickName: gothUser.NickName,
  105. Description: gothUser.Description,
  106. AvatarURL: gothUser.AvatarURL,
  107. Location: gothUser.Location,
  108. AccessToken: gothUser.AccessToken,
  109. AccessTokenSecret: gothUser.AccessTokenSecret,
  110. RefreshToken: gothUser.RefreshToken,
  111. ExpiresAt: gothUser.ExpiresAt,
  112. }
  113. has, err := x.Where("external_id=? AND login_source_id=?", gothUser.UserID, loginSource.ID).
  114. NoAutoCondition().
  115. Exist(externalLoginUser)
  116. if err != nil {
  117. return err
  118. } else if !has {
  119. return ErrExternalLoginUserNotExist{user.ID, loginSource.ID}
  120. }
  121. _, err = x.Where("external_id=? AND login_source_id=?", gothUser.UserID, loginSource.ID).AllCols().Update(externalLoginUser)
  122. return err
  123. }
  124. // FindExternalUserOptions represents an options to find external users
  125. type FindExternalUserOptions struct {
  126. Provider string
  127. Limit int
  128. Start int
  129. }
  130. func (opts FindExternalUserOptions) toConds() builder.Cond {
  131. var cond = builder.NewCond()
  132. if len(opts.Provider) > 0 {
  133. cond = cond.And(builder.Eq{"provider": opts.Provider})
  134. }
  135. return cond
  136. }
  137. // FindExternalUsersByProvider represents external users via provider
  138. func FindExternalUsersByProvider(opts FindExternalUserOptions) ([]ExternalLoginUser, error) {
  139. var users []ExternalLoginUser
  140. err := x.Where(opts.toConds()).
  141. Limit(opts.Limit, opts.Start).
  142. OrderBy("login_source_id ASC, external_id ASC").
  143. Find(&users)
  144. if err != nil {
  145. return nil, err
  146. }
  147. return users, nil
  148. }
  149. // UpdateMigrationsByType updates all migrated repositories' posterid from gitServiceType to replace originalAuthorID to posterID
  150. func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID string, userID int64) error {
  151. if err := UpdateIssuesMigrationsByType(tp, externalUserID, userID); err != nil {
  152. return err
  153. }
  154. if err := UpdateCommentsMigrationsByType(tp, externalUserID, userID); err != nil {
  155. return err
  156. }
  157. if err := UpdateReleasesMigrationsByType(tp, externalUserID, userID); err != nil {
  158. return err
  159. }
  160. if err := UpdateReactionsMigrationsByType(tp, externalUserID, userID); err != nil {
  161. return err
  162. }
  163. return UpdateReviewsMigrationsByType(tp, externalUserID, userID)
  164. }