123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- module ApplicationController::HasUser
- extend ActiveSupport::Concern
- included do
- before_action :set_user, :session_update
- end
- private
- def current_user
- current_user_on_behalf || current_user_real
- end
- # Finds the User with the ID stored in the session with the key
- # :current_user_id This is a common way to handle user login in
- # a Rails application; logging in sets the session value and
- # logging out removes it.
- def current_user_real
- @_current_user ||= User.lookup(id: session[:user_id]) # rubocop:disable Naming/MemoizedInstanceVariableName
- end
- def request_header_from
- @request_header_from ||= begin
- if request.headers['X-On-Behalf-Of'].present?
- ActiveSupport::Deprecation.warn("Header 'X-On-Behalf-Of' is deprecated. Please use header 'From' instead.")
- end
- request.headers['From'] || request.headers['X-On-Behalf-Of']
- end
- end
- # Finds the user based on the id, login or email which is given
- # in the headers. If it is found then all api activities are done
- # with the behalf of user. With this functionality it is possible
- # to do changes with a user which is different from the admin user.
- # E.g. create a ticket as a customer user based on a user with admin rights.
- def current_user_on_behalf
- return if request_header_from.blank? # require header
- return @_user_on_behalf if @_user_on_behalf # return memoized user
- return if !current_user_real # require session user
- if !SessionsPolicy.new(current_user_real, Sessions).impersonate?
- raise Exceptions::Forbidden, __("Current user has no permission to use 'From'/'X-On-Behalf-Of'!")
- end
- @_user_on_behalf = find_on_behalf_user request_header_from.to_s.downcase.strip
- # no behalf of user found
- if !@_user_on_behalf
- raise Exceptions::Forbidden, "No such user '#{request_header_from}'"
- end
- @_user_on_behalf
- end
- def current_user_set(user, auth_type = 'session')
- session[:user_id] = user.id
- @_auth_type = auth_type
- @_current_user = user
- set_user
- end
- # Sets the current user into a named Thread location so that it can be accessed
- # by models and observers
- def set_user
- UserInfo.current_user_id = current_user&.id || 1
- end
- # update session updated_at
- def session_update
- # sleep 0.6
- session[:ping] = Time.zone.now.iso8601
- # check if remote ip needs to be updated
- if session[:user_id]
- if !session[:remote_ip] || session[:remote_ip] != request.remote_ip # rubocop:disable Style/SoleNestedConditional
- session[:remote_ip] = request.remote_ip
- session[:geo] = Service::GeoIp.location(request.remote_ip)
- end
- end
- # fill user agent
- return if session[:user_agent]
- session[:user_agent] = request.env['HTTP_USER_AGENT']
- end
- # find on behalf user by ID, login or email
- def find_on_behalf_user(identifier)
- # ActiveRecord casts string beginning with a numeric characters
- # to numeric characters by dropping textual bits altogether
- # thus 123@example.com returns user with ID 123
- if identifier.match?(%r{^\d+$})
- user = User.find_by(id: identifier)
- return user if user
- end
- # find user for execution based on the header
- User.where('login = :param OR email = :param', param: identifier).first
- end
- end
|