2022-01-01 13:38:12 +00:00
|
|
|
|
# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
|
2021-06-01 12:20:20 +00:00
|
|
|
|
|
2019-02-19 10:29:42 +00:00
|
|
|
|
require 'rails_helper'
|
|
|
|
|
|
|
|
|
|
RSpec.describe Token, type: :model do
|
|
|
|
|
subject(:token) { create(:password_reset_token) }
|
|
|
|
|
|
|
|
|
|
describe '.check' do
|
|
|
|
|
context 'with name and action matching existing token' do
|
|
|
|
|
it 'returns the token’s user' do
|
2019-09-16 15:04:17 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: token.name)).to eq(token.user)
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with invalid name' do
|
|
|
|
|
it 'returns nil' do
|
2022-03-01 08:00:40 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: '1NV4L1D')).to be_nil
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with invalid action' do
|
|
|
|
|
it 'returns nil' do
|
2022-03-01 08:00:40 +00:00
|
|
|
|
expect(described_class.check(action: 'PasswordReset_NotExisting', name: token.name)).to be_nil
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe 'persistence handling' do
|
|
|
|
|
context 'for persistent token' do
|
|
|
|
|
subject(:token) { create(:ical_token, persistent: true, created_at: created_at) }
|
|
|
|
|
|
|
|
|
|
context 'at any time' do
|
|
|
|
|
let(:created_at) { 1.month.ago }
|
|
|
|
|
|
|
|
|
|
it 'returns the token’s user' do
|
2019-09-16 15:04:17 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: token.name)).to eq(token.user)
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'does not delete the token' do
|
|
|
|
|
token # create token
|
|
|
|
|
|
2019-09-16 15:04:17 +00:00
|
|
|
|
expect { described_class.check(action: token.action, name: token.name) }
|
|
|
|
|
.not_to change(described_class, :count)
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'for non-persistent token' do
|
|
|
|
|
subject(:token) { create(:password_reset_token, persistent: false, created_at: created_at) }
|
|
|
|
|
|
|
|
|
|
context 'less than one day after creation' do
|
|
|
|
|
let(:created_at) { 1.day.ago + 5 }
|
|
|
|
|
|
|
|
|
|
it 'returns the token’s user' do
|
2019-09-16 15:04:17 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: token.name)).to eq(token.user)
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'does not delete the token' do
|
|
|
|
|
token # create token
|
|
|
|
|
|
2019-09-16 15:04:17 +00:00
|
|
|
|
expect { described_class.check(action: token.action, name: token.name) }
|
|
|
|
|
.not_to change(described_class, :count)
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'at least one day after creation' do
|
|
|
|
|
let(:created_at) { 1.day.ago }
|
|
|
|
|
|
|
|
|
|
it 'returns nil' do
|
2022-03-01 08:00:40 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: token.name)).to be_nil
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'deletes the token' do
|
|
|
|
|
token # create token
|
|
|
|
|
|
2019-09-16 15:04:17 +00:00
|
|
|
|
expect { described_class.check(action: token.action, name: token.name) }
|
|
|
|
|
.to change(described_class, :count).by(-1)
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe 'permission matching' do
|
|
|
|
|
subject(:token) { create(:api_token, user: agent, preferences: preferences) }
|
2019-04-15 01:41:17 +00:00
|
|
|
|
|
2020-06-19 09:17:18 +00:00
|
|
|
|
let(:agent) { create(:agent) }
|
2019-02-19 10:29:42 +00:00
|
|
|
|
let(:preferences) { { permission: %w[admin ticket.agent] } } # agent has no access to admin.*
|
|
|
|
|
|
|
|
|
|
context 'with a permission shared by both token.user and token.preferences' do
|
|
|
|
|
it 'returns token.user' do
|
2019-09-16 15:04:17 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: token.name, permission: 'ticket.agent')).to eq(agent)
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with the child of a permission shared by both token.user and token.preferences' do
|
|
|
|
|
it 'returns token.user' do
|
2019-09-16 15:04:17 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: token.name, permission: 'ticket.agent.foo')).to eq(agent)
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with the parent of a permission shared by both token.user and token.preferences' do
|
|
|
|
|
it 'returns nil' do
|
2022-03-01 08:00:40 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: token.name, permission: 'ticket')).to be_nil
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with a permission in token.preferences, but not on token.user' do
|
|
|
|
|
it 'returns nil' do
|
2022-03-01 08:00:40 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: token.name, permission: 'admin')).to be_nil
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with a permission not in token.preferences, but on token.user' do
|
|
|
|
|
it 'returns nil' do
|
2022-03-01 08:00:40 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: token.name, permission: 'cti.agent')).to be_nil
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with non-existent permission' do
|
|
|
|
|
it 'returns nil' do
|
2022-03-01 08:00:40 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: token.name, permission: 'foo')).to be_nil
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with multiple permissions, where at least one is shared by both token.user and token.preferences' do
|
|
|
|
|
it 'returns token.user' do
|
2019-09-16 15:04:17 +00:00
|
|
|
|
expect(described_class.check(action: token.action, name: token.name, permission: %w[foo ticket.agent])).to eq(agent)
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2020-08-14 11:12:41 +00:00
|
|
|
|
describe '#permissions?' do
|
|
|
|
|
subject(:token) do
|
|
|
|
|
create(:token, user: user, preferences: { permission: [permission_name] })
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let(:user) { create(:user, roles: [role]) }
|
|
|
|
|
let(:role) { create(:role, permissions: [permission]) }
|
|
|
|
|
let(:permission) { create(:permission, name: permission_name) }
|
|
|
|
|
|
|
|
|
|
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(token.permissions?('foo')).to be(true)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when given a sub-permission (i.e., child permission)' do
|
|
|
|
|
let(:subpermission) { create(:permission, name: 'foo.bar') }
|
|
|
|
|
|
|
|
|
|
context 'that exists' do
|
|
|
|
|
before { subpermission }
|
|
|
|
|
|
|
|
|
|
it 'returns true' do
|
|
|
|
|
expect(token.permissions?('foo.bar')).to be(true)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'that is inactive' do
|
|
|
|
|
before { subpermission.update(active: false) }
|
|
|
|
|
|
|
|
|
|
it 'returns false' do
|
|
|
|
|
expect(token.permissions?('foo.bar')).to be(false)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'that does not exist' do
|
|
|
|
|
it 'returns true' do
|
|
|
|
|
expect(token.permissions?('foo.bar')).to be(true)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when given a glob' do
|
|
|
|
|
context 'matching that permission' do
|
|
|
|
|
it 'returns true' do
|
|
|
|
|
expect(token.permissions?('foo.*')).to be(true)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'NOT matching that permission' do
|
|
|
|
|
it 'returns false' do
|
|
|
|
|
expect(token.permissions?('bar.*')).to be(false)
|
|
|
|
|
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(token.permissions?('foo.bar')).to be(true)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'but the permission is inactive' do
|
|
|
|
|
before { permission.update(active: false) }
|
|
|
|
|
|
|
|
|
|
it 'returns false' do
|
|
|
|
|
expect(token.permissions?('foo.bar')).to be(false)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when given a sibling sub-permission' do
|
|
|
|
|
let(:sibling_permission) { create(:permission, name: 'foo.baz') }
|
|
|
|
|
|
|
|
|
|
context 'that exists' do
|
|
|
|
|
before { sibling_permission }
|
|
|
|
|
|
|
|
|
|
it 'returns false' do
|
|
|
|
|
expect(token.permissions?('foo.baz')).to be(false)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'that does not exist' do
|
|
|
|
|
it 'returns false' do
|
|
|
|
|
expect(token.permissions?('foo.baz')).to be(false)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when given the parent permission' do
|
|
|
|
|
it 'returns false' do
|
|
|
|
|
expect(token.permissions?('foo')).to be(false)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when given a glob' do
|
|
|
|
|
context 'matching that sub-permission' do
|
|
|
|
|
it 'returns true' do
|
|
|
|
|
expect(token.permissions?('foo.*')).to be(true)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'but the permission is inactive' do
|
|
|
|
|
before { permission.update(active: false) }
|
|
|
|
|
|
|
|
|
|
context 'and user.permissions?(...) doesn’t fail' do
|
|
|
|
|
let(:role) { create(:role, permissions: [parent_permission]) }
|
|
|
|
|
let(:parent_permission) { create(:permission, name: permission_name.split('.').first) }
|
|
|
|
|
|
|
|
|
|
it 'returns false' do
|
|
|
|
|
expect(token.permissions?('foo.*')).to be(false)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'NOT matching that sub-permission' do
|
|
|
|
|
it 'returns false' do
|
|
|
|
|
expect(token.permissions?('bar.*')).to be(false)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-02-19 10:29:42 +00:00
|
|
|
|
describe 'Attributes:' do
|
|
|
|
|
describe '#persistent' do
|
|
|
|
|
context 'when not set on creation' do
|
2019-09-16 15:04:17 +00:00
|
|
|
|
subject(:token) { described_class.create(action: 'foo', user_id: User.first.id) }
|
2019-02-19 10:29:42 +00:00
|
|
|
|
|
|
|
|
|
it 'defaults to nil' do
|
2022-03-01 08:00:40 +00:00
|
|
|
|
expect(token.persistent).to be_nil
|
2019-02-19 10:29:42 +00:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|