> Add some rights to give non admin users so they can perform some normal
> actions on the hosts they own.
>
> Signed-off-by: Olivier Favre <olivier@yakaz.com>
> —
> …/compute_resources/vms_controller.rb | 2 ±
> app/controllers/compute_resources_controller.rb | 22 +++++++++++±
> app/models/compute_resource.rb | 33
> ++++++++++++++++++++
> app/models/host.rb | 2 +
> app/models/user.rb | 4 +±
> …/compute_resources/vms/index/_libvirt.html.erb | 2 ±
> …/compute_resources/vms/index/_ovirt.html.erb | 2 ±
> app/views/hosts/_form.html.erb | 2 ±
> app/views/users/_filters.html.erb | 9 +++++
> …/20120514113900_add_user_compute_resources.rb | 14 ++++++++
> …115814_add_compute_resources_boolean_to_user.rb | 9 +++++
> lib/foreman/access_permissions.rb | 16 +++++++++
> 12 files changed, 111 insertions(+), 6 deletions(-)
> create mode 100644 db/migrate/20120514113900_add_user_compute_resources.rb
> create mode 100644
> db/migrate/20120514115814_add_compute_resources_boolean_to_user.rb
>
> diff --git a/app/controllers/compute_resources/vms_controller.rb
> b/app/controllers/compute_resources/vms_controller.rb
> index 370e9ba…890bf76 100644
> — a/app/controllers/compute_resources/vms_controller.rb
> +++ b/app/controllers/compute_resources/vms_controller.rb
> @@ -60,7 +60,7 @@ class ComputeResources::VmsController <
> ApplicationController
> private
>
> def find_compute_resource
> - @compute_resource = ComputeResource.find(params[:compute_resource_id])
> + @compute_resource =
> ComputeResource.my_compute_resources.find(params[:compute_resource_id])
> end
>
> def find_vm
> diff --git a/app/controllers/compute_resources_controller.rb
> b/app/controllers/compute_resources_controller.rb
> index e0adb31…7723e16 100644
> — a/app/controllers/compute_resources_controller.rb
> +++ b/app/controllers/compute_resources_controller.rb
> @@ -5,7 +5,14 @@ class ComputeResourcesController < ApplicationController
> before_filter :find_by_id, :only => %w{show edit update destroy} +
> AJAX_REQUESTS
>
> def index
> - values = ComputeResource.search_for(params[:search], :order =>
> params[:order])
> + begin
> + my_compute_resources = User.current.admin? ? ComputeResource :
> ComputeResource.my_compute_resources
>
do you mind moving the user check into the scope? this would allow us to
use the scope everywhere by default.
also, i think the current scheme of having Host.my_host,
ComputeResource.my_compute_resources etc gets way too verbose, maybe a
simple ComputeResource.mine or something like that would be better?
> + values = my_compute_resources.search_for(params[:search], :order =>
> params[:order])
> + rescue => e
> + error e.to_s
> + values = my_compute_resources.search_for ""
> + end
> +
> respond_to do |format|
> format.html { @compute_resources = values.paginate :page =>
> params[:page] }
> format.json { render :json => values }
> @@ -16,10 +23,21 @@ class ComputeResourcesController <
> ApplicationController
> @compute_resource = ComputeResource.new
> end
>
> + def show
> + auth = User.current.admin? ? true :
> ComputeResource.my_compute_resources.include?(@compute_resource)
> + not_found and return unless auth
> + respond_to do |format|
> + format.html
> + format.json { render :json => @compute_resource }
> + end
> + end
> +
> def create
> if params[:compute_resource].present? &&
> params[:compute_resource][:provider].present?
> @compute_resource = ComputeResource.new_provider
> params[:compute_resource]
> if @compute_resource.save
> + # Add the new compute resource to the user's filters
> + @compute_resource.users << User.current
> process_success
> else
> process_error
> @@ -32,6 +50,8 @@ class ComputeResourcesController < ApplicationController
> end
>
> def edit
> + auth = User.current.admin? ? true :
> ComputeResource.my_compute_resources.include?(@compute_resource)
> + not_found and return unless auth
>
I think this is probably better as a before_filter?
> end
>
> def update
> diff --git a/app/models/compute_resource.rb
> b/app/models/compute_resource.rb
> index b8106b6…5912b3f 100644
> — a/app/models/compute_resource.rb
> +++ b/app/models/compute_resource.rb
> @@ -8,6 +8,7 @@ class ComputeResource < ActiveRecord::Base
> STI_PREFIX= "Foreman::Model"
>
> include Authorization
> + has_and_belongs_to_many :users, :join_table => "user_compute_resources"
> validates_format_of :name, :with => /\A(\S+)\Z/, :message => "can't be
> blank or contain white spaces."
> validates_uniqueness_of :name
> validates_presence_of :provider, :in => PROVIDERS
> @@ -16,6 +17,38 @@ class ComputeResource < ActiveRecord::Base
> before_save :sanitize_url
> has_many :hosts
>
> + default_scope :order => 'LOWER(compute_resources.name)'
> +
> + # returns reports for hosts in the User's filter set
> + scope :my_compute_resources, lambda {
> + user = User.current
> + if user.admin?
> + conditions = { }
>
Oh, you already do that, so i guess the User check in the controllers are
not needed?
> + else
> + conditions = sanitize_sql_for_conditions([" (compute_resources.idin (?))", user.compute_resources.map(&:id)])
> + conditions.sub!(/\s*()\s*/, "")
> + conditions.sub!(/^(?:())?\s?(?:and|or)\s*/, "")
> + conditions.sub!(/(\s*(?:or|and)\s*(/, "((")
> + end
> + {:conditions => conditions}
> + }
> +
>
should be a private method.
> + def enforce_permissions operation
> + # We get called again with the operation being set to create
> + return true if operation == "edit" and new_record?
> + current = User.current
> + if current.allowed_to?("#{operation}_compute_resources".to_sym)
> + # If you can create compute resources then you can create them
> anywhere
> + return true if operation == "create"
> + # edit or delete
> + if current.allowed_to?("#{operation}_compute_resources".to_sym)
> + return true if
> ComputeResource.my_compute_resources(current).include? self
> + end
> + end
> + errors.add :base, "You do not have permission to #{operation} this
> domain"
> + false
> + end
> +
> # allows to create a specific compute class based on the provider.
> def self.new_provider args
> raise "must provider a provider" unless provider = args[:provider]
> diff --git a/app/models/host.rb b/app/models/host.rb
> index 3d2520a…37bb3e2 100644
> — a/app/models/host.rb
> +++ b/app/models/host.rb
> @@ -79,6 +79,7 @@ class Host < Puppet::Rails::Host
> user = User.current
> owner_conditions = sanitize_sql_for_conditions(["((hosts.owner_id
> in (?) AND hosts.owner_type = 'Usergroup') OR (hosts.owner_id = ? AND
> hosts.owner_type = 'User'))", user.my_usergroups.map(&:id), user.id])
> domain_conditions = sanitize_sql_for_conditions([" (hosts.domain_id
> in (?))",dms = (user.domains).map(&:id)])
> + compute_resource_conditions = sanitize_sql_for_conditions(["
> (hosts.compute_resource_id in (?))",(crs =
> user.compute_resources).map(&:id)])
> hostgroup_conditions = sanitize_sql_for_conditions(["
> (hosts.hostgroup_id in (?))",(hgs = user.hostgroups).map(&:id)])
>
> fact_conditions = ""
> @@ -94,6 +95,7 @@ class Host < Puppet::Rails::Host
> if user.filtering?
> conditions = "#{owner_conditions}"
>
> if user.filter_on_owner
> (conditions = (user.domains_andor == "and") ? "(#{conditions})
> and #{domain_conditions} " : "#{conditions} or #{domain_conditions} ")
> unless dms.empty?
> + (conditions = (user.compute_resources_andor == "and") ?
> "(#{conditions}) and #{compute_resource_conditions} " : "#{conditions} or
> #{compute_resource_conditions} ") unless crs.empty?
> (conditions = (user.hostgroups_andor == "and") ? "(#{conditions})
> and #{hostgroup_conditions} " : "#{conditions} or #{hostgroup_conditions}
> ") unless hgs.empty?
> (conditions = (user.facts_andor == "and") ? "(#{conditions})
> and #{fact_conditions} " : "#{conditions} or #{fact_conditions} ")
> unless ufs.empty?
> conditions.sub!(/\s*()\s*/, "")
> diff --git a/app/models/user.rb b/app/models/user.rb
> index abe67d4…42917df 100644
> — a/app/models/user.rb
> +++ b/app/models/user.rb
> @@ -15,6 +15,7 @@ class User < ActiveRecord::Base
> has_and_belongs_to_many :notices, :join_table => 'user_notices'
> has_many :user_roles
> has_many :roles, :through => :user_roles
> + has_and_belongs_to_many :compute_resources, :join_table =>
> "user_compute_resources"
> has_and_belongs_to_many :domains, :join_table => "user_domains"
> has_and_belongs_to_many :hostgroups, :join_table => "user_hostgroups"
> has_many :user_facts, :dependent => :destroy
> @@ -36,7 +37,7 @@ class User < ActiveRecord::Base
> before_destroy EnsureNotUsedBy.new(:hosts), :ensure_admin_is_not_deleted
> validate :name_used_in_a_usergroup, :ensure_admin_is_not_renamed
> before_validation :prepare_password
> - after_destroy Proc.new {|user| user.domains.clear;
> user.hostgroups.clear}
> + after_destroy Proc.new {|user| user.compute_resources.clear;
> user.domains.clear; user.hostgroups.clear}
>
> scoped_search :on => :login, :complete_value => :true
> scoped_search :on => :firstname, :complete_value => :true
> @@ -153,6 +154,7 @@ class User < ActiveRecord::Base
> # Returns : Boolean
> def filtering?
> filter_on_owner or
> + compute_resources.any? or
> domains.any? or
> hostgroups.any? or
> facts.any?
> diff --git a/app/views/compute_resources/vms/index/_libvirt.html.erb
> b/app/views/compute_resources/vms/index/_libvirt.html.erb
> index 901c37a…880a163 100644
> — a/app/views/compute_resources/vms/index/_libvirt.html.erb
> +++ b/app/views/compute_resources/vms/index/_libvirt.html.erb
> @@ -10,7 +10,7 @@
> </tr>
> <% @compute_resource.vms.each do |vm| -%>
> <tr>
> - <td><%= link_to vm.name,
> hash_for_compute_resource_vm_path(:compute_resource_id =>
> @compute_resource, :id => vm.uuid) %></td>
> + <td><%= link_to_if_authorized vm.name,
> hash_for_compute_resource_vm_path(:compute_resource_id =>
> @compute_resource, :id => vm.uuid) %></td>
> <td><%= vm.cpus %></td>
> <td> <%= number_to_human_size vm.memory_size*1024 %> </td>
> <td <%= vm_power_class(vm.ready?)%>> <%= vm_state(!vm.ready?) %>
> </td>
> diff --git a/app/views/compute_resources/vms/index/_ovirt.html.erb
> b/app/views/compute_resources/vms/index/_ovirt.html.erb
> index 4964996…03d6e3b 100644
> — a/app/views/compute_resources/vms/index/_ovirt.html.erb
> +++ b/app/views/compute_resources/vms/index/_ovirt.html.erb
> @@ -10,7 +10,7 @@
> </tr>
> <% @compute_resource.vms.each do |vm| -%>
> <tr>
> - <td><%= link_to vm.name,
> hash_for_compute_resource_vm_path(:compute_resource_id =>
> @compute_resource, :id => vm.identity) %></td>
> + <td><%= link_to_if_authorized vm.name,
> hash_for_compute_resource_vm_path(:compute_resource_id =>
> @compute_resource, :id => vm.identity) %></td>
> <td><%= vm.cores %></td>
> <td> <%= number_to_human_size vm.memory %> </td>
> <td <%= vm_power_class(vm.ready?) %>> <%= vm_state(!vm.ready?) %>
> </td>
> diff --git a/app/views/hosts/_form.html.erb
> b/app/views/hosts/_form.html.erb
> index d15dfcf…fdcb622 100644
> — a/app/views/hosts/_form.html.erb
> +++ b/app/views/hosts/_form.html.erb
> @@ -25,7 +25,7 @@
> <div class="tab-pane active" id="primary">
> <%= text_f f, :name, :class => "input-xlarge", :value =>
> name_field(@host) %>
> <% libvirt = Hypervisor.first.nil? ? [] : [OpenStruct.new(:to_label
> => 'Libvirt')] -%>
> - <%= select_f f, :compute_resource_id, libvirt +
> ComputeResource.all, :id, :to_label,
> + <%= select_f f, :compute_resource_id, libvirt +
> ComputeResource.my_compute_resources, :id, :to_label,
> { :include_blank => 'Bare Metal' },
> {:label => "Deploy on", :disabled => !@host.new_record?,
> :'data-url' => compute_resource_selected_hosts_path ,
> :onchange => 'computeResourceSelected(this);'} if
> @host.new_record? || @host.compute_resource_id %>
> diff --git a/app/views/users/_filters.html.erb
> b/app/views/users/_filters.html.erb
> index 41a7113…ea59ab6 100644
> — a/app/views/users/_filters.html.erb
> +++ b/app/views/users/_filters.html.erb
> @@ -16,6 +16,15 @@
> </div>
> <% end %>
>
> + <%= field_set_tag "Compute resources" do %>
> + <div class="control-group">
> + <%= f.select :compute_resources_andor, [["must be", "and"],
> ["plus all", "or"]], {}, :class => "input-small" %>
> + <div class="offset1">
> + <%= edit_habtm @user, ComputeResource %>
> + </div>
> + </div>
> + <% end %>
> +
> <%= field_set_tag "Hostgroup hosts" do %>
> <div class="control-group">
> <%= f.select :hostgroups_andor, [["must be", "and"], ["plus all",
> "or"]], {}, :class => "input-small" %>
> diff --git a/db/migrate/20120514113900_add_user_compute_resources.rb
> b/db/migrate/20120514113900_add_user_compute_resources.rb
> new file mode 100644
> index 0000000…3023a31
> — /dev/null
> +++ b/db/migrate/20120514113900_add_user_compute_resources.rb
> @@ -0,0 +1,14 @@
> +# To suport "Edit my compute resource" security access control we need
> +# a mechanism to associate a user with some compute resources
> +class AddUserComputeResources < ActiveRecord::Migration
> + def self.up
> + create_table :user_compute_resources, :id => false do |t|
> + t.references :user
> + t.references :compute_resource
> + end
> + end
> +
> + def self.down
> + drop_table :user_compute_resources
> + end
> +end
> diff --git
> a/db/migrate/20120514115814_add_compute_resources_boolean_to_user.rb
> b/db/migrate/20120514115814_add_compute_resources_boolean_to_user.rb
> new file mode 100644
> index 0000000…05e6727
> — /dev/null
> +++ b/db/migrate/20120514115814_add_compute_resources_boolean_to_user.rb
> @@ -0,0 +1,9 @@
> +class AddComputeResourcesBooleanToUser < ActiveRecord::Migration
> + def self.up
> + add_column :users, :compute_resources_andor, :string, :limit => 3,
> :default => "or"
> + end
> +
> + def self.down
> + remove_column :users, :compute_resources_andor
> + end
> +end
> diff --git a/lib/foreman/access_permissions.rb
> b/lib/foreman/access_permissions.rb
> index 3f568e5…9bdcde9 100644
> — a/lib/foreman/access_permissions.rb
> +++ b/lib/foreman/access_permissions.rb
> @@ -23,6 +23,20 @@ Foreman::AccessControl.map do |map|
> map.permission :destroy_bookmarks, {:bookmarks => [:destroy]}
> end
>
> + map.security_block :compute_resources do |map|
> + map.permission :view_compute_resources, {:compute_resources =>
> [:index, :show]}
> + map.permission :create_compute_resources, {:compute_resources =>
> [:new, :create]}
> + map.permission :edit_compute_resources, {:compute_resources =>
> [:edit, :update]}
> + map.permission :destroy_compute_resources, {:compute_resources =>
> [:destroy]}
> + end
> +
> + map.security_block :compute_resources_vms do |map|
> + map.permission :view_compute_resources_vms,
> {:compute_resources_vms => [:index, :show]}
> + map.permission :create_compute_resources_vms,
> {:compute_resources_vms => [:create, :update]}
> + map.permission :destroy_compute_resources_vms,
> {:compute_resources_vms => [:destroy]}
> + map.permission :power_compute_resources_vms,
> {:compute_resources_vms => [:power]}
> + end
> +
> map.security_block :config_templates do |map|
> map.permission :view_templates, {:config_templates => [:index,
> :show]}
> map.permission :create_templates, {:config_templates => [:new,
> :create]}
> @@ -75,6 +89,8 @@ Foreman::AccessControl.map do |map|
> :update_multiple_hostgroup,
> :update_multiple_parameters, :toggle_manage]}
> map.permission :destroy_hosts, {:hosts => [:destroy,
> :multiple_actions, :reset_multiple, :multiple_destroy,
> :submit_multiple_destroy]}
> map.permission :build_hosts, {:hosts => [:setBuild, :cancelBuild]}
> + map.permission :power_hosts, {:hosts => [:power]}
> + map.permission :console_hosts, {:hosts => [:console]}
> end
>
> map.security_block :host_editing do |map|
> –
> 1.7.2.5
>
>
+1, however I'm missing some basic tests around this, any chance you could
add a few?
thanks!
···
On Mon, May 21, 2012 at 5:43 PM, Olivier Favre wrote: