Fixes #3186 - Endpoint api/v1/ticket_articles/by_ticket ignores X-On-Behalf-Of
This commit is contained in:
parent
3af0e35821
commit
5dde117a14
5 changed files with 78 additions and 34 deletions
|
@ -22,39 +22,6 @@ module ApplicationController::Authorizes
|
||||||
[:controllers, self]
|
[:controllers, self]
|
||||||
end
|
end
|
||||||
|
|
||||||
# We need a special UserContext when authorizing in controller context
|
|
||||||
# because of Token authentication which has it's own permissions
|
|
||||||
# See: https://github.com/varvet/pundit#additional-context
|
|
||||||
# We use a Delegator here to have transparent / DuckType access
|
|
||||||
# to the underlying User instance in the Policy
|
|
||||||
class UserContext < Delegator
|
|
||||||
|
|
||||||
def initialize(user, token)
|
|
||||||
@user = user
|
|
||||||
@token = token
|
|
||||||
end
|
|
||||||
|
|
||||||
def __getobj__
|
|
||||||
@user
|
|
||||||
end
|
|
||||||
|
|
||||||
def permissions!(permissions)
|
|
||||||
raise Exceptions::NotAuthorized, 'authentication failed' if !@user
|
|
||||||
raise Exceptions::NotAuthorized, 'Not authorized (user)!' if !@user.permissions?(permissions)
|
|
||||||
return if !@token
|
|
||||||
return if @token.permissions?(permissions)
|
|
||||||
|
|
||||||
raise Exceptions::NotAuthorized, 'Not authorized (token)!'
|
|
||||||
end
|
|
||||||
|
|
||||||
def permissions?(permissions)
|
|
||||||
permissions!(permissions)
|
|
||||||
true
|
|
||||||
rescue Exceptions::NotAuthorized
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def pundit_user
|
def pundit_user
|
||||||
@pundit_user ||= UserContext.new(current_user, @_token)
|
@pundit_user ||= UserContext.new(current_user, @_token)
|
||||||
end
|
end
|
||||||
|
|
|
@ -109,11 +109,22 @@ cleanup old token
|
||||||
end
|
end
|
||||||
|
|
||||||
def permissions?(names)
|
def permissions?(names)
|
||||||
return false if !user.permissions?(names)
|
return false if !effective_user.permissions?(names)
|
||||||
|
|
||||||
super(names)
|
super(names)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# allows to evaluate token permissions in context of given user instead of owner
|
||||||
|
# @param [User] user to use as context for the given block
|
||||||
|
# @param block to evaluate in given context
|
||||||
|
def with_context(user:, &block)
|
||||||
|
@effective_user = user
|
||||||
|
|
||||||
|
instance_eval(&block) if block_given?
|
||||||
|
ensure
|
||||||
|
@effective_user = nil
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def generate_token
|
def generate_token
|
||||||
|
@ -123,4 +134,9 @@ cleanup old token
|
||||||
end
|
end
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# token owner or user set by #with_context
|
||||||
|
def effective_user
|
||||||
|
@effective_user || user
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
32
lib/user_context.rb
Normal file
32
lib/user_context.rb
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# We need a special UserContext when authorizing in controller context
|
||||||
|
# because of Token authentication which has it's own permissions
|
||||||
|
# See: https://github.com/varvet/pundit#additional-context
|
||||||
|
# We use a Delegator here to have transparent / DuckType access
|
||||||
|
# to the underlying User instance in the Policy
|
||||||
|
class UserContext < Delegator
|
||||||
|
|
||||||
|
def initialize(user, token)
|
||||||
|
@user = user
|
||||||
|
@token = token
|
||||||
|
end
|
||||||
|
|
||||||
|
def __getobj__
|
||||||
|
@user
|
||||||
|
end
|
||||||
|
|
||||||
|
def permissions!(permissions)
|
||||||
|
raise Exceptions::NotAuthorized, 'authentication failed' if !@user
|
||||||
|
raise Exceptions::NotAuthorized, 'Not authorized (user)!' if !@user.permissions?(permissions)
|
||||||
|
return if !@token
|
||||||
|
return if @token.with_context(user: @user) { permissions?(permissions) }
|
||||||
|
|
||||||
|
raise Exceptions::NotAuthorized, 'Not authorized (token)!'
|
||||||
|
end
|
||||||
|
|
||||||
|
def permissions?(permissions)
|
||||||
|
permissions!(permissions)
|
||||||
|
true
|
||||||
|
rescue Exceptions::NotAuthorized
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,5 +7,9 @@ FactoryBot.define do
|
||||||
factory :agent_role do
|
factory :agent_role do
|
||||||
permissions { Permission.where(name: 'ticket.agent') }
|
permissions { Permission.where(name: 'ticket.agent') }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
trait :admin do
|
||||||
|
permissions { Permission.where(name: 'admin') }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
25
spec/lib/user_context_spec.rb
Normal file
25
spec/lib/user_context_spec.rb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe UserContext do
|
||||||
|
subject(:user_context) { described_class.new(user, token) }
|
||||||
|
|
||||||
|
describe '#permissions?' do
|
||||||
|
context 'when user with ticket.agent permission' do
|
||||||
|
let(:user) { create(:user, roles: [create(:agent_role)]) }
|
||||||
|
let(:token) { nil }
|
||||||
|
|
||||||
|
it { is_expected.to be_permissions('ticket.agent') }
|
||||||
|
it { is_expected.not_to be_permissions('admin') }
|
||||||
|
end
|
||||||
|
|
||||||
|
# https://github.com/zammad/zammad/issues/3186
|
||||||
|
context 'when user with ticket.agent permission and token created by user who doesn\'t' do
|
||||||
|
let(:user) { create(:user, roles: [create(:agent_role)]) }
|
||||||
|
let(:token_owner) { create(:user, roles: [create(:role, :admin)]) }
|
||||||
|
let(:token) { create(:token, user: token_owner, preferences: { permission: %w[ticket.agent] }) }
|
||||||
|
|
||||||
|
it { is_expected.to be_permissions('ticket.agent') }
|
||||||
|
it { is_expected.not_to be_permissions('admin') }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue