Revision 08d4fc31
Added by Ori Rabin over 8 years ago
app/helpers/layout_helper.rb | ||
---|---|---|
# add hidden field for options[:disabled]
|
||
def multiple_selects(f, attr, associations, selected_ids, options = {}, html_options = {})
|
||
options.merge!(:size => "col-md-10")
|
||
authorized = authorized_associations(associations).all
|
||
authorized = AssociationAuthorizer.authorized_associations(associations).all
|
||
unauthorized = selected_ids.blank? ? [] : selected_ids - authorized.map(&:id)
|
||
field(f, attr, options) do
|
||
attr_ids = (attr.to_s.singularize+"_ids").to_sym
|
||
... | ... | |
|
||
private
|
||
|
||
def authorized_associations(associations)
|
||
if associations.included_modules.include?(Authorizable)
|
||
if associations.respond_to?(:klass)
|
||
associations.authorized(authorized_associations_permission_name(associations.klass), associations.klass)
|
||
else
|
||
associations.authorized(authorized_associations_permission_name(associations), associations)
|
||
end
|
||
else
|
||
associations
|
||
end
|
||
end
|
||
|
||
def authorized_associations_permission_name(klass)
|
||
permission = "view_#{klass.to_s.underscore.pluralize}"
|
||
unless Permission.where(:name => permission).present?
|
||
raise Foreman::Exception.new(N_('unknown permission %s'), permission)
|
||
end
|
||
permission
|
||
end
|
||
|
||
def table_css_classes(classes = '')
|
||
"table table-bordered table-striped table-condensed " + classes
|
||
end
|
app/models/smart_proxy.rb | ||
---|---|---|
|
||
attr_accessible :name, :url, :location_ids, :organization_ids
|
||
validates_lengths_from_database
|
||
before_destroy EnsureNotUsedBy.new(:hosts, :hostgroups, :subnets, :domains, :puppet_ca_hosts, :puppet_ca_hostgroups, :realms)
|
||
before_destroy EnsureNotUsedBy.new(:hosts, :hostgroups, :subnets, :domains, [:puppet_ca_hosts, :hosts], [:puppet_ca_hostgroups, :hostgroups], :realms)
|
||
#TODO check if there is a way to look into the tftp_id too
|
||
# maybe with a predefined sql
|
||
has_and_belongs_to_many :features
|
app/models/user.rb | ||
---|---|---|
attr_protected :password_hash, :password_salt, :admin
|
||
attr_accessor :password, :password_confirmation
|
||
after_save :ensure_default_role
|
||
before_destroy EnsureNotUsedBy.new(:direct_hosts), :ensure_hidden_users_are_not_deleted, :ensure_last_admin_is_not_deleted
|
||
before_destroy EnsureNotUsedBy.new([:direct_hosts, :hosts]), :ensure_hidden_users_are_not_deleted, :ensure_last_admin_is_not_deleted
|
||
|
||
belongs_to :auth_source
|
||
belongs_to :default_organization, :class_name => 'Organization'
|
app/services/association_authorizer.rb | ||
---|---|---|
class AssociationAuthorizer
|
||
def self.authorized_associations(associations, klass_name = nil, should_raise_exception = true)
|
||
if associations.included_modules.include?(Authorizable)
|
||
associations_klass = associations
|
||
if associations.respond_to?(:klass)
|
||
associations_klass = associations.klass
|
||
end
|
||
klass_name ||= associations_klass
|
||
permission = view_permission_name(klass_name, should_raise_exception)
|
||
associations.authorized(permission, associations_klass) if permission
|
||
else
|
||
associations
|
||
end
|
||
end
|
||
|
||
def self.view_permission_name(klass, should_raise_exception)
|
||
permission = "view_#{klass.to_s.underscore.pluralize}"
|
||
if Permission.where(:name => permission).present?
|
||
permission
|
||
elsif should_raise_exception
|
||
raise Foreman::Exception.new(N_('unknown permission %s'), permission)
|
||
else
|
||
false
|
||
end
|
||
end
|
||
end
|
lib/core_extensions.rb | ||
---|---|---|
end
|
||
|
||
def before_destroy(record)
|
||
klasses.each do |klass|
|
||
record.send(klass.to_sym).each do |what|
|
||
what = what.to_label unless what.is_a? String
|
||
record.errors.add :base, _("%{record} is used by %{what}") % { :record => record, :what => what }
|
||
klasses.each do |klass, klass_name = klass|
|
||
record.association(klass.to_sym).association_scope.each do |what|
|
||
error_message = _("%{record} is used by %{what}")
|
||
unless what.is_a? String
|
||
authorized_associations = AssociationAuthorizer.authorized_associations(record.class.reflect_on_association(klass.to_sym).klass, klass_name, false)
|
||
if !authorized_associations.respond_to?(:to_a) || authorized_associations.to_a.include?(what)
|
||
what = what.to_label
|
||
else
|
||
what = _(what.class.name)
|
||
error_message = _("%{record} is being used by a hidden %{what} resource")
|
||
end
|
||
end
|
||
record.errors.add :base, error_message % { :record => record, :what => what }
|
||
end
|
||
end
|
||
if record.errors.empty?
|
test/unit/association_authorizer_test.rb | ||
---|---|---|
require 'test_helper'
|
||
|
||
class AssociationAuthorizerTest < ActiveSupport::TestCase
|
||
def setup
|
||
@hostgroup = FactoryGirl.create(:hostgroup)
|
||
@host = FactoryGirl.create(:host, :managed, :hostgroup => @hostgroup)
|
||
@user = FactoryGirl.create(:user)
|
||
end
|
||
|
||
test "user with permissions can view host" do
|
||
role = FactoryGirl.create(:role, :name => 'can_view_host')
|
||
role.add_permissions!(['view_hosts'])
|
||
@user.update_attribute :roles, [role]
|
||
|
||
as_user @user do
|
||
authorized = AssociationAuthorizer.authorized_associations(Hostgroup.reflect_on_association(:hosts).klass, :hosts)
|
||
assert authorized.include?(@host)
|
||
end
|
||
end
|
||
|
||
test "user without permissions can't view host" do
|
||
as_user @user do
|
||
authorized = AssociationAuthorizer.authorized_associations(Hostgroup.reflect_on_association(:hosts).klass, :hosts)
|
||
refute authorized.include?(@host)
|
||
end
|
||
end
|
||
|
||
test "authorized_associations should raise unknown permission exception when should_raise_exception is true" do
|
||
assert_raise(Foreman::Exception) do
|
||
AssociationAuthorizer.view_permission_name('non_existing_permission', true)
|
||
end
|
||
end
|
||
|
||
test "authorized_associations should return false for unknown permission when should_raise_exception is false" do
|
||
permission = AssociationAuthorizer.view_permission_name('non_existing_permission', false)
|
||
assert_equal false, permission
|
||
end
|
||
|
||
test "authorized_associations should return permission if it exists" do
|
||
permission = AssociationAuthorizer.view_permission_name(:host, false)
|
||
assert_equal "view_hosts", permission
|
||
end
|
||
end
|
test/unit/ensure_not_used_by_test.rb | ||
---|---|---|
require 'test_helper'
|
||
|
||
class EnsureNotUsedByTest < ActiveSupport::TestCase
|
||
def setup
|
||
@org1 = FactoryGirl.create(:organization)
|
||
@org2 = FactoryGirl.create(:organization)
|
||
@user = FactoryGirl.build(:user, :with_mail, :organizations => [@org1])
|
||
@user.save(:validate => false)
|
||
role = FactoryGirl.create(:role, :name => 'can_view_host')
|
||
role.add_permissions!(['view_hosts'])
|
||
@user.update_attribute :roles, [role]
|
||
end
|
||
|
||
test "hostgroup should not be deleted if used by host in user org" do
|
||
hostgroup = FactoryGirl.create(:hostgroup, :organizations => [@org1, @org2])
|
||
host = FactoryGirl.create(:host, :managed, :hostgroup => hostgroup, :organization => @org1)
|
||
|
||
as_user @user do
|
||
in_taxonomy @org1 do
|
||
refute hostgroup.destroy
|
||
assert_equal "#{hostgroup.name} is used by #{host.name}", hostgroup.errors.full_messages.first
|
||
end
|
||
end
|
||
end
|
||
|
||
test "hostgroup should not be deleted if used by host in different org" do
|
||
hostgroup = FactoryGirl.create(:hostgroup, :organizations => [@org1, @org2])
|
||
FactoryGirl.create(:host, :hostgroup => hostgroup, :organization => @org2)
|
||
|
||
as_user @user do
|
||
in_taxonomy @org1 do
|
||
refute hostgroup.destroy
|
||
assert_equal "#{hostgroup.name} is being used by a hidden Host::Managed resource", hostgroup.errors.full_messages.first
|
||
end
|
||
end
|
||
end
|
||
|
||
test "hostgroup should not be deleted if used by host" do
|
||
hostgroup = FactoryGirl.create(:hostgroup, :organizations => [@org1, @org2])
|
||
FactoryGirl.create(:host, :hostgroup => hostgroup, :organization => @org2)
|
||
|
||
as_user FactoryGirl.create(:user, :with_mail) do
|
||
in_taxonomy @org1 do
|
||
refute hostgroup.destroy
|
||
assert_equal "#{hostgroup.name} is being used by a hidden Host::Managed resource", hostgroup.errors.full_messages.first
|
||
end
|
||
end
|
||
end
|
||
|
||
test "hostgroup should be deleted if not used by host" do
|
||
hostgroup = FactoryGirl.create(:hostgroup, :organizations => [@org1, @org2])
|
||
FactoryGirl.create(:host, :organization => @org2)
|
||
|
||
as_user @user do
|
||
assert hostgroup.destroy
|
||
end
|
||
end
|
||
|
||
test "host using hostgroup should not be shown to user without permissions" do
|
||
hostgroup = FactoryGirl.create(:hostgroup)
|
||
FactoryGirl.create(:host, :managed, :hostgroup => hostgroup)
|
||
|
||
as_user FactoryGirl.create(:user, :with_mail) do
|
||
refute hostgroup.destroy
|
||
assert_equal "#{hostgroup.name} is being used by a hidden Host::Managed resource", hostgroup.errors.full_messages.first
|
||
end
|
||
end
|
||
end
|
Also available in: Unified diff
Fixes #11188 - EnsureNotUsedBy checks for unscoped associations before destroying