auth.rb 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class Auth
  3. attr_reader :user, :password, :auth_user, :two_factor_method, :two_factor_payload, :only_verify_password
  4. delegate :user, to: :auth_user
  5. attr_accessor :increase_login_failed_attempts
  6. BRUTE_FORCE_SLEEP = 1.second
  7. # Initializes a Auth object for the given user.
  8. #
  9. # @param username [String] the user name for the user object which needs an authentication.
  10. #
  11. # @example
  12. # auth = Auth.new('admin@example.com', 'some+password')
  13. def initialize(username, password, two_factor_method: nil, two_factor_payload: nil, only_verify_password: false)
  14. @auth_user = username.present? ? Auth::User.new(username) : nil
  15. @password = password
  16. @two_factor_payload = two_factor_payload
  17. @two_factor_method = two_factor_method
  18. @increase_login_failed_attempts = false
  19. @only_verify_password = only_verify_password
  20. return if !@two_factor_payload.is_a?(Hash)
  21. @two_factor_payload = @two_factor_payload.symbolize_keys
  22. end
  23. # Validates the given credentials for the user to the configured auth backends which should
  24. # be performed.
  25. #
  26. # @return true if the user was authenticated, otherwise it raises an Exception.
  27. def valid!
  28. if verify_credentials!
  29. auth_user.update_last_login if !only_verify_password
  30. return true
  31. end
  32. wait_and_raise Auth::Error::AuthenticationFailed
  33. end
  34. private
  35. def verify_credentials!
  36. # Wrap in a lock to synchronize concurrent requests.
  37. auth_user&.user&.with_lock do
  38. next false if !auth_user.can_login?
  39. if !backends.valid?
  40. # Failed log-in attempts are only recorded if the password backend requests so.
  41. auth_user.increase_login_failed if increase_login_failed_attempts && !only_verify_password
  42. next false
  43. end
  44. verify_two_factor!
  45. end
  46. end
  47. def verify_two_factor!
  48. return true if only_verify_password
  49. return true if !auth_user.requires_two_factor?
  50. if two_factor_method.blank?
  51. raise Auth::Error::TwoFactorRequired, auth_user
  52. end
  53. auth_user.two_factor_payload_valid?(two_factor_method, two_factor_payload) || wait_and_raise(Auth::Error::TwoFactorFailed)
  54. end
  55. def wait_and_raise(...)
  56. # Sleep for a second to avoid brute force attacks.
  57. sleep BRUTE_FORCE_SLEEP
  58. raise(...)
  59. end
  60. def backends
  61. Auth::Backend.new(self)
  62. end
  63. end