Fixes #3186 - Endpoint api/v1/ticket_articles/by_ticket ignores X-On-Behalf-Of

This commit is contained in:
Mantas 2020-09-14 09:34:42 +03:00 committed by Thorsten Eckel
parent 3af0e35821
commit 5dde117a14
5 changed files with 78 additions and 34 deletions

View file

@ -22,39 +22,6 @@ module ApplicationController::Authorizes
[:controllers, self]
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
@pundit_user ||= UserContext.new(current_user, @_token)
end

View file

@ -109,11 +109,22 @@ cleanup old token
end
def permissions?(names)
return false if !user.permissions?(names)
return false if !effective_user.permissions?(names)
super(names)
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
def generate_token
@ -123,4 +134,9 @@ cleanup old token
end
true
end
# token owner or user set by #with_context
def effective_user
@effective_user || user
end
end

32
lib/user_context.rb Normal file
View 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

View file

@ -7,5 +7,9 @@ FactoryBot.define do
factory :agent_role do
permissions { Permission.where(name: 'ticket.agent') }
end
trait :admin do
permissions { Permission.where(name: 'admin') }
end
end
end

View 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