From 639ee18b9cc81953479774673d841f7b8be89e85 Mon Sep 17 00:00:00 2001 From: Tim Wade Date: Fri, 28 Jul 2017 15:46:31 -0700 Subject: [PATCH 1/2] Serialize expressions --- app/models/entitlement.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/entitlement.rb b/app/models/entitlement.rb index b00f31703c7..09735307230 100644 --- a/app/models/entitlement.rb +++ b/app/models/entitlement.rb @@ -3,6 +3,7 @@ class Entitlement < ApplicationRecord belongs_to :miq_user_role serialize :filters + serialize :filter_expression def self.valid_filters?(filters_hash) return true unless filters_hash # nil ok From 33a722b751fe7ffad2128c5d288534d3c23eb6c5 Mon Sep 17 00:00:00 2001 From: Tim Wade Date: Thu, 13 Jul 2017 09:22:41 -0700 Subject: [PATCH 2/2] Support evaluation of expression filters for entitlements in RBAC Resolves https://www.pivotaltracker.com/story/show/148794877 --- lib/rbac/filterer.rb | 5 +++- spec/lib/rbac/filterer_spec.rb | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/rbac/filterer.rb b/lib/rbac/filterer.rb index 7329a470641..94b3a73af0a 100644 --- a/lib/rbac/filterer.rb +++ b/lib/rbac/filterer.rb @@ -351,9 +351,11 @@ def get_self_service_objects(user, miq_group, klass) def calc_filtered_ids(scope, user_filters, user, miq_group, scope_tenant_filter) klass = scope.respond_to?(:klass) ? scope.klass : scope + expression = miq_group.try(:entitlement).try(:filter_expression) + expression.set_tagged_target(klass) if expression u_filtered_ids = pluck_ids(get_self_service_objects(user, miq_group, klass)) b_filtered_ids = get_belongsto_filter_object_ids(klass, user_filters['belongsto']) - m_filtered_ids = pluck_ids(get_managed_filter_object_ids(scope, user_filters['managed'])) + m_filtered_ids = pluck_ids(get_managed_filter_object_ids(scope, expression || user_filters['managed'])) d_filtered_ids = pluck_ids(matches_via_descendants(rbac_class(klass), user_filters['match_via_descendants'], :user => user, :miq_group => miq_group)) @@ -417,6 +419,7 @@ def get_belongsto_filter_object_ids(klass, filter) end def get_managed_filter_object_ids(scope, filter) + return scope.where(filter.to_sql.first) if filter.kind_of?(MiqExpression) klass = scope.respond_to?(:klass) ? scope.klass : scope return nil if !TAGGABLE_FILTER_CLASSES.include?(safe_base_class(klass).name) || filter.blank? scope.find_tags_by_grouping(filter, :ns => '*').reorder(nil) diff --git a/spec/lib/rbac/filterer_spec.rb b/spec/lib/rbac/filterer_spec.rb index b9a5891cd7c..a9e629f5be5 100644 --- a/spec/lib/rbac/filterer_spec.rb +++ b/spec/lib/rbac/filterer_spec.rb @@ -1,4 +1,54 @@ describe Rbac::Filterer do + describe "using expressions as managed filters" do + it "supports OR conditions across categories" do + filter = MiqExpression.new( + "OR" => [ + {"CONTAINS" => {"tag" => "managed-environment", "value" => "prod"}}, + {"CONTAINS" => {"tag" => "managed-location", "value" => "ny"}} + ] + ) + group = create_group_with_expression(filter) + user = FactoryGirl.create(:user, :miq_groups => [group]) + vm1, vm2, _vm3 = FactoryGirl.create_list(:vm_vmware, 3) + vm1.tag_with("/managed/environment/prod", :ns => "*") + vm2.tag_with("/managed/location/ny", :ns => "*") + + actual, = Rbac::Filterer.search(:targets => Vm, :user => user) + + expected = [vm1, vm2] + expect(actual).to match(expected) + end + + it "supports AND conditions within categories" do + filter = MiqExpression.new( + "AND" => [ + {"CONTAINS" => {"tag" => "managed-environment", "value" => "prod"}}, + {"CONTAINS" => {"tag" => "managed-environment", "value" => "test"}} + ] + ) + group = create_group_with_expression(filter) + user = FactoryGirl.create(:user, :miq_groups => [group]) + vm1, vm2, vm3 = FactoryGirl.create_list(:vm_vmware, 3) + vm1.tag_with("/managed/environment/prod /managed/environment/test", :ns => "*") + vm2.tag_with("/managed/environment/prod", :ns => "*") + vm3.tag_with("/managed/environment/test", :ns => "*") + + actual, = Rbac::Filterer.search(:targets => Vm, :user => user) + + expected = [vm1] + expect(actual).to match(expected) + end + + def create_group_with_expression(expression) + role = FactoryGirl.create(:miq_user_role) + group = FactoryGirl.create(:miq_group, :tenant => Tenant.root_tenant, :miq_user_role => role) + group.entitlement = Entitlement.new + group.entitlement.filter_expression = expression + group.save! + group + end + end + describe '.combine_filtered_ids' do # Algorithm (from Rbac::Filterer.combine_filtered_ids): # Algorithm: b_intersection_m = (b_filtered_ids INTERSECTION m_filtered_ids)