Skip to content

Commit

Permalink
Merge pull request #15145 from lpichler/add_rbac_for_virtual_attributes
Browse files Browse the repository at this point in the history
Add RBAC for virtual attributes in API
  • Loading branch information
gtanzillo authored Jun 14, 2017
2 parents dfc0146 + 0d479b1 commit bec2d7a
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 2 deletions.
17 changes: 15 additions & 2 deletions app/controllers/api/base_controller/renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,19 @@ def collection_search(is_subcollection, type, klass)
Rbac.filtered(res, options)
end

def virtual_attribute_search(resource, attribute)
if resource.class < ApplicationRecord
# is relation in 'attribute' variable plural in the model class (from 'resource.class') ?
if [:has_many, :has_and_belongs_to_many].include?(resource.class.reflection_with_virtual(attribute).try(:macro))
Rbac.filtered(resource.public_send(attribute))
else
Rbac.filtered_object(resource).try(:public_send, attribute)
end
else
resource.public_send(attribute)
end
end

#
# Let's expand subcollections for objects if asked for
#
Expand Down Expand Up @@ -204,7 +217,7 @@ def expand_virtual_attributes(json, type, resource)
def fetch_direct_virtual_attribute(type, resource, attr)
return unless attr_accessible?(resource, attr)
virtattr_accessor = virtual_attribute_accessor(type, attr)
value = virtattr_accessor.nil? ? resource.public_send(attr) : send(virtattr_accessor, resource)
value = virtattr_accessor ? send(virtattr_accessor, resource) : virtual_attribute_search(resource, attr)
result = {attr => normalize_attr(attr, value)}
# set nil vtype above to "#{type}/#{resource.id}/#{attr}" to support id normalization
[value, result]
Expand All @@ -213,7 +226,7 @@ def fetch_direct_virtual_attribute(type, resource, attr)
def fetch_indirect_virtual_attribute(_type, resource, base, attr, object_hash)
query_related_objects(base, resource, object_hash)
return unless attr_accessible?(object_hash[base], attr)
value = object_hash[base].public_send(attr)
value = virtual_attribute_search(object_hash[base], attr)
result = {attr => normalize_attr(attr, value)}
# set nil vtype above to "#{type}/#{resource.id}/#{base.tr('.', '/')}/#{attr}" to support id normalization
base.split(".").reverse_each { |level| result = {level => result} }
Expand Down
47 changes: 47 additions & 0 deletions spec/requests/api/providers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,53 @@ def have_endpoint_attributes(expected_hash)
have_attributes(h)
end

context 'Provider\'s virtual attributes(= direct or indirect associations) with RBAC' do
let(:ems_openstack) { FactoryGirl.create(:ems_openstack, :tenant_mapping_enabled => true) }
let(:ems_cinder) { FactoryGirl.create(:ems_cinder, :parent_manager => ems_openstack) }
let(:ems_cinder_url) { providers_url(ems_cinder.id) }

let(:tenant) { FactoryGirl.create(:tenant, :source_type => 'CloudTenant') }
let!(:cloud_tenant_1) { FactoryGirl.create(:cloud_tenant, :source_tenant => tenant, :ext_management_system => ems_openstack) }
let!(:cloud_tenant_2) { FactoryGirl.create(:cloud_tenant, :source_tenant => Tenant.root_tenant, :ext_management_system => ems_openstack) }

let(:role) { FactoryGirl.create(:miq_user_role) }
let!(:group) { FactoryGirl.create(:miq_group, :tenant => tenant, :miq_user_role => role) }
let!(:vm) { FactoryGirl.create(:vm_openstack, :ext_management_system => ems_cinder, :miq_group => group) }
let!(:vm_1) { FactoryGirl.create(:vm_openstack, :ext_management_system => ems_cinder) }

context 'with restricted user' do
let(:user) do
FactoryGirl.create(:user, :miq_groups => [group], :password => api_config(:password), :userid => api_config(:user), :name => api_config(:user_name))
end

def define_user
@role = role
user
end

it 'lists only CloudTenant for the restricted user(indirect association)' do
api_basic_authorize action_identifier(:providers, :read, :resource_actions, :get)
run_get(ems_cinder_url, :attributes => 'parent_manager.cloud_tenants')
cloud_tenant_ids = response.parsed_body['parent_manager']['cloud_tenants'].map { |x| x['id'] }
expect([cloud_tenant_1.id]).to match_array(cloud_tenant_ids)
end

it 'lists only CloudTenant for the restricted user(direct association)' do
api_basic_authorize action_identifier(:providers, :read, :resource_actions, :get)
run_get(ems_cinder_url, :attributes => 'vms')
vm_ids = response.parsed_body['vms'].map { |x| x['id'] }
expect([vm.id]).to match_array(vm_ids)
end
end

it 'lists all CloudTenants' do
api_basic_authorize action_identifier(:providers, :read, :resource_actions, :get)
run_get(ems_cinder_url, :attributes => 'parent_manager.cloud_tenants')
cloud_tenant_ids = response.parsed_body['parent_manager']['cloud_tenants'].map { |x| x['id'] }
expect([cloud_tenant_1.id, cloud_tenant_2.id]).to match_array(cloud_tenant_ids)
end
end

context "Provider custom_attributes" do
let(:provider) { FactoryGirl.create(:ext_management_system, sample_rhevm) }
let(:provider_url) { providers_url(provider.id) }
Expand Down

0 comments on commit bec2d7a

Please sign in to comment.