mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
Merge pull request #15198 from opf/remove-old-allowed-methods
Remove old `allowed_to?` methods
This commit is contained in:
@@ -30,8 +30,6 @@ module Users::PermissionChecks
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
delegate :preload_projects_allowed_to, to: :user_allowed_service
|
||||
|
||||
# Some Ruby magic. Create methods for each entity we can have memberships on automatically
|
||||
# i.e. allowed_in_work_package? and allowed_in_any_work_package?
|
||||
Member::ALLOWED_ENTITIES.each do |entity_model_name|
|
||||
@@ -150,28 +148,8 @@ module Users::PermissionChecks
|
||||
end
|
||||
end
|
||||
|
||||
# Old allowed_to? interface. Marked as deprecated, should be removed at some point ... Guessing 14.0?
|
||||
def allowed_to?(action, context, global: false)
|
||||
OpenProject::Deprecation.deprecate_method(User, :allowed_to?)
|
||||
user_allowed_service.call(action, context, global:)
|
||||
end
|
||||
|
||||
def allowed_to_in_project?(action, project)
|
||||
OpenProject::Deprecation.replaced(:allowed_to_in_project?, :allowed_in_project?, caller)
|
||||
allowed_to?(action, project)
|
||||
end
|
||||
|
||||
def allowed_to_globally?(action)
|
||||
OpenProject::Deprecation.replaced(:allowed_to_globally?, :allowed_globally?, caller)
|
||||
allowed_to?(action, nil, global: true)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_allowed_service
|
||||
@user_allowed_service ||= ::Authorization::UserAllowedService.new(self, role_cache: project_role_cache)
|
||||
end
|
||||
|
||||
def user_permissible_service
|
||||
@user_permissible_service ||= ::Authorization::UserPermissibleService.new(self)
|
||||
end
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) 2012-2024 the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
class Authorization::UserAllowedService
|
||||
attr_accessor :user
|
||||
|
||||
def initialize(user, role_cache: Users::ProjectRoleCache.new(user))
|
||||
self.user = user
|
||||
self.project_role_cache = role_cache
|
||||
end
|
||||
|
||||
# Return true if the user is allowed to do the specified action on a specific context
|
||||
# Action can be:
|
||||
# * a parameter-like Hash (eg. { controller: '/projects', action: 'edit' })
|
||||
# * a permission Symbol (eg. :edit_project)
|
||||
# Context can be:
|
||||
# * a project : returns true if user is allowed to do the specified action on this project
|
||||
# * a group of projects : returns true if user is allowed on every project
|
||||
# * an entity that a user can become a member of specifically (listed in Member::ALLOWED_ENTITIES) :
|
||||
# * returns true if user is allowed to do the specified action on the given item or
|
||||
# * returns ture if user is allowed to do the specified action on the project the entity belongs to
|
||||
# * nil with +global+ set to +true+ : check if user has at least one role allowed for this action,
|
||||
# or falls back to Non Member / Anonymous permissions depending if the user is logged
|
||||
def call(action, context, global: false)
|
||||
if supported_context?(context, global:)
|
||||
allowed_to?(action, context, global:)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def preload_projects_allowed_to(action)
|
||||
project_authorization_cache.cache(action)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :project_role_cache
|
||||
|
||||
def allowed_to?(action, context, global: false)
|
||||
action = normalize_action(action)
|
||||
|
||||
if context.nil? && global
|
||||
allowed_to_globally?(action)
|
||||
elsif context.is_a? Project
|
||||
allowed_to_in_project?(action, context)
|
||||
elsif supported_entity?(context)
|
||||
allowed_to_in_entity?(action, context)
|
||||
elsif context.respond_to?(:to_a)
|
||||
allowed_to_in_all_projects?(action, context)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def allowed_to_in_entity?(action, entity)
|
||||
# Inactive users are never authorized
|
||||
return false unless authorizable_user?
|
||||
|
||||
# Short circuit: When the user is already allowed to execute the action baed
|
||||
# on the project, there's no need to do a check on the entity
|
||||
return true if entity.respond_to?(:project) && allowed_to_in_project?(action, entity.project)
|
||||
|
||||
# Admin users are authorized for anything else
|
||||
# unless the permission is explicitly flagged not to be granted to admins.
|
||||
return true if granted_to_admin?(action)
|
||||
|
||||
has_authorized_role?(action, entity)
|
||||
end
|
||||
|
||||
def allowed_to_in_project?(action, project)
|
||||
return false if project.nil?
|
||||
|
||||
if project_authorization_cache.cached?(action)
|
||||
return project_authorization_cache.allowed?(action, project)
|
||||
end
|
||||
|
||||
# No action allowed on archived projects
|
||||
return false unless project.active? || project.being_archived?
|
||||
# No action allowed on disabled modules
|
||||
return false unless project.allows_to?(action)
|
||||
# Inactive users are never authorized
|
||||
return false unless authorizable_user?
|
||||
# Admin users are authorized for anything else
|
||||
# unless the permission is explicitly flagged not to be granted to admins.
|
||||
return true if granted_to_admin?(action)
|
||||
|
||||
has_authorized_role?(action, project)
|
||||
end
|
||||
|
||||
# Authorize if user is authorized on every element of the array
|
||||
def allowed_to_in_all_projects?(action, projects)
|
||||
projects.present? && Array(projects).all? do |project|
|
||||
allowed_to?(action, project)
|
||||
end
|
||||
end
|
||||
|
||||
# Is the user allowed to do the specified action on any project?
|
||||
# See allowed_to? for the action parameter description.
|
||||
def allowed_to_globally?(action)
|
||||
# Inactive users are never authorized
|
||||
return false unless authorizable_user?
|
||||
# Admin users are always authorized
|
||||
return true if granted_to_admin?(action)
|
||||
|
||||
has_authorized_role?(action)
|
||||
end
|
||||
|
||||
##
|
||||
# Only users that are not locked may be granted actions
|
||||
# with the exception of a temporary-granted system user
|
||||
def authorizable_user?
|
||||
!user.locked? || user.is_a?(SystemUser)
|
||||
end
|
||||
|
||||
# Admin users are granted every permission unless the
|
||||
# permission explicitly disables it.
|
||||
def granted_to_admin?(action)
|
||||
user.admin? && OpenProject::AccessControl.grant_to_admin?(action)
|
||||
end
|
||||
|
||||
def has_authorized_role?(action, context = nil)
|
||||
project_role_cache
|
||||
.fetch(context)
|
||||
.any? do |role|
|
||||
role.allowed_to?(action)
|
||||
end
|
||||
end
|
||||
|
||||
def project_authorization_cache
|
||||
@project_authorization_cache ||= Users::ProjectAuthorizationCache.new(user)
|
||||
end
|
||||
|
||||
def normalize_action(action)
|
||||
if action.is_a?(Hash) && action[:controller] && action[:controller].to_s.starts_with?("/")
|
||||
action = action.dup
|
||||
action[:controller] = action[:controller][1..]
|
||||
end
|
||||
|
||||
action
|
||||
end
|
||||
|
||||
def supported_context?(context, global:)
|
||||
(context.nil? && global) ||
|
||||
context.is_a?(Project) ||
|
||||
supported_entity?(context) ||
|
||||
(!context.nil? && context.respond_to?(:to_a))
|
||||
end
|
||||
|
||||
def supported_entity?(entity)
|
||||
Member.can_be_member_of?(entity)
|
||||
end
|
||||
end
|
||||
@@ -33,9 +33,6 @@ module API
|
||||
resource :available_projects do
|
||||
after_validation do
|
||||
authorize_in_any_project(:add_work_packages)
|
||||
|
||||
checked_permissions = Projects::ProjectCollectionRepresenter.checked_permissions
|
||||
current_user.preload_projects_allowed_to(checked_permissions)
|
||||
end
|
||||
|
||||
get &::API::V3::Utilities::Endpoints::SqlFallbackedIndex
|
||||
|
||||
@@ -33,9 +33,6 @@ module API
|
||||
resource :available_projects do
|
||||
after_validation do
|
||||
authorize_in_work_package(:edit_work_packages, work_package: @work_package)
|
||||
|
||||
checked_permissions = Projects::ProjectCollectionRepresenter.checked_permissions
|
||||
current_user.preload_projects_allowed_to(checked_permissions)
|
||||
end
|
||||
|
||||
get &::API::V3::Utilities::Endpoints::SqlFallbackedIndex
|
||||
|
||||
@@ -1,525 +0,0 @@
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) 2012-2024 the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe User, "allowed_to?" do
|
||||
let(:user) { build(:user) }
|
||||
let(:anonymous) { build(:anonymous) }
|
||||
let(:project) { build(:project, public: false) }
|
||||
let(:project2) { build(:project, public: false) }
|
||||
let(:work_package) { build(:work_package, project:) }
|
||||
let(:role) { build(:project_role) }
|
||||
let(:role2) { build(:project_role) }
|
||||
let(:wp_role) { build(:work_package_role) }
|
||||
let(:wp_member) { build(:member, project:, entity: work_package, roles: [wp_role], principal: user) }
|
||||
let(:anonymous_role) { build(:anonymous_role) }
|
||||
let(:member) { build(:member, project:, roles: [role], principal: user) }
|
||||
let(:member2) { build(:member, project: project2, roles: [role2], principal: user) }
|
||||
let(:global_permission) { OpenProject::AccessControl.permissions.find(&:global?) }
|
||||
let(:global_role) { build(:global_role, permissions: [global_permission.name]) }
|
||||
let(:global_member) { build(:global_member, principal: user, roles: [global_role]) }
|
||||
|
||||
before do
|
||||
anonymous_role.save!
|
||||
ProjectRole.non_member
|
||||
user.save!
|
||||
end
|
||||
|
||||
shared_examples_for "when inquiring for project" do
|
||||
let(:permission) { :add_work_packages }
|
||||
let(:final_setup_step) {}
|
||||
|
||||
before do
|
||||
project.save
|
||||
end
|
||||
|
||||
context "with the user being admin" do
|
||||
before { user.update(admin: true) }
|
||||
|
||||
context "with the project being persisted and active" do
|
||||
before do
|
||||
project.save
|
||||
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(user).to be_allowed_to(permission, project) }
|
||||
end
|
||||
|
||||
context "with the project being archived" do
|
||||
before do
|
||||
project.update(active: false)
|
||||
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(user).not_to be_allowed_to(permission, project) }
|
||||
end
|
||||
|
||||
context "with the required module being inactive" do
|
||||
let(:permission) { :create_meetings } # pick a permission from a module
|
||||
|
||||
before do
|
||||
project.enabled_module_names -= ["meetings"]
|
||||
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(user).not_to be_allowed_to(permission, project) }
|
||||
end
|
||||
|
||||
context "with the permission not being automatically granted to admins" do
|
||||
let(:permission) { :work_package_assigned } # permission that is not automatically granted to admins
|
||||
|
||||
before do
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(user).not_to be_allowed_to(permission, project) }
|
||||
end
|
||||
end
|
||||
|
||||
context "without the user being a member in the project" do
|
||||
context "with the project being private" do
|
||||
before { project.update(public: false) }
|
||||
|
||||
context "with the user being a member of a single work package inside the project" do
|
||||
before do
|
||||
work_package.save!
|
||||
wp_member.save!
|
||||
end
|
||||
|
||||
context "with the role granting the permission" do
|
||||
before do
|
||||
wp_role.add_permission!(permission)
|
||||
end
|
||||
|
||||
it { expect(user).not_to be_allowed_to(permission, project) }
|
||||
end
|
||||
end
|
||||
|
||||
context "and the permission being assigend to the non-member role" do
|
||||
before do
|
||||
non_member = ProjectRole.non_member
|
||||
non_member.add_permission! permission
|
||||
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it do
|
||||
expect(user).not_to be_allowed_to(permission, project)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "and the project being public" do
|
||||
before { project.update(public: true) }
|
||||
|
||||
context "and the permission not being assigend to the non-member role" do
|
||||
before do
|
||||
non_member = ProjectRole.non_member
|
||||
non_member.remove_permission! permission
|
||||
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(user).not_to be_allowed_to(permission, project) }
|
||||
end
|
||||
|
||||
context "and the permission being assigned to the non-member role" do
|
||||
before do
|
||||
non_member = ProjectRole.non_member
|
||||
non_member.add_permission! permission
|
||||
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it do
|
||||
expect(user).to be_allowed_to(permission, project)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with the user being a member in the project" do
|
||||
before { member.save! }
|
||||
|
||||
context "without the role granting the requested permission" do
|
||||
before do
|
||||
role.remove_permission!(permission)
|
||||
end
|
||||
|
||||
context "and no permissions being assigned to the non-member role" do
|
||||
before { final_setup_step }
|
||||
|
||||
it { expect(user).not_to be_allowed_to(permission, project) }
|
||||
end
|
||||
end
|
||||
|
||||
context "with the role granting the requested permission" do
|
||||
let(:permission) { :view_news }
|
||||
|
||||
before do
|
||||
role.add_permission!(permission)
|
||||
end
|
||||
|
||||
context "with the module being active" do
|
||||
before do
|
||||
project.enabled_module_names += ["news"]
|
||||
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
context "and the permission being requested with the permission name" do
|
||||
it { expect(user).to be_allowed_to(permission, project) }
|
||||
end
|
||||
|
||||
context "and the permission being requested with the controller name and action" do
|
||||
it { expect(user).to be_allowed_to({ controller: "news", action: "show" }, project) }
|
||||
end
|
||||
end
|
||||
|
||||
context "without the module being active" do
|
||||
before do
|
||||
project.enabled_module_names -= ["news"]
|
||||
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
context "and the permission being requested with the permission name" do
|
||||
it { expect(user).not_to be_allowed_to(permission, project) }
|
||||
end
|
||||
|
||||
context "and the permission being requested with the controller name and action" do
|
||||
it { expect(user).not_to be_allowed_to({ controller: "news", action: "show" }, project) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with the user being anonymous" do
|
||||
context "with the project being public" do
|
||||
before { project.update(public: true) }
|
||||
|
||||
context "without the anonymous role being given the permission" do
|
||||
before do
|
||||
anonymous_role.remove_permission!(permission)
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(anonymous).not_to be_allowed_to(permission, project) }
|
||||
end
|
||||
|
||||
context "with the anonymous role being given the permission" do
|
||||
before do
|
||||
anonymous_role.add_permission!(permission)
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(anonymous).to be_allowed_to(permission, project) }
|
||||
end
|
||||
|
||||
context "with a controller and action that is allowed via multiple permissions" do
|
||||
let(:permission) { :manage_categories }
|
||||
|
||||
before do
|
||||
anonymous_role.add_permission! permission
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(anonymous).to be_allowed_to({ controller: "/projects/settings/categories", action: "show" }, project) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when requesting permission for multiple projects" do
|
||||
context "with the user being a member of multiple projects" do
|
||||
before do
|
||||
member.save
|
||||
member2.save
|
||||
end
|
||||
|
||||
context "with the permission being granted in both projects" do
|
||||
before do
|
||||
role.add_permission! permission
|
||||
role2.add_permission! permission
|
||||
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(user).to be_allowed_to(permission, [project, project2]) }
|
||||
end
|
||||
end
|
||||
|
||||
context "with the permission being granted in only one of the two projects" do
|
||||
before do
|
||||
role.add_permission! permission
|
||||
role2.remove_permission! permission
|
||||
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(user).not_to be_allowed_to(permission, [project, project2]) }
|
||||
end
|
||||
|
||||
context "with the user not being member of any projects, but both projects being public" do
|
||||
before do
|
||||
project.update(public: true)
|
||||
project2.update(public: true)
|
||||
end
|
||||
|
||||
context "with non-member role having the permission" do
|
||||
before do
|
||||
non_member = ProjectRole.non_member
|
||||
non_member.add_permission! permission
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(user).to be_allowed_to(permission, [project, project2]) }
|
||||
end
|
||||
|
||||
context "without non-member role having the permission" do
|
||||
before do
|
||||
non_member = ProjectRole.non_member
|
||||
non_member.remove_permission! permission
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(user).not_to be_allowed_to(permission, [project, project2]) }
|
||||
end
|
||||
end
|
||||
|
||||
context "with the user not being member of any projects, but one of the projects being public" do
|
||||
before do
|
||||
project.update(public: true)
|
||||
project2.update(public: false)
|
||||
end
|
||||
|
||||
context "with non-member role having the permission" do
|
||||
before do
|
||||
non_member = ProjectRole.non_member
|
||||
non_member.add_permission! permission
|
||||
final_setup_step
|
||||
end
|
||||
|
||||
it { expect(user).not_to be_allowed_to(permission, [project, project2]) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when requesting a global permission, but with the project as a context" do
|
||||
before do
|
||||
global_member.save!
|
||||
end
|
||||
|
||||
it "is false" do
|
||||
expect(user).not_to be_allowed_to(global_permission.name, project)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for "when inquiring globally" do
|
||||
let(:permission) { :add_work_packages }
|
||||
|
||||
context "when the user is an admin" do
|
||||
before { user.update(admin: true) }
|
||||
|
||||
it { expect(user).to be_allowed_to(permission, nil, global: true) }
|
||||
end
|
||||
|
||||
context "when the non-member role has the permission" do
|
||||
before do
|
||||
ProjectRole.non_member.add_permission! permission
|
||||
end
|
||||
|
||||
it { expect(user).to be_allowed_to(permission, nil, global: true) }
|
||||
end
|
||||
|
||||
context "when there is a global role giving the permission" do
|
||||
before { global_role.save! }
|
||||
|
||||
context "without the user having the role assigned" do
|
||||
it { expect(user).not_to be_allowed_to(global_permission.name, nil, global: true) }
|
||||
end
|
||||
|
||||
context "with the user having the role assigned" do
|
||||
before { global_member.save! }
|
||||
|
||||
context "with the role having the global permission" do
|
||||
it { expect(user).to be_allowed_to(global_permission.name, nil, global: true) }
|
||||
end
|
||||
|
||||
context "without the role having the global permission" do
|
||||
before do
|
||||
global_role.remove_permission!(global_permission.name)
|
||||
end
|
||||
|
||||
it { expect(user).not_to be_allowed_to(global_permission.name, nil, global: true) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the user is member of a project" do
|
||||
before { member.save }
|
||||
|
||||
context "and a project permission is requested globally" do
|
||||
context "without the permission being assigned to the role" do
|
||||
it { expect(user).not_to be_allowed_to(permission, nil, global: true) }
|
||||
end
|
||||
|
||||
# TODO: Ask somebody why this is supposed to work!?
|
||||
context "with the permissio being assigned to the role" do
|
||||
before do
|
||||
role.add_permission! permission
|
||||
end
|
||||
|
||||
it { expect(user).to be_allowed_to(permission, nil, global: true) }
|
||||
end
|
||||
end
|
||||
|
||||
context "when requesting a controller and action allowed by multiple permissions" do
|
||||
let(:permission) { :manage_categories }
|
||||
|
||||
context "without the role having the permission" do
|
||||
before { role.remove_permission!(permission) }
|
||||
|
||||
it do
|
||||
expect(user)
|
||||
.not_to be_allowed_to({ controller: "/projects/settings/categories", action: "show" }, nil, global: true)
|
||||
end
|
||||
|
||||
context "with the non-member having the permission" do
|
||||
before do
|
||||
ProjectRole.non_member.add_permission! permission
|
||||
end
|
||||
|
||||
it do
|
||||
expect(user)
|
||||
.to be_allowed_to({ controller: "/projects/settings/categories", action: "show" }, nil, global: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the user is anonymous" do
|
||||
context "with the anonymous role having the permission allowed" do
|
||||
before do
|
||||
anonymous_role.add_permission! permission
|
||||
end
|
||||
|
||||
it { expect(anonymous).to be_allowed_to(permission, nil, global: true) }
|
||||
end
|
||||
|
||||
context "without the anonymous role having the permission allowed" do
|
||||
it { expect(anonymous).not_to be_allowed_to(permission, nil, global: true) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for "when inquiring for work_package" do
|
||||
let(:permission) { :view_work_packages }
|
||||
before do
|
||||
project.save!
|
||||
work_package.save!
|
||||
end
|
||||
|
||||
context "with the user being a member of the work package" do
|
||||
before do
|
||||
wp_member.save!
|
||||
end
|
||||
|
||||
context "with the role granting the permission" do
|
||||
before do
|
||||
wp_role.add_permission!(permission)
|
||||
end
|
||||
|
||||
it { expect(user).to be_allowed_to(permission, work_package) }
|
||||
end
|
||||
|
||||
context "without the role granting the permission" do
|
||||
it { expect(user).not_to be_allowed_to(permission, work_package) }
|
||||
|
||||
context "with a membership on the project granting the permission" do
|
||||
before do
|
||||
role.save!
|
||||
member.save!
|
||||
role.add_permission!(permission)
|
||||
end
|
||||
|
||||
it { expect(user).to be_allowed_to(permission, work_package) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "without the user being a member of the work package" do
|
||||
context "with the user being a member of the project the work package belongs to" do
|
||||
before do
|
||||
member.save!
|
||||
end
|
||||
|
||||
context "and the project role does not grant the permission" do
|
||||
it { expect(user).not_to be_allowed_to(permission, work_package) }
|
||||
end
|
||||
|
||||
context "and the project role grants the permission" do
|
||||
before do
|
||||
role.add_permission!(permission)
|
||||
end
|
||||
|
||||
it { expect(user).to be_allowed_to(permission, work_package) }
|
||||
end
|
||||
end
|
||||
|
||||
context "with the user being a member of another project where the role grants the permission" do
|
||||
before do
|
||||
role.save!
|
||||
member2.save!
|
||||
role.add_permission!(permission)
|
||||
end
|
||||
|
||||
it { expect(user).not_to be_allowed_to(permission, work_package) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "without preloaded permissions" do
|
||||
it_behaves_like "when inquiring for project"
|
||||
it_behaves_like "when inquiring globally"
|
||||
it_behaves_like "when inquiring for work_package"
|
||||
end
|
||||
|
||||
context "with preloaded permissions" do
|
||||
it_behaves_like "when inquiring for project" do
|
||||
let(:final_setup_step) do
|
||||
user.preload_projects_allowed_to(permission)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,298 +0,0 @@
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) 2012-2024 the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
# TODO: Fix tests here
|
||||
|
||||
RSpec.describe Authorization::UserAllowedService do
|
||||
let(:user) { build_stubbed(:user) }
|
||||
let(:instance) { described_class.new(user) }
|
||||
let(:action) { :an_action }
|
||||
let(:action_hash) { { controller: "/controller", action: "action" } }
|
||||
let(:project) { build_stubbed(:project) }
|
||||
let(:other_project) { build_stubbed(:project) }
|
||||
let(:role) { build_stubbed(:project_role) }
|
||||
let(:user_roles_in_project) do
|
||||
array = [role]
|
||||
allow(array)
|
||||
.to receive(:eager_load)
|
||||
.and_return(array)
|
||||
|
||||
array
|
||||
end
|
||||
let(:role_grants_action) { true }
|
||||
let(:project_allows_to) { true }
|
||||
|
||||
subject { instance.call(action, context) }
|
||||
|
||||
describe "#initialize" do
|
||||
it "has the user" do
|
||||
expect(instance.user).to eql user
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples_for "allowed to checked" do
|
||||
before do
|
||||
Array(context).each do |project|
|
||||
project.active = true
|
||||
|
||||
allow(project).to receive(:allows_to?).with(action).and_return(project_allows_to)
|
||||
allow(Authorization).to receive(:roles).with(user, project).and_return(user_roles_in_project)
|
||||
end
|
||||
|
||||
allow(role).to receive(:allowed_to?).with(action).and_return(role_grants_action)
|
||||
end
|
||||
|
||||
context "with the user having a granting role" do
|
||||
it "is true" do
|
||||
expect(subject).to be_truthy
|
||||
end
|
||||
|
||||
it "does not call the db twice for a project" do
|
||||
Array(context).each do |project|
|
||||
allow(Authorization).to receive(:roles).with(user, project).and_return(user_roles_in_project)
|
||||
end
|
||||
|
||||
subject
|
||||
subject
|
||||
|
||||
Array(context).each do |project|
|
||||
expect(Authorization)
|
||||
.to have_received(:roles)
|
||||
.once
|
||||
.with(user, project)
|
||||
end
|
||||
end
|
||||
|
||||
context "but the user not being active" do
|
||||
before do
|
||||
user.lock
|
||||
end
|
||||
|
||||
it "returns false", :aggregate_failures do
|
||||
expect(instance.call(action, nil, global: true)).not_to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with the user having a nongranting role" do
|
||||
let(:role_grants_action) { false }
|
||||
|
||||
it "is false" do
|
||||
expect(subject).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the user being admin
|
||||
with the user not having a granting role' do
|
||||
let(:user_roles_in_project) { [] }
|
||||
|
||||
before do
|
||||
user.admin = true
|
||||
end
|
||||
|
||||
it "is true" do
|
||||
expect(subject).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context "with the project not being active" do
|
||||
before do
|
||||
Array(context).each do |project|
|
||||
project.active = false
|
||||
project.clear_changes_information
|
||||
end
|
||||
end
|
||||
|
||||
it "is false" do
|
||||
expect(subject).to be_falsey
|
||||
end
|
||||
|
||||
it "is false even if the user is admin" do
|
||||
user.admin = true
|
||||
|
||||
expect(subject).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context "with the project being archived" do
|
||||
before do
|
||||
Array(context).each do |project|
|
||||
project.active = false
|
||||
end
|
||||
end
|
||||
|
||||
it "is true" do
|
||||
expect(subject).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context "with the project not having the action enabled" do
|
||||
let(:project_allows_to) { false }
|
||||
|
||||
it "is false" do
|
||||
expect(subject).to be_falsey
|
||||
end
|
||||
|
||||
it "is false even if the user is admin" do
|
||||
user.admin = true
|
||||
|
||||
expect(subject).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context "with having precached the results" do
|
||||
before do
|
||||
auth_cache = double("auth_cache")
|
||||
|
||||
allow(Users::ProjectAuthorizationCache)
|
||||
.to receive(:new)
|
||||
.and_return(auth_cache)
|
||||
|
||||
allow(auth_cache)
|
||||
.to receive(:cache)
|
||||
.with(action)
|
||||
|
||||
allow(auth_cache)
|
||||
.to receive(:cached?)
|
||||
.with(action)
|
||||
.and_return(true)
|
||||
|
||||
Array(context).each do |project|
|
||||
allow(auth_cache)
|
||||
.to receive(:allowed?)
|
||||
.with(action, project)
|
||||
.and_return(true)
|
||||
end
|
||||
|
||||
instance.preload_projects_allowed_to(action)
|
||||
end
|
||||
|
||||
it "is true" do
|
||||
expect(subject).to be_truthy
|
||||
end
|
||||
|
||||
it "does not call the db" do
|
||||
subject
|
||||
|
||||
expect(Authorization)
|
||||
.not_to have_received(:roles)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#call" do
|
||||
context "for a project" do
|
||||
let(:context) { project }
|
||||
|
||||
it_behaves_like "allowed to checked"
|
||||
end
|
||||
|
||||
context "for an array of projects" do
|
||||
let(:context) { [project, other_project] }
|
||||
|
||||
it_behaves_like "allowed to checked"
|
||||
|
||||
it "is false" do
|
||||
expect(instance.call(action, [])).to be_falsey
|
||||
end
|
||||
|
||||
context "with one project not allowing an action" do
|
||||
before do
|
||||
allow(project)
|
||||
.to receive(:allows_to?)
|
||||
.with(action)
|
||||
.and_return(false)
|
||||
end
|
||||
|
||||
it "is false" do
|
||||
expect(instance.call(action, [project, other_project])).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "for a relation of projects" do
|
||||
let(:context) { double("relation", class: ActiveRecord::Relation, to_a: [project]) }
|
||||
|
||||
it_behaves_like "allowed to checked"
|
||||
end
|
||||
|
||||
context "for anything else" do
|
||||
let(:context) { nil }
|
||||
|
||||
it "is false" do
|
||||
expect(subject).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context "for a global check" do
|
||||
context "with the user being admin" do
|
||||
before do
|
||||
user.admin = true
|
||||
end
|
||||
|
||||
it "is true" do
|
||||
expect(instance.call(action, nil, global: true)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context "with the user having a granting role" do
|
||||
before do
|
||||
allow(Authorization).to receive(:roles).with(user, nil).and_return(user_roles_in_project)
|
||||
allow(role).to receive(:allowed_to?).with(action).and_return(true)
|
||||
end
|
||||
|
||||
context "but the user not being active" do
|
||||
before do
|
||||
user.lock
|
||||
end
|
||||
|
||||
it "is unsuccessful", :aggregate_failures do
|
||||
expect(instance.call(action, nil, global: true)).not_to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
it "is successful", :aggregate_failures do
|
||||
expect(instance.call(action, nil, global: true)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context "with the user not having a granting role" do
|
||||
before do
|
||||
allow(Authorization).to receive(:roles).with(user, nil).and_return(user_roles_in_project)
|
||||
allow(role).to receive(:allowed_to?).with(action).and_return(false)
|
||||
end
|
||||
|
||||
it "is false" do
|
||||
expect(instance.call(action, nil, global: true)).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -170,26 +170,6 @@ module MockedPermissionHelper
|
||||
(entity.respond_to?(:project) && permission_mock.permitted_entities[entity.project].intersect?(permissions)) ||
|
||||
permission_mock.permitted_entities[entity].intersect?(permissions)
|
||||
end
|
||||
|
||||
# Also mock the legacy interface using the `allowed_to?` method
|
||||
allow(user).to receive(:allowed_to?) do |permission_or_action, project, global: false|
|
||||
next true if permission_mock.allow_all_permissions
|
||||
|
||||
permissions = Authorization.permissions_for(permission_or_action).map(&:name)
|
||||
|
||||
if global
|
||||
# global permission is true, when it is either allowed globally (for global permissions) or
|
||||
# when it is allowed in any project (for project permissions).
|
||||
permission_mock.permitted_entities[:global].intersect?(permissions) ||
|
||||
permission_mock.permitted_entities
|
||||
.select { |k, _| k.is_a?(Project) }
|
||||
.values
|
||||
.flatten
|
||||
.intersect?(permissions)
|
||||
elsif project
|
||||
permission_mock.permitted_entities[project].intersect?(permissions)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -116,11 +116,6 @@ RSpec.describe MockedPermissionHelper do
|
||||
expect(user).to be_allowed_in_any_project(:add_work_packages)
|
||||
expect(user).to be_allowed_in_work_package(:add_work_packages, work_package_in_project)
|
||||
expect(user).to be_allowed_in_any_work_package(:add_work_packages)
|
||||
|
||||
# legacy interface
|
||||
expect(user).to be_allowed_to_globally(:add_project)
|
||||
expect(user).to be_allowed_to_in_project(:add_work_packages, project)
|
||||
expect(user).to be_allowed_to_globally(:add_work_packages)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -156,11 +151,6 @@ RSpec.describe MockedPermissionHelper do
|
||||
it "allows the global permission when querying with controller and action hash" do
|
||||
expect(user).to be_allowed_globally({ controller: "projects", action: "new" })
|
||||
end
|
||||
|
||||
it "allows the global permission using the deprecated interface" do
|
||||
expect(user).to be_allowed_to_globally(:add_project)
|
||||
expect(user).to be_allowed_to(:add_project, nil, global: true)
|
||||
end
|
||||
end
|
||||
|
||||
context "when mocking a permission in the project" do
|
||||
@@ -183,12 +173,6 @@ RSpec.describe MockedPermissionHelper do
|
||||
expect(user).to be_allowed_in_any_project({ controller: "work_packages", action: "index" })
|
||||
end
|
||||
|
||||
it "allows the permission when using the deprecated interface" do
|
||||
expect(user).to be_allowed_to_in_project(:view_work_packages, project)
|
||||
expect(user).to be_allowed_to(:view_work_packages, project)
|
||||
expect(user).to be_allowed_to_globally(:view_work_packages)
|
||||
end
|
||||
|
||||
it "allows the permissions when asking for any project" do
|
||||
expect(user).to be_allowed_in_any_project(:view_work_packages)
|
||||
expect(user).to be_allowed_in_any_project(:add_work_packages)
|
||||
|
||||
Reference in New Issue
Block a user