users.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Copyright 2020 The Gogs 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 db
  5. import (
  6. "fmt"
  7. "strings"
  8. "github.com/jinzhu/gorm"
  9. "github.com/pkg/errors"
  10. "gogs.io/gogs/internal/errutil"
  11. )
  12. // UsersStore is the persistent interface for users.
  13. //
  14. // NOTE: All methods are sorted in alphabetical order.
  15. type UsersStore interface {
  16. // Authenticate validates username and password via given login source ID.
  17. // It returns ErrUserNotExist when the user was not found.
  18. //
  19. // When the "loginSourceID" is negative, it aborts the process and returns
  20. // ErrUserNotExist if the user was not found in the database.
  21. //
  22. // When the "loginSourceID" is non-negative, it returns ErrLoginSourceMismatch
  23. // if the user has different login source ID than the "loginSourceID".
  24. //
  25. // When the "loginSourceID" is positive, it tries to authenticate via given
  26. // login source and creates a new user when not yet exists in the database.
  27. Authenticate(username, password string, loginSourceID int64) (*User, error)
  28. // GetByID returns the user with given ID. It returns ErrUserNotExist when not found.
  29. GetByID(id int64) (*User, error)
  30. // GetByUsername returns the user with given username. It returns ErrUserNotExist
  31. // when not found.
  32. GetByUsername(username string) (*User, error)
  33. }
  34. var Users UsersStore
  35. type users struct {
  36. *gorm.DB
  37. }
  38. type ErrLoginSourceMismatch struct {
  39. args errutil.Args
  40. }
  41. func (err ErrLoginSourceMismatch) Error() string {
  42. return fmt.Sprintf("login source mismatch: %v", err.args)
  43. }
  44. func (db *users) Authenticate(username, password string, loginSourceID int64) (*User, error) {
  45. username = strings.ToLower(username)
  46. var query *gorm.DB
  47. if strings.Contains(username, "@") {
  48. query = db.Where("email = ?", username)
  49. } else {
  50. query = db.Where("lower_name = ?", username)
  51. }
  52. user := new(User)
  53. err := query.First(user).Error
  54. if err != nil && err != gorm.ErrRecordNotFound {
  55. return nil, errors.Wrap(err, "get user")
  56. }
  57. // User found in the database
  58. if err == nil {
  59. // Note: This check is unnecessary but to reduce user confusion at login page
  60. // and make it more consistent from user's perspective.
  61. if loginSourceID >= 0 && user.LoginSource != loginSourceID {
  62. return nil, ErrLoginSourceMismatch{args: errutil.Args{"expect": loginSourceID, "actual": user.LoginSource}}
  63. }
  64. // Validate password hash fetched from database for local accounts.
  65. if user.LoginType == LoginNotype || user.LoginType == LoginPlain {
  66. if user.ValidatePassword(password) {
  67. return user, nil
  68. }
  69. return nil, ErrUserNotExist{args: map[string]interface{}{"userID": user.ID, "name": user.Name}}
  70. }
  71. source, err := LoginSources.GetByID(user.LoginSource)
  72. if err != nil {
  73. return nil, errors.Wrap(err, "get login source")
  74. }
  75. _, err = authenticateViaLoginSource(source, username, password, false)
  76. if err != nil {
  77. return nil, errors.Wrap(err, "authenticate via login source")
  78. }
  79. return user, nil
  80. }
  81. // Non-local login source is always greater than 0.
  82. if loginSourceID <= 0 {
  83. return nil, ErrUserNotExist{args: map[string]interface{}{"name": username}}
  84. }
  85. source, err := LoginSources.GetByID(loginSourceID)
  86. if err != nil {
  87. return nil, errors.Wrap(err, "get login source")
  88. }
  89. user, err = authenticateViaLoginSource(source, username, password, true)
  90. if err != nil {
  91. return nil, errors.Wrap(err, "authenticate via login source")
  92. }
  93. return user, nil
  94. }
  95. func (db *users) GetByID(id int64) (*User, error) {
  96. user := new(User)
  97. err := db.Where("id = ?", id).First(user).Error
  98. if err != nil {
  99. if gorm.IsRecordNotFoundError(err) {
  100. return nil, ErrUserNotExist{args: map[string]interface{}{"userID": id}}
  101. }
  102. return nil, err
  103. }
  104. return user, nil
  105. }
  106. func (db *users) GetByUsername(username string) (*User, error) {
  107. user := new(User)
  108. err := db.Where("lower_name = ?", strings.ToLower(username)).First(user).Error
  109. if err != nil {
  110. if gorm.IsRecordNotFoundError(err) {
  111. return nil, ErrUserNotExist{args: map[string]interface{}{"name": username}}
  112. }
  113. return nil, err
  114. }
  115. return user, nil
  116. }