authenticates.rb 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. module ApplicationController::Authenticates
  3. extend ActiveSupport::Concern
  4. private
  5. def authentication_check(basic_auth_prompt: nil)
  6. user = authentication_check_only
  7. # check if basic_auth fallback is possible
  8. if basic_auth_prompt && !user
  9. request_http_basic_authentication
  10. return false
  11. end
  12. # return auth not ok
  13. if !user
  14. raise Exceptions::Forbidden, __('Authentication required')
  15. end
  16. # return auth ok
  17. true
  18. end
  19. def authentication_check_only
  20. if %w[test development].include?(Rails.env) && ENV['FAKE_SELENIUM_LOGIN_USER_ID'].present? && session[:user_id].blank?
  21. session[:user_id] = ENV['FAKE_SELENIUM_LOGIN_USER_ID'].to_i
  22. session[:user_device_updated_at] = Time.zone.now
  23. session[:authentication_type] = 'password'
  24. end
  25. # logger.debug 'authentication_check'
  26. # logger.debug params.inspect
  27. # logger.debug session.inspect
  28. # logger.debug cookies.inspect
  29. authentication_errors = []
  30. # already logged in, early exit
  31. if session.id && session[:user_id]
  32. logger.debug { 'session based auth check' }
  33. user = User.lookup(id: session[:user_id])
  34. return authentication_check_prerequesits(user, 'session') if user
  35. authentication_errors.push("Can't find User with ID #{session[:user_id]} from Session")
  36. end
  37. # check http basic based authentication
  38. authenticate_with_http_basic do |username, password|
  39. request.session_options[:skip] = true # do not send a session cookie
  40. logger.debug { "http basic auth check '#{username}'" }
  41. if Setting.get('api_password_access') == false
  42. raise Exceptions::Forbidden, 'API password access disabled!'
  43. end
  44. auth = Auth.new(username, password)
  45. begin
  46. auth.valid!
  47. return authentication_check_prerequesits(auth.user, 'basic_auth')
  48. rescue Auth::Error::AuthenticationFailed
  49. authentication_errors.push(__('Invalid BasicAuth credentials'))
  50. rescue Auth::Error::TwoFactorRequired
  51. authentication_errors.push(__('Two-factor authentication is not supported with HTTP BasicAuth.'))
  52. end
  53. end
  54. # check http token based authentication
  55. authenticate_with_http_token do |token_string, _options|
  56. logger.debug { "http token auth check '#{token_string}'" }
  57. request.session_options[:skip] = true # do not send a session cookie
  58. if Setting.get('api_token_access') == false
  59. raise Exceptions::Forbidden, 'API token access disabled!'
  60. end
  61. user = Token.check(
  62. action: 'api',
  63. token: token_string,
  64. inactive_user: true,
  65. )
  66. if user
  67. token = Token.find_by(token: token_string)
  68. token.last_used_at = Time.zone.now
  69. token.save!
  70. if token.expires_at &&
  71. Time.zone.today >= token.expires_at
  72. raise Exceptions::NotAuthorized, __('Not authorized (token expired)!')
  73. end
  74. @_token = token # remember for Pundit authorization / permit!
  75. end
  76. @_token_auth = token_string # remember for permission_check
  77. return authentication_check_prerequesits(user, 'token_auth') if user
  78. authentication_errors.push(__("Can't find User for Token"))
  79. end
  80. # check oauth2 token based authentication
  81. token = Doorkeeper::OAuth::Token.from_bearer_authorization(request)
  82. if token
  83. request.session_options[:skip] = true # do not send a session cookie
  84. logger.debug { "OAuth2 token auth check '#{token}'" }
  85. access_token = Doorkeeper::AccessToken.by_token(token)
  86. raise Exceptions::NotAuthorized, __('The provided token is invalid.') if !access_token
  87. # check expire
  88. if access_token.expires_in && (access_token.created_at + access_token.expires_in) < Time.zone.now
  89. raise Exceptions::NotAuthorized, __('OAuth2 token is expired!')
  90. end
  91. # if access_token.scopes.empty?
  92. # raise Exceptions::NotAuthorized, 'OAuth2 scope missing for token!'
  93. # end
  94. user = User.find(access_token.resource_owner_id)
  95. return authentication_check_prerequesits(user, 'token_auth') if user
  96. authentication_errors.push("Can't find User with ID #{access_token.resource_owner_id} for OAuth2 token")
  97. end
  98. return false if authentication_errors.blank?
  99. raise Exceptions::NotAuthorized, authentication_errors.join(', ')
  100. end
  101. def authentication_check_prerequesits(user, auth_type)
  102. raise Exceptions::Forbidden, __('Maintenance mode enabled!') if in_maintenance_mode?(user)
  103. raise Exceptions::NotAuthorized, Auth::Error::AuthenticationFailed::MESSAGE if !user.active
  104. current_user_set(user, auth_type)
  105. user_device_log(user, auth_type)
  106. logger.debug { "#{auth_type} for '#{user.login}'" }
  107. user
  108. end
  109. def authenticate_and_authorize!
  110. authentication_check && authorize!
  111. end
  112. end