123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- require 'rails_helper'
- RSpec.describe Auth::Permissions, type: :request do
- shared_examples 'verify permissions checking' do
- let(:permission) { create(:permission, name: permission_name) }
- let(:permission_names) { [permission.name] }
- let(:role) { create(:role, permission_names:) }
- context 'with privileges for a root permission (e.g., "foo", not "foo.bar")' do
- let(:permission_name) { 'foo' }
- context 'when given that exact permission' do
- it 'returns true' do
- expect(described_class).to be_authorized(object, 'foo')
- end
- end
- context 'when given an active sub-permission' do
- before { create(:permission, name: 'foo.bar') }
- it 'returns true' do
- expect(described_class).to be_authorized(object, 'foo.bar')
- end
- end
- describe 'chain-of-ancestry quirk' do
- context 'when given an inactive sub-permission' do
- before { create(:permission, name: 'foo.bar.baz', active: false) }
- it 'returns false, even with active ancestors' do
- expect(described_class).not_to be_authorized(object, 'foo.bar.baz')
- end
- end
- context 'when given a sub-permission that does not exist' do
- before { create(:permission, name: 'foo.bar', active: false) }
- it 'can return true, even with inactive ancestors' do
- expect(described_class).to be_authorized(object, 'foo.bar.baz')
- end
- end
- end
- context 'when given a glob' do
- context 'when matching that permission' do
- it 'returns true' do
- expect(described_class).to be_authorized(object, 'foo.*')
- end
- end
- context 'when NOT matching that permission' do
- it 'returns false' do
- expect(described_class).not_to be_authorized(object, 'bar.*')
- end
- end
- end
- end
- context 'with privileges for a sub-permission (e.g., "foo.bar", not "foo")' do
- let(:permission_name) { 'foo.bar' }
- context 'when given that exact sub-permission' do
- it 'returns true' do
- expect(described_class).to be_authorized(object, 'foo.bar')
- end
- context 'when the permission is inactive' do
- before { permission.update(active: false) }
- it 'returns false' do
- expect(described_class).not_to be_authorized(object, 'foo.bar')
- end
- end
- end
- context 'when given a sibling sub-permission' do
- let(:sibling_permission) { create(:permission, name: 'foo.baz') }
- context 'when sibling exists' do
- before { sibling_permission }
- it 'returns false' do
- expect(described_class).not_to be_authorized(object, 'foo.baz')
- end
- end
- context 'when sibling does not exist' do
- it 'returns false' do
- expect(described_class).not_to be_authorized(object, 'foo.baz')
- end
- end
- end
- context 'when given the parent permission' do
- it 'returns false' do
- expect(described_class).not_to be_authorized(object, 'foo')
- end
- end
- context 'when given a glob' do
- context 'when matching that sub-permission' do
- it 'returns true' do
- expect(described_class).to be_authorized(object, 'foo.*')
- end
- context 'when the permission is inactive' do
- before { permission.update(active: false) }
- it 'returns false' do
- expect(described_class).not_to be_authorized(object, 'foo.*')
- end
- end
- end
- context 'when NOT matching that sub-permission' do
- it 'returns false' do
- expect(described_class).not_to be_authorized(object, 'bar.*')
- end
- end
- end
- context 'when given a plus' do
- let(:permission_names) { [permission.name, 'ticket.agent'] }
- context 'when matching both permissions' do
- it 'returns true' do
- expect(described_class).to be_authorized(object, 'foo.bar+ticket.agent')
- end
- it 'returns true if vice versa order given' do
- expect(described_class).to be_authorized(object, 'ticket.agent+foo.bar')
- end
- it 'returns true if given a glob' do
- expect(described_class).to be_authorized(object, 'foo.*+ticket.agent')
- end
- context 'when one of the permissions is inactive' do
- before { permission.update(active: false) }
- it 'returns false' do
- expect(described_class).not_to be_authorized(object, 'ticket.agent+foo.bar')
- end
- end
- end
- context 'when not matching one of permissions' do
- it 'returns false' do
- expect(described_class).not_to be_authorized(object, 'bar+ticket.agent')
- end
- it 'returns false if vice versa order given' do
- expect(described_class).not_to be_authorized(object, 'ticket.agent+bar')
- end
- end
- end
- end
- end
- describe 'user handling' do
- let(:object) { create(:user, roles: [role]) }
- include_examples 'verify permissions checking'
- end
- describe 'token handling' do
- let(:user) { create(:user, roles: [role]) }
- let(:object) { create(:token, user:, preferences: { permission: permission_names }) }
- include_examples 'verify permissions checking'
- end
- describe 'caching' do
- let(:user) { create(:agent) }
- before do
- allow(described_class).to receive(:new).and_call_original
- end
- it 'caches response with same arguments' do
- described_class.authorized?(user, 'ticket.agent')
- described_class.authorized?(user, 'ticket.agent')
- expect(described_class).to have_received(:new).once
- end
- it 'does not cache response with different queries' do
- described_class.authorized?(user, 'ticket.agent')
- described_class.authorized?(user, 'other')
- expect(described_class).to have_received(:new).twice
- end
- it 'does not cache response with different objects' do
- described_class.authorized?(user, 'ticket.agent')
- described_class.authorized?(create(:user), 'ticket.agent')
- expect(described_class).to have_received(:new).twice
- end
- end
- end
|