-
Notifications
You must be signed in to change notification settings - Fork 897
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix RBAC call for templates and vms #18128
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1761,13 +1761,25 @@ def self.reconfigurable?(ids) | |
vms.all?(&:reconfigurable?) | ||
end | ||
|
||
PUBLIC_TEMPLATE_CLASSES = %w(ManageIQ::Providers::Openstack::CloudManager::Template).freeze | ||
|
||
def self.tenant_id_clause(user_or_group) | ||
template_tenant_ids = MiqTemplate.accessible_tenant_ids(user_or_group, Rbac.accessible_tenant_ids_strategy(MiqTemplate)) | ||
vm_tenant_ids = Vm.accessible_tenant_ids(user_or_group, Rbac.accessible_tenant_ids_strategy(Vm)) | ||
return if template_tenant_ids.empty? && vm_tenant_ids.empty? | ||
|
||
["(vms.template = true AND vms.tenant_id IN (?)) OR (vms.template = false AND vms.tenant_id IN (?))", | ||
template_tenant_ids, vm_tenant_ids] | ||
tenant = user_or_group.current_tenant | ||
tenant_vms = "vms.template = false AND vms.tenant_id IN (?)" | ||
public_templates = "vms.template = true AND vms.publicly_available = true AND vms.type IN (?)" | ||
tenant_templates = "vms.template = true AND vms.tenant_id IN (?)" | ||
|
||
if tenant.source_id | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. looks great and I wrote summary and during I had a idea to write these condition in more understandable way - i am just using variables: git diff: diff --git a/app/models/vm_or_template.rb b/app/models/vm_or_template.rb
index e3babcf6c8..05ef73f54b 100644
--- a/app/models/vm_or_template.rb
+++ b/app/models/vm_or_template.rb
@@ -1766,12 +1766,19 @@ class VmOrTemplate < ApplicationRecord
vm_tenant_ids = Vm.accessible_tenant_ids(user_or_group, Rbac.accessible_tenant_ids_strategy(Vm))
return if template_tenant_ids.empty? && vm_tenant_ids.empty?
tenant = user_or_group.current_tenant
+
+ tenant_vms = "vms.template = false AND vms.tenant_id IN (?)"
+ public_templates = "vms.template = true AND vms.publicly_available = true"
+
if tenant.source_id
- ["(vms.template = true AND (vms.tenant_id = (?) AND vms.publicly_available = false OR vms.publicly_available = true)) OR (vms.template = false AND vms.tenant_id IN (?))", tenant.id, vm_tenant_ids]
+ private_tenant_templates = "vms.template = true AND vms.tenant_id = (?) AND vms.publicly_available = false"
+
+ ["#{private_tenant_templates} OR #{public_templates} OR #{tenant_vms}", tenant.id, vm_tenant_ids]
elsif template_tenant_ids.empty?
- ["vms.template = false AND vms.tenant_id IN (?)", vm_tenant_ids]
+ [tenant_vms, vm_tenant_ids]
else
- ["(vms.template = true AND (vms.tenant_id IN (?) OR vms.publicly_available = true)) OR (vms.template = false AND vms.tenant_id IN (?))", template_tenant_ids, vm_tenant_ids] a there is how it looks like tenant_vms = "vms.template = false AND vms.tenant_id IN (?)"
public_templates = "vms.template = true AND vms.publicly_available = true"
if tenant.source_id
private_tenant_templates = "vms.template = true AND vms.tenant_id = (?) AND vms.publicly_available = false"
["#{private_tenant_templates} OR #{public_templates} OR #{tenant_vms}", tenant.id, vm_tenant_ids]
elsif template_tenant_ids.empty?
[tenant_vms, vm_tenant_ids]
else
tenant_templates = "vms.template = true AND vms.tenant_id IN (?)"
["#{tenant_templates} OR #{public_templates} OR #{tenant_vms}", template_tenant_ids, vm_tenant_ids]
end it looks to me more understandable, if you like also can you use it ? I also tried remove each condition and run specs to confirm if we have test coverage - and you did great job! the only thing which I found that it not covered is if leg: elsif template_tenant_ids.empty?
[tenant_vms, vm_tenant_ids] so if can also add covered for this it would be great! thanks !!! |
||
private_tenant_templates = "vms.template = true AND vms.tenant_id = (?) AND vms.publicly_available = false" | ||
tenant_templates += " AND vms.type NOT IN (?)" | ||
["#{private_tenant_templates} OR #{tenant_vms} OR #{tenant_templates} OR #{public_templates}", tenant.id, vm_tenant_ids, template_tenant_ids, PUBLIC_TEMPLATE_CLASSES, PUBLIC_TEMPLATE_CLASSES] | ||
else | ||
["#{tenant_templates} OR #{public_templates} OR #{tenant_vms}", template_tenant_ids, PUBLIC_TEMPLATE_CLASSES, vm_tenant_ids] | ||
end | ||
end | ||
|
||
def self.with_ownership | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why the base class is knowledgeable about a public template class from openstack. Why does this need to be in the base class?
I don't know what this means. can you please explain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, @lpichler explained here #18128 (comment) why inheritance breaks RBAC filtering for UI, also when using explorer view the RBAC call will be made for the base model, which is vm_or_template. We are trying to apply some custom RBAC rules for openstack provider, so we placed the RBAC call in base model and we want to not change it's behaviour for anything except
ManageIQ::Providers::Openstack::CloudManager::Template
@lpichler correct me if I'm wrong :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alexander-demichev maybe you can add #18128 (comment) to the description.
@jrafanie if we will leave this RBAC rule (it is restriction) only in TemplateCloud model, we will get this restriction only for API call
/api/<request_for_list_of_template_cloud>
but it will not prevent list of restricted
TemplateCloud
s(restricted by this rule) in this api call:/api/<request_for_list_of_vm_or_template>
- which can any client call.so to have it in base class is about security and basically it implies general RBAC rule (cc @himdel ):
so that it has a basic RBAC rule (learned from @himdel):
Do not implement RBAC behavior in special models beucase api can call basic models
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed,
/api/vms
will ignore any restriction defined in subclasses ofVm
.I think the same goes for
Rbac.filtered(Vm.where(...))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation.
For a future PR... would it make sense to have the subclass register this class into the base class? It seems odd to me for a base class to know about a subclass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable 👍 (though I don't know that much about RBAC internals)
Some kind of registration mechanism would keep the logic in the right place, while allowing it to work even when asking for the basest class.
(Assuming different subclasses don't have conflicting ideas about these restrictions, I guess.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, very good point about different subclasses treating this registration thing differently. I'm fine with doing this for now and if we need to do something "like" this for another class, we should really consider a way to register this subclass with the base class.
Alternatively, you could have the subclass implement a method
publicly_visible?
or something that the base class can thencollect
to get a list of publicly visible classes. It would require all subclasses are loaded first, but could be a way to "register" them automatically based on an interface.Either way, this is good for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @jrafanie I am making a note for it.