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.

source_authenticate.go 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package smtp
  4. import (
  5. "errors"
  6. "net/smtp"
  7. "net/textproto"
  8. "strings"
  9. auth_model "code.gitea.io/gitea/models/auth"
  10. user_model "code.gitea.io/gitea/models/user"
  11. "code.gitea.io/gitea/modules/util"
  12. "code.gitea.io/gitea/services/mailer"
  13. )
  14. // Authenticate queries if the provided login/password is authenticates against the SMTP server
  15. // Users will be autoregistered as required
  16. func (source *Source) Authenticate(user *user_model.User, userName, password string) (*user_model.User, error) {
  17. // Verify allowed domains.
  18. if len(source.AllowedDomains) > 0 {
  19. idx := strings.Index(userName, "@")
  20. if idx == -1 {
  21. return nil, user_model.ErrUserNotExist{Name: userName}
  22. } else if !util.SliceContainsString(strings.Split(source.AllowedDomains, ","), userName[idx+1:], true) {
  23. return nil, user_model.ErrUserNotExist{Name: userName}
  24. }
  25. }
  26. var auth smtp.Auth
  27. switch source.Auth {
  28. case PlainAuthentication:
  29. auth = smtp.PlainAuth("", userName, password, source.Host)
  30. case LoginAuthentication:
  31. auth = &loginAuthenticator{userName, password}
  32. case CRAMMD5Authentication:
  33. auth = smtp.CRAMMD5Auth(userName, password)
  34. default:
  35. return nil, errors.New("unsupported SMTP auth type")
  36. }
  37. if err := Authenticate(auth, source); err != nil {
  38. // Check standard error format first,
  39. // then fallback to worse case.
  40. tperr, ok := err.(*textproto.Error)
  41. if (ok && tperr.Code == 535) ||
  42. strings.Contains(err.Error(), "Username and Password not accepted") {
  43. return nil, user_model.ErrUserNotExist{Name: userName}
  44. }
  45. if (ok && tperr.Code == 534) ||
  46. strings.Contains(err.Error(), "Application-specific password required") {
  47. return nil, user_model.ErrUserNotExist{Name: userName}
  48. }
  49. return nil, err
  50. }
  51. if user != nil {
  52. return user, nil
  53. }
  54. username := userName
  55. idx := strings.Index(userName, "@")
  56. if idx > -1 {
  57. username = userName[:idx]
  58. }
  59. user = &user_model.User{
  60. LowerName: strings.ToLower(username),
  61. Name: strings.ToLower(username),
  62. Email: userName,
  63. Passwd: password,
  64. LoginType: auth_model.SMTP,
  65. LoginSource: source.authSource.ID,
  66. LoginName: userName,
  67. }
  68. overwriteDefault := &user_model.CreateUserOverwriteOptions{
  69. IsActive: util.OptionalBoolTrue,
  70. }
  71. if err := user_model.CreateUser(user, overwriteDefault); err != nil {
  72. return user, err
  73. }
  74. mailer.SendRegisterNotifyMail(user)
  75. return user, nil
  76. }
  77. // IsSkipLocalTwoFA returns if this source should skip local 2fa for password authentication
  78. func (source *Source) IsSkipLocalTwoFA() bool {
  79. return source.SkipLocalTwoFA
  80. }