has_user.rb 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. module ApplicationController::HasUser
  3. extend ActiveSupport::Concern
  4. included do
  5. before_action :set_user, :session_update
  6. end
  7. private
  8. def current_user
  9. current_user_on_behalf || current_user_real
  10. end
  11. # Finds the User with the ID stored in the session with the key
  12. # :current_user_id This is a common way to handle user login in
  13. # a Rails application; logging in sets the session value and
  14. # logging out removes it.
  15. def current_user_real
  16. @_current_user ||= User.lookup(id: session[:user_id]) # rubocop:disable Naming/MemoizedInstanceVariableName
  17. end
  18. def request_header_from
  19. @request_header_from ||= begin
  20. if request.headers['X-On-Behalf-Of'].present?
  21. ActiveSupport::Deprecation.warn("Header 'X-On-Behalf-Of' is deprecated. Please use header 'From' instead.")
  22. end
  23. request.headers['From'] || request.headers['X-On-Behalf-Of']
  24. end
  25. end
  26. # Finds the user based on the id, login or email which is given
  27. # in the headers. If it is found then all api activities are done
  28. # with the behalf of user. With this functionality it is possible
  29. # to do changes with a user which is different from the admin user.
  30. # E.g. create a ticket as a customer user based on a user with admin rights.
  31. def current_user_on_behalf
  32. return if request_header_from.blank? # require header
  33. return @_user_on_behalf if @_user_on_behalf # return memoized user
  34. return if !current_user_real # require session user
  35. if !SessionsPolicy.new(current_user_real, Sessions).impersonate?
  36. raise Exceptions::Forbidden, __("Current user has no permission to use 'From'/'X-On-Behalf-Of'!")
  37. end
  38. @_user_on_behalf = find_on_behalf_user request_header_from.to_s.downcase.strip
  39. # no behalf of user found
  40. if !@_user_on_behalf
  41. raise Exceptions::Forbidden, "No such user '#{request_header_from}'"
  42. end
  43. @_user_on_behalf
  44. end
  45. def current_user_set(user, auth_type = 'session')
  46. session[:user_id] = user.id
  47. @_auth_type = auth_type
  48. @_current_user = user
  49. set_user
  50. end
  51. # Sets the current user into a named Thread location so that it can be accessed
  52. # by models and observers
  53. def set_user
  54. UserInfo.current_user_id = current_user&.id || 1
  55. end
  56. # update session updated_at
  57. def session_update
  58. # sleep 0.6
  59. session[:ping] = Time.zone.now.iso8601
  60. # check if remote ip needs to be updated
  61. if session[:user_id]
  62. if !session[:remote_ip] || session[:remote_ip] != request.remote_ip # rubocop:disable Style/SoleNestedConditional
  63. session[:remote_ip] = request.remote_ip
  64. session[:geo] = Service::GeoIp.location(request.remote_ip)
  65. end
  66. end
  67. # fill user agent
  68. return if session[:user_agent]
  69. session[:user_agent] = request.env['HTTP_USER_AGENT']
  70. end
  71. # find on behalf user by ID, login or email
  72. def find_on_behalf_user(identifier)
  73. # ActiveRecord casts string beginning with a numeric characters
  74. # to numeric characters by dropping textual bits altogether
  75. # thus 123@example.com returns user with ID 123
  76. if identifier.match?(%r{^\d+$})
  77. user = User.find_by(id: identifier)
  78. return user if user
  79. end
  80. # find user for execution based on the header
  81. User.where('login = :param OR email = :param', param: identifier).first
  82. end
  83. end