Fixes #3113 - Prefer HTTP standard header "From" over custom "X-On-Behalf-Of" for impersonation.

This commit is contained in:
Rolf Schmidt 2021-08-10 13:00:34 +01:00 committed by Thorsten Eckel
parent 884b5c6455
commit 55ed75cfd7
4 changed files with 45 additions and 35 deletions

View File

@ -272,7 +272,7 @@ RSpec/ExampleLength:
- 'spec/models/trigger_spec.rb'
- 'spec/models/user_spec.rb'
- 'spec/requests/admin/knowledge_base/public_menu_spec.rb'
- 'spec/requests/api_auth_on_behalf_of_spec.rb'
- 'spec/requests/api_auth_from_spec.rb'
- 'spec/requests/api_auth_spec.rb'
- 'spec/requests/calendar_spec.rb'
- 'spec/requests/external_credentials_spec.rb'
@ -346,7 +346,7 @@ RSpec/InstanceVariable:
- 'spec/lib/notification_factory/renderer_spec.rb'
- 'spec/models/import_job_spec.rb'
- 'spec/models/scheduler_spec.rb'
- 'spec/requests/api_auth_on_behalf_of_spec.rb'
- 'spec/requests/api_auth_from_spec.rb'
- 'spec/requests/integration/monitoring_spec.rb'
- 'spec/requests/integration/sipgate_spec.rb'
- 'spec/requests/organization_spec.rb'
@ -558,7 +558,7 @@ RSpec/MultipleExpectations:
- 'spec/models/trigger_spec.rb'
- 'spec/models/type_lookup_spec.rb'
- 'spec/models/user_spec.rb'
- 'spec/requests/api_auth_on_behalf_of_spec.rb'
- 'spec/requests/api_auth_from_spec.rb'
- 'spec/requests/api_auth_spec.rb'
- 'spec/requests/calendar_spec.rb'
- 'spec/requests/error_spec.rb'

View File

@ -21,24 +21,34 @@ module ApplicationController::HasUser
@_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.headers['X-On-Behalf-Of'].blank? # require header
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 'X-On-Behalf-Of'!"
raise Exceptions::Forbidden, "Current user has no permission to use 'From'/'X-On-Behalf-Of'!"
end
@_user_on_behalf = find_on_behalf_user request.headers['X-On-Behalf-Of'].to_s.downcase.strip
@_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.headers['X-On-Behalf-Of']}'"
raise Exceptions::Forbidden, "No such user '#{request_header_from}'"
end
@_user_on_behalf

View File

@ -2,7 +2,7 @@
require 'rails_helper'
RSpec.describe 'Api Auth On Behalf Of', type: :request do
RSpec.describe 'Api Auth From', type: :request do
let(:admin) do
create(:admin, groups: Group.all)
@ -11,12 +11,12 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
create(:agent)
end
let(:customer) do
create(:customer, firstname: 'Behalf of')
create(:customer, firstname: 'From')
end
describe 'request handling' do
it 'does X-On-Behalf-Of auth - ticket create admin for customer by id' do
it 'does From auth - ticket create admin for customer by id' do
params = {
title: 'a new ticket #3',
group: 'Users',
@ -27,14 +27,14 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
body: 'some test 123',
},
}
authenticated_as(admin, on_behalf_of: customer.id)
authenticated_as(admin, from: customer.id)
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
it 'does X-On-Behalf-Of auth - ticket create admin for customer by login (upcase)' do
it 'does From auth - ticket create admin for customer by login (upcase)' do
params = {
title: 'a new ticket #3',
group: 'Users',
@ -45,14 +45,14 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
body: 'some test 123',
},
}
authenticated_as(admin, on_behalf_of: customer.login.upcase)
authenticated_as(admin, from: customer.login.upcase)
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
it 'does X-On-Behalf-Of auth - ticket create admin for customer by login' do
it 'does From auth - ticket create admin for customer by login' do
ActivityStream.cleanup(1.year)
params = {
@ -65,7 +65,7 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
body: 'some test 123',
},
}
authenticated_as(admin, on_behalf_of: customer.login)
authenticated_as(admin, from: customer.login)
post '/api/v1/tickets', params: params, as: :json
expect(response).to have_http_status(:created)
json_response_ticket = json_response
@ -108,7 +108,7 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
expect(customer.id).to eq(ticket_created.created_by_id)
end
it 'does X-On-Behalf-Of auth - ticket create admin for customer by email' do
it 'does From auth - ticket create admin for customer by email' do
params = {
title: 'a new ticket #3',
group: 'Users',
@ -119,14 +119,14 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
body: 'some test 123',
},
}
authenticated_as(admin, on_behalf_of: customer.email)
authenticated_as(admin, from: customer.email)
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
it 'does X-On-Behalf-Of auth - ticket create admin for unknown' do
it 'does From auth - ticket create admin for unknown' do
params = {
title: 'a new ticket #3',
group: 'Users',
@ -137,7 +137,7 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
body: 'some test 123',
},
}
authenticated_as(admin, on_behalf_of: 99_449_494_949)
authenticated_as(admin, from: 99_449_494_949)
post '/api/v1/tickets', params: params, as: :json
expect(response).to have_http_status(:forbidden)
expect(@response.header).not_to be_key('Access-Control-Allow-Origin')
@ -145,7 +145,7 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
expect(json_response['error']).to eq("No such user '99449494949'")
end
it 'does X-On-Behalf-Of auth - ticket create customer for admin' do
it 'does From auth - ticket create customer for admin' do
params = {
title: 'a new ticket #3',
group: 'Users',
@ -156,15 +156,15 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
body: 'some test 123',
},
}
authenticated_as(customer, on_behalf_of: admin.email)
authenticated_as(customer, from: admin.email)
post '/api/v1/tickets', params: params, as: :json
expect(response).to have_http_status(:forbidden)
expect(@response.header).not_to be_key('Access-Control-Allow-Origin')
expect(json_response).to be_a_kind_of(Hash)
expect(json_response['error']).to eq("Current user has no permission to use 'X-On-Behalf-Of'!")
expect(json_response['error']).to eq("Current user has no permission to use 'From'/'X-On-Behalf-Of'!")
end
it 'does X-On-Behalf-Of auth - ticket create admin for customer by email but no permitted action' do
it 'does From auth - ticket create admin for customer by email but no permitted action' do
params = {
title: 'a new ticket #3',
group: 'secret1234',
@ -175,7 +175,7 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
body: 'some test 123',
},
}
authenticated_as(admin, on_behalf_of: customer.email)
authenticated_as(admin, from: customer.email)
post '/api/v1/tickets', params: params, as: :json
expect(response).to have_http_status(:unprocessable_entity)
expect(@response.header).not_to be_key('Access-Control-Allow-Origin')
@ -204,7 +204,7 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
body: 'some test 123',
},
}
authenticated_as(admin, on_behalf_of: customer.email, token: token)
authenticated_as(admin, from: 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)
@ -232,7 +232,7 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
body: 'some test 123',
},
}
authenticated_as(admin, on_behalf_of: customer.email)
authenticated_as(admin, from: customer.email)
post '/api/v1/tickets', params: params, as: :json
expect(response).to have_http_status(:created)
expect(customer.id).to eq(json_response['created_by_id'])
@ -243,29 +243,29 @@ RSpec.describe 'Api Auth On Behalf Of', type: :request do
end
describe 'user lookup' do
it 'does X-On-Behalf-Of auth - user lookup by ID' do
authenticated_as(admin, on_behalf_of: customer.id)
it 'does From auth - user lookup by ID' do
authenticated_as(admin, from: customer.id)
get '/api/v1/users/me', as: :json
expect(json_response.fetch('id')).to be customer.id
end
it 'does X-On-Behalf-Of auth - user lookup by login' do
authenticated_as(admin, on_behalf_of: customer.login)
it 'does From auth - user lookup by login' do
authenticated_as(admin, from: customer.login)
get '/api/v1/users/me', as: :json
expect(json_response.fetch('id')).to be customer.id
end
it 'does X-On-Behalf-Of auth - user lookup by email' do
authenticated_as(admin, on_behalf_of: customer.email)
it 'does From auth - user lookup by email' do
authenticated_as(admin, from: customer.email)
get '/api/v1/users/me', as: :json
expect(json_response.fetch('id')).to be customer.id
end
# https://github.com/zammad/zammad/issues/2851
it 'does X-On-Behalf-Of auth - user lookup by email even if email starts with a digit' do
it 'does From auth - user lookup by email even if email starts with a digit' do
customer.update! email: "#{agent.id}#{customer.email}"
authenticated_as(admin, on_behalf_of: customer.email)
authenticated_as(admin, from: customer.email)
get '/api/v1/users/me', as: :json
expect(json_response.fetch('id')).to be customer.id
end

View File

@ -80,7 +80,7 @@ module ZammadSpecSupportRequest
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])
add_headers('From' => options[:from])
# if we want to authenticate by token
credentials = if options[:token].present?