From a56245defa932231d5d52d857496853dfb06843b Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Thu, 1 Apr 2021 15:14:25 +0000 Subject: [PATCH] Fixes #3468: Not authorized error using Im X-On-Behalf-Of. --- .../application_controller/authorizes.rb | 8 ++++- lib/user_context.rb | 2 +- spec/factories/token.rb | 14 +++++++++ spec/requests/api_auth_on_behalf_of_spec.rb | 31 ++++++++++++++++++- spec/support/request.rb | 17 +++++----- 5 files changed, 62 insertions(+), 10 deletions(-) diff --git a/app/controllers/application_controller/authorizes.rb b/app/controllers/application_controller/authorizes.rb index 7e37fa3b4..65b309a5c 100644 --- a/app/controllers/application_controller/authorizes.rb +++ b/app/controllers/application_controller/authorizes.rb @@ -23,6 +23,12 @@ module ApplicationController::Authorizes end def pundit_user - @pundit_user ||= UserContext.new(current_user, @_token) + @pundit_user ||= begin + if current_user_on_behalf + UserContext.new(current_user_on_behalf) + else + UserContext.new(current_user_real, @_token) + end + end end end diff --git a/lib/user_context.rb b/lib/user_context.rb index 49ab58a89..4676d0437 100644 --- a/lib/user_context.rb +++ b/lib/user_context.rb @@ -5,7 +5,7 @@ # to the underlying User instance in the Policy class UserContext < Delegator - def initialize(user, token) # rubocop:disable Lint/MissingSuper + def initialize(user, token = nil) # rubocop:disable Lint/MissingSuper @user = user @token = token end diff --git a/spec/factories/token.rb b/spec/factories/token.rb index 7700886fa..54c5cdebb 100644 --- a/spec/factories/token.rb +++ b/spec/factories/token.rb @@ -3,6 +3,20 @@ FactoryBot.define do user action { 'api' } persistent { true } + preferences do + + permission_hash = permissions.each_with_object({}) do |permission, result| + result[permission] = true + end + + { + permission: permission_hash + } + end + + transient do + permissions { [] } + end factory :token_password_reset, aliases: %i[password_reset_token] do action { 'PasswordReset' } diff --git a/spec/requests/api_auth_on_behalf_of_spec.rb b/spec/requests/api_auth_on_behalf_of_spec.rb index 53d08a3e4..d122f37cd 100644 --- a/spec/requests/api_auth_on_behalf_of_spec.rb +++ b/spec/requests/api_auth_on_behalf_of_spec.rb @@ -9,7 +9,7 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do create(:agent) end let(:customer) do - create(:customer) + create(:customer, firstname: 'Behalf of') end describe 'request handling' do @@ -180,5 +180,34 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do expect(json_response).to be_a_kind_of(Hash) expect(json_response['error']).to eq('No lookup value found for \'group\': "secret1234"') end + + context 'when Token Admin has no ticket.* permission' do + + let(:admin) { create(:user, firstname: 'Requester', roles: [admin_user_role]) } + + let(:token) { create(:token, user: admin, permissions: %w[admin.user]) } + + let(:admin_user_role) do + create(:role).tap { |role| role.permission_grant('admin.user') } + end + + it 'creates Ticket because of behalf of user permission' do + params = { + title: 'a new ticket #3', + group: 'Users', + priority: '2 normal', + state: 'new', + customer_id: customer.id, + article: { + body: 'some test 123', + }, + } + authenticated_as(admin, on_behalf_of: customer.email, token: token) + post '/api/v1/tickets', params: params, as: :json + expect(response).to have_http_status(:created) + expect(json_response).to be_a_kind_of(Hash) + expect(customer.id).to eq(json_response['created_by_id']) + end + end end end diff --git a/spec/support/request.rb b/spec/support/request.rb index 034a2aa7d..91044f910 100644 --- a/spec/support/request.rb +++ b/spec/support/request.rb @@ -76,15 +76,18 @@ module ZammadSpecSupportRequest case via when :api_client + # ensure that always the correct header value is set + # otherwise previous header configurations will be re-used + add_headers('X-On-Behalf-Of' => options[:on_behalf_of]) + # if we want to authenticate by token - if options[:token].present? - credentials = "Token token=#{options[:token].name}" + credentials = if options[:token].present? + "Token token=#{options[:token].name}" + else + ActionController::HttpAuthentication::Basic.encode_credentials(login, password) + end - return add_headers('Authorization' => credentials) - end - - credentials = ActionController::HttpAuthentication::Basic.encode_credentials(login, password) - add_headers('Authorization' => credentials, 'X-On-Behalf-Of' => options[:on_behalf_of]) + add_headers('Authorization' => credentials) when :browser post '/api/v1/signin', params: { username: login, password: password, fingerprint: Faker::Number.number(9) } end