From acfbc45886c4d81a2a3ca5af433a6124a0a7191a Mon Sep 17 00:00:00 2001 From: Marek Hulan Date: Wed, 20 Nov 2013 10:58:13 +0100 Subject: [PATCH] fixes #812 - new permissions model, user group role and nest support, role filters for better granularity Contributions from: * Daniel Lobato * Joseph Magen * Tom McKay * Greg Sutcliffe * Dominic Cleal --- .gitignore | 2 + Gemfile | 3 +- app/assets/javascripts/filters.js | 15 + app/controllers/about_controller.rb | 4 +- app/controllers/api/base_controller.rb | 39 +- .../api/v1/architectures_controller.rb | 4 +- app/controllers/api/v1/audits_controller.rb | 2 +- .../api/v1/common_parameters_controller.rb | 7 +- .../api/v1/compute_resources_controller.rb | 8 +- .../api/v1/config_templates_controller.rb | 10 +- app/controllers/api/v1/domains_controller.rb | 4 +- .../api/v1/environments_controller.rb | 4 +- .../api/v1/fact_values_controller.rb | 6 +- .../api/v1/hostgroups_controller.rb | 4 +- app/controllers/api/v1/hosts_controller.rb | 13 +- app/controllers/api/v1/images_controller.rb | 7 +- .../api/v1/lookup_keys_controller.rb | 6 +- app/controllers/api/v1/media_controller.rb | 4 +- app/controllers/api/v1/models_controller.rb | 5 +- .../api/v1/operatingsystems_controller.rb | 5 +- app/controllers/api/v1/ptables_controller.rb | 4 +- .../api/v1/puppetclasses_controller.rb | 4 +- app/controllers/api/v1/reports_controller.rb | 9 +- .../api/v1/smart_proxies_controller.rb | 13 +- .../api/v1/statistics_controller.rb | 32 +- app/controllers/api/v1/subnets_controller.rb | 4 +- .../api/v1/usergroups_controller.rb | 4 +- app/controllers/api/v1/users_controller.rb | 5 +- .../api/v2/architectures_controller.rb | 4 +- app/controllers/api/v2/audits_controller.rb | 5 +- .../api/v2/common_parameters_controller.rb | 7 +- .../api/v2/compute_resources_controller.rb | 15 +- .../api/v2/config_templates_controller.rb | 10 +- app/controllers/api/v2/domains_controller.rb | 4 +- .../api/v2/environments_controller.rb | 4 +- .../api/v2/fact_values_controller.rb | 5 +- app/controllers/api/v2/filters_controller.rb | 76 ++ .../api/v2/host_classes_controller.rb | 6 +- .../api/v2/hostgroups_controller.rb | 4 +- app/controllers/api/v2/hosts_controller.rb | 32 +- app/controllers/api/v2/images_controller.rb | 7 +- app/controllers/api/v2/media_controller.rb | 4 +- app/controllers/api/v2/models_controller.rb | 5 +- .../api/v2/operatingsystems_controller.rb | 5 +- .../api/v2/override_values_controller.rb | 1 + .../api/v2/parameters_controller.rb | 9 + .../api/v2/permissions_controller.rb | 32 + app/controllers/api/v2/ptables_controller.rb | 4 +- .../api/v2/puppetclasses_controller.rb | 2 +- app/controllers/api/v2/reports_controller.rb | 9 +- app/controllers/api/v2/roles_controller.rb | 1 - .../api/v2/smart_proxies_controller.rb | 13 +- .../api/v2/statistics_controller.rb | 32 +- app/controllers/api/v2/subnets_controller.rb | 4 +- .../v2/template_combinations_controller.rb | 2 +- .../api/v2/usergroups_controller.rb | 4 +- app/controllers/api/v2/users_controller.rb | 7 +- app/controllers/application_controller.rb | 41 +- app/controllers/architectures_controller.rb | 3 +- app/controllers/audits_controller.rb | 13 +- .../auth_source_ldaps_controller.rb | 8 +- app/controllers/autosign_controller.rb | 16 +- app/controllers/bookmarks_controller.rb | 2 +- .../common_parameters_controller.rb | 16 +- .../compute_profiles_controller.rb | 10 +- .../compute_resources_controller.rb | 19 +- .../compute_resources_vms_controller.rb | 24 +- .../import_puppetclasses_common_controller.rb | 8 +- .../api/v2/lookup_keys_common_controller.rb | 39 +- .../concerns/api/v2/taxonomies_controller.rb | 2 +- .../controller/taxonomies_controller.rb | 2 +- .../foreman/controller/taxonomy_multiple.rb | 10 +- .../foreman/controller/users_mixin.rb | 3 +- .../config_templates_controller.rb | 10 +- app/controllers/domains_controller.rb | 2 +- app/controllers/environments_controller.rb | 2 +- app/controllers/fact_values_controller.rb | 11 +- app/controllers/filters_controller.rb | 80 +++ app/controllers/hostgroups_controller.rb | 24 +- app/controllers/hosts_controller.rb | 86 ++- app/controllers/images_controller.rb | 6 +- app/controllers/lookup_keys_controller.rb | 17 +- app/controllers/media_controller.rb | 9 +- app/controllers/models_controller.rb | 7 +- .../operatingsystems_controller.rb | 10 +- app/controllers/permissions_controller.rb | 18 + app/controllers/ptables_controller.rb | 10 +- app/controllers/puppetca_controller.rb | 9 +- app/controllers/puppetclasses_controller.rb | 8 +- app/controllers/reports_controller.rb | 9 +- app/controllers/roles_controller.rb | 55 +- app/controllers/smart_proxies_controller.rb | 52 +- app/controllers/statistics_controller.rb | 24 +- app/controllers/subnets_controller.rb | 10 +- app/controllers/usergroups_controller.rb | 17 +- app/controllers/users_controller.rb | 13 +- app/helpers/ancestry_helper.rb | 6 +- app/helpers/application_helper.rb | 58 +- app/helpers/autosign_helper.rb | 2 +- app/helpers/bmc_helper.rb | 10 +- app/helpers/common_parameters_helper.rb | 8 +- app/helpers/compute_resources_helper.rb | 8 +- app/helpers/compute_resources_vms_helper.rb | 28 +- app/helpers/dashboard_helper.rb | 2 +- app/helpers/filters_helper.rb | 22 + app/helpers/hosts_and_hostgroups_helper.rb | 4 +- app/helpers/hosts_helper.rb | 21 +- app/helpers/layout_helper.rb | 18 +- app/models/architecture.rb | 2 +- app/models/auth_source.rb | 2 +- app/models/bookmark.rb | 2 + app/models/cached_user_role.rb | 10 + app/models/cached_usergroup_member.rb | 7 + app/models/compute_profile.rb | 3 +- app/models/compute_resource.rb | 32 +- .../compute_resources/foreman/model/ec2.rb | 2 +- .../foreman/model/libvirt.rb | 2 +- .../foreman/model/openstack.rb | 2 +- .../compute_resources/foreman/model/ovirt.rb | 2 +- .../foreman/model/rackspace.rb | 2 +- .../compute_resources/foreman/model/vmware.rb | 2 +- app/models/concerns/audit_extensions.rb | 2 + app/models/concerns/authorizable.rb | 23 + app/models/concerns/authorization.rb | 68 -- app/models/concerns/hostext/search.rb | 18 +- app/models/concerns/taxonomix.rb | 52 +- app/models/config_template.rb | 12 +- app/models/domain.rb | 21 +- app/models/environment.rb | 2 +- app/models/fact_value.rb | 6 +- app/models/filter.rb | 138 ++++ app/models/filtering.rb | 6 + app/models/host/base.rb | 37 +- app/models/host/managed.rb | 35 +- app/models/host_class.rb | 16 +- app/models/hostgroup.rb | 4 +- app/models/hostgroup_class.rb | 16 +- app/models/image.rb | 1 + app/models/lookup_key.rb | 2 +- app/models/lookup_value.rb | 22 +- app/models/medium.rb | 2 +- app/models/model.rb | 2 +- app/models/operatingsystem.rb | 2 +- app/models/operatingsystems/archlinux.rb | 1 + app/models/parameter.rb | 2 +- app/models/parameters/domain_parameter.rb | 17 - app/models/parameters/group_parameter.rb | 16 - app/models/parameters/host_parameter.rb | 10 - app/models/parameters/os_parameter.rb | 10 - app/models/permission.rb | 20 + app/models/ptable.rb | 2 +- app/models/puppetclass.rb | 2 +- app/models/report.rb | 17 +- app/models/role.rb | 80 ++- app/models/setting/general.rb | 1 + app/models/smart_proxy.rb | 10 +- app/models/subnet.rb | 2 +- app/models/taxonomy.rb | 3 +- app/models/template_combination.rb | 4 - app/models/user.rb | 58 +- app/models/user_role.rb | 48 +- app/models/usergroup.rb | 15 +- app/models/usergroup_member.rb | 108 +++ app/services/authorizer.rb | 136 ++++ app/services/cache_manager.rb | 23 + app/services/dashboard.rb | 2 +- app/services/foreman/access_permissions.rb | 31 +- app/services/foreman/plugin.rb | 9 +- app/views/about/index.html.erb | 4 +- app/views/api/v2/filters/base.json.rabl | 3 + app/views/api/v2/filters/create.json.rabl | 3 + app/views/api/v2/filters/index.json.rabl | 3 + app/views/api/v2/filters/main.json.rabl | 5 + app/views/api/v2/filters/show.json.rabl | 20 + app/views/api/v2/permissions/base.json.rabl | 3 + app/views/api/v2/permissions/index.json.rabl | 3 + app/views/api/v2/permissions/main.json.rabl | 3 + app/views/api/v2/permissions/show.json.rabl | 3 + app/views/api/v2/roles/main.json.rabl | 2 +- app/views/api/v2/roles/show.json.rabl | 4 + app/views/architectures/index.html.erb | 6 +- app/views/audits/show.html.erb | 4 +- app/views/autosign/index.html.erb | 5 +- app/views/common_parameters/index.html.erb | 5 +- app/views/compute_profiles/index.html.erb | 8 +- app/views/compute_profiles/show.html.erb | 2 +- app/views/compute_resources/index.html.erb | 4 +- app/views/compute_resources/show.html.erb | 6 +- .../compute_resources_vms/index/_ec2.html.erb | 5 +- .../compute_resources_vms/index/_gce.html.erb | 5 +- .../index/_libvirt.html.erb | 6 +- .../index/_ovirt.html.erb | 6 +- .../index/_rackspace.html.erb | 4 +- .../index/_vmware.html.erb | 10 +- app/views/compute_resources_vms/show.html.erb | 4 +- app/views/config_templates/index.html.erb | 4 +- app/views/domains/index.html.erb | 4 +- app/views/environments/index.html.erb | 6 +- app/views/filters/_form.html.erb | 69 ++ app/views/filters/edit.html.erb | 3 + app/views/filters/index.html.erb | 48 ++ app/views/filters/new.html.erb | 3 + app/views/hostgroups/index.html.erb | 4 +- app/views/hosts/_form.html.erb | 8 +- app/views/hosts/_list.html.erb | 8 +- app/views/hosts/_provisioning.html.erb | 2 +- app/views/hosts/edit.html.erb | 4 +- app/views/lookup_keys/index.html.erb | 7 +- app/views/media/index.html.erb | 5 +- app/views/models/index.html.erb | 5 +- app/views/operatingsystems/index.html.erb | 5 +- app/views/permissions/index.js.erb | 20 + app/views/ptables/index.html.erb | 4 +- .../puppetclasses/_class_selection.html.erb | 2 +- app/views/puppetclasses/_classes.html.erb | 2 +- app/views/puppetclasses/index.html.erb | 7 +- app/views/reports/_list.html.erb | 11 +- app/views/roles/_form.html.erb | 33 +- app/views/roles/index.html.erb | 15 +- app/views/roles/report.html.erb | 52 -- app/views/smart_proxies/_form.html.erb | 8 +- app/views/smart_proxies/index.html.erb | 16 +- app/views/subnets/index.html.erb | 4 +- app/views/usergroups/_form.html.erb | 23 +- app/views/usergroups/index.html.erb | 5 +- app/views/users/_filters.html.erb | 2 +- app/views/users/_form.html.erb | 10 - app/views/users/_user_fact.html.erb | 2 +- app/views/users/index.html.erb | 5 +- bundler.d/test.rb | 1 + config/application.rb | 1 + config/initializers/fix_cache.rb | 12 + config/initializers/foreman.rb | 4 - config/routes.rb | 22 +- config/routes/api/v2.rb | 17 +- db/migrate/20131114084718_extend_user_role.rb | 23 + ...20131114094841_create_cached_user_roles.rb | 15 + ...122093940_calculate_cache_for_user_role.rb | 10 + ...2170726_create_cached_usergroup_members.rb | 15 + ...31128150357_add_admin_flag_to_usergroup.rb | 5 + .../20131202120621_create_permissions.rb | 12 + db/migrate/20131202131847_create_filters.rb | 10 + .../20131202144415_create_filterings.rb | 13 + ..._foreign_keys_to_filters_and_filterings.rb | 13 + .../20140219183343_migrate_permissions.rb | 298 ++++++++ ...9183345_add_taxonomy_searches_to_filter.rb | 21 + db/seeds.d/05-architectures.rb | 5 + db/seeds.d/07-config_templates.rb | 59 ++ db/seeds.d/08-partition_tables.rb | 21 + db/seeds.d/10-installation_media.rb | 17 + db/seeds.d/11-smart_proxy_features.rb | 5 + db/seeds.d/12-auth_sources.rb | 17 + db/seeds.d/13-compute_profiles.rb | 13 + db/seeds.d/15-bookmarks.rb | 16 + db/seeds.d/20-permissions.rb | 152 ++++ db/seeds.d/25-roles.rb | 70 ++ db/seeds.rb | 173 +---- foreman.spec | 5 +- lib/core_extensions.rb | 43 ++ lib/foreman/default_data/loader.rb | 166 ----- lib/foreman/exception.rb | 3 + lib/tasks/backup.rake | 75 ++ lib/tasks/fix_cache.rake | 22 + lib/tasks/load_default_data.rake | 16 - test/factories/architecture.rb | 5 + test/factories/domain.rb | 6 + test/factories/taxonomies.rb | 9 + test/factories/user_related.rb | 80 +++ test/factories/usergroups.rb | 5 - test/fixtures/filterings.yml | 408 +++++++++++ test/fixtures/filters.yml | 134 ++++ test/fixtures/permissions.yml | 676 ++++++++++++++++++ test/fixtures/roles.yml | 160 ----- test/fixtures/user_facts.yml | 8 - test/fixtures/user_roles.yml | 8 +- .../v1/compute_resources_controller_test.rb | 41 +- .../v1/config_templates_controller_test.rb | 18 +- .../api/v1/hosts_controller_test.rb | 54 +- .../api/v1/smart_proxies_controller_test.rb | 6 +- .../api/v1/statistics_controller_test.rb | 8 +- .../api/v1/users_controller_test.rb | 4 +- .../v2/compute_resources_controller_test.rb | 43 +- .../api/v2/filters_controller_test.rb | 40 ++ .../api/v2/hosts_controller_test.rb | 49 +- .../v2/operatingsystems_controller_test.rb | 2 - .../api/v2/override_values_controller_test.rb | 10 +- .../api/v2/parameters_controller_test.rb | 16 +- .../api/v2/statistics_controller_test.rb | 19 +- .../api/v2/users_controller_test.rb | 4 +- .../compute_resources_controller_test.rb | 24 +- .../compute_resources_vms_controller_test.rb | 30 +- test/functional/hostgroups_controller_test.rb | 13 +- test/functional/hosts_controller_test.rb | 115 +-- test/functional/roles_controller_test.rb | 88 +-- test/functional/users_controller_test.rb | 21 +- test/integration/host_test.rb | 4 +- test/test_helper.rb | 37 +- test/unit/architecture_test.rb | 70 +- test/unit/auth_source_ldap_test.rb | 55 -- test/unit/authorizer_test.rb | 248 +++++++ test/unit/cached_user_role_test.rb | 7 + test/unit/cached_usergroup_member_test.rb | 7 + test/unit/common_parameter_test.rb | 54 -- test/unit/compute_resource_test.rb | 81 --- test/unit/domain_parameter_test.rb | 76 +- test/unit/domain_test.rb | 77 -- test/unit/ensure_no_cycle_test.rb | 57 ++ test/unit/filter_test.rb | 157 ++++ test/unit/group_parameter_test.rb | 76 -- test/unit/helpers/host_groups_helper_test.rb | 1 + test/unit/host_class_test.rb | 43 -- test/unit/host_parameter_test.rb | 79 -- test/unit/host_test.rb | 209 +----- test/unit/hostgroup_class_test.rb | 43 -- test/unit/hostgroup_test.rb | 59 +- test/unit/lookup_value_test.rb | 60 +- test/unit/medium_test.rb | 61 -- test/unit/model_test.rb | 61 -- test/unit/operatingsystem_test.rb | 62 -- test/unit/permission_test.rb | 18 + test/unit/ptable_test.rb | 61 -- test/unit/puppetclass_test.rb | 80 +-- test/unit/report_test.rb | 42 -- test/unit/role_test.rb | 88 ++- test/unit/subnet_test.rb | 64 -- test/unit/user_role_test.rb | 85 +++ test/unit/user_test.rb | 80 +-- test/unit/usergroup_member_test.rb | 368 ++++++++++ test/unit/usergroup_test.rb | 70 +- 329 files changed, 5865 insertions(+), 3407 deletions(-) create mode 100644 app/assets/javascripts/filters.js create mode 100644 app/controllers/api/v2/filters_controller.rb create mode 100644 app/controllers/api/v2/permissions_controller.rb create mode 100644 app/controllers/filters_controller.rb create mode 100644 app/controllers/permissions_controller.rb create mode 100644 app/helpers/filters_helper.rb create mode 100644 app/models/cached_user_role.rb create mode 100644 app/models/cached_usergroup_member.rb create mode 100644 app/models/concerns/authorizable.rb delete mode 100644 app/models/concerns/authorization.rb create mode 100644 app/models/filter.rb create mode 100644 app/models/filtering.rb create mode 100644 app/models/permission.rb create mode 100644 app/services/authorizer.rb create mode 100644 app/services/cache_manager.rb create mode 100644 app/views/api/v2/filters/base.json.rabl create mode 100644 app/views/api/v2/filters/create.json.rabl create mode 100644 app/views/api/v2/filters/index.json.rabl create mode 100644 app/views/api/v2/filters/main.json.rabl create mode 100644 app/views/api/v2/filters/show.json.rabl create mode 100644 app/views/api/v2/permissions/base.json.rabl create mode 100644 app/views/api/v2/permissions/index.json.rabl create mode 100644 app/views/api/v2/permissions/main.json.rabl create mode 100644 app/views/api/v2/permissions/show.json.rabl create mode 100644 app/views/filters/_form.html.erb create mode 100644 app/views/filters/edit.html.erb create mode 100644 app/views/filters/index.html.erb create mode 100644 app/views/filters/new.html.erb create mode 100644 app/views/permissions/index.js.erb delete mode 100644 app/views/roles/report.html.erb create mode 100644 config/initializers/fix_cache.rb create mode 100644 db/migrate/20131114084718_extend_user_role.rb create mode 100644 db/migrate/20131114094841_create_cached_user_roles.rb create mode 100644 db/migrate/20131122093940_calculate_cache_for_user_role.rb create mode 100644 db/migrate/20131122170726_create_cached_usergroup_members.rb create mode 100644 db/migrate/20131128150357_add_admin_flag_to_usergroup.rb create mode 100644 db/migrate/20131202120621_create_permissions.rb create mode 100644 db/migrate/20131202131847_create_filters.rb create mode 100644 db/migrate/20131202144415_create_filterings.rb create mode 100644 db/migrate/20140110164135_add_foreign_keys_to_filters_and_filterings.rb create mode 100644 db/migrate/20140219183343_migrate_permissions.rb create mode 100644 db/migrate/20140219183345_add_taxonomy_searches_to_filter.rb create mode 100644 db/seeds.d/05-architectures.rb create mode 100644 db/seeds.d/07-config_templates.rb create mode 100644 db/seeds.d/08-partition_tables.rb create mode 100644 db/seeds.d/10-installation_media.rb create mode 100644 db/seeds.d/11-smart_proxy_features.rb create mode 100644 db/seeds.d/12-auth_sources.rb create mode 100644 db/seeds.d/13-compute_profiles.rb create mode 100644 db/seeds.d/15-bookmarks.rb create mode 100644 db/seeds.d/20-permissions.rb create mode 100644 db/seeds.d/25-roles.rb delete mode 100644 lib/foreman/default_data/loader.rb create mode 100644 lib/tasks/backup.rake create mode 100644 lib/tasks/fix_cache.rake delete mode 100644 lib/tasks/load_default_data.rake create mode 100644 test/factories/architecture.rb create mode 100644 test/factories/domain.rb create mode 100644 test/factories/taxonomies.rb create mode 100644 test/factories/user_related.rb delete mode 100644 test/factories/usergroups.rb create mode 100644 test/fixtures/filterings.yml create mode 100644 test/fixtures/filters.yml create mode 100644 test/fixtures/permissions.yml create mode 100644 test/functional/api/v2/filters_controller_test.rb create mode 100644 test/unit/authorizer_test.rb create mode 100644 test/unit/cached_user_role_test.rb create mode 100644 test/unit/cached_usergroup_member_test.rb create mode 100644 test/unit/ensure_no_cycle_test.rb create mode 100644 test/unit/filter_test.rb create mode 100644 test/unit/permission_test.rb create mode 100644 test/unit/user_role_test.rb create mode 100644 test/unit/usergroup_member_test.rb diff --git a/.gitignore b/.gitignore index 2b8191857f2..d7b5a6bfa97 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,5 @@ locale/*/LC_MESSAGES coverage/ tags _build +zeus.json +custom_plan.rb diff --git a/Gemfile b/Gemfile index a4cb4aa8469..6f7dfd80e77 100644 --- a/Gemfile +++ b/Gemfile @@ -11,12 +11,13 @@ gem 'rest-client', :require => 'rest_client' gem "audited-activerecord", "3.0.0" gem "will_paginate", "~> 3.0.2" gem "ancestry", "~> 2.0" -gem 'scoped_search', '>= 2.5' +gem 'scoped_search', '>= 2.6.2' gem 'net-ldap' gem 'uuidtools' gem "apipie-rails", "~> 0.0.23" gem 'rabl', '>= 0.7.5', '<= 0.9.0' gem 'oauth' +gem 'deep_cloneable' gem 'foreigner', '~> 1.4.2' if RUBY_VERSION =~ /^1\.8/ diff --git a/app/assets/javascripts/filters.js b/app/assets/javascripts/filters.js new file mode 100644 index 00000000000..ef04743c515 --- /dev/null +++ b/app/assets/javascripts/filters.js @@ -0,0 +1,15 @@ +$(document).ready(function () { + $('#filter_resource_type').change(function () { + $.ajax({ + url: $(this).data('url'), + data: { + resource_type: $('#filter_resource_type').val() + }, + dataType: "script" + }); + }); + + $('#filter_unlimited').change(function () { + $('#search').prop('disabled', $(this).prop('checked')); + }); +}); diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb index e1acf765617..94b5e23e834 100644 --- a/app/controllers/about_controller.rb +++ b/app/controllers/about_controller.rb @@ -2,8 +2,8 @@ class AboutController < ApplicationController skip_before_filter :authorize, :only => :index def index - @proxies = SmartProxy.my_proxies.includes(:features) - @compute_resources = ComputeResource.my_compute_resources + @smart_proxies = SmartProxy.authorized(:view_smart_proxies).includes(:features) + @compute_resources = ComputeResource.authorized(:view_compute_resources) @plugins = Foreman::Plugin.all end diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index c58ea9104c9..824f4b9bf6c 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -43,8 +43,15 @@ def resource_class @resource_class ||= resource_name.classify.constantize end - def resource_scope - @resource_scope ||= resource_class.scoped + def resource_scope(controller = controller_name) + @resource_scope ||= begin + scope = resource_class.scoped + if resource_class.respond_to?(:authorized) + scope.authorized("#{action_permission}_#{controller}", resource_class) + else + scope + end + end end def api_request? @@ -138,14 +145,15 @@ def resource_identifying_attributes # # example: # @host = Host.find_resource params[:id] - def find_resource + def find_resource(controller = controller_name) resource = resource_identifying_attributes.find do |key| next if key=='name' and (params[:id] =~ /\A\d+\z/) method = "find_by_#{key}" id = key=='id' ? params[:id].to_i : params[:id] - resource_scope.respond_to?(method) and - (resource = resource_scope.send method, id) and - break resource + scope = resource_scope(controller) + if scope.respond_to?(method) + (resource = scope.send method, id) and break resource + end end if resource @@ -219,7 +227,10 @@ def find_nested_object if allowed_nested_id.include?(param) resource_identifying_attributes.each do |key| find_method = "find_by_#{key}" - @nested_obj ||= md[1].classify.constantize.send(find_method, params[param]) + model = md[1].classify.constantize + controller = "#{md[1].pluralize}_#{controller_name}" + authorized_scope = model.authorized("#{action_permission}_#{controller}") + @nested_obj ||= authorized_scope.send(find_method, params[param]) end else # there should be a route error before getting here, but just in case, @@ -250,5 +261,19 @@ def skip_nested_id [] end + def action_permission + case params[:action] + when 'new', 'create' + 'create' + when 'edit', 'update' + 'edit' + when 'destroy' + 'destroy' + when 'index', 'show', 'status' + 'view' + else + raise ::Foreman::Exception.new(N_("unknown permission for %s"), "#{params[:controller]}##{params[:action]}") + end + end end end diff --git a/app/controllers/api/v1/architectures_controller.rb b/app/controllers/api/v1/architectures_controller.rb index 545075ddbde..0a0c57a2232 100644 --- a/app/controllers/api/v1/architectures_controller.rb +++ b/app/controllers/api/v1/architectures_controller.rb @@ -10,7 +10,9 @@ class ArchitecturesController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @architectures = Architecture.includes(:operatingsystems). + @architectures = Architecture. + authorized(:view_architectures). + includes(:operatingsystems). search_for(*search_options).paginate(paginate_options) end diff --git a/app/controllers/api/v1/audits_controller.rb b/app/controllers/api/v1/audits_controller.rb index d070811e6be..56d2f0b4a98 100644 --- a/app/controllers/api/v1/audits_controller.rb +++ b/app/controllers/api/v1/audits_controller.rb @@ -12,7 +12,7 @@ class AuditsController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - Audit.unscoped { @audits = Audit.search_for(*search_options).paginate(paginate_options) } + Audit.unscoped { @audits = Audit.authorized(:view_audit_logs).search_for(*search_options).paginate(paginate_options) } end api :GET, "/audits/:id/", "Show an audit" diff --git a/app/controllers/api/v1/common_parameters_controller.rb b/app/controllers/api/v1/common_parameters_controller.rb index 51fb944b56e..e61f6dc3b07 100644 --- a/app/controllers/api/v1/common_parameters_controller.rb +++ b/app/controllers/api/v1/common_parameters_controller.rb @@ -1,7 +1,7 @@ module Api module V1 class CommonParametersController < V1::BaseController - before_filter :find_resource, :only => [:show, :update, :destroy] + before_filter(:only => %w{show update destroy}) { find_resource('globals') } api :GET, "/common_parameters/", "List all common parameters." param :search, String, :desc => "filter results" @@ -10,7 +10,10 @@ class CommonParametersController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @common_parameters = CommonParameter.search_for(*search_options).paginate(paginate_options) + @common_parameters = CommonParameter. + authorized(:view_globals). + search_for(*search_options). + paginate(paginate_options) end api :GET, "/common_parameters/:id/", "Show a common parameter." diff --git a/app/controllers/api/v1/compute_resources_controller.rb b/app/controllers/api/v1/compute_resources_controller.rb index a956319b3b1..7bf52596cc6 100644 --- a/app/controllers/api/v1/compute_resources_controller.rb +++ b/app/controllers/api/v1/compute_resources_controller.rb @@ -10,7 +10,9 @@ class ComputeResourcesController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @compute_resources = ComputeResource.my_compute_resources.search_for(*search_options).paginate(paginate_options) + @compute_resources = ComputeResource. + authorized(:view_compute_resources). + search_for(*search_options).paginate(paginate_options) end api :GET, "/compute_resources/:id/", "Show an compute resource." @@ -66,10 +68,6 @@ def destroy process_response @compute_resource.destroy end - def resource_scope - resource_class.my_compute_resources - end - end end end diff --git a/app/controllers/api/v1/config_templates_controller.rb b/app/controllers/api/v1/config_templates_controller.rb index c7885430bb4..9a655b43031 100644 --- a/app/controllers/api/v1/config_templates_controller.rb +++ b/app/controllers/api/v1/config_templates_controller.rb @@ -3,7 +3,7 @@ module V1 class ConfigTemplatesController < V1::BaseController include Foreman::Renderer - before_filter :find_resource, :only => [:show, :update, :destroy] + before_filter(:only => %w{show update destroy}) { find_resource('templates') } before_filter :handle_template_upload, :only => [:create, :update] before_filter :process_template_kind, :only => [:create, :update] @@ -14,7 +14,9 @@ class ConfigTemplatesController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @config_templates = ConfigTemplate.search_for(*search_options).paginate(paginate_options). + @config_templates = ConfigTemplate. + authorized(:view_templates). + search_for(*search_options).paginate(paginate_options). includes(:operatingsystems, :template_combinations, :template_kind) end @@ -61,7 +63,7 @@ def update param :version, String, :desc => "template version" def revision - audit = Audit.find(params[:version]) + audit = Audit.authorized(:view_audit_logs).find(params[:version]) render :json => audit.revision.template end @@ -75,7 +77,7 @@ def destroy api :GET, "/config_templates/build_pxe_default", "Change the default PXE menu on all configured TFTP servers" def build_pxe_default - status, msg = ConfigTemplate.build_pxe_default(self) + status, msg = ConfigTemplate.authorized(:deploy_templates).build_pxe_default(self) render :json => msg, :status => status end diff --git a/app/controllers/api/v1/domains_controller.rb b/app/controllers/api/v1/domains_controller.rb index def3a6d2a9d..02ad341c956 100644 --- a/app/controllers/api/v1/domains_controller.rb +++ b/app/controllers/api/v1/domains_controller.rb @@ -22,7 +22,9 @@ class DomainsController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @domains = Domain.search_for(*search_options).paginate(paginate_options) + @domains = Domain. + authorized(:view_domains). + search_for(*search_options).paginate(paginate_options) end api :GET, "/domains/:id/", "Show a domain." diff --git a/app/controllers/api/v1/environments_controller.rb b/app/controllers/api/v1/environments_controller.rb index 3fafb2f8c90..23bbf5152fb 100644 --- a/app/controllers/api/v1/environments_controller.rb +++ b/app/controllers/api/v1/environments_controller.rb @@ -12,7 +12,9 @@ class EnvironmentsController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @environments = Environment.search_for(*search_options).paginate(paginate_options) + @environments = Environment. + authorized(:view_environments). + search_for(*search_options).paginate(paginate_options) end api :GET, "/environments/:id/", "Show an environment." diff --git a/app/controllers/api/v1/fact_values_controller.rb b/app/controllers/api/v1/fact_values_controller.rb index 65b990ff382..0d2cf4255b5 100644 --- a/app/controllers/api/v1/fact_values_controller.rb +++ b/app/controllers/api/v1/fact_values_controller.rb @@ -1,7 +1,6 @@ module Api module V1 class FactValuesController < V1::BaseController - before_filter :find_resource, :only => %w{show update destroy} before_filter :setup_search_options, :only => :index api :GET, "/fact_values/", "List all fact values." @@ -12,7 +11,10 @@ class FactValuesController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - values = FactValue.my_facts.no_timestamp_facts. + values = FactValue. + authorized(:view_facts). + my_facts. + no_timestamp_facts. search_for(*search_options).paginate(paginate_options). includes(:fact_name, :host) render :json => FactValue.build_facts_hash(values.all) diff --git a/app/controllers/api/v1/hostgroups_controller.rb b/app/controllers/api/v1/hostgroups_controller.rb index f57b9012c71..019d3c11322 100644 --- a/app/controllers/api/v1/hostgroups_controller.rb +++ b/app/controllers/api/v1/hostgroups_controller.rb @@ -10,7 +10,9 @@ class HostgroupsController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @hostgroups = Hostgroup.includes(:hostgroup_classes, :group_parameters). + @hostgroups = Hostgroup. + authorized(:view_hostgroups). + includes(:hostgroup_classes, :group_parameters). search_for(*search_options).paginate(paginate_options) end diff --git a/app/controllers/api/v1/hosts_controller.rb b/app/controllers/api/v1/hosts_controller.rb index 014a59a4c66..3da4e895418 100644 --- a/app/controllers/api/v1/hosts_controller.rb +++ b/app/controllers/api/v1/hosts_controller.rb @@ -10,7 +10,9 @@ class HostsController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @hosts = Host.my_hosts.search_for(*search_options).paginate(paginate_options) + @hosts = Host. + authorized(:view_hosts, Host). + search_for(*search_options).paginate(paginate_options) end api :GET, "/hosts/:id/", "Show a host." @@ -121,13 +123,12 @@ def status render :json => { :status => @host.host_status }.to_json if @host end - # we need to limit resources for a current user - def resource_scope - resource_class.my_hosts - end - private + def resource_scope(controller = controller_name) + Host.authorized("#{action_permission}_#{controller}", Host) + end + # this is required for template generation (such as pxelinux) which is not done via a web request def forward_request_url @host.request_url = request.host_with_port if @host.respond_to?(:request_url) diff --git a/app/controllers/api/v1/images_controller.rb b/app/controllers/api/v1/images_controller.rb index 269ee76a1e0..a0298d42843 100644 --- a/app/controllers/api/v1/images_controller.rb +++ b/app/controllers/api/v1/images_controller.rb @@ -12,7 +12,10 @@ class ImagesController < V1::BaseController param :compute_resource_id, :identifier, :required => true def index - @images = @compute_resource.images.search_for(*search_options).paginate(paginate_options) + @images = @compute_resource. + images. + authorized(:view_images). + search_for(*search_options).paginate(paginate_options) end api :GET, "/compute_resources/:compute_resource_id/images/:id/", "Show an image" @@ -65,7 +68,7 @@ def destroy private def find_compute_resource - @compute_resource = ComputeResource.find(params[:compute_resource_id]) + @compute_resource = ComputeResource.authorized(:view_compute_resources).find(params[:compute_resource_id]) end end diff --git a/app/controllers/api/v1/lookup_keys_controller.rb b/app/controllers/api/v1/lookup_keys_controller.rb index 328593e740e..b85ca5b085e 100644 --- a/app/controllers/api/v1/lookup_keys_controller.rb +++ b/app/controllers/api/v1/lookup_keys_controller.rb @@ -1,7 +1,7 @@ module Api module V1 class LookupKeysController < V1::BaseController - before_filter :find_resource, :only => %w{show update destroy} + before_filter(:only => %w{show update destroy}) { find_resource('external_variables') } before_filter :setup_search_options, :only => :index api :GET, "/lookup_keys/", "List all lookup_keys." @@ -11,7 +11,9 @@ class LookupKeysController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @lookup_keys = LookupKey.search_for(*search_options).paginate(paginate_options) + @lookup_keys = LookupKey. + authorized(:view_external_variables). + search_for(*search_options).paginate(paginate_options) end api :GET, "/lookup_keys/:id/", "Show a lookup key." diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb index 58c484929b5..1e1d3a51023 100644 --- a/app/controllers/api/v1/media_controller.rb +++ b/app/controllers/api/v1/media_controller.rb @@ -30,7 +30,9 @@ class MediaController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @media = Medium.search_for(*search_options).paginate(paginate_options) + @media = Medium. + authorized(:view_media). + search_for(*search_options).paginate(paginate_options) end api :GET, "/media/:id/", "Show a medium." diff --git a/app/controllers/api/v1/models_controller.rb b/app/controllers/api/v1/models_controller.rb index e7d5d831c81..4defc36d76d 100644 --- a/app/controllers/api/v1/models_controller.rb +++ b/app/controllers/api/v1/models_controller.rb @@ -10,7 +10,10 @@ class ModelsController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @models = Model.search_for(*search_options).paginate(paginate_options) + @models = Model. + authorized(:view_models). + search_for(*search_options). + paginate(paginate_options) end api :GET, "/models/:id/", "Show a model." diff --git a/app/controllers/api/v1/operatingsystems_controller.rb b/app/controllers/api/v1/operatingsystems_controller.rb index dbe2687859b..5e76efddff8 100644 --- a/app/controllers/api/v1/operatingsystems_controller.rb +++ b/app/controllers/api/v1/operatingsystems_controller.rb @@ -16,6 +16,7 @@ class OperatingsystemsController < V1::BaseController def index @operatingsystems = Operatingsystem. + authorized(:view_operatingsystems). includes(:media, :architectures, :ptables, :config_templates, :os_default_templates). search_for(*search_options).paginate(paginate_options) end @@ -69,8 +70,8 @@ def destroy param :architecture, String def bootfiles - medium = Medium.find_by_name(params[:medium]) - arch = Architecture.find_by_name(params[:architecture]) + medium = Medium.authorized(:view_media).find_by_name(params[:medium]) + arch = Architecture.authorized(:view_architectures).find_by_name(params[:architecture]) render :json => @operatingsystem.pxe_files(medium, arch) rescue => e render :json => e.to_s, :status => :unprocessable_entity diff --git a/app/controllers/api/v1/ptables_controller.rb b/app/controllers/api/v1/ptables_controller.rb index ef7c86bc9dc..e873b5ba55e 100644 --- a/app/controllers/api/v1/ptables_controller.rb +++ b/app/controllers/api/v1/ptables_controller.rb @@ -10,7 +10,9 @@ class PtablesController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @ptables = Ptable.search_for(*search_options).paginate(paginate_options) + @ptables = Ptable. + authorized(:view_ptables). + search_for(*search_options).paginate(paginate_options) end api :GET, "/ptables/:id/", "Show a ptable." diff --git a/app/controllers/api/v1/puppetclasses_controller.rb b/app/controllers/api/v1/puppetclasses_controller.rb index e49cf8f0f2e..31f388e76c0 100644 --- a/app/controllers/api/v1/puppetclasses_controller.rb +++ b/app/controllers/api/v1/puppetclasses_controller.rb @@ -12,7 +12,9 @@ class PuppetclassesController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - values = Puppetclass.search_for(*search_options).paginate(paginate_options). + values = Puppetclass. + authorized(:view_puppetclasses). + search_for(*search_options).paginate(paginate_options). select([:name, :id]). includes(:lookup_keys) render :json => Puppetclass.classes2hash(values.all) diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index 89001a01629..6117c4b084d 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -11,7 +11,10 @@ class ReportsController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @reports = Report.my_reports.includes(:logs => [:source, :message]). + @reports = Report. + authorized(:view_reports). + my_reports. + includes(:logs => [:source, :message]). search_for(*search_options).paginate(paginate_options) end @@ -33,8 +36,8 @@ def destroy def last conditions = { :host_id => Host.find_by_name(params[:host_id]).try(:id) } unless params[:host_id].blank? - max_id = Report.my_reports.where(conditions).maximum(:id) - @report = Report.includes(:logs => [:message, :source]).find(max_id) + max_id = Report.authorized(:view_reports).my_reports.where(conditions).maximum(:id) + @report = Report.authorized(:view_reports).includes(:logs => [:message, :source]).find(max_id) render :show end diff --git a/app/controllers/api/v1/smart_proxies_controller.rb b/app/controllers/api/v1/smart_proxies_controller.rb index b5342e446f2..1f03d3e1f18 100644 --- a/app/controllers/api/v1/smart_proxies_controller.rb +++ b/app/controllers/api/v1/smart_proxies_controller.rb @@ -58,9 +58,18 @@ def refresh end private + def action_permission + case params[:action] + when 'refresh' + :edit + else + super + end + end + def proxies_by_type(type) - return SmartProxy.includes(:features).try(type.downcase+"_proxies") if not type.nil? - return SmartProxy.includes(:features).all + return SmartProxy.authorized(:view_smart_proxies).includes(:features).try(type.downcase+"_proxies") if not type.nil? + return SmartProxy.authorized(:view_smart_proxies).includes(:features).all end def check_feature_type diff --git a/app/controllers/api/v1/statistics_controller.rb b/app/controllers/api/v1/statistics_controller.rb index a56e533aaa8..e70fd087dbf 100644 --- a/app/controllers/api/v1/statistics_controller.rb +++ b/app/controllers/api/v1/statistics_controller.rb @@ -6,22 +6,22 @@ class StatisticsController < V1::BaseController api :GET, "/statistics/", "Get statistics" def index - @os_count = Host.my_hosts.count_distribution :operatingsystem - @arch_count = Host.my_hosts.count_distribution :architecture - @env_count = Host.my_hosts.count_distribution :environment - @klass_count = Host.my_hosts.count_habtm "puppetclass" - @cpu_count = FactValue.my_facts.count_each "processorcount" - @model_count = FactValue.my_facts.count_each "manufacturer" - @mem_size = FactValue.my_facts.mem_average "memorysize" - @mem_free = FactValue.my_facts.mem_average "memoryfree" - @swap_size = FactValue.my_facts.mem_average "swapsize" - @swap_free = FactValue.my_facts.mem_average "swapfree" - @mem_totsize = FactValue.my_facts.mem_sum "memorysize" - @mem_totfree = FactValue.my_facts.mem_sum "memoryfree" - render :json => { :statistics => { :os_count => @os_count, :arch_count => @arch_count, - :env_count => @env_count, :klass_count => @klass_count, :cpu_count => @cpu_count, - :model_count => @model_count, :mem_size => @mem_size, :mem_free => @mem_free, :swap_size => @swap_size, - :swap_free => @swap_free, :mem_totsize => @mem_totsize, :mem_totfree => @mem_totfree } } + @os_count = Host.authorized(:view_hosts).count_distribution :operatingsystem + @arch_count = Host.authorized(:view_hosts).count_distribution :architecture + @env_count = Host.authorized(:view_hosts).count_distribution :environment + @klass_count = Host.authorized(:view_hosts).count_habtm "puppetclass" + @cpu_count = FactValue.authorized(:view_facts).my_facts.count_each "processorcount" + @model_count = FactValue.authorized(:view_facts).my_facts.count_each "manufacturer" + @mem_size = FactValue.authorized(:view_facts).my_facts.mem_average "memorysize" + @mem_free = FactValue.authorized(:view_facts).my_facts.mem_average "memoryfree" + @swap_size = FactValue.authorized(:view_facts).my_facts.mem_average "swapsize" + @swap_free = FactValue.authorized(:view_facts).my_facts.mem_average "swapfree" + @mem_totsize = FactValue.authorized(:view_facts).my_facts.mem_sum "memorysize" + @mem_totfree = FactValue.authorized(:view_facts).my_facts.mem_sum "memoryfree" + render :json => { :os_count => @os_count, :arch_count => @arch_count, :swap_size => @swap_size, + :env_count => @env_count, :klass_count => @klass_count, :cpu_count => @cpu_count, + :model_count => @model_count, :mem_size => @mem_size, :mem_free => @mem_free, + :swap_free => @swap_free, :mem_totsize => @mem_totsize, :mem_totfree => @mem_totfree } end end diff --git a/app/controllers/api/v1/subnets_controller.rb b/app/controllers/api/v1/subnets_controller.rb index d79b0341813..5ef0dcc9105 100644 --- a/app/controllers/api/v1/subnets_controller.rb +++ b/app/controllers/api/v1/subnets_controller.rb @@ -11,7 +11,9 @@ class SubnetsController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @subnets = Subnet.includes(:tftp, :dhcp, :dns). + @subnets = Subnet. + authorized(:view_subnets). + includes(:tftp, :dhcp, :dns). search_for(*search_options).paginate(paginate_options) end diff --git a/app/controllers/api/v1/usergroups_controller.rb b/app/controllers/api/v1/usergroups_controller.rb index eafefc62a8b..bc96d1c5921 100644 --- a/app/controllers/api/v1/usergroups_controller.rb +++ b/app/controllers/api/v1/usergroups_controller.rb @@ -10,7 +10,9 @@ class UsergroupsController < V1::BaseController param :order, String, :desc => "sort results" def index - @usergroups = Usergroup.search_for(*search_options).paginate(paginate_options) + @usergroups = Usergroup. + authorized(:view_usergroups). + search_for(*search_options).paginate(paginate_options) end api :GET, "/usergroups/:id/", "Show a usergroup." diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index 2827aac8dd1..0a0944d360e 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -12,14 +12,15 @@ class UsersController < V1::BaseController param :per_page, String, :desc => "number of entries per request" def index - @users = User.search_for(*search_options).paginate(paginate_options) + @users = User. + authorized(:view_users). + search_for(*search_options).paginate(paginate_options) end api :GET, "/users/:id/", "Show an user." param :id, String, :required => true def show - @user end api :POST, "/users/", "Create an user." diff --git a/app/controllers/api/v2/architectures_controller.rb b/app/controllers/api/v2/architectures_controller.rb index 6c701b8a8cc..ce560a1ee26 100644 --- a/app/controllers/api/v2/architectures_controller.rb +++ b/app/controllers/api/v2/architectures_controller.rb @@ -10,7 +10,9 @@ class ArchitecturesController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @architectures = Architecture.includes(:operatingsystems). + @architectures = Architecture. + authorized(:view_architectures). + includes(:operatingsystems). search_for(*search_options).paginate(paginate_options) end diff --git a/app/controllers/api/v2/audits_controller.rb b/app/controllers/api/v2/audits_controller.rb index 59612f4f2fb..402ceb85fb9 100644 --- a/app/controllers/api/v2/audits_controller.rb +++ b/app/controllers/api/v2/audits_controller.rb @@ -1,7 +1,8 @@ module Api module V2 class AuditsController < V2::BaseController - before_filter :find_resource, :only => %w{show update destroy} + before_filter :find_resource, :only => %w{show} + before_filter(:only => %w{show}) { find_resource('audit_logs') } before_filter :setup_search_options, :only => :index api :GET, "/audits/", "List all audits." @@ -12,7 +13,7 @@ class AuditsController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - Audit.unscoped { @audits = Audit.search_for(*search_options).paginate(paginate_options) } + Audit.unscoped { @audits = Audit.authorized(:view_audit_logs).search_for(*search_options).paginate(paginate_options) } end api :GET, "/audits/:id/", "Show an audit" diff --git a/app/controllers/api/v2/common_parameters_controller.rb b/app/controllers/api/v2/common_parameters_controller.rb index 18fcc2a291b..2e9dce23cc1 100644 --- a/app/controllers/api/v2/common_parameters_controller.rb +++ b/app/controllers/api/v2/common_parameters_controller.rb @@ -2,7 +2,7 @@ module Api module V2 class CommonParametersController < V2::BaseController - before_filter :find_resource, :only => [:show, :update, :destroy] + before_filter(:only => %w{show update destroy}) { find_resource('globals') } api :GET, "/common_parameters/", "List all common parameters." param :search, String, :desc => "filter results" @@ -11,7 +11,10 @@ class CommonParametersController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @common_parameters = CommonParameter.search_for(*search_options).paginate(paginate_options) + @common_parameters = CommonParameter. + authorized(:view_globals). + search_for(*search_options). + paginate(paginate_options) end api :GET, "/common_parameters/:id/", "Show a common parameter." diff --git a/app/controllers/api/v2/compute_resources_controller.rb b/app/controllers/api/v2/compute_resources_controller.rb index c579fe37df6..dc4f1af2426 100644 --- a/app/controllers/api/v2/compute_resources_controller.rb +++ b/app/controllers/api/v2/compute_resources_controller.rb @@ -43,8 +43,8 @@ def show param_group :compute_resource, :as => :create def create - @compute_resource = ComputeResource.new_provider(params[:compute_resource]) - process_response @compute_resource.save + @compute_resource = ComputeResource.new_provider(params[:compute_resource]) + process_response @compute_resource.save end @@ -91,8 +91,15 @@ def available_storage_domains render :available_storage_domains, :layout => 'api/v2/layouts/index_layout' end - def resource_scope - ComputeResource.my_compute_resources + private + + def action_permission + case params[:action] + when 'available_images', 'available_clusters', 'available_networks', 'available_storage_domains' + :view + else + super + end end end end diff --git a/app/controllers/api/v2/config_templates_controller.rb b/app/controllers/api/v2/config_templates_controller.rb index 7492db45b5a..a6cc00096e5 100644 --- a/app/controllers/api/v2/config_templates_controller.rb +++ b/app/controllers/api/v2/config_templates_controller.rb @@ -5,7 +5,7 @@ class ConfigTemplatesController < V2::BaseController include Api::TaxonomyScope include Foreman::Renderer - before_filter :find_resource, :only => [:show, :update, :destroy] + before_filter(:only => %w{show update destroy}) { find_resource('templates') } before_filter :handle_template_upload, :only => [:create, :update] before_filter :process_template_kind, :only => [:create, :update] before_filter :process_operatingsystems, :only => [:create, :update] @@ -17,7 +17,9 @@ class ConfigTemplatesController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @config_templates = ConfigTemplate.search_for(*search_options).paginate(paginate_options). + @config_templates = ConfigTemplate. + authorized(:view_templates). + search_for(*search_options).paginate(paginate_options). includes(:operatingsystems, :template_combinations, :template_kind) end @@ -60,7 +62,7 @@ def update param :version, String, :desc => "template version" def revision - audit = Audit.find(params[:version]) + audit = Audit.authorized(:view_audit_logs).find(params[:version]) render :json => audit.revision.template end @@ -74,7 +76,7 @@ def destroy api :GET, "/config_templates/build_pxe_default", "Change the default PXE menu on all configured TFTP servers" def build_pxe_default - status, msg = ConfigTemplate.build_pxe_default(self) + status, msg = ConfigTemplate.authorized(:deploy_templates).build_pxe_default(self) render :json => msg, :status => status end diff --git a/app/controllers/api/v2/domains_controller.rb b/app/controllers/api/v2/domains_controller.rb index c2ec7d90bcb..5b6583e4b5c 100644 --- a/app/controllers/api/v2/domains_controller.rb +++ b/app/controllers/api/v2/domains_controller.rb @@ -26,7 +26,9 @@ class DomainsController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @domains = Domain.search_for(*search_options).paginate(paginate_options) + @domains = Domain. + authorized(:view_domains). + search_for(*search_options).paginate(paginate_options) end api :GET, "/domains/:id/", "Show a domain." diff --git a/app/controllers/api/v2/environments_controller.rb b/app/controllers/api/v2/environments_controller.rb index 972f25b9b13..c06afd08746 100644 --- a/app/controllers/api/v2/environments_controller.rb +++ b/app/controllers/api/v2/environments_controller.rb @@ -14,7 +14,9 @@ class EnvironmentsController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @environments = Environment.search_for(*search_options).paginate(paginate_options) + @environments = Environment. + authorized(:view_environments). + search_for(*search_options).paginate(paginate_options) end api :GET, "/environments/:id/", "Show an environment." diff --git a/app/controllers/api/v2/fact_values_controller.rb b/app/controllers/api/v2/fact_values_controller.rb index deacb9cdcd0..e2719256025 100644 --- a/app/controllers/api/v2/fact_values_controller.rb +++ b/app/controllers/api/v2/fact_values_controller.rb @@ -1,7 +1,6 @@ module Api module V2 class FactValuesController < V2::BaseController - before_filter :find_resource, :only => %w{show update destroy} before_filter :setup_search_options, :only => :index api :GET, "/fact_values/", "List all fact values." @@ -16,8 +15,8 @@ def index @fact_values = FactValue.build_facts_hash(values.all) end - def resource_scope - FactValue.my_facts.no_timestamp_facts + def resource_scope(controller = controller_name) + FactValue.authorized(:view_facts).my_facts.no_timestamp_facts end end diff --git a/app/controllers/api/v2/filters_controller.rb b/app/controllers/api/v2/filters_controller.rb new file mode 100644 index 00000000000..de10cf7c1ed --- /dev/null +++ b/app/controllers/api/v2/filters_controller.rb @@ -0,0 +1,76 @@ +module Api + module V2 + class FiltersController < V2::BaseController + include Api::Version2 + include Api::TaxonomyScope + + before_filter :find_role + before_filter :find_resource, :only => %w{show update destroy} + + api :GET, "/filters/", "List all filters." + param :search, String, :desc => "filter results", :required => false + param :page, String, :desc => "paginate results" + param :per_page, String, :desc => "number of entries per request" + + def index + @filters = resource_scope.search_for(*search_options).paginate(paginate_options) + end + + api :GET, "/filters/:id/", "Show a filter." + param :id, :identifier, :required => true + + def show + end + + def_param_group :filter do + param :filter, Hash, :action_aware => true, :required => true do + param :role_id, String, :required => true + param :search, String + param :permission_ids, Array + param :organization_ids, Array + param :location_ids, Array + end + end + + api :POST, "/filters/", "Create a filter." + param_group :filter, :as => :create + + def create + @filter = Filter.new(params[:filter]) + process_response @filter.save + end + + api :PUT, "/filters/:id/", "Update a filter." + param :id, String, :required => true + param_group :filter + + def update + process_response @filter.update_attributes(params[:filter]) + end + + api :DELETE, "/filters/:id/", "Delete a filter." + param :id, String, :required => true + + def destroy + process_response @filter.destroy + end + + private + + def find_role + @role = Role.find_by_id(role_id) + end + + def resource_scope(controller = controller_name) + @resource_scope ||= @role.present? ? + @role.filters.authorized("#{action_permission}_#{controller}") : + resource_class.scoped.authorized("#{action_permission}_#{controller}") + end + + def role_id + params[:role_id] + end + + end + end +end diff --git a/app/controllers/api/v2/host_classes_controller.rb b/app/controllers/api/v2/host_classes_controller.rb index c44a18683ba..c3dc41b2bfd 100644 --- a/app/controllers/api/v2/host_classes_controller.rb +++ b/app/controllers/api/v2/host_classes_controller.rb @@ -10,7 +10,7 @@ class HostClassesController < V2::BaseController api :GET, "/hosts/:host_id/puppetclass_ids/", "List all puppetclass id's for host" def index - render :json => { root_node_name => HostClass.where(:host_id => host_id).pluck('puppetclass_id') } + render :json => { root_node_name => HostClass.authorized(:edit_classes).where(:host_id => host_id).pluck('puppetclass_id') } end api :POST, "/hosts/:host_id/puppetclass_ids", "Add a puppetclass to host" @@ -27,7 +27,7 @@ def create param :id, String, :required => true, :desc => "id of puppetclass" def destroy - @host_class = HostClass.where(:host_id => host_id, :puppetclass_id => params[:id]) + @host_class = HostClass.authorized(:edit_classes).where(:host_id => host_id, :puppetclass_id => params[:id]) process_response @host_class.destroy_all end @@ -38,7 +38,7 @@ def find_host_id if params[:host_id] =~ /^\d+$/ return @host_id = params[:host_id].to_i else - @host ||= Host::Managed.find_by_name(params[:host_id]) + @host ||= Host::Managed.authorized(:view_hosts).find_by_name(params[:host_id]) return @host_id = @host.id if @host not_found end diff --git a/app/controllers/api/v2/hostgroups_controller.rb b/app/controllers/api/v2/hostgroups_controller.rb index 448178f5ce5..0ac7a2c8a39 100644 --- a/app/controllers/api/v2/hostgroups_controller.rb +++ b/app/controllers/api/v2/hostgroups_controller.rb @@ -14,7 +14,9 @@ class HostgroupsController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @hostgroups = Hostgroup.includes(:hostgroup_classes, :group_parameters). + @hostgroups = Hostgroup. + authorized(:view_hostgroups). + includes(:hostgroup_classes, :group_parameters). search_for(*search_options).paginate(paginate_options) end diff --git a/app/controllers/api/v2/hosts_controller.rb b/app/controllers/api/v2/hosts_controller.rb index 849924832d7..842e6184f43 100644 --- a/app/controllers/api/v2/hosts_controller.rb +++ b/app/controllers/api/v2/hosts_controller.rb @@ -7,7 +7,9 @@ class HostsController < V2::BaseController include Api::TaxonomyScope include Foreman::Controller::SmartProxyAuth - before_filter :find_resource, :except => [:index, :create, :facts] + before_filter :find_resource, :except => %w{index create facts} + before_filter :permissions_check, :only => %w{power boot puppetrun} + add_puppetmaster_filters :facts api :GET, "/hosts/", "List all hosts." @@ -104,11 +106,6 @@ def status render :json => { :status => @host.host_status }.to_json if @host end - # we need to limit resources for a current user - def resource_scope - Host.my_hosts - end - api :PUT, "/hosts/:id/puppetrun", "Force a puppet run on the agent." param :id, :identifier_dottable, :required => true @@ -158,6 +155,25 @@ def facts private + def resource_scope(controller = controller_name) + Host.authorized("#{action_permission}_#{controller}", Host) + end + + def action_permission + case params[:action] + when 'puppetrun' + :puppetrun + when 'power' + :power + when 'boot' + :ipmi_boot + when 'console' + :console + else + super + end + end + # this is required for template generation (such as pxelinux) which is not done via a web request def forward_request_url @host.request_url = request.host_with_port if @host.respond_to?(:request_url) @@ -175,6 +191,10 @@ def detect_host_type raise ::Foreman::Exception.new("A problem occurred when detecting host type: #{e.message}") end + def permissions_check + permission = "#{params[:action]}_hosts".to_sym + deny_access unless Host.authorized(permission).find(@host.id) + end end end end diff --git a/app/controllers/api/v2/images_controller.rb b/app/controllers/api/v2/images_controller.rb index 4b7c40ec390..acf77d58541 100644 --- a/app/controllers/api/v2/images_controller.rb +++ b/app/controllers/api/v2/images_controller.rb @@ -12,8 +12,9 @@ class ImagesController < V2::BaseController param :compute_resource_id, :identifier, :required => true def index - @images = @compute_resource.images.search_for(*search_options).paginate(paginate_options) - @total = @compute_resource.images.count + base = @compute_resource.images.authorized(:view_images) + @images = base.search_for(*search_options).paginate(paginate_options) + @total = base.count end api :GET, "/compute_resources/:compute_resource_id/images/:id/", "Show an image" @@ -63,7 +64,7 @@ def destroy private def find_compute_resource - @compute_resource = ComputeResource.find(params[:compute_resource_id]) + @compute_resource = ComputeResource.authorized(:view_compute_resources).find(params[:compute_resource_id]) end end diff --git a/app/controllers/api/v2/media_controller.rb b/app/controllers/api/v2/media_controller.rb index 847058c73e1..0788de4a2f8 100644 --- a/app/controllers/api/v2/media_controller.rb +++ b/app/controllers/api/v2/media_controller.rb @@ -34,7 +34,9 @@ class MediaController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @media = Medium.search_for(*search_options).paginate(paginate_options) + @media = Medium. + authorized(:view_media). + search_for(*search_options).paginate(paginate_options) end api :GET, "/media/:id/", "Show a medium." diff --git a/app/controllers/api/v2/models_controller.rb b/app/controllers/api/v2/models_controller.rb index ad9b17c84ac..25504fc80a5 100644 --- a/app/controllers/api/v2/models_controller.rb +++ b/app/controllers/api/v2/models_controller.rb @@ -10,7 +10,10 @@ class ModelsController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @models = Model.search_for(*search_options).paginate(paginate_options) + @models = Model. + authorized(:view_models). + search_for(*search_options). + paginate(paginate_options) end api :GET, "/models/:id/", "Show a model." diff --git a/app/controllers/api/v2/operatingsystems_controller.rb b/app/controllers/api/v2/operatingsystems_controller.rb index cc237dac797..99e673429a9 100644 --- a/app/controllers/api/v2/operatingsystems_controller.rb +++ b/app/controllers/api/v2/operatingsystems_controller.rb @@ -16,6 +16,7 @@ class OperatingsystemsController < V2::BaseController def index @operatingsystems = Operatingsystem. + authorized(:view_operatingsystems). includes(:media, :architectures, :ptables, :config_templates, :os_default_templates). search_for(*search_options).paginate(paginate_options) end @@ -66,8 +67,8 @@ def destroy param :architecture, String def bootfiles - medium = Medium.find_by_name(params[:medium]) - arch = Architecture.find_by_name(params[:architecture]) + medium = Medium.authorized(:view_media).find_by_name(params[:medium]) + arch = Architecture.authorized(:view_architectures).find_by_name(params[:architecture]) render :json => @operatingsystem.pxe_files(medium, arch) rescue => e render :json => e.to_s, :status => :unprocessable_entity diff --git a/app/controllers/api/v2/override_values_controller.rb b/app/controllers/api/v2/override_values_controller.rb index f033f40a78e..ecaba9f2366 100644 --- a/app/controllers/api/v2/override_values_controller.rb +++ b/app/controllers/api/v2/override_values_controller.rb @@ -63,6 +63,7 @@ def destroy render 'api/v2/override_values/show' end + private def find_override_values if @smart @override_values = @smart.lookup_values.paginate(paginate_options) diff --git a/app/controllers/api/v2/parameters_controller.rb b/app/controllers/api/v2/parameters_controller.rb index 68fb756a143..8f47ee17c1a 100644 --- a/app/controllers/api/v2/parameters_controller.rb +++ b/app/controllers/api/v2/parameters_controller.rb @@ -136,6 +136,15 @@ def reset private + def action_permission + case params[:action] + when 'reset' + :destroy + else + super + end + end + def parameters_method # hostgroup.rb has a method def parameters, so I didn't create has_many :parameters like Host, Domain, Os nested_obj.is_a?(Hostgroup) ? :group_parameters : :parameters diff --git a/app/controllers/api/v2/permissions_controller.rb b/app/controllers/api/v2/permissions_controller.rb new file mode 100644 index 00000000000..c043fa2ac8b --- /dev/null +++ b/app/controllers/api/v2/permissions_controller.rb @@ -0,0 +1,32 @@ +module Api + module V2 + class PermissionsController < V2::BaseController + before_filter :find_resource, :only => %w{show} + + api :GET, "/permissions/", "List all permissions." + param :page, String, :desc => "paginate results" + param :per_page, String, :desc => "number of entries per request" + param :resource_type, String + param :name, String + + def index + type = params[:resource_type].blank? ? nil : params[:resource_type] + name = params[:name].blank? ? nil : params[:name] + if type + @permissions = Permission.find_all_by_resource_type(type) + elsif name + @permissions = Permission.find_all_by_name(name) + else + @permissions = Permission.all + end + end + + api :GET, "/permissions/:id/", "Show a permission." + param :id, :identifier, :required => true + + def show + end + + end + end +end diff --git a/app/controllers/api/v2/ptables_controller.rb b/app/controllers/api/v2/ptables_controller.rb index ed239b0c879..832aefb2b5c 100644 --- a/app/controllers/api/v2/ptables_controller.rb +++ b/app/controllers/api/v2/ptables_controller.rb @@ -10,7 +10,9 @@ class PtablesController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @ptables = Ptable.search_for(*search_options).paginate(paginate_options) + @ptables = Ptable. + authorized(:view_ptables). + search_for(*search_options).paginate(paginate_options) end api :GET, "/ptables/:id/", "Show a ptable." diff --git a/app/controllers/api/v2/puppetclasses_controller.rb b/app/controllers/api/v2/puppetclasses_controller.rb index 8f868b1a2c7..c6a77fe1e74 100644 --- a/app/controllers/api/v2/puppetclasses_controller.rb +++ b/app/controllers/api/v2/puppetclasses_controller.rb @@ -21,7 +21,7 @@ class PuppetclassesController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - values = Puppetclass.search_for(*search_options) unless nested_obj + values = Puppetclass.authorized(:view_puppetclasses).search_for(*search_options) unless nested_obj values ||= case nested_obj when Host::Base, Hostgroup #NOTE: no search_for on array generated by all_puppetclasses diff --git a/app/controllers/api/v2/reports_controller.rb b/app/controllers/api/v2/reports_controller.rb index c8a95f79905..f81da8eaca2 100644 --- a/app/controllers/api/v2/reports_controller.rb +++ b/app/controllers/api/v2/reports_controller.rb @@ -15,7 +15,10 @@ class ReportsController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @reports = Report.my_reports.includes(:logs => [:source, :message]). + @reports = Report. + authorized(:view_reports). + my_reports. + includes(:logs => [:source, :message]). search_for(*search_options).paginate(paginate_options) @total = Report.my_reports.count end @@ -58,8 +61,8 @@ def destroy def last conditions = { :host_id => Host.find_by_name(params[:host_id]).try(:id) } unless params[:host_id].blank? - max_id = Report.my_reports.where(conditions).maximum(:id) - @report = Report.includes(:logs => [:message, :source]).find(max_id) + max_id = Report.authorized(:view_reports).my_reports.where(conditions).maximum(:id) + @report = Report.authorized(:view_reports).includes(:logs => [:message, :source]).find(max_id) render :show end diff --git a/app/controllers/api/v2/roles_controller.rb b/app/controllers/api/v2/roles_controller.rb index baa810ec706..835b762c397 100644 --- a/app/controllers/api/v2/roles_controller.rb +++ b/app/controllers/api/v2/roles_controller.rb @@ -1,7 +1,6 @@ module Api module V2 class RolesController < V2::BaseController - before_filter :require_admin before_filter :find_resource, :only => %w{show update destroy} api :GET, "/roles/", "List all roles." diff --git a/app/controllers/api/v2/smart_proxies_controller.rb b/app/controllers/api/v2/smart_proxies_controller.rb index 29b5012b8f2..3dfca2f5b30 100644 --- a/app/controllers/api/v2/smart_proxies_controller.rb +++ b/app/controllers/api/v2/smart_proxies_controller.rb @@ -63,8 +63,17 @@ def refresh private def proxies_by_type(type = nil) - return SmartProxy.includes(:features).try(type.downcase+"_proxies") if type.present? - return SmartProxy.includes(:features).scoped + return SmartProxy.authorized(:view_smart_proxies).includes(:features).try(type.downcase+"_proxies") if type.present? + return SmartProxy.authorized(:view_smart_proxies).includes(:features).scoped + end + + def action_permission + case params[:action] + when 'refresh' + :edit + else + super + end end def check_feature_type diff --git a/app/controllers/api/v2/statistics_controller.rb b/app/controllers/api/v2/statistics_controller.rb index 94a2ad5ca07..e059c8eaa78 100644 --- a/app/controllers/api/v2/statistics_controller.rb +++ b/app/controllers/api/v2/statistics_controller.rb @@ -6,22 +6,22 @@ class StatisticsController < V2::BaseController api :GET, "/statistics/", "Get statistics" def index - @os_count = Host.my_hosts.count_distribution :operatingsystem - @arch_count = Host.my_hosts.count_distribution :architecture - @env_count = Host.my_hosts.count_distribution :environment - @klass_count = Host.my_hosts.count_habtm "puppetclass" - @cpu_count = FactValue.my_facts.count_each "processorcount" - @model_count = FactValue.my_facts.count_each "manufacturer" - @mem_size = FactValue.my_facts.mem_average "memorysize" - @mem_free = FactValue.my_facts.mem_average "memoryfree" - @swap_size = FactValue.my_facts.mem_average "swapsize" - @swap_free = FactValue.my_facts.mem_average "swapfree" - @mem_totsize = FactValue.my_facts.mem_sum "memorysize" - @mem_totfree = FactValue.my_facts.mem_sum "memoryfree" - render :json => { :os_count => @os_count, :arch_count => @arch_count, - :env_count => @env_count, :klass_count => @klass_count, :cpu_count => @cpu_count, - :model_count => @model_count, :mem_size => @mem_size, :mem_free => @mem_free, :swap_size => @swap_size, - :swap_free => @swap_free, :mem_totsize => @mem_totsize, :mem_totfree => @mem_totfree } + @os_count = Host.authorized(:view_hosts).count_distribution :operatingsystem + @arch_count = Host.authorized(:view_hosts).count_distribution :architecture + @env_count = Host.authorized(:view_hosts).count_distribution :environment + @klass_count = Host.authorized(:view_hosts).count_habtm "puppetclass" + @cpu_count = FactValue.authorized(:view_facts).my_facts.count_each "processorcount" + @model_count = FactValue.authorized(:view_facts).my_facts.count_each "manufacturer" + @mem_size = FactValue.authorized(:view_facts).my_facts.mem_average "memorysize" + @mem_free = FactValue.authorized(:view_facts).my_facts.mem_average "memoryfree" + @swap_size = FactValue.authorized(:view_facts).my_facts.mem_average "swapsize" + @swap_free = FactValue.authorized(:view_facts).my_facts.mem_average "swapfree" + @mem_totsize = FactValue.authorized(:view_facts).my_facts.mem_sum "memorysize" + @mem_totfree = FactValue.authorized(:view_facts).my_facts.mem_sum "memoryfree" + render :json => { :os_count => @os_count, :arch_count => @arch_count, :swap_size => @swap_size, + :env_count => @env_count, :klass_count => @klass_count, :cpu_count => @cpu_count, + :model_count => @model_count, :mem_size => @mem_size, :mem_free => @mem_free, + :swap_free => @swap_free, :mem_totsize => @mem_totsize, :mem_totfree => @mem_totfree } end end diff --git a/app/controllers/api/v2/subnets_controller.rb b/app/controllers/api/v2/subnets_controller.rb index dd19b96f00f..cdababf52a6 100644 --- a/app/controllers/api/v2/subnets_controller.rb +++ b/app/controllers/api/v2/subnets_controller.rb @@ -14,7 +14,9 @@ class SubnetsController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @subnets = Subnet.includes(:tftp, :dhcp, :dns). + @subnets = Subnet. + authorized(:view_subnets). + includes(:tftp, :dhcp, :dns). search_for(*search_options).paginate(paginate_options) end diff --git a/app/controllers/api/v2/template_combinations_controller.rb b/app/controllers/api/v2/template_combinations_controller.rb index fc8cff5480e..3dd355be34d 100644 --- a/app/controllers/api/v2/template_combinations_controller.rb +++ b/app/controllers/api/v2/template_combinations_controller.rb @@ -36,7 +36,7 @@ def destroy end def find_parent_config_template - @config_template = ConfigTemplate.find(params[:config_template_id]) + @config_template = ConfigTemplate.authorized(:view_templates).find(params[:config_template_id]) not_found unless @config_template @config_template end diff --git a/app/controllers/api/v2/usergroups_controller.rb b/app/controllers/api/v2/usergroups_controller.rb index 9a251e103ea..79ca59592fd 100644 --- a/app/controllers/api/v2/usergroups_controller.rb +++ b/app/controllers/api/v2/usergroups_controller.rb @@ -10,7 +10,9 @@ class UsergroupsController < V2::BaseController param :order, String, :desc => "sort results" def index - @usergroups = Usergroup.search_for(*search_options).paginate(paginate_options) + @usergroups = Usergroup. + authorized(:view_usergroups). + search_for(*search_options).paginate(paginate_options) end api :GET, "/usergroups/:id/", "Show a usergroup." diff --git a/app/controllers/api/v2/users_controller.rb b/app/controllers/api/v2/users_controller.rb index af8c745330e..1f2af027f03 100644 --- a/app/controllers/api/v2/users_controller.rb +++ b/app/controllers/api/v2/users_controller.rb @@ -1,10 +1,10 @@ module Api module V2 class UsersController < V2::BaseController + before_filter :find_resource, :only => %w{show update destroy} include Foreman::Controller::UsersMixin include Api::Version2 include Api::TaxonomyScope - before_filter :find_resource, :only => %w{show update destroy} api :GET, "/users/", "List all users." param :search, String, :desc => "filter results" @@ -13,14 +13,15 @@ class UsersController < V2::BaseController param :per_page, String, :desc => "number of entries per request" def index - @users = User.search_for(*search_options).paginate(paginate_options) + @users = User. + authorized(:view_users). + search_for(*search_options).paginate(paginate_options) end api :GET, "/users/:id/", "Show an user." param :id, String, :required => true def show - @user end def_param_group :user do diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e79d97a05f5..390345b10f2 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -10,6 +10,7 @@ class ApplicationController < ActionController::Base # standard layout to all controllers helper 'layout' + helper_method :authorizer before_filter :require_ssl, :require_login before_filter :set_gettext_locale_db, :set_gettext_locale @@ -45,6 +46,10 @@ def authorize authorized ? true : deny_access end + def authorizer + @authorizer ||= Authorizer.new(User.current, :collection => instance_variable_get("@#{controller_name}")) + end + def deny_access (User.current.logged? || request.xhr?) ? render_403 : require_login end @@ -111,7 +116,7 @@ def set_admin_user end def model_of_controller - controller_path.singularize.camelize.gsub('/','::').constantize + @model_of_controller ||= controller_path.singularize.camelize.gsub('/','::').constantize end @@ -124,10 +129,38 @@ def find_by_name not_found and return if params[:id].blank? name = controller_name.singularize - model = model_of_controller - # determine if we are searching for a numerical id or plain name cond = "find" + (params[:id] =~ /\A\d+(-.+)?\Z/ ? "" : "_by_name") - not_found and return unless instance_variable_set("@#{name}", model.send(cond, params[:id])) + not_found and return unless instance_variable_set("@#{name}", resource_base.send(cond, params[:id])) + end + + def current_permission + [action_permission, controller_permission].join('_') + end + + def controller_permission + controller_name + end + + def action_permission + case params[:action] + when 'new', 'create' + 'create' + when 'edit', 'update' + 'edit' + when 'destroy' + 'destroy' + when 'index', 'show' + 'view' + else + raise ::Foreman::Exception.new(N_("unknown permission for %s"), "#{params[:controller]}##{params[:action]}") + end + end + + # not all models includes Authorizable so we detect whether we should apply authorized scope or not + def resource_base + @resource_base ||= model_of_controller.respond_to?(:authorized) ? + model_of_controller.authorized(current_permission) : + model_of_controller.scoped end def notice notice diff --git a/app/controllers/architectures_controller.rb b/app/controllers/architectures_controller.rb index ad8a7105e15..7e9604eb404 100644 --- a/app/controllers/architectures_controller.rb +++ b/app/controllers/architectures_controller.rb @@ -3,7 +3,8 @@ class ArchitecturesController < ApplicationController before_filter :find_by_name, :only => %w{edit update destroy} def index - @architectures = Architecture.includes(:operatingsystems).search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + base = resource_base.includes(:operatingsystems).search_for(params[:search], :order => params[:order]) + @architectures = base.paginate(:page => params[:page]) end def new diff --git a/app/controllers/audits_controller.rb b/app/controllers/audits_controller.rb index 7a0a3a1236e..ac1316dcef2 100644 --- a/app/controllers/audits_controller.rb +++ b/app/controllers/audits_controller.rb @@ -4,11 +4,18 @@ class AuditsController < ApplicationController before_filter :setup_search_options, :only => :index def index - Audit.unscoped { @audits = Audit.search_for(params[:search], :order => params[:order]).paginate :page => params[:page] } + Audit.unscoped { @audits = resource_base.search_for(params[:search], :order => params[:order]).paginate :page => params[:page] } end def show - @audit = Audit.find(params[:id]) - @history = Audit.descending.where(:auditable_id => @audit.auditable_id, :auditable_type => @audit.auditable_type) + @audit = resource_base.find(params[:id]) + @history = resource_base.descending.where(:auditable_id => @audit.auditable_id, :auditable_type => @audit.auditable_type) end + + private + + def controller_permission + 'audit_logs' + end + end diff --git a/app/controllers/auth_source_ldaps_controller.rb b/app/controllers/auth_source_ldaps_controller.rb index f5992ff9bc2..341f078a541 100644 --- a/app/controllers/auth_source_ldaps_controller.rb +++ b/app/controllers/auth_source_ldaps_controller.rb @@ -1,6 +1,8 @@ class AuthSourceLdapsController < ApplicationController + before_filter :find_by_name, :only => [:edit, :update, :destroy] + def index - @auth_source_ldaps = AuthSourceLdap.all + @auth_source_ldaps = resource_base.all end def new @@ -17,11 +19,9 @@ def create end def edit - @auth_source_ldap = AuthSourceLdap.find(params[:id]) end def update - @auth_source_ldap = AuthSourceLdap.find(params[:id]) # remove from hash :account_password if blank? params[:auth_source_ldap].except!(:account_password) if params[:auth_source_ldap][:account_password].blank? if @auth_source_ldap.update_attributes(params[:auth_source_ldap]) @@ -32,12 +32,10 @@ def update end def destroy - @auth_source_ldap = AuthSourceLdap.find(params[:id]) if @auth_source_ldap.destroy process_success else process_error end - end end diff --git a/app/controllers/autosign_controller.rb b/app/controllers/autosign_controller.rb index f4137149d74..ac205eec3cb 100644 --- a/app/controllers/autosign_controller.rb +++ b/app/controllers/autosign_controller.rb @@ -1,7 +1,9 @@ class AutosignController < ApplicationController - before_filter :find_proxy, :setup_proxy def index + @proxy = SmartProxy.authorized(:view_smart_proxies_autosign).find(params[:smart_proxy_id]) + setup_proxy + begin autosign = @api.autosign rescue => e @@ -12,9 +14,14 @@ def index end def new + @proxy = SmartProxy.authorized(:create_smart_proxies_autosign).find(params[:smart_proxy_id]) + setup_proxy end def create + @proxy = SmartProxy.authorized(:create_smart_proxies_autosign).find(params[:smart_proxy_id]) + setup_proxy + if @api.set_autosign(params[:id]) process_success({:success_redirect => smart_proxy_autosign_index_path(@proxy), :object_name => 'puppet autosign entry'}) else @@ -23,6 +30,9 @@ def create end def destroy + @proxy = SmartProxy.authorized(:destroy_smart_proxies_autosign).find(params[:smart_proxy_id]) + setup_proxy + if @api.del_autosign(params[:id]) process_success({:success_redirect => smart_proxy_autosign_index_path(@proxy), :object_name => 'puppet autosign entry'}) else @@ -32,10 +42,6 @@ def destroy private - def find_proxy - @proxy = SmartProxy.find(params[:smart_proxy_id]) - end - def setup_proxy @api = ProxyAPI::Puppetca.new({:url => @proxy.url}) end diff --git a/app/controllers/bookmarks_controller.rb b/app/controllers/bookmarks_controller.rb index ad08ec4256e..58f7f1db323 100644 --- a/app/controllers/bookmarks_controller.rb +++ b/app/controllers/bookmarks_controller.rb @@ -2,7 +2,7 @@ class BookmarksController < ApplicationController before_filter :find_by_name, :only => %w{show edit update destroy} def index - @bookmarks = Bookmark.paginate(:page => params[:page]) + @bookmarks = resource_base.paginate(:page => params[:page]) end def new diff --git a/app/controllers/common_parameters_controller.rb b/app/controllers/common_parameters_controller.rb index 51e819336bf..72bc99df271 100644 --- a/app/controllers/common_parameters_controller.rb +++ b/app/controllers/common_parameters_controller.rb @@ -1,8 +1,9 @@ class CommonParametersController < ApplicationController include Foreman::Controller::AutoCompleteSearch + before_filter :find_by_name, :only => [:edit, :update, :destroy] def index - @common_parameters = CommonParameter.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @common_parameters = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) end def new @@ -19,11 +20,9 @@ def create end def edit - @common_parameter = CommonParameter.find(params[:id]) end def update - @common_parameter = CommonParameter.find(params[:id]) if @common_parameter.update_attributes(params[:common_parameter]) process_success else @@ -32,11 +31,20 @@ def update end def destroy - @common_parameter = CommonParameter.find(params[:id]) if @common_parameter.destroy process_success else process_error end end + + private + + def controller_permission + 'globals' + end + + def resource_base + model_of_controller.authorized(current_permission, CommonParameter) + end end diff --git a/app/controllers/compute_profiles_controller.rb b/app/controllers/compute_profiles_controller.rb index 99f689b614b..252bd875fb7 100644 --- a/app/controllers/compute_profiles_controller.rb +++ b/app/controllers/compute_profiles_controller.rb @@ -1,10 +1,9 @@ class ComputeProfilesController < ApplicationController - include Foreman::Controller::AutoCompleteSearch - before_filter :find_compute_profile, :only => %w{edit show update destroy} + before_filter :find_by_name, :only => [:show, :edit, :update, :destroy] def index - @compute_profiles = ComputeProfile.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @compute_profiles = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) end def show @@ -42,10 +41,5 @@ def destroy end end - private - - def find_compute_profile - @compute_profile = ComputeProfile.find(params[:id]) - end end diff --git a/app/controllers/compute_resources_controller.rb b/app/controllers/compute_resources_controller.rb index c351706979a..17352c5c641 100644 --- a/app/controllers/compute_resources_controller.rb +++ b/app/controllers/compute_resources_controller.rb @@ -2,10 +2,10 @@ class ComputeResourcesController < ApplicationController include Foreman::Controller::AutoCompleteSearch AJAX_REQUESTS = %w{template_selected cluster_selected} before_filter :ajax_request, :only => AJAX_REQUESTS - before_filter :find_by_id, :only => [:show, :edit, :update, :destroy, :ping, :associate] + AJAX_REQUESTS + before_filter :find_by_name, :only => [:show, :edit, :associate, :update, :destroy, :ping] + AJAX_REQUESTS def index - @compute_resources = ComputeResource.my_compute_resources.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @compute_resources = resource_base.search_for(params[:search], :order => params[:order]).paginate :page => params[:page] end def new @@ -86,7 +86,7 @@ def test_connection # cr_id is posted from AJAX function. cr_id is nil if new Rails.logger.info "CR_ID IS #{params[:cr_id]}" if params[:cr_id].present? && params[:cr_id] != 'null' - @compute_resource = ComputeResource.find(params[:cr_id]) + @compute_resource = ComputeResource.authorized(:edit_compute_resources).find(params[:cr_id]) params[:compute_resource].delete(:password) if params[:compute_resource][:password].blank? @compute_resource.attributes = params[:compute_resource] else @@ -112,9 +112,14 @@ def cluster_selected private - def find_by_id - @compute_resource = ComputeResource.find(params[:id]) - not_found and return unless @compute_resource - deny_access and return unless ComputeResource.my_compute_resources.include?(@compute_resource) + def action_permission + case params[:action] + when 'associate' + 'edit' + when 'ping', 'template_selected', 'cluster_selected' + 'view' + else + super + end end end diff --git a/app/controllers/compute_resources_vms_controller.rb b/app/controllers/compute_resources_vms_controller.rb index 0e5fa6c6eff..658f3dffdd7 100644 --- a/app/controllers/compute_resources_vms_controller.rb +++ b/app/controllers/compute_resources_vms_controller.rb @@ -1,9 +1,9 @@ class ComputeResourcesVmsController < ApplicationController - before_filter :find_compute_resource - before_filter :find_vm, :only => [:show, :power, :pause, :console, :associate] def index + @compute_resource = find_compute_resource(:view_compute_resources_vms) @vms = @compute_resource.vms.all(params[:filters] || {}) + @authorizer = Authorizer.new(User.current, :collection => [@compute_resource]) respond_to do |format| format.html format.json { render :json => @vms } @@ -13,10 +13,12 @@ def index end def new + @compute_resource = find_compute_resource @vm = @compute_resource.new_vm end def create + @compute_resource = find_compute_resource if @compute_resource.create_vm params[:vm] process_success :success_redirect => compute_resource_vms_path(@compute_resource) else @@ -25,6 +27,8 @@ def create end def associate + @compute_resource = find_compute_resource(:edit_compute_resources) + @vm = find_vm if Host.where(:uuid => @vm.identity).any? process_error(:error_msg => _("VM already associated with a host"), :redirect => compute_resource_vm_path(:compute_resource_id => params[:compute_resource_id], :id => @vm.identity)) else @@ -41,6 +45,8 @@ def associate end def show + @compute_resource = find_compute_resource(:view_compute_resources_vms) + @vm = find_vm respond_to do |format| format.html format.json { render :json => @vm } @@ -48,14 +54,19 @@ def show end def power + @compute_resource = find_compute_resource(:power_compute_resources_vms) + @vm = find_vm run_vm_action(@vm.ready? ? :stop : :start) end def pause + @compute_resource = find_compute_resource(:power_compute_resources_vms) + @vm = find_vm run_vm_action(@vm.ready? ? :pause : :start) end def destroy + @compute_resource = find_compute_resource(:destroy_compute_resources_vms) if @compute_resource.destroy_vm params[:id] process_success({ :success_redirect => compute_resource_vms_path(@compute_resource) }) else @@ -64,6 +75,8 @@ def destroy end def console + @compute_resource = find_compute_resource(:console_compute_resources_vms) + @vm = find_vm @console = @compute_resource.console @vm.identity render case @console[:type] when 'spice' @@ -79,13 +92,12 @@ def console private - def find_compute_resource - @compute_resource = ComputeResource.find(params[:compute_resource_id]) - @compute_resource = ComputeResource.my_compute_resources.find(params[:compute_resource_id]) rescue deny_access + def find_compute_resource(permission = :view_compute_resources) + ComputeResource.authorized(permission).find(params[:compute_resource_id]) end def find_vm - @vm = @compute_resource.find_vm_by_uuid params[:id] + @compute_resource.find_vm_by_uuid params[:id] end def run_vm_action(action) diff --git a/app/controllers/concerns/api/import_puppetclasses_common_controller.rb b/app/controllers/concerns/api/import_puppetclasses_common_controller.rb index 19225dc9a18..c8ac305e476 100644 --- a/app/controllers/concerns/api/import_puppetclasses_common_controller.rb +++ b/app/controllers/concerns/api/import_puppetclasses_common_controller.rb @@ -90,8 +90,8 @@ def changed_environments def find_required_puppet_proxy id = params.keys.include?('smart_proxy_id') ? params['smart_proxy_id'] : params['id'] - @smart_proxy = SmartProxy.find_by_id(id.to_i) if id.to_i > 0 - @smart_proxy ||= SmartProxy.find_by_name(id) + @smart_proxy = SmartProxy.authorized(:view_smart_proxies).find_by_id(id.to_i) if id.to_i > 0 + @smart_proxy ||= SmartProxy.authorized(:view_smart_proxies).find_by_name(id) unless @smart_proxy && SmartProxy.puppet_proxies.pluck("smart_proxies.id").include?(@smart_proxy.id) not_found 'We did not find a foreman proxy that can provide the information, ensure that this proxy has the puppet feature turned on.' end @@ -108,8 +108,8 @@ def get_environment_id end def find_optional_environment - @environment = Environment.find_by_id(@env_id.to_i) if @env_id.to_i > 0 - @environment ||= Environment.find_by_name(@env_id) + @environment = Environment.authorized(:view_environments).find_by_id(@env_id.to_i) if @env_id.to_i > 0 + @environment ||= Environment.authorized(:view_environments).find_by_name(@env_id) @environment end diff --git a/app/controllers/concerns/api/v2/lookup_keys_common_controller.rb b/app/controllers/concerns/api/v2/lookup_keys_common_controller.rb index ed491ecba79..ce4a679dc0d 100644 --- a/app/controllers/concerns/api/v2/lookup_keys_common_controller.rb +++ b/app/controllers/concerns/api/v2/lookup_keys_common_controller.rb @@ -44,34 +44,34 @@ def smart_class_parameter_id? end def find_puppetclass - @puppetclass = Puppetclass.find_by_id(params['puppetclass_id'].to_i) if params['puppetclass_id'].to_i > 0 - @puppetclass ||= Puppetclass.find_by_name(params['puppetclass_id']) + @puppetclass = Puppetclass.authorized(:view_puppetclasses).find_by_id(params['puppetclass_id'].to_i) if params['puppetclass_id'].to_i > 0 + @puppetclass ||= Puppetclass.authorized(:view_puppetclasses).find_by_name(params['puppetclass_id']) @puppetclass end def find_environment - @environment = Environment.find_by_id(params['environment_id'].to_i) if params['environment_id'].to_i > 0 - @environment ||= Environment.find_by_name(params['environment_id']) + @environment = Environment.authorized(:view_environments).find_by_id(params['environment_id'].to_i) if params['environment_id'].to_i > 0 + @environment ||= Environment.authorized(:view_environments).find_by_name(params['environment_id']) @environment end def find_host - @host = Host::Base.find_by_id(params['host_id'].to_i) if params['host_id'].to_i > 0 - @host ||= Host::Base.find_by_name(params['host_id']) + @host = Host::Base.authorized(:view_hosts).find_by_id(params['host_id'].to_i) if params['host_id'].to_i > 0 + @host ||= Host::Base.authorized(:view_hosts).find_by_name(params['host_id']) @host end def find_hostgroup - @hostgroup = Hostgroup.find_by_id(params['hostgroup_id'].to_i) if params['hostgroup_id'].to_i > 0 - @hostgroup ||= Hostgroup.find_by_name(params['hostgroup_id']) + @hostgroup = Hostgroup.authorized(:view_hostgroups).find_by_id(params['hostgroup_id'].to_i) if params['hostgroup_id'].to_i > 0 + @hostgroup ||= Hostgroup.authorized(:view_hostgroups).find_by_name(params['hostgroup_id']) @hostgroup end def find_smart_variable id = params.keys.include?('smart_variable_id') ? params['smart_variable_id'] : params['id'] - @smart_variable = LookupKey.smart_variables.find_by_id(id.to_i) if id.to_i > 0 + @smart_variable = LookupKey.authorized(:view_external_variables).smart_variables.find_by_id(id.to_i) if id.to_i > 0 @smart_variable ||= (puppet_cond = { :puppetclass_id => @puppetclass.id } if @puppetclass - LookupKey.smart_variables.where(puppet_cond).find_by_key(id) + LookupKey.authorized(:view_external_variables).smart_variables.where(puppet_cond).find_by_key(id) ) @smart_variable end @@ -81,19 +81,19 @@ def find_smart_variables end def smart_variables_resource_scope - return LookupKey.smart_variables unless (@puppetclass || @host || @hostgroup) + return LookupKey.authorized(:view_external_variables).smart_variables unless (@puppetclass || @host || @hostgroup) puppetclass_ids = @puppetclass.id if @puppetclass puppetclass_ids ||= @hostgroup.all_puppetclasses.map(&:id) if @hostgroup puppetclass_ids ||= @host.all_puppetclasses.map(&:id) if @host - LookupKey.global_parameters_for_class(puppetclass_ids) + LookupKey.authorized(:view_external_variables).global_parameters_for_class(puppetclass_ids) end def find_smart_class_parameter id = params.keys.include?('smart_class_parameter_id') ? params['smart_class_parameter_id'] : params['id'] - @smart_class_parameter = LookupKey.smart_class_parameters.find_by_id(id.to_i) if id.to_i > 0 + @smart_class_parameter = LookupKey.authorized(:view_external_variables).smart_class_parameters.find_by_id(id.to_i) if id.to_i > 0 @smart_class_parameter ||= (puppet_cond = { 'environment_classes.puppetclass_id'=> @puppetclass.id } if @puppetclass env_cond = { 'environment_classes.environment_id' => @environment.id } if @environment - LookupKey.smart_class_parameters.where(puppet_cond).where(env_cond).where(:key => id).first + LookupKey.authorized(:view_external_variables).smart_class_parameters.where(puppet_cond).where(env_cond).where(:key => id).first ) @smart_class_parameter end @@ -103,20 +103,21 @@ def find_smart_class_parameters end def smart_class_parameters_resource_scope - return LookupKey.smart_class_parameters unless (@puppetclass || @environment || @host || @hostgroup) + base = LookupKey.authorized(:view_external_variables) + return base.smart_class_parameters unless (@puppetclass || @environment || @host || @hostgroup) if @puppetclass && @environment - LookupKey.smart_class_parameters_for_class(@puppetclass.id, @environment.id) + base.smart_class_parameters_for_class(@puppetclass.id, @environment.id) elsif @puppetclass && !@environment environment_ids = @puppetclass.environment_classes.pluck(:environment_id).uniq - LookupKey.smart_class_parameters_for_class(@puppetclass.id, environment_ids) + base.smart_class_parameters_for_class(@puppetclass.id, environment_ids) elsif !@puppetclass && @environment puppetclass_ids = @environment.environment_classes.pluck(:puppetclass_id).uniq - LookupKey.smart_class_parameters_for_class(puppetclass_ids, @environment.id) + base.smart_class_parameters_for_class(puppetclass_ids, @environment.id) elsif @host || @hostgroup puppetclass_ids = (@host || @hostgroup).all_puppetclasses.map(&:id) environment_id = (@host || @hostgroup).environment_id # scope :parameters_for_class uses .override - LookupKey.parameters_for_class(puppetclass_ids, environment_id) + base.parameters_for_class(puppetclass_ids, environment_id) end end diff --git a/app/controllers/concerns/api/v2/taxonomies_controller.rb b/app/controllers/concerns/api/v2/taxonomies_controller.rb index e89cceb508f..078054f4f34 100644 --- a/app/controllers/concerns/api/v2/taxonomies_controller.rb +++ b/app/controllers/concerns/api/v2/taxonomies_controller.rb @@ -100,7 +100,7 @@ def find_taxonomy end def allowed_nested_id - %w(domain_id compute_resource_id subnet_id environment_id hostgroup_id smart_proxy_id user_id medium_id organization_id location_id) + %w(domain_id compute_resource_id subnet_id environment_id hostgroup_id smart_proxy_id user_id medium_id organization_id location_id filter_id) end end diff --git a/app/controllers/concerns/foreman/controller/taxonomies_controller.rb b/app/controllers/concerns/foreman/controller/taxonomies_controller.rb index bb95515f454..825447b4646 100644 --- a/app/controllers/concerns/foreman/controller/taxonomies_controller.rb +++ b/app/controllers/concerns/foreman/controller/taxonomies_controller.rb @@ -135,7 +135,7 @@ def import_mismatches def assign_hosts @taxonomy_type = taxonomy_single.classify - @hosts = Host.my_hosts.send("no_#{taxonomy_single}").includes(included_associations).search_for(params[:search],:order => params[:order]).paginate(:page => params[:page]) + @hosts = Host.authorized(:view_hosts, Host).send("no_#{taxonomy_single}").includes(included_associations).search_for(params[:search],:order => params[:order]).paginate(:page => params[:page]) render "hosts/assign_hosts" end diff --git a/app/controllers/concerns/foreman/controller/taxonomy_multiple.rb b/app/controllers/concerns/foreman/controller/taxonomy_multiple.rb index 9f0316c5ee1..8f4b2b963ff 100644 --- a/app/controllers/concerns/foreman/controller/taxonomy_multiple.rb +++ b/app/controllers/concerns/foreman/controller/taxonomy_multiple.rb @@ -8,20 +8,20 @@ module Foreman::Controller::TaxonomyMultiple end def select_multiple_organization - find_multiple + @hosts = find_multiple end def select_multiple_location - find_multiple + @hosts = find_multiple end def update_multiple_organization - find_multiple + @hosts = find_multiple update_multiple_taxonomies(:organization) end def update_multiple_location - find_multiple + @hosts = find_multiple update_multiple_taxonomies(:location) end @@ -53,4 +53,4 @@ def update_multiple_taxonomies type redirect_back_or_to hosts_path end -end \ No newline at end of file +end diff --git a/app/controllers/concerns/foreman/controller/users_mixin.rb b/app/controllers/concerns/foreman/controller/users_mixin.rb index 63def79836b..e038b003791 100644 --- a/app/controllers/concerns/foreman/controller/users_mixin.rb +++ b/app/controllers/concerns/foreman/controller/users_mixin.rb @@ -13,7 +13,6 @@ def set_admin_on_creation end def clear_params_on_update - find_resource if params[:user] @admin = params[:user].has_key?(:admin) ? params[:user].delete(:admin) : nil # Remove keys for restricted variables when the user is editing their own account @@ -44,4 +43,4 @@ def update_sub_hostgroups_owners sub_hg = Hostgroup.where(:id => hostgroup_ids).map(&:subtree).flatten.reject { |hg| hg.user_ids.include?(@user.id) } sub_hg.each { |hg| hg.users << @user } end -end \ No newline at end of file +end diff --git a/app/controllers/config_templates_controller.rb b/app/controllers/config_templates_controller.rb index 2cc030e5d6a..e29a4813903 100644 --- a/app/controllers/config_templates_controller.rb +++ b/app/controllers/config_templates_controller.rb @@ -2,12 +2,12 @@ class ConfigTemplatesController < ApplicationController include Foreman::Controller::AutoCompleteSearch include Foreman::Renderer - before_filter :find_by_id, :only => [:edit, :update, :destroy] - before_filter :load_history, :only => :edit before_filter :handle_template_upload, :only => [:create, :update] + before_filter :find_by_name, :only => [:edit, :update, :destroy] + before_filter :load_history, :only => :edit def index - @config_templates = ConfigTemplate.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]).includes(:template_kind, :template_combinations => [:hostgroup, :environment]) + @config_templates = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]).includes(:template_kind, :template_combinations => [:hostgroup, :environment]) end def new @@ -72,7 +72,7 @@ def default_template_url template, hostgroup :id => template.name, :hostgroup => hostgroup.name end - def find_by_id - @config_template = ConfigTemplate.find(params[:id]) + def controller_permission + 'templates' end end diff --git a/app/controllers/domains_controller.rb b/app/controllers/domains_controller.rb index 66fa9d662ae..619111b65e1 100644 --- a/app/controllers/domains_controller.rb +++ b/app/controllers/domains_controller.rb @@ -3,7 +3,7 @@ class DomainsController < ApplicationController before_filter :find_by_name, :only => %w{edit update destroy} def index - @domains = Domain.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @domains = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) @host_counter = Host.group(:domain_id).where(:domain_id => @domains.select(&:id)).count end diff --git a/app/controllers/environments_controller.rb b/app/controllers/environments_controller.rb index b62e759640f..5fd5e0be47f 100644 --- a/app/controllers/environments_controller.rb +++ b/app/controllers/environments_controller.rb @@ -5,7 +5,7 @@ class EnvironmentsController < ApplicationController before_filter :find_by_name, :only => %w{edit update destroy} def index - @environments = Environment.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @environments = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) @host_counter = Host.group(:environment_id).where(:environment_id => @environments.select(&:id)).count end diff --git a/app/controllers/fact_values_controller.rb b/app/controllers/fact_values_controller.rb index 97ee081bd27..65f441d0152 100644 --- a/app/controllers/fact_values_controller.rb +++ b/app/controllers/fact_values_controller.rb @@ -4,11 +4,12 @@ class FactValuesController < ApplicationController before_filter :setup_search_options, :only => :index def index + base = resource_base.no_timestamp_facts begin - values = FactValue.my_facts.search_for(params[:search], :order => params[:order]) + values = base.my_facts.search_for(params[:search], :order => params[:order]) rescue => e error e.to_s - values = FactValue.search_for "" + values = base.search_for "" end conds = (original_search_parameter || '').split(/AND|OR/i) @@ -26,4 +27,10 @@ def index @fact_values = values.no_timestamp_facts.required_fields.paginate :page => params[:page] end + private + + def controller_permission + 'facts' + end + end diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb new file mode 100644 index 00000000000..8d52ad04963 --- /dev/null +++ b/app/controllers/filters_controller.rb @@ -0,0 +1,80 @@ +class FiltersController < ApplicationController + include Foreman::Controller::AutoCompleteSearch + + before_filter :find_role + before_filter :setup_search_options, :only => :index + + def index + @filters = resource_base.includes(:role, :permissions).search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @roles_authorizer = Authorizer.new(User.current, :collection => @filters.map(&:role_id)) + end + + def new + @filter = resource_base.build + end + + def create + @filter = Filter.new(params[:filter]) + if @filter.save + process_success :success_redirect => filters_path(:role_id => @role) + else + process_error + end + end + + def edit + @filter = resource_base.includes(:permissions).find(params[:id]) + end + + def update + @filter = resource_base.find(params[:id]) + if @filter.update_attributes(params[:filter]) + process_success :success_redirect => filters_path(:role_id => @role) + else + process_error + end + end + + def destroy + @filter = resource_base.find(params[:id]) + if @filter.destroy + process_success :success_redirect => filters_path(:role_id => @role) + else + process_error + end + end + + protected + + def find_role + @role = Role.find_by_id(role_id) + end + + def resource_base + @resource_base ||= @role.present? ? + @role.filters.authorized(current_permission) : + Filter.scoped.authorized(current_permission) + end + + def role_id + params[:role_id] + end + + def setup_search_options + @original_search_parameter = params[:search] + params[:search] ||= "" + params.keys.each do |param| + if param =~ /role_id$/ + unless (role = Role.find_by_id(params[param])).blank? + query = "role = \"#{role.name}\"" + params[:search] += query unless params[:search].include? query + end + elsif param =~ /(\w+)_id$/ + unless params[param].blank? + query = "#{$1} = #{params[param]}" + params[:search] += query unless params[:search].include? query + end + end + end + end +end diff --git a/app/controllers/hostgroups_controller.rb b/app/controllers/hostgroups_controller.rb index 24588e653c6..b0a7ab28227 100644 --- a/app/controllers/hostgroups_controller.rb +++ b/app/controllers/hostgroups_controller.rb @@ -1,11 +1,10 @@ class HostgroupsController < ApplicationController include Foreman::Controller::HostDetails include Foreman::Controller::AutoCompleteSearch - - before_filter :find_hostgroup, :only => [:edit, :update, :destroy, :clone] + before_filter :find_by_name, :only => [:nest, :clone, :edit, :update, :destroy] def index - @hostgroups = Hostgroup.my_groups.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @hostgroups = resource_base.search_for(params[:search], :order => params[:order]).paginate :page => params[:page] end def new @@ -13,7 +12,7 @@ def new end def nest - @parent = Hostgroup.find(params[:id]) + @parent = @hostgroup @hostgroup = Hostgroup.new(:parent_id => @parent.id) load_vars_for_ajax @@ -56,8 +55,6 @@ def create end def edit - auth = User.current.admin? ? true : Hostgroup.my_groups.include?(@hostgroup) - not_found and return unless auth load_vars_for_ajax end @@ -96,7 +93,7 @@ def environment_selected def process_hostgroup - @parent = Hostgroup.find(params[:hostgroup][:parent_id]) if params[:hostgroup][:parent_id].to_i > 0 + @parent = Hostgroup.authorized(:view_hostgroups).find(params[:hostgroup][:parent_id]) if params[:hostgroup][:parent_id].to_i > 0 return head(:not_found) unless @parent @hostgroup = Hostgroup.new(params[:hostgroup]) @@ -117,10 +114,6 @@ def taxonomy_scope private - def find_hostgroup - @hostgroup = Hostgroup.find(params[:id]) - end - def load_vars_for_ajax return unless @hostgroup @architecture = @hostgroup.architecture @@ -140,4 +133,13 @@ def subscribed_users User.where(:subscribe_to_all_hostgroups => true) end + def action_permission + case params[:action] + when 'nest', 'clone' + 'view' + else + super + end + end + end diff --git a/app/controllers/hosts_controller.rb b/app/controllers/hosts_controller.rb index 349c048bf44..f9a80c1b3a9 100644 --- a/app/controllers/hosts_controller.rb +++ b/app/controllers/hosts_controller.rb @@ -8,26 +8,30 @@ class HostsController < ApplicationController SEARCHABLE_ACTIONS= %w[index active errors out_of_sync pending disabled ] AJAX_REQUESTS=%w{compute_resource_selected hostgroup_or_environment_selected current_parameters puppetclass_parameters process_hostgroup process_taxonomy} BOOT_DEVICES={ :disk => N_('Disk'), :cdrom => N_('CDROM'), :pxe => N_('PXE'), :bios => N_('BIOS') } + MULTIPLE_ACTIONS = %w(multiple_parameters update_multiple_parameters select_multiple_hostgroup + update_multiple_hostgroup select_multiple_environment update_multiple_environment + multiple_destroy submit_multiple_destroy multiple_build + submit_multiple_build multiple_disable submit_multiple_disable + multiple_enable submit_multiple_enable multiple_puppetrun + update_multiple_puppetrun multiple_disassociate update_multiple_disassociate) add_puppetmaster_filters PUPPETMASTER_ACTIONS before_filter :ajax_request, :only => AJAX_REQUESTS - before_filter :find_multiple, :only => [:update_multiple_parameters, :multiple_build, - :select_multiple_hostgroup, :select_multiple_environment, :multiple_parameters, :multiple_destroy, - :multiple_enable, :multiple_disable, :submit_multiple_disable, :submit_multiple_enable, :update_multiple_hostgroup, - :update_multiple_environment, :submit_multiple_build, :submit_multiple_destroy, :update_multiple_puppetrun, - :multiple_puppetrun, :multiple_disassociate, :update_multiple_disassociate] - before_filter :find_by_name, :only => %w[show edit update destroy puppetrun setBuild cancelBuild - storeconfig_klasses clone pxe_config toggle_manage power console bmc ipmi_boot disassociate] + before_filter :find_by_name, :only => [:show, :clone, :edit, :update, :destroy, :puppetrun, + :setBuild, :cancelBuild, :power, :bmc, :ipmi_boot, + :console, :toggle_manage, :pxe_config, + :storeconfig_klasses, :disassociate] before_filter :taxonomy_scope, :only => [:new, :edit] + AJAX_REQUESTS before_filter :set_host_type, :only => [:update] + before_filter :find_multiple, :only => MULTIPLE_ACTIONS helper :hosts, :reports def index (title = nil) begin - search = Host.my_hosts.search_for(params[:search],:order => params[:order]) + search = resource_base.search_for(params[:search], :order => params[:order]) rescue => e error e.to_s - search = Host.my_hosts.search_for '' + search = resource_base.search_for '' end respond_to do |format| format.html do @@ -35,6 +39,7 @@ def index (title = nil) # SQL optimizations queries @last_reports = Report.where(:host_id => @hosts.map(&:id)).group(:host_id).maximum(:id) # rendering index page for non index page requests (out of sync hosts etc) + @hostgroup_authorizer = Authorizer.new(User.current, :collection => @hosts.map(&:hostgroup_id).compact.uniq) render :index if title and (@title = title) end format.yaml do @@ -133,7 +138,7 @@ def compute_resource_selected return not_found unless (params[:host] && (id=params[:host][:compute_resource_id])) Taxonomy.as_taxonomy @organization, @location do compute_profile_id = params[:host][:compute_profile_id] || Hostgroup.find_by_id(params[:host][:hostgroup_id]).try(:compute_profile_id) - compute_resource = ComputeResource.find(id) + compute_resource = ComputeResource.authorized(:view_compute_resources).find_by_id(id) render :partial => "compute", :locals => { :compute_resource => compute_resource, :vm_attrs => compute_resource.compute_profile_attributes_for(compute_profile_id) } end @@ -168,8 +173,8 @@ def puppetclass_parameters def externalNodes certname = params[:name] - @host ||= Host.find_by_certname certname - @host ||= Host.find_by_name certname + @host ||= resource_base.find_by_certname certname + @host ||= resource_base.find_by_name certname not_found and return unless @host begin @@ -475,7 +480,7 @@ def process_hostgroup @compute_profile = @hostgroup.compute_profile @host = if params[:host][:id] - host = Host::Base.find(params[:host][:id]) + host = Host::Base.authorized(:view_hosts, Host).find(params[:host][:id]) host = host.becomes Host::Managed host.attributes = params[:host] host @@ -528,8 +533,41 @@ def template_used private + def resource_base + @resource_base ||= Host.authorized(current_permission, Host) + end + + def action_permission + case params[:action] + when 'clone', 'externalNodes', 'bmc', 'pxe_config', 'storeconfig_klasses', + 'active', 'errors', 'out_of_sync', 'pending', 'disabled' + :view + when 'puppetrun', 'multiple_puppetrun', 'update_multiple_puppetrun' + :puppetrun + when 'setBuild', 'cancelBuild', 'multiple_build', 'submit_multiple_build' + :build + when 'power' + :power + when 'ipmi_boot' + :ipmi_boot + when 'console' + :console + when 'toggle_manage', 'multiple_parameters', 'update_multiple_parameters', + 'select_multiple_hostgroup', 'update_multiple_hostgroup', 'select_multiple_environment', + 'update_multiple_environment', 'multiple_disable', 'submit_multiple_disable', + 'multiple_enable', 'submit_multiple_enable', + 'update_multiple_organization', 'select_multiple_organization', + 'update_multiple_location', 'select_multiple_location' + :edit + when 'multiple_destroy', 'submit_multiple_destroy' + :destroy + else + super + end + end + def refresh_host - @host = Host::Base.find_by_id(params['host_id']) + @host = Host::Base.authorized(:view_hosts, Host).find_by_id(params['host_id']) if @host unless @host.kind_of?(Host::Managed) @host = @host.becomes(Host::Managed) @@ -585,13 +623,14 @@ def find_by_name # determine if we are searching for a numerical id or plain name if id =~ /^\d+$/ - @host = Host::Base.my_hosts.find_by_id id.to_i + @host = resource_base.find_by_id id.to_i else - @host = Host::Base.my_hosts.find_by_name id.downcase - @host ||= Host::Base.my_hosts.find_by_mac params[:host][:mac] if params[:host] && params[:host][:mac] + @host = resource_base.find_by_name id.downcase + @host ||= resource_base.find_by_mac params[:host][:mac] if params[:host] && params[:host][:mac] end - not_found and return false unless @host + not_found and return(false) unless @host + @host end def load_vars_for_ajax @@ -611,7 +650,7 @@ def load_vars_for_ajax def find_multiple # Lets search by name or id and make sure one of them exists first if params[:host_names].present? or params[:host_ids].present? - @hosts = Host::Base.where("id IN (?) or name IN (?)", params[:host_ids], params[:host_names] ) + @hosts = resource_base.where("id IN (?) or name IN (?)", params[:host_ids], params[:host_names] ) if @hosts.empty? error _('No hosts were found with that id or name') redirect_to(hosts_path) and return false @@ -621,9 +660,12 @@ def find_multiple redirect_to(hosts_path) and return false end - rescue => e - error _("Something went wrong while selecting hosts - %s") % (e) - redirect_to hosts_path + return @hosts + rescue => e + error _("Something went wrong while selecting hosts - %s") % (e) + logger.debug e.message + logger.debug e.backtrace.join("\n") + redirect_to hosts_path and return false end def toggle_hostmode mode=true diff --git a/app/controllers/images_controller.rb b/app/controllers/images_controller.rb index 258a10605f1..248eccd926d 100644 --- a/app/controllers/images_controller.rb +++ b/app/controllers/images_controller.rb @@ -1,10 +1,10 @@ class ImagesController < ApplicationController before_filter :find_compute_resource - before_filter :find_by_name, :except => [:index, :new, :create] + before_filter :find_by_name, :only => [:edit, :update, :destroy] def index # Listing images in /hosts/new consumes this method as JSON - values = @compute_resource.images.search_for(params[:search], :order => params[:order]) + values = resource_base.where(:compute_resource_id => @compute_resource.id).search_for(params[:search], :order => params[:order]) respond_to do |format| format.html { @images = values.paginate :page => params[:page] } format.json { render :json => values } @@ -46,7 +46,7 @@ def destroy private def find_compute_resource - @compute_resource = ComputeResource.find(params[:compute_resource_id]) + @compute_resource = ComputeResource.authorized(:view_compute_resources).find(params[:compute_resource_id]) end end diff --git a/app/controllers/lookup_keys_controller.rb b/app/controllers/lookup_keys_controller.rb index 39cef78120d..4a26e3e7c8d 100644 --- a/app/controllers/lookup_keys_controller.rb +++ b/app/controllers/lookup_keys_controller.rb @@ -1,10 +1,11 @@ class LookupKeysController < ApplicationController include Foreman::Controller::AutoCompleteSearch - before_filter :find_by_key, :except => :index before_filter :setup_search_options, :only => :index + before_filter :find_by_key, :only => [:edit, :update, :destroy], :if => Proc.new { params[:id] } def index - @lookup_keys = LookupKey.search_for(params[:search], :order => params[:order]).includes(:puppetclass).paginate(:page => params[:page]) + @lookup_keys = resource_base.search_for(params[:search], :order => params[:order]).includes(:param_classes, :puppetclass).paginate(:page => params[:page]) + @puppetclass_authorizer = Authorizer.new(User.current, :collection => @lookup_keys.map(&:puppetclass_id).compact.uniq) end def edit @@ -27,10 +28,14 @@ def destroy end private + def find_by_key - if params[:id] - @lookup_key = LookupKey.find(params[:id]) - not_found and return if @lookup_key.blank? - end + @lookup_key = resource_base.find(params[:id]) + not_found and return if @lookup_key.blank? + @lookup_key + end + + def controller_permission + 'external_variables' end end diff --git a/app/controllers/media_controller.rb b/app/controllers/media_controller.rb index abd65fd7680..76d13b22934 100644 --- a/app/controllers/media_controller.rb +++ b/app/controllers/media_controller.rb @@ -1,9 +1,9 @@ class MediaController < ApplicationController include Foreman::Controller::AutoCompleteSearch - before_filter :find_medium, :only => %w{edit update destroy} + before_filter :find_by_name, :only => %w{edit update destroy} def index - @media = Medium.includes(:operatingsystems).search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @media = resource_base.includes(:operatingsystems).search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) end def new @@ -38,9 +38,4 @@ def destroy end end - private - def find_medium - @medium = Medium.find(params[:id]) - end - end diff --git a/app/controllers/models_controller.rb b/app/controllers/models_controller.rb index 23b00226c3b..ef7de838b52 100644 --- a/app/controllers/models_controller.rb +++ b/app/controllers/models_controller.rb @@ -1,8 +1,9 @@ class ModelsController < ApplicationController include Foreman::Controller::AutoCompleteSearch + before_filter :find_by_name, :only => [:edit, :update, :destroy] def index - @models = Model.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @models = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) @host_counter = Host.group(:model_id).where(:model_id => @models.select(&:id)).count end @@ -20,11 +21,9 @@ def create end def edit - @model = Model.find(params[:id]) end def update - @model = Model.find(params[:id]) if @model.update_attributes(params[:model]) process_success else @@ -33,11 +32,11 @@ def update end def destroy - @model = Model.find(params[:id]) if @model.destroy process_success else process_error end end + end diff --git a/app/controllers/operatingsystems_controller.rb b/app/controllers/operatingsystems_controller.rb index 518725d062a..c1ad640f073 100644 --- a/app/controllers/operatingsystems_controller.rb +++ b/app/controllers/operatingsystems_controller.rb @@ -1,9 +1,9 @@ class OperatingsystemsController < ApplicationController include Foreman::Controller::AutoCompleteSearch - before_filter :find_os, :only => %w{edit update destroy bootfiles} + before_filter :find_by_name, :only => %w{edit update destroy} def index - @operatingsystems = Operatingsystem.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @operatingsystems = resource_base.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) @host_counter = Host.group(:operatingsystem_id).where(:operatingsystem_id => @operatingsystems.collect(&:id)).count end @@ -44,10 +44,4 @@ def destroy process_error end end - - private - def find_os - @operatingsystem = Operatingsystem.find(params[:id]) - end - end diff --git a/app/controllers/permissions_controller.rb b/app/controllers/permissions_controller.rb new file mode 100644 index 00000000000..702c8849603 --- /dev/null +++ b/app/controllers/permissions_controller.rb @@ -0,0 +1,18 @@ +class PermissionsController < ApplicationController + include FiltersHelper + respond_to :js + + def index + type = params[:resource_type].blank? ? nil : params[:resource_type] + @permissions = Permission.find_all_by_resource_type(type) + @search_path = search_path(type) + @granular = granular?(type) + end + + private + + def granular?(type) + Filter.new(:resource_type => type).granular? + end + +end diff --git a/app/controllers/ptables_controller.rb b/app/controllers/ptables_controller.rb index 3b507818f10..ab34c65a306 100644 --- a/app/controllers/ptables_controller.rb +++ b/app/controllers/ptables_controller.rb @@ -1,9 +1,10 @@ class PtablesController < ApplicationController include Foreman::Controller::AutoCompleteSearch - before_filter :find_ptable, :only => %w{edit update destroy} + before_filter :find_by_name, :only => [:edit, :update, :destroy] def index - @ptables = Ptable.includes(:operatingsystems).search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @ptables = resource_base.includes(:operatingsystems). + search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) end def new @@ -38,9 +39,4 @@ def destroy end end - private - def find_ptable - @ptable = Ptable.find(params[:id]) - end - end diff --git a/app/controllers/puppetca_controller.rb b/app/controllers/puppetca_controller.rb index 7e0dbf34e87..49af71fff07 100644 --- a/app/controllers/puppetca_controller.rb +++ b/app/controllers/puppetca_controller.rb @@ -1,10 +1,9 @@ class PuppetcaController < ApplicationController - before_filter :find_proxy def index + @proxy = find_proxy # expire cache if forced Rails.cache.delete("ca_#{@proxy.id}") if params[:expire_cache] == "true" - begin certs = if params[:state].blank? SmartProxies::PuppetCA.find_by_state(@proxy, "valid") + SmartProxies::PuppetCA.find_by_state(@proxy, "pending") @@ -26,6 +25,7 @@ def index end def update + @proxy = find_proxy(:edit_smart_proxies_puppetca) cert = SmartProxies::PuppetCA.find(@proxy, params[:id]) if cert.sign process_success({ :success_redirect => smart_proxy_puppetca_index_path(@proxy, :state => params[:state]), :object_name => cert.to_s }) @@ -37,6 +37,7 @@ def update end def destroy + @proxy = find_proxy(:destroy_smart_proxies_puppetca) cert = SmartProxies::PuppetCA.find(@proxy, params[:id]) if cert.destroy process_success({ :success_redirect => smart_proxy_puppetca_index_path(@proxy, :state => params[:state]), :object_name => cert.to_s }) @@ -47,8 +48,8 @@ def destroy private - def find_proxy - @proxy = SmartProxy.find(params[:smart_proxy_id]) + def find_proxy(permission = :view_smart_proxies_puppetca) + SmartProxy.authorized(permission).find(params[:smart_proxy_id]) end end diff --git a/app/controllers/puppetclasses_controller.rb b/app/controllers/puppetclasses_controller.rb index f276b74dd37..63fc2727d24 100644 --- a/app/controllers/puppetclasses_controller.rb +++ b/app/controllers/puppetclasses_controller.rb @@ -1,15 +1,16 @@ class PuppetclassesController < ApplicationController include Foreman::Controller::Environments include Foreman::Controller::AutoCompleteSearch - before_filter :find_by_name, :only => [:edit, :update, :destroy, :assign] + before_filter :find_by_name, :only => [:edit, :update, :destroy] before_filter :setup_search_options, :only => :index before_filter :reset_redirect_to_url, :only => :index before_filter :store_redirect_to_url, :only => :edit def index - @puppetclasses = Puppetclass.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page]) + @puppetclasses = resource_base.search_for(params[:search], :order => params[:order]).includes(:environments, :hostgroups).paginate(:page => params[:page]) @host_counter = Host.group(:puppetclass_id).joins(:puppetclasses).where(:puppetclasses => {:id => @puppetclasses.collect(&:id)}).count @keys_counter = Puppetclass.joins(:class_params).select('distinct environment_classes.lookup_key_id').group(:name).count + @hostgroups_authorizer = Authorizer.new(User.current, :collection => HostgroupClass.find_all_by_puppetclass_id(@puppetclasses.map(&:id)).compact.uniq.map(&:hostgroup_id)) end def new @@ -96,8 +97,9 @@ def redirect_back_or_default(default) def find_by_name not_found and return if params[:id].blank? - pc = Puppetclass.includes(:class_params => [:environment_classes, :environments, :lookup_values]) + pc = resource_base.includes(:class_params => [:environment_classes, :environments, :lookup_values]) @puppetclass = (params[:id] =~ /\A\d+\Z/) ? pc.find(params[:id]) : pc.find_by_name(params[:id]) not_found and return unless @puppetclass end + end diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index 922af0abcd7..26eb17246ed 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -4,24 +4,25 @@ class ReportsController < ApplicationController before_filter :setup_search_options, :only => :index def index - @reports = Report.my_reports.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page], :per_page => params[:per_page]).includes(:host) + report_authorized = resource_base.my_reports + @reports = report_authorized.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page], :per_page => params[:per_page]).includes(:host) end def show # are we searching for the last report? if params[:id] == "last" conditions = { :host_id => Host.find_by_name(params[:host_id]).try(:id) } unless params[:host_id].blank? - params[:id] = Report.my_reports.where(conditions).maximum(:id) + params[:id] = resource_base.where(conditions).maximum(:id) end return not_found if params[:id].blank? - @report = Report.my_reports.includes(:logs => [:message, :source]).find(params[:id]) + @report = resource_base.includes(:logs => [:message, :source]).find(params[:id]) @offset = @report.reported_at - @report.created_at end def destroy - @report = Report.find(params[:id]) + @report = resource_base.find(params[:id]) if @report.destroy notice _("Successfully destroyed report.") else diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb index 3b6008a6f0e..bbf5c5b263d 100644 --- a/app/controllers/roles_controller.rb +++ b/app/controllers/roles_controller.rb @@ -17,7 +17,7 @@ class RolesController < ApplicationController include Foreman::Controller::AutoCompleteSearch - before_filter :require_admin + before_filter :find_by_id, :only => [:clone, :edit, :update, :destroy] def index @roles = Role.search_for(params[:search], :order => params[:order]).paginate :page => params[:page] @@ -25,11 +25,12 @@ def index def new # Prefills the form with 'default user' role permissions - @role = Role.new({:permissions => Role.default_user.permissions}) + @role = Role.new({:permissions => Role.default_user.permissions}) end def create - @role = Role.new(params[:role]) + @role = role_from_form + if @role.save process_success else @@ -37,12 +38,19 @@ def create end end + def clone + @cloned_role = true + @original_role_id = @role.id + flash[:notice] = _("Role cloned from role %{old_name}") % + { :old_name => @role.name } + @role = Role.new + render :action => :new + end + def edit - @role = Role.find(params[:id]) end def update - @role = Role.find(params[:id]) if @role.update_attributes(params[:role]) process_success else @@ -51,7 +59,6 @@ def update end def destroy - @role = Role.find(params[:id]) if @role.destroy process_success else @@ -59,16 +66,32 @@ def destroy end end - def report - @roles = Role.all(:order => 'builtin, name') - @permissions = Foreman::AccessControl.permissions.select { |p| !p.public? } - if request.post? - @roles.each do |role| - role.permissions = params[:permissions][role.id.to_s] - role.save - end - notice _("All non public permissions successfully updated") - redirect_to roles_url + private + + def find_by_id + @role = Role.find(params[:id]) + end + + def action_permission + case params[:action] + when 'clone' + 'view' + else + super + end + end + + def role_from_form + if params[:original_role_id].present? + new_role = Role.find(params[:original_role_id]). + dup(:include => [:filters => :filterings]) + new_role.name = params[:role][:name] + new_role.builtin = false + else + new_role = Role.new(params[:role]) end + + new_role end + end diff --git a/app/controllers/smart_proxies_controller.rb b/app/controllers/smart_proxies_controller.rb index fa81940c7b7..dcc8d41d166 100644 --- a/app/controllers/smart_proxies_controller.rb +++ b/app/controllers/smart_proxies_controller.rb @@ -1,20 +1,22 @@ class SmartProxiesController < ApplicationController - before_filter :find_by_id, :only => [:edit, :update, :destroy, :ping, :refresh] + + include Foreman::Controller::AutoCompleteSearch + before_filter :find_by_name, :only => [:edit, :update, :refresh, :ping, :destroy] def index - @proxies = SmartProxy.includes(:features).paginate :page => params[:page] + @smart_proxies = resource_base.includes(:features).paginate :page => params[:page] end def new - @proxy = SmartProxy.new + @smart_proxy = SmartProxy.new end def create - @proxy = SmartProxy.new(params[:smart_proxy]) - if @proxy.save - process_success :object => @proxy + @smart_proxy = SmartProxy.new(params[:smart_proxy]) + if @smart_proxy.save + process_success :object => @smart_proxy else - process_error :object => @proxy + process_error :object => @smart_proxy end end @@ -23,38 +25,46 @@ def edit def ping respond_to do |format| - format.json {render :json => errors_hash(@proxy.refresh)} + format.json {render :json => errors_hash(@smart_proxy.refresh)} end end def refresh - old_features = @proxy.features - if @proxy.refresh.blank? && @proxy.save - msg = @proxy.features == old_features ? _("No changes found when refreshing features from %s.") : _("Successfully refreshed features from %s.") - process_success :object => @proxy, :success_msg => msg % @proxy.name + old_features = @smart_proxy.features + if @smart_proxy.refresh.blank? && @smart_proxy.save + msg = @smart_proxy.features == old_features ? _("No changes found when refreshing features from %s.") : _("Successfully refreshed features from %s.") + process_success :object => @smart_proxy, :success_msg => msg % @smart_proxy.name else - process_error :object => @proxy + process_error :object => @smart_proxy end end def update - if @proxy.update_attributes(params[:smart_proxy]) - process_success :object => @proxy + if @smart_proxy.update_attributes(params[:smart_proxy]) + process_success :object => @smart_proxy else - process_error :object => @proxy + process_error :object => @smart_proxy end end def destroy - if @proxy.destroy - process_success :object => @proxy + if @smart_proxy.destroy + process_success :object => @smart_proxy else - process_error :object => @proxy + process_error :object => @smart_proxy end end private - def find_by_id - @proxy = SmartProxy.find(params[:id]) + + def action_permission + case params[:action] + when 'refresh' + :edit + when 'ping' + :view + else + super + end end end diff --git a/app/controllers/statistics_controller.rb b/app/controllers/statistics_controller.rb index 6d744c81c75..294c328d44d 100644 --- a/app/controllers/statistics_controller.rb +++ b/app/controllers/statistics_controller.rb @@ -1,18 +1,18 @@ class StatisticsController < ApplicationController def index - @os_count = Host.my_hosts.count_distribution :operatingsystem - @arch_count = Host.my_hosts.count_distribution :architecture - @env_count = Host.my_hosts.count_distribution :environment - @klass_count = Host.my_hosts.count_habtm "puppetclass" - @cpu_count = FactValue.my_facts.count_each "processorcount" - @model_count = FactValue.my_facts.count_each "manufacturer" - @mem_size = FactValue.my_facts.mem_average "memorysize" - @mem_free = FactValue.my_facts.mem_average "memoryfree" - @swap_size = FactValue.my_facts.mem_average "swapsize" - @swap_free = FactValue.my_facts.mem_average "swapfree" - @mem_totsize = FactValue.my_facts.mem_sum "memorysize" - @mem_totfree = FactValue.my_facts.mem_sum "memoryfree" + @os_count = Host.authorized(:view_hosts, Host).count_distribution :operatingsystem + @arch_count = Host.authorized(:view_hosts, Host).count_distribution :architecture + @env_count = Host.authorized(:view_hosts, Host).count_distribution :environment + @klass_count = Host.authorized(:view_hosts, Host).count_habtm "puppetclass" + @cpu_count = FactValue.authorized(:view_facts).my_facts.count_each "processorcount" + @model_count = FactValue.authorized(:view_facts).my_facts.count_each "manufacturer" + @mem_size = FactValue.authorized(:view_facts).my_facts.mem_average "memorysize" + @mem_free = FactValue.authorized(:view_facts).my_facts.mem_average "memoryfree" + @swap_size = FactValue.authorized(:view_facts).my_facts.mem_average "swapsize" + @swap_free = FactValue.authorized(:view_facts).my_facts.mem_average "swapfree" + @mem_totsize = FactValue.authorized(:view_facts).my_facts.mem_sum "memorysize" + @mem_totfree = FactValue.authorized(:view_facts).my_facts.mem_sum "memoryfree" respond_to do |format| format.html format.json do diff --git a/app/controllers/subnets_controller.rb b/app/controllers/subnets_controller.rb index 151f09de40c..6239ec4a406 100644 --- a/app/controllers/subnets_controller.rb +++ b/app/controllers/subnets_controller.rb @@ -1,8 +1,9 @@ class SubnetsController < ApplicationController include Foreman::Controller::AutoCompleteSearch + before_filter :find_by_name, :only => [:edit, :update, :destroy] def index - @subnets = Subnet.search_for(params[:search], :order => params[:order]).includes(:domains, :dhcp).paginate :page => params[:page] + @subnets = resource_base.search_for(params[:search], :order => params[:order]).includes(:domains, :dhcp).paginate :page => params[:page] end def new @@ -19,11 +20,9 @@ def create end def edit - @subnet = Subnet.find(params[:id]) end def update - @subnet = Subnet.find(params[:id]) if @subnet.update_attributes(params[:subnet]) process_success else @@ -32,7 +31,6 @@ def update end def destroy - @subnet = Subnet.find(params[:id]) if @subnet.destroy process_success else @@ -46,7 +44,7 @@ def freeip organization = params[:organization_id].blank? ? nil : Organization.find(params[:organization_id]) location = params[:location_id].blank? ? nil : Location.find(params[:location_id]) Taxonomy.as_taxonomy organization, location do - not_found and return unless (subnet = Subnet.find(s)) + not_found and return unless (subnet = Subnet.authorized(:view_subnets).find(s)) if (ip = subnet.unused_ip(params[:host_mac])) render :json => {:ip => ip} else @@ -55,7 +53,7 @@ def freeip end end rescue => e - logger.warn "Failed to query #{subnet} for free ip: #{e}" + logger.warn "Failed to query subnet #{s} for free ip: #{e}" head :status => 500 end diff --git a/app/controllers/usergroups_controller.rb b/app/controllers/usergroups_controller.rb index 3b43c0a7320..1eca10ebcc6 100644 --- a/app/controllers/usergroups_controller.rb +++ b/app/controllers/usergroups_controller.rb @@ -1,6 +1,9 @@ class UsergroupsController < ApplicationController + include Foreman::Controller::AutoCompleteSearch + before_filter :find_by_name, :only => [:edit, :update, :destroy] + def index - @usergroups = Usergroup.paginate :page => params[:page] + @usergroups = resource_base.paginate :page => params[:page] end def new @@ -17,24 +20,30 @@ def create end def edit - @usergroup = Usergroup.find(params[:id]) end def update - @usergroup = Usergroup.find(params[:id]) if @usergroup.update_attributes(params[:usergroup]) process_success else process_error end + rescue Foreman::CyclicGraphException => e + @usergroup.errors[:usergroups] = e.record.errors[:base].join(' ') + process_error end def destroy - @usergroup = Usergroup.find(params[:id]) if @usergroup.destroy process_success else process_error end end + + private + + def find_by_id(permission = :view_usergroups) + Usergroup.authorized(permission).find(params[:id]) + end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index afc426752ef..8e81dce4b06 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -2,14 +2,14 @@ class UsersController < ApplicationController include Foreman::Controller::AutoCompleteSearch include Foreman::Controller::UsersMixin - before_filter :find_resource, :only => [:edit, :update, :destroy] skip_before_filter :require_mail, :only => [:edit, :update, :logout] skip_before_filter :require_login, :authorize, :session_expiry, :update_activity_time, :set_taxonomy, :set_gettext_locale_db, :only => [:login, :logout, :extlogout] skip_before_filter :authorize, :only => :extlogin after_filter :update_activity_time, :only => :login + skip_before_filter :update_admin_flag, :only => :update def index - @users = User.search_for(params[:search], :order => params[:order]).includes(:auth_source).paginate(:page => params[:page]) + @users = User.authorized(:view_users).search_for(params[:search], :order => params[:order]).includes(:auth_source).paginate(:page => params[:page]) end def new @@ -26,6 +26,7 @@ def create def edit editing_self? + @user = find_resource(:edit_users) if @user.user_facts.count == 0 user_fact = @user.user_facts.build :operator => "==", :andor => "or" user_fact.fact_name_id = FactName.first.id if FactName.first @@ -33,6 +34,9 @@ def edit end def update + editing_self? + @user = find_resource(:edit_users) + update_admin_flag if @user.update_attributes(params[:user]) update_sub_hostgroups_owners @@ -43,6 +47,7 @@ def update end def destroy + @user = find_resource(:destroy_users) if @user == User.current notice _("You are currently logged in, suicidal?") redirect_to :back and return @@ -102,8 +107,8 @@ def extlogout private - def find_resource - @user ||= User.find(params[:id]) + def find_resource(permission = :view_users) + editing_self? ? User.current : User.authorized(permission).find(params[:id]) end def login_user(user) diff --git a/app/helpers/ancestry_helper.rb b/app/helpers/ancestry_helper.rb index a4a816ba8f2..0c13255f8c5 100644 --- a/app/helpers/ancestry_helper.rb +++ b/app/helpers/ancestry_helper.rb @@ -1,7 +1,7 @@ module AncestryHelper # this helper is used for hostgroup names and location/organization names. Both have ancestry - def label_with_link(obj, max_length = 1000) + def label_with_link(obj, max_length = 1000, authorizer = nil) return if obj.blank? options = (obj.title.to_s.size > max_length) ? { :'data-original-title' => obj.title, :rel => 'twipsy' } : {} nesting = obj.title.to_s.gsub(/[^\/]+\/?$/, '') @@ -10,7 +10,7 @@ def label_with_link(obj, max_length = 1000) link_to_if_authorized( content_tag(:span, content_tag(:span, nesting, :class => 'gray') + name, options), - send("hash_for_edit_#{obj.class.name.tableize.singularize}_path", obj)) + send("hash_for_edit_#{obj.class.name.tableize.singularize}_path", obj).merge(:auth_object => obj, :authorizer => authorizer)) end -end \ No newline at end of file +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 68ca18e65d2..e02279e4850 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -113,31 +113,39 @@ def add_html_classes options, classes options end - def check_all_roles_links - link_to(_("Check all"), "#", :id => "check_all_roles", :remote => true) + - link_to(_("Uncheck all"), "#", :id => "uncheck_all_roles", :remote => true) - end - # Return true if user is authorized for controller/action, otherwise false - # +controller+ : String or symbol for the controller - # +action+ : String or symbol for the action - def authorized_for(controller, action, id = nil) - User.current.allowed_to?({:controller => controller, :action => action, :id => id}) rescue false + # +options+ : Hash containing + # :controller : String or symbol for the controller, defaults to params[:controller] + # :action : String or symbol for the action + # :id : Id parameter + # :auth_action: String or symbol for the action, this has higher priority that :action + # :auth_object: Specific object on which we may verify particular permission + # :authorizer : Specific authorizer to perform authorization on (handy to inject authorizer with base collection) + # :permission : Specific permission to check authorization on (handy on custom permission names) + def authorized_for(options) + action = options.delete(:auth_action) || options.delete(:action) + object = options.delete(:auth_object) + user = User.current + controller = options[:controller] || params[:controller] + controller_name = controller.to_s.gsub(/::/, "_").underscore + id = options[:id] + permission = options.delete(:permission) || [action, controller_name].join('_') + + if object.nil? + user.allowed_to?({ :controller => controller_name, :action => action, :id => id }) rescue false + else + authorizer = options.delete(:authorizer) || Authorizer.new(user) + authorizer.can?(permission, object) rescue false + end end # Display a link if user is authorized, otherwise a string # +name+ : String to be displayed - # +options+ : Hash containing - # :controller : String or Symbol representing the controller - # :auth_action : String or Symbol representing the action to be used for authorization checks + # +options+ : Hash containing options for authorized_for and link_to # +html_options+ : Hash containing html options for the link or span def link_to_if_authorized(name, options = {}, html_options = {}) - auth_options = { - :controller => options[:controller] || params[:controller], - :action => options.delete(:auth_action) || options[:action], - :id => options[:id] - } - if User.current.allowed_to?(auth_options) + enable_link = authorized_for(options) + if enable_link link_to name, options, html_options else link_to_function name, nil, html_options.merge!(:class => "#{html_options[:class]} disabled", :disabled => true) @@ -149,16 +157,14 @@ def display_delete_if_authorized(options ={}, html_options ={}) html_options = {:confirm => _('Are you sure?'), :method => :delete, :class => 'delete'}.merge(html_options) display_link_if_authorized(_("Delete"), options, html_options) end + # Display a link if user is authorized, otherwise nothing # +name+ : String to be displayed - # +options+ : Hash containing - # :controller : String or Symbol representing the controller - # :auth_action : String or Symbol representing the action to be used for authorization checks + # +options+ : Hash containing options for authorized_for and link_to # +html_options+ : Hash containing html options for the link or span def display_link_if_authorized(name, options = {}, html_options = {}) - auth_action = options.delete :auth_action enable_link = html_options.has_key?(:disabled) ? !html_options[:disabled] : true - if enable_link and authorized_for(options[:controller] || params[:controller], auth_action || options[:action]) + if enable_link and authorized_for(options) link_to(name, options, html_options) else "" @@ -166,7 +172,9 @@ def display_link_if_authorized(name, options = {}, html_options = {}) end def authorized_edit_habtm klass, association, prefix = nil, options = {} - return edit_habtm(klass, association, prefix, options) if authorized_for params[:controller], params[:action] + if authorized_for :controller => params[:controller], :action => params[:action] + return edit_habtm(klass, association, prefix, options) + end show_habtm klass.send(association.name.pluralize.downcase) end @@ -198,7 +206,7 @@ def searchable? end def auto_complete_search(name, val, options = {}) - path = send("#{controller_name}_path") + path = options[:path] || send("#{controller_name}_path") options.merge!(:class => "autocomplete-input form-control", :'data-url' => "#{path}/auto_complete_#{name}" ) text_field_tag(name, val, options) end diff --git a/app/helpers/autosign_helper.rb b/app/helpers/autosign_helper.rb index 1aa0784f1d2..7d0729d8498 100644 --- a/app/helpers/autosign_helper.rb +++ b/app/helpers/autosign_helper.rb @@ -1,6 +1,6 @@ module AutosignHelper def autosign_form - link_to "New", new_smart_proxy_autosign_path(@proxy) if authorized_for("SmartProxies::Autosign", :create) + link_to "New", new_smart_proxy_autosign_path(@proxy) if authorized_for(:controller => "SmartProxies::Autosign", :action => :create, :auth_object => @proxy) end end diff --git a/app/helpers/bmc_helper.rb b/app/helpers/bmc_helper.rb index 713750782ff..a4c816288f4 100644 --- a/app/helpers/bmc_helper.rb +++ b/app/helpers/bmc_helper.rb @@ -11,20 +11,22 @@ def power_status s def power_actions action_buttons( (PowerManager::SUPPORTED_ACTIONS - ['state']).map do |action| - display_link_if_authorized(_(action.to_s.capitalize), { :action => "power", :id => @host, :power_action => action}, + display_link_if_authorized(_(action.to_s.capitalize), + { :action => "power", :id => @host, :power_action => action, :auth_object => @host }, :confirm => _('Are you sure?'), :method => :put) end ) end def boot_actions - controller_options = { :action => "ipmi_boot", :id => @host } + controller_options = { :action => "ipmi_boot", :id => @host, :auth_object => @host, :permission => 'ipmi_boot' } confirm = _('Are you sure?') links = HostsController::BOOT_DEVICES.map do |device,label| - display_link_if_authorized(_(label), controller_options.merge(:ipmi_device => device), - :confirm => confirm, :method => :put) + display_link_if_authorized(_(label), + controller_options.merge(:ipmi_device => device), + :confirm => confirm, :method => :put) end action_buttons("Select device", links) end diff --git a/app/helpers/common_parameters_helper.rb b/app/helpers/common_parameters_helper.rb index a0fc1f4e18d..f27021589b8 100644 --- a/app/helpers/common_parameters_helper.rb +++ b/app/helpers/common_parameters_helper.rb @@ -1,10 +1,8 @@ module CommonParametersHelper # Return true if user is authorized for controller/action OR controller/action@type, otherwise false - def authorized_via_my_scope(controller, action) - return true if authorized_for(controller, action) - - operation = "#{action}_my_#{controller.singularize}".to_sym - User.current.allowed_to?(operation) and User.current.send(controller).include?(instance_variable_get("@#{controller.singularize}")) + # third argument may be specific object (usually for edit and destroy actions) + def authorized_via_my_scope(controller, action, object = nil) + authorized_for(:controller => controller, :action => action, :auth_object => object) end def parameters_title diff --git a/app/helpers/compute_resources_helper.rb b/app/helpers/compute_resources_helper.rb index 21c2aa01d31..366757c9c35 100644 --- a/app/helpers/compute_resources_helper.rb +++ b/app/helpers/compute_resources_helper.rb @@ -21,16 +21,16 @@ def vm_power_class s "class='label #{s ? "label-success" : "label-default"}'".html_safe end - def vm_power_action vm - opts = hash_for_power_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity) + def vm_power_action vm, authorizer = nil + opts = hash_for_power_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :permission => 'power_compute_resources_vms', :authorizer => authorizer) html = vm.ready? ? { :confirm =>_("Are you sure you want to power %{act} %{vm}?") % { :act => action_string(vm).downcase.strip, :vm => vm } , :class => "btn btn-danger" } : { :class => "btn btn-info" } display_link_if_authorized "Power #{action_string(vm)}", opts, html.merge(:method => :put) end - def vm_pause_action vm - opts = hash_for_pause_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity) + def vm_pause_action vm, authorizer = nil + opts = hash_for_pause_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :permission => 'power_compute_resources_vms', :authorizer => authorizer) pause_action = vm.ready? ? _('Pause') : _('Resume') html = vm.state.downcase == 'paused' ? { :class => "btn btn-info" } : { :confirm =>_("Are you sure you want to %{act} %{vm}?") % { :act => pause_action.downcase, :vm => vm } , :class => "btn btn-danger" } diff --git a/app/helpers/compute_resources_vms_helper.rb b/app/helpers/compute_resources_vms_helper.rb index 49a2f91bfd2..1af1b3b9a86 100644 --- a/app/helpers/compute_resources_vms_helper.rb +++ b/app/helpers/compute_resources_vms_helper.rb @@ -3,10 +3,10 @@ module ComputeResourcesVmsHelper # little helper to help show VM properties def prop method, title = nil content_tag :tr do - result = content_tag :td do + result = content_tag(:td) do title || method.to_s.humanize end - result += content_tag :td do + result += content_tag(:td) do value = @vm.send(method) rescue nil case value when Array @@ -67,32 +67,32 @@ def vsphere_datastores(compute) end end - def available_actions(vm) + def available_actions(vm, authorizer = nil) case vm when Fog::Compute::OpenStack::Server - openstack_available_actions(vm) + openstack_available_actions(vm, authorizer) else - default_available_actions(vm) + default_available_actions(vm, authorizer) end end - def openstack_available_actions(vm) + def openstack_available_actions(vm, authorizer = nil) actions = [] if vm.state == 'ACTIVE' - actions << vm_power_action(vm) - actions << vm_pause_action(vm) + actions << vm_power_action(vm, authorizer) + actions << vm_pause_action(vm, authorizer) elsif vm.state == 'PAUSED' - actions << vm_pause_action(vm) + actions << vm_pause_action(vm, authorizer) else - actions << vm_power_action(vm) + actions << vm_power_action(vm, authorizer) end - actions << display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity)) + actions << display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => authorizer)) end - def default_available_actions(vm) - [vm_power_action(vm), - display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity))] + def default_available_actions(vm, authorizer = nil) + [vm_power_action(vm, authorizer), + display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => authorizer))] end def vpc_security_group_hash(security_groups) diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index 070af99a928..81d853ccdd9 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -39,7 +39,7 @@ def searchable_links name, search, counter def latest_events # 6 reports + header fits the events box nicely... - summary = Report.my_reports.interesting.search_for('reported > "7 days ago"').limit(6) + summary = Report.authorized(:view_reports).my_reports.interesting.search_for('reported > "7 days ago"').limit(6) end def translated_header(shortname, longname) diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb new file mode 100644 index 00000000000..05f0bf6b2eb --- /dev/null +++ b/app/helpers/filters_helper.rb @@ -0,0 +1,22 @@ +module FiltersHelper + def search_path(type) + if type.nil? + '' + else + case type + when 'Image' + '' # images are nested resource for CR, we can't autocomplete + when 'HostClass' + '' # host classes is only used in API + when 'Parameter' + '' # parameter is only used in API + else + resource_path(type) + '/auto_complete_search' + end + end + end + + def resource_path(type) + send(type.pluralize.underscore + '_path') + end +end diff --git a/app/helpers/hosts_and_hostgroups_helper.rb b/app/helpers/hosts_and_hostgroups_helper.rb index 30ff7124eee..244d2318b0e 100644 --- a/app/helpers/hosts_and_hostgroups_helper.rb +++ b/app/helpers/hosts_and_hostgroups_helper.rb @@ -8,7 +8,7 @@ def model_name host end def accessible_hostgroups - hg = (User.current.hostgroups.any? and !User.current.admin?) ? User.current.hostgroups.with_taxonomy_scope_override(@location,@organization) : Hostgroup.with_taxonomy_scope_override(@location,@organization) + hg = Hostgroup.with_taxonomy_scope_override(@location,@organization) hg.sort{ |l, r| l.to_label <=> r.to_label } end @@ -19,7 +19,7 @@ def parent_classes obj end def accessible_domains - (User.current.domains.any? and !User.current.admin?) ? User.current.domains.with_taxonomy_scope_override(@location,@organization) : Domain.with_taxonomy_scope_override(@location,@organization) + Domain.with_taxonomy_scope_override(@location,@organization) end def domain_subnets(domain=@domain) diff --git a/app/helpers/hosts_helper.rb b/app/helpers/hosts_helper.rb index 4ea526333ec..b2a49b59b92 100644 --- a/app/helpers/hosts_helper.rb +++ b/app/helpers/hosts_helper.rb @@ -68,7 +68,8 @@ def days_ago time end def authorized? - authorized_for(:hosts, :edit) or authorized_for(:hosts, :destroy) + authorized_for(:controller => :hosts, :action => :edit) or + authorized_for(:controller => :hosts, :action => :destroy) end def searching? @@ -226,12 +227,14 @@ def state s def host_title_actions(host, vm) title_actions( button_group( - link_to_if_authorized(_("Edit"), hash_for_edit_host_path(:id => host), :title => _("Edit your host")), + link_to_if_authorized(_("Edit"), hash_for_edit_host_path(:id => host).merge(:auth_object => host), :title => _("Edit your host")), if host.build - link_to_if_authorized(_("Cancel Build"), hash_for_cancelBuild_host_path(:id => host), :disabled => host.can_be_built?, + link_to_if_authorized(_("Cancel Build"), hash_for_cancelBuild_host_path(:id => host).merge(:auth_object => host, :permission => 'build_hosts'), + :disabled => host.can_be_built?, :title => _("Cancel build request for this host")) else - link_to_if_authorized(_("Build"), hash_for_setBuild_host_path(:id => host), :disabled => !host.can_be_built?, + link_to_if_authorized(_("Build"), hash_for_setBuild_host_path(:id => host).merge(:auth_object => host, :permission => 'build_hosts'), + :disabled => !host.can_be_built?, :title => _("Enable rebuild on next host boot"), :confirm => _("Rebuild %s on next reboot?\nThis would also delete all of its current facts and reports") % host) end @@ -240,22 +243,24 @@ def host_title_actions(host, vm) button_group( if vm html_opts = vm.ready? ? {:confirm => _('Are you sure?'), :class => "btn btn-danger"} : {:class => "btn btn-success"} - link_to_if_authorized _("Power%s") % state(vm.ready?), hash_for_power_host_path(:power_action => vm.ready? ? :stop : :start), html_opts.merge(:method => :put) + link_to_if_authorized _("Power%s") % state(vm.ready?), hash_for_power_host_path(:power_action => vm.ready? ? :stop : :start).merge(:auth_object => host, :permission => 'power_hosts'), + html_opts.merge(:method => :put) else link_to(_("Unknown Power State"), '#', :disabled => true, :class => "btn btn-warning") end + - link_to_if_authorized(_("Console"), hash_for_console_host_path(), {:disabled => vm.nil? || !vm.ready?, :class => "btn btn-info"}) + link_to_if_authorized(_("Console"), hash_for_console_host_path().merge(:auth_object => host, :permission => 'console_hosts'), + {:disabled => vm.nil? || !vm.ready?, :class => "btn btn-info"}) ) end, button_group( if host.try(:puppet_proxy) - link_to_if_authorized(_("Run puppet"), hash_for_puppetrun_host_path(:id => host).merge(:auth_action => :edit), + link_to_if_authorized(_("Run puppet"), hash_for_puppetrun_host_path(:id => host).merge(:auth_object => host, :permission => 'puppetrun_hosts'), :disabled => !Setting[:puppetrun], :title => _("Trigger a puppetrun on a node; requires that puppet run is enabled")) end ), button_group( - link_to_if_authorized(_("Delete"), hash_for_host_path(:id => host, :auth_action => :destroy), + link_to_if_authorized(_("Delete"), hash_for_host_path(:id => host).merge(:auth_object => host, :permission => 'destroy_hosts'), :class => "btn btn-danger", :confirm => _('Are you sure?'), :method => :delete) ) ) diff --git a/app/helpers/layout_helper.rb b/app/helpers/layout_helper.rb index c5bd2510bb0..8e709c09675 100644 --- a/app/helpers/layout_helper.rb +++ b/app/helpers/layout_helper.rb @@ -125,6 +125,20 @@ def file_field_f(f, attr, options = {}) end end + def autocomplete_f(f, attr, options = {}) + field(f, attr, options) do + path = options.delete(:path) || send("#{f.object.class.pluralize.underscore}_path") + auto_complete_search(attr, + f.object.send(attr).try(:squeeze, " "), + options.merge( + :placeholder => _("Filter") + ' ...', + :path => path, + :name => "#{f.object_name}[#{attr}]" + ) + ).html_safe + end + end + def field(f, attr, options = {}) error = f.object.errors[attr] if f && f.object.respond_to?(:errors) help_inline = help_inline(options.delete(:help_inline), error) @@ -132,7 +146,9 @@ def field(f, attr, options = {}) help_block = content_tag(:span, options.delete(:help_block), :class => "help-block") size_class = options.delete(:size) || "col-md-4" content_tag(:div, :class=> "clearfix") do - content_tag :div, :class => "form-group #{error.empty? ? "" : 'has-error'}" do + content_tag :div, :class => "form-group #{error.empty? ? "" : 'has-error'}", + :id => options.delete(:control_group_id) do + label = options.delete(:label) label ||= ((clazz = f.object.class).respond_to?(:gettext_translation_for_attribute_name) && s_(clazz.gettext_translation_for_attribute_name attr)) if f diff --git a/app/models/architecture.rb b/app/models/architecture.rb index 3931baca325..ec71a941d56 100644 --- a/app/models/architecture.rb +++ b/app/models/architecture.rb @@ -1,5 +1,5 @@ class Architecture < ActiveRecord::Base - include Authorization + include Authorizable before_destroy EnsureNotUsedBy.new(:hosts, :hostgroups) diff --git a/app/models/auth_source.rb b/app/models/auth_source.rb index 98eb2b88c08..5912e8bb70c 100644 --- a/app/models/auth_source.rb +++ b/app/models/auth_source.rb @@ -16,8 +16,8 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class AuthSource < ActiveRecord::Base - include Authorization audited :allow_mass_assignment => true + before_destroy EnsureNotUsedBy.new(:users) has_many :users diff --git a/app/models/bookmark.rb b/app/models/bookmark.rb index f24dd5de157..493fb7ddd63 100644 --- a/app/models/bookmark.rb +++ b/app/models/bookmark.rb @@ -1,4 +1,6 @@ class Bookmark < ActiveRecord::Base + include Authorizable + belongs_to :owner, :polymorphic => true attr_accessible :name, :controller, :query, :public audited :allow_mass_assignment => true diff --git a/app/models/cached_user_role.rb b/app/models/cached_user_role.rb new file mode 100644 index 00000000000..2c7cb32f4fb --- /dev/null +++ b/app/models/cached_user_role.rb @@ -0,0 +1,10 @@ +class CachedUserRole < ActiveRecord::Base + attr_accessible :role_id, :user_id, :user_role_id, :role, :user, :user_role + + belongs_to :user + belongs_to :role + + # this UserRole created this cache + belongs_to :user_role + +end diff --git a/app/models/cached_usergroup_member.rb b/app/models/cached_usergroup_member.rb new file mode 100644 index 00000000000..56f0dee35b3 --- /dev/null +++ b/app/models/cached_usergroup_member.rb @@ -0,0 +1,7 @@ +class CachedUsergroupMember < ActiveRecord::Base + attr_accessible :user_id, :usergroup_id, :user, :usergroup + + belongs_to :user + belongs_to :usergroup + +end diff --git a/app/models/compute_profile.rb b/app/models/compute_profile.rb index 43e09b6bd50..43af9e761df 100644 --- a/app/models/compute_profile.rb +++ b/app/models/compute_profile.rb @@ -1,6 +1,7 @@ class ComputeProfile < ActiveRecord::Base - include Authorization + include Authorizable + attr_accessible :name audited has_associated_audits diff --git a/app/models/compute_resource.rb b/app/models/compute_resource.rb index afcfc18bd27..5b2d3acfd0f 100644 --- a/app/models/compute_resource.rb +++ b/app/models/compute_resource.rb @@ -2,6 +2,7 @@ class ComputeResource < ActiveRecord::Base include Taxonomix include Encryptable + include Authorizable encrypts :password SUPPORTED_PROVIDERS = %w[Libvirt Ovirt EC2 Vmware Openstack Rackspace GCE] PROVIDERS = SUPPORTED_PROVIDERS.reject { |p| !SETTINGS[p.downcase.to_sym] } @@ -13,12 +14,12 @@ class ComputeResource < ActiveRecord::Base STI_PREFIX= "Foreman::Model" before_destroy EnsureNotUsedBy.new(:hosts) - include Authorization has_and_belongs_to_many :users, :join_table => "user_compute_resources" validates :name, :uniqueness => true, :format => { :with => /\A(\S+)\Z/, :message => N_("can't be blank or contain white spaces.") } validates :provider, :presence => true, :inclusion => { :in => PROVIDERS } validates :url, :presence => true scoped_search :on => :name, :complete_value => :true + scoped_search :on => :id, :complete_value => :true before_save :sanitize_url has_many_hosts has_many :images, :dependent => :destroy @@ -36,19 +37,6 @@ class ComputeResource < ActiveRecord::Base end } - scope :my_compute_resources, lambda { - user = User.current - if user.admin? - conditions = { } - else - conditions = sanitize_sql_for_conditions([" (compute_resources.id in (?))", user.compute_resource_ids]) - conditions.sub!(/\s*\(\)\s*/, "") - conditions.sub!(/^(?:\(\))?\s?(?:and|or)\s*/, "") - conditions.sub!(/\(\s*(?:or|and)\s*\(/, "((") - end - where(conditions).reorder('type, name') - } - # allows to create a specific compute class based on the provider. def self.new_provider args raise ::Foreman::Exception.new(N_("must provide a provider")) unless provider = args[:provider] @@ -243,22 +231,6 @@ def nested_attributes_for type, opts private - 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.include? self - end - end - errors.add :base, _("You do not have permission to %s this compute resource") % operation - false - end - def set_attributes_hash self.attrs ||= {} end diff --git a/app/models/compute_resources/foreman/model/ec2.rb b/app/models/compute_resources/foreman/model/ec2.rb index f38736f4ddc..52f4ee78eaf 100644 --- a/app/models/compute_resources/foreman/model/ec2.rb +++ b/app/models/compute_resources/foreman/model/ec2.rb @@ -91,7 +91,7 @@ def update_required?(old_attrs, new_attrs) end def associated_host(vm) - Host.my_hosts.where(:ip => [vm.public_ip_address, vm.private_ip_address]).first + Host.authorized(:view_hosts, Host).where(:ip => [vm.public_ip_address, vm.private_ip_address]).first end private diff --git a/app/models/compute_resources/foreman/model/libvirt.rb b/app/models/compute_resources/foreman/model/libvirt.rb index 79c8a9c7618..a73f5bd0142 100644 --- a/app/models/compute_resources/foreman/model/libvirt.rb +++ b/app/models/compute_resources/foreman/model/libvirt.rb @@ -127,7 +127,7 @@ def hypervisor end def associated_host(vm) - Host.my_hosts.where(:mac => vm.mac).first + Host.authorized(:view_hosts, Host).where(:mac => vm.mac).first end protected diff --git a/app/models/compute_resources/foreman/model/openstack.rb b/app/models/compute_resources/foreman/model/openstack.rb index 7eba98a592e..83a97374159 100644 --- a/app/models/compute_resources/foreman/model/openstack.rb +++ b/app/models/compute_resources/foreman/model/openstack.rb @@ -83,7 +83,7 @@ def console(uuid) end def associated_host(vm) - Host.my_hosts.where(:ip => [vm.floating_ip_address, vm.private_ip_address]).first + Host.authorized(:view_hosts, Host).where(:ip => [vm.floating_ip_address, vm.private_ip_address]).first end def flavor_name(flavor_ref) diff --git a/app/models/compute_resources/foreman/model/ovirt.rb b/app/models/compute_resources/foreman/model/ovirt.rb index d83944160eb..b724d37cb47 100644 --- a/app/models/compute_resources/foreman/model/ovirt.rb +++ b/app/models/compute_resources/foreman/model/ovirt.rb @@ -207,7 +207,7 @@ def update_required?(old_attrs, new_attrs) end def associated_host(vm) - Host.my_hosts.where(:mac => vm.mac).first + Host.authorized(:view_hosts, Host).where(:mac => vm.mac).first end def provider_friendly_name diff --git a/app/models/compute_resources/foreman/model/rackspace.rb b/app/models/compute_resources/foreman/model/rackspace.rb index 98f932931f9..199b8f21cbc 100644 --- a/app/models/compute_resources/foreman/model/rackspace.rb +++ b/app/models/compute_resources/foreman/model/rackspace.rb @@ -88,7 +88,7 @@ def ensure_valid_region end def associated_host(vm) - Host.my_hosts.where(:ip => [vm.public_ip_address, vm.private_ip_address]).first + Host.authorized(:view_hosts, Host).where(:ip => [vm.public_ip_address, vm.private_ip_address]).first end private diff --git a/app/models/compute_resources/foreman/model/vmware.rb b/app/models/compute_resources/foreman/model/vmware.rb index bd4ec9f81b6..476ebc49e89 100644 --- a/app/models/compute_resources/foreman/model/vmware.rb +++ b/app/models/compute_resources/foreman/model/vmware.rb @@ -165,7 +165,7 @@ def pubkey_hash= key end def associated_host(vm) - Host.my_hosts.where(:mac => vm.mac).first + Host.authorized(:view_hosts, Host).where(:mac => vm.mac).first end def provider_friendly_name diff --git a/app/models/concerns/audit_extensions.rb b/app/models/concerns/audit_extensions.rb index b495fcbda9e..31f7593a5e7 100644 --- a/app/models/concerns/audit_extensions.rb +++ b/app/models/concerns/audit_extensions.rb @@ -29,6 +29,8 @@ module AuditExtensions before_save :ensure_username, :ensure_audtiable_and_associated_name after_validation :fix_auditable_type + + include Authorizable end private diff --git a/app/models/concerns/authorizable.rb b/app/models/concerns/authorizable.rb new file mode 100644 index 00000000000..a70913e8023 --- /dev/null +++ b/app/models/concerns/authorizable.rb @@ -0,0 +1,23 @@ +module Authorizable + extend ActiveSupport::Concern + + included do + # permission can be nil (therefore we use Proc instead of lambda) + # same applies for resource class + # + # e.g. + # FactValue.authorized + # FactValue.authorized(:view_facts) + # Host::Base.authorized(:view_hosts, Host) + # + scope :authorized, Proc.new { |permission, resource| + if User.current.nil? + self.where('1=0') + elsif User.current.admin? + self.scoped + else + Authorizer.new(User.current).find_collection(resource || self, :permission => permission) + end + } + end +end diff --git a/app/models/concerns/authorization.rb b/app/models/concerns/authorization.rb deleted file mode 100644 index 5aefc105be2..00000000000 --- a/app/models/concerns/authorization.rb +++ /dev/null @@ -1,68 +0,0 @@ -module Authorization - extend ActiveSupport::Concern - - included do - before_save :enforce_edit_permissions - before_destroy :enforce_destroy_permissions - before_create :enforce_create_permissions - end - - # We must enforce the security model - def enforce_edit_permissions - enforce_permissions("edit") if enforce? - end - - def enforce_destroy_permissions - enforce_permissions("destroy") if enforce? - end - - def enforce_create_permissions - enforce_permissions("create") if enforce? - end - - def enforce_permissions operation - # We get called again with the operation being set to create - return true if operation == "edit" and new_record? - - if self.class < Operatingsystem - klass = 'operatingsystem' - klasses = 'operatingsystems' - else - klass = self.class.name.downcase - klasses = self.class.name.tableize - end - - #TODO: Extract all fo the specific implementations into each individual class - klasses.gsub!(/auth_source.*/, "authenticators") - klasses.gsub!(/common_parameters.*/, "global_variables") - klasses.gsub!(/lookup_key.*/, "external_variables") - klasses.gsub!(/lookup_value.*/, "external_variables") - # editing own user is a special case - if User.current - action = if klass == 'user' - { :controller => 'users', :action => operation, :id => self.id } - else - "#{operation}_#{klasses}".to_sym - end - return true if User.current.allowed_to?(action) - end - - errors.add :base, _("You do not have permission to %{operation} this %{klass}") % { :operation => operation, :klass => klass } - @permission_failed = operation - false - end - - # @return false or name of failed operation - def permission_failed? - return false unless @permission_failed - @permission_failed - end - - private - def enforce? - return false if (User.current and User.current.admin?) - return true if defined?(Rake) and Rails.env == "test" - return false if defined?(Rake) - true - end -end diff --git a/app/models/concerns/hostext/search.rb b/app/models/concerns/hostext/search.rb index 1dfb6f7bf09..f1548405c60 100644 --- a/app/models/concerns/hostext/search.rb +++ b/app/models/concerns/hostext/search.rb @@ -11,6 +11,8 @@ module Search scoped_search :on => :ip, :complete_value => true scoped_search :on => :comment, :complete_value => true scoped_search :on => :enabled, :complete_value => {:true => true, :false => false}, :rename => :'status.enabled' + scoped_search :on => :owner_type, :complete_value => true, :only_explicit => true + scoped_search :on => :owner_id, :complete_value => true, :only_explicit => true scoped_search :on => :puppet_status, :offset => 0, :word_size => Report::BIT_NUM*4, :complete_value => {:true => true, :false => false}, :rename => :'status.interesting' scoped_search :on => :puppet_status, :offset => Report::METRIC.index("applied"), :word_size => Report::BIT_NUM, :rename => :'status.applied' scoped_search :on => :puppet_status, :offset => Report::METRIC.index("restarted"), :word_size => Report::BIT_NUM, :rename => :'status.restarted' @@ -19,12 +21,14 @@ module Search scoped_search :on => :puppet_status, :offset => Report::METRIC.index("skipped"), :word_size => Report::BIT_NUM, :rename => :'status.skipped' scoped_search :on => :puppet_status, :offset => Report::METRIC.index("pending"), :word_size => Report::BIT_NUM, :rename => :'status.pending' - scoped_search :in => :model, :on => :name, :complete_value => true, :rename => :model - scoped_search :in => :hostgroup, :on => :name, :complete_value => true, :rename => :hostgroup - scoped_search :in => :hostgroup, :on => :title, :complete_value => true, :rename => :hostgroup_fullname - scoped_search :in => :hostgroup, :on => :title, :complete_value => true, :rename => :hostgroup_title - scoped_search :in => :domain, :on => :name, :complete_value => true, :rename => :domain - scoped_search :in => :environment, :on => :name, :complete_value => true, :rename => :environment + scoped_search :in => :model, :on => :name, :complete_value => true, :rename => :model + scoped_search :in => :hostgroup, :on => :name, :complete_value => true, :rename => :hostgroup + scoped_search :in => :hostgroup, :on => :title, :complete_value => true, :rename => :hostgroup_fullname + scoped_search :in => :hostgroup, :on => :title, :complete_value => true, :rename => :hostgroup_title + scoped_search :in => :hostgroup, :on => :id, :complete_value => false, :rename => :hostgroup_id, :only_explicit => true + scoped_search :in => :domain, :on => :name, :complete_value => true, :rename => :domain + scoped_search :in => :domain, :on => :id, :complete_value => true, :rename => :domain_id + scoped_search :in => :environment, :on => :name, :complete_value => true, :rename => :environment scoped_search :in => :architecture, :on => :name, :complete_value => true, :rename => :architecture scoped_search :in => :puppet_proxy, :on => :name, :complete_value => true, :rename => :puppetmaster scoped_search :in => :puppet_ca_proxy, :on => :name, :complete_value => true, :rename => :puppet_ca @@ -73,7 +77,7 @@ def search_by_user(key, operator, value) def search_by_puppetclass(key, operator, value) conditions = sanitize_sql_for_conditions(["puppetclasses.name #{operator} ?", value_to_sql(operator, value)]) - hosts = Host.my_hosts.all(:conditions => conditions, :joins => :puppetclasses, :select => 'DISTINCT hosts.id').map(&:id) + hosts = Host.authorized(:view_hosts, Host).all(:conditions => conditions, :joins => :puppetclasses, :select => 'DISTINCT hosts.id').map(&:id) host_groups = Hostgroup.all(:conditions => conditions, :joins => :puppetclasses, :select => 'DISTINCT hostgroups.id').map(&:id) opts = '' diff --git a/app/models/concerns/taxonomix.rb b/app/models/concerns/taxonomix.rb index cd46330741a..1fee1c69345 100644 --- a/app/models/concerns/taxonomix.rb +++ b/app/models/concerns/taxonomix.rb @@ -11,14 +11,56 @@ module Taxonomix after_initialize :set_current_taxonomy scoped_search :in => :locations, :on => :name, :rename => :location, :complete_value => true + scoped_search :in => :locations, :on => :id, :rename => :location_id, :complete_value => true scoped_search :in => :organizations, :on => :name, :rename => :organization, :complete_value => true + scoped_search :in => :organizations, :on => :id, :rename => :organization_id, :complete_value => true end module ClassMethods + attr_accessor :which_ancestry_method, :which_location, :which_organization + # default inner_method includes children (subtree_ids) def with_taxonomy_scope(loc = Location.current, org = Organization.current, inner_method = :subtree_ids) + self.which_ancestry_method = inner_method + self.which_location = loc + self.which_organization = org scope = block_given? ? yield : where('1=1') + scope = scope.where(:id => taxable_ids) if taxable_ids + scope.readonly(false) + end + + # default inner_method includes parents (path_ids) + def with_taxonomy_scope_override(loc = nil, org = nil, inner_method = :path_ids) + # need to .unscoped or default_scope {with_taxonomy_scope} overrides inner_method + unscoped.with_taxonomy_scope(loc, org, inner_method) + end + + def used_taxonomy_ids + used_location_ids + used_organization_ids + end + + def used_location_ids + enforce_default + return [] unless which_location && SETTINGS[:locations_enabled] + (which_location.send(which_ancestry_method) + which_location.ancestor_ids).uniq + end + + def used_organization_ids + enforce_default + return [] unless which_organization && SETTINGS[:organizations_enabled] + (which_organization.send(which_ancestry_method) + which_organization.ancestor_ids).uniq + end + + # default scope is not called if we just use #scoped therefore we have to enforce quering + # to get correct default values + def enforce_default + if which_ancestry_method.nil? + self.scoped.limit(0).all + end + end + + def taxable_ids(loc = which_location, org = which_organization, inner_method = which_ancestry_method) if SETTINGS[:locations_enabled] && loc inner_ids_loc = if Location.ignore?(self.to_s) self.pluck(:id) @@ -38,16 +80,10 @@ def with_taxonomy_scope(loc = Location.current, org = Organization.current, inne inner_ids ||= inner_ids_org if inner_ids_org # In the case of users we want the taxonomy scope to get both the users of the taxonomy and admins. inner_ids << admin_ids if inner_ids && self == User - scope = scope.where(:id => inner_ids) if inner_ids - scope.readonly(false) - end - - # default inner_method includes parents (path_ids) - def with_taxonomy_scope_override(loc = nil, org = nil, inner_method = :path_ids) - with_taxonomy_scope(loc, org, inner_method) + inner_ids end - def inner_select(taxonomy, inner_method) + def inner_select(taxonomy, inner_method = which_ancestry_method) # always include ancestor_ids in inner select taxonomy_ids = (taxonomy.send(inner_method) + taxonomy.ancestor_ids).uniq TaxableTaxonomy.where(:taxable_type => self.name, :taxonomy_id => taxonomy_ids).pluck(:taxable_id).compact.uniq diff --git a/app/models/config_template.rb b/app/models/config_template.rb index 53c9f0b5d1d..70a0d4be3ad 100644 --- a/app/models/config_template.rb +++ b/app/models/config_template.rb @@ -1,5 +1,5 @@ class ConfigTemplate < ActiveRecord::Base - include Authorization + include Authorizable include Taxonomix audited :allow_mass_assignment => true self.auditing_enabled = !(File.basename($0) == "rake" && ARGV.include?("db:migrate")) @@ -78,16 +78,6 @@ def self.find_template opts = {} template.is_a?(ConfigTemplate) ? template : nil end - def enforce_permissions operation - # We get called again with the operation being set to create - return true if operation == "edit" and new_record? - - return true if User.current and User.current.allowed_to?("#{operation}_templates".to_sym) - - errors.add :base, (_("You do not have permission to %s this template") % operation) - false - end - def self.build_pxe_default(renderer) if (proxies = SmartProxy.tftp_proxies).empty? error_msg = _("No TFTP proxies defined, can't continue") diff --git a/app/models/domain.rb b/app/models/domain.rb index 31034538a94..8059e68fd96 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -1,7 +1,7 @@ require "resolv" # This models a DNS domain and so represents a site. class Domain < ActiveRecord::Base - include Authorization + include Authorizable include Taxonomix audited :allow_mass_assignment => true @@ -40,25 +40,6 @@ def to_param "#{id}-#{name.parameterize}" end - 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}_domains".to_sym) - # If you can create domains then you can create them anywhere - return true if operation == "create" - # However if you are editing or destroying and you have a domain list then you are constrained - if current.domains.empty? or current.domains.map(&:id).include? self.id - return true - end - end - - errors.add(:base, _("You do not have permission to %s this domain") % operation) - false - end - # return the primary name server for our domain based on DNS lookup # it first searches for SOA record, if it failed it will search for NS records def nameservers diff --git a/app/models/environment.rb b/app/models/environment.rb index ec41bf33064..9665dc38211 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -1,6 +1,6 @@ class Environment < ActiveRecord::Base include Taxonomix - include Authorization + include Authorizable before_destroy EnsureNotUsedBy.new(:hosts) diff --git a/app/models/fact_value.rb b/app/models/fact_value.rb index 410003e219f..667c0bb3a19 100644 --- a/app/models/fact_value.rb +++ b/app/models/fact_value.rb @@ -1,4 +1,5 @@ class FactValue < ActiveRecord::Base + include Authorizable belongs_to_host belongs_to :fact_name @@ -22,9 +23,8 @@ class FactValue < ActiveRecord::Base } scope :my_facts, lambda { unless User.current.admin? and Organization.current.nil? and Location.current.nil? - #TODO: Remove pluck after upgrade to newer rails as it would be - #done via INNER select automatically - where(:fact_values => {:host_id => Host.my_hosts.pluck(:id)}) + host_ids = Host.authorized(:view_hosts, Host).select('hosts.id').all + where(:fact_values => {:host_id => host_ids}) end } diff --git a/app/models/filter.rb b/app/models/filter.rb new file mode 100644 index 00000000000..143b27674d8 --- /dev/null +++ b/app/models/filter.rb @@ -0,0 +1,138 @@ +class Filter < ActiveRecord::Base + include Taxonomix + include Authorizable + + # tune up taxonomix for filters, we don't want to set current taxonomy + def self.add_current_organization? + false + end + + def self.add_current_location? + false + end + + attr_accessible :search, :resource_type, :permission_ids, :role_id, :unlimited, + :organization_ids, :location_ids + attr_writer :resource_type + attr_accessor :unlimited + + belongs_to :role + has_many :filterings, :dependent => :destroy + has_many :permissions, :through => :filterings + + default_scope lambda { order(['role_id', "#{self.table_name}.id"]) } + scope :unlimited, lambda { where(:search => nil, :taxonomy_search => nil) } + scope :limited, lambda { where("search IS NOT NULL OR taxonomy_search IS NOT NULL") } + + scoped_search :on => :search, :complete_value => true + scoped_search :on => :limited, :complete_value => { :true => true, :false => false }, :ext_method => :search_by_limited + scoped_search :on => :unlimited, :complete_value => { :true => true, :false => false }, :ext_method => :search_by_unlimited + scoped_search :in => :role, :on => :id, :rename => :role_id + scoped_search :in => :role, :on => :name, :rename => :role + scoped_search :in => :permissions, :on => :resource_type, :rename => :resource + + before_validation :build_taxonomy_search, :nilify_empty_searches + + validates :search, :presence => true, :unless => Proc.new { |o| o.search.nil? } + validates :role, :presence => true + validate :same_resource_type_permissions, :not_empty_permissions + + def self.search_by_unlimited(key, operator, value) + search_by_limited(key, operator, value == 'true' ? 'false' : 'true') + end + + def self.search_by_limited(key, operator, value) + value = value == 'true' + value = !value if operator == '<>' + conditions = value ? limited.where_values.join(' AND ') : unlimited.where_values.map(&:to_sql).join(' AND ') + { :conditions => conditions } + end + + def self.get_resource_class(resource_type) + resource_type.constantize + rescue NameError => e + Rails.logger.debug "unknown klass #{resource_type}, ignoring" + return nil + end + + def unlimited? + search.nil? && taxonomy_search.nil? + end + + def limited? + !unlimited? + end + + def to_s + _('filter for %s role') % self.role.try(:name) || 'unknown' + end + + def resource_type + type = @resource_type || permissions.first.try(:resource_type) + type.blank? ? nil : type + end + + def resource_class + @resource_class ||= self.class.get_resource_class(resource_type) + end + + # We detect granularity by inclusion of Authorizable module and scoped_search definition + # we can define exceptions for resources with more complex hierarchy (e.g. Host is proxy module) + def granular? + @granular ||= begin + return false if resource_class.nil? + return true if resource_type == 'Host' + resource_class.included_modules.include?(Authorizable) && resource_class.respond_to?(:search_for) + end + end + + def search_condition + searches = [self.search, self.taxonomy_search].compact + searches = searches.map { |s| parenthesize(s) } if searches.size > 1 + searches.join(' and ') + end + + private + + def build_taxonomy_search + orgs = build_taxonomy_search_string('organization') + locs = build_taxonomy_search_string('location') + + if self.organizations.empty? && self.locations.empty? + self.taxonomy_search = nil + else + taxonomies = [orgs, locs].reject {|t| t.blank? } + self.taxonomy_search = taxonomies.join(' and ') + end + end + + def build_taxonomy_search_string(name) + relation = name.pluralize + taxes = self.send(relation).empty? ? [] : self.send(relation).map { |t| "#{name}_id = #{t.id}" } + taxes = taxes.join(' or ') + parenthesize(taxes) + end + + def nilify_empty_searches + self.search = nil if self.search.empty? || self.unlimited == '1' + self.taxonomy_search = nil if self.taxonomy_search.empty? + end + + def parenthesize(string) + if string.blank? || (string.start_with?('(') && string.end_with?(')')) + string + else + "(#{string})" + end + end + + # if we have 0 types, empty validation will set error, we can't have more than one type + def same_resource_type_permissions + errors.add(:permissions, _('Permissions must be of same resource type')) if self.permissions.map(&:resource_type).uniq.size > 1 + end + + def not_empty_permissions + errors.add(:permissions, _('You must select at least one permission')) if self.permissions.blank? && self.filterings.blank? + end + +end diff --git a/app/models/filtering.rb b/app/models/filtering.rb new file mode 100644 index 00000000000..59df77f2a93 --- /dev/null +++ b/app/models/filtering.rb @@ -0,0 +1,6 @@ +class Filtering < ActiveRecord::Base + attr_accessible :filter_id, :permission_id + + belongs_to :filter + belongs_to :permission +end diff --git a/app/models/host/base.rb b/app/models/host/base.rb index 749c78a0753..3cbf8191960 100644 --- a/app/models/host/base.rb +++ b/app/models/host/base.rb @@ -3,6 +3,7 @@ module Host class Base < ActiveRecord::Base include Foreman::STI + include Authorizable self.table_name = :hosts OWNER_TYPES = %w(User Usergroup) @@ -20,42 +21,6 @@ class Base < ActiveRecord::Base :allow_blank => true, :message => (_("Owner type needs to be one of the following: %s") % OWNER_TYPES.join(', ')) - scope :my_hosts, lambda { - user = User.current - return if user.admin? # Admin can see all hosts - - 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.domain_ids)]) - compute_resource_conditions = sanitize_sql_for_conditions([" (hosts.compute_resource_id in (?))",(crs = user.compute_resource_ids)]) - hostgroup_conditions = sanitize_sql_for_conditions([" (hosts.hostgroup_id in (?))",(hgs = user.hostgroup_ids)]) - organization_conditions = sanitize_sql_for_conditions([" (hosts.organization_id in (?))",orgs = (user.organization_ids)]) - location_conditions = sanitize_sql_for_conditions([" (hosts.location_id in (?))",locs = (user.location_ids)]) - - fact_conditions = "" - for user_fact in (ufs = user.user_facts) - fact_conditions += sanitize_sql_for_conditions ["(hosts.id = fact_values.host_id and fact_values.fact_name_id = ? and fact_values.value #{user_fact.operator} ?)", user_fact.fact_name_id, user_fact.criteria] - fact_conditions = user_fact.andor == "and" ? "(#{fact_conditions}) and " : "#{fact_conditions} or " - end - if (match = fact_conditions.match(/\A(.*).....\Z/)) - fact_conditions = "(#{match[1]})" - end - - conditions = "" - 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 = (user.organizations_andor == "and") ? "(#{conditions}) and #{organization_conditions} " : "#{conditions} or #{organization_conditions} ") unless orgs.empty? - (conditions = (user.locations_andor == "and") ? "(#{conditions}) and #{location_conditions} " : "#{conditions} or #{location_conditions} ") unless locs.empty? - conditions.sub!(/\s*\(\)\s*/, "") - conditions.sub!(/\A(?:\(\))?\s?(?:and|or)\s*/, "") - conditions.sub!(/\(\s*(?:or|and)\s*\(/, "((") - end - - joins(ufs.empty? ? nil : :fact_values).where(conditions) - } def self.attributes_protected_by_default super - [ inheritance_column ] end diff --git a/app/models/host/managed.rb b/app/models/host/managed.rb index 8b0a6e243e3..d6d45435279 100644 --- a/app/models/host/managed.rb +++ b/app/models/host/managed.rb @@ -1,5 +1,4 @@ class Host::Managed < Host::Base - include Authorization include ReportCommon include Hostext::Search @@ -94,8 +93,6 @@ class Jail < ::Safemode::Jail scope :alerts_enabled, lambda { where(:enabled => true) } - scope :completer_scope, lambda { |opts| my_hosts } - scope :run_distribution, lambda { |fromtime,totime| if fromtime.nil? or totime.nil? raise ::Foreman.Exception.new(N_("invalid time range")) @@ -457,11 +454,13 @@ def importNode nodeinfo # counts each association of a given host # e.g. how many hosts belongs to each os # returns sorted hash - def self.count_distribution assocication + def self.count_distribution association output = [] - group(assocication).count.each do |k,v| + data = group("#{Host.table_name}.#{association}_id").reorder('').count + associations = association.to_s.camelize.constantize.where(:id => data.keys).all + data.each do |k,v| begin - output << {:label => k.to_label, :data => v } unless v == 0 + output << {:label => associations.detect {|a| a.id == k }.to_label, :data => v } unless v == 0 rescue logger.info "skipped #{k} as it has has no label" end @@ -474,7 +473,7 @@ def self.count_distribution assocication # e.g. how many hosts belongs to each os # returns sorted hash def self.count_habtm association - counter = Host::Managed.joins(association.tableize.to_sym).group("#{association.tableize.to_sym}.id").count + counter = Host::Managed.joins(association.tableize.to_sym).group("#{association.tableize.to_sym}.id").reorder('').count #Puppetclass.find(counter.keys.compact)... association.camelize.constantize.find(counter.keys.compact).map {|i| {:label=>i.to_label, :data =>counter[i.id]}} end @@ -489,28 +488,6 @@ def can_be_built? managed? and SETTINGS[:unattended] and capabilities.include?(:build) ? build == false : false end - def enforce_permissions operation - if operation == "edit" and new_record? - return true # We get called again with the operation being set to create - end - current = User.current - if (operation == "edit") or operation == "destroy" - if current.allowed_to?("#{operation}_hosts".to_sym) - return true if Host::Base.my_hosts.include? self - end - else # create - if current.allowed_to?(:create_hosts) - # We are unconstrained - return true if current.domains.empty? and current.hostgroups.empty? - # We are constrained and the constraint is matched - return true if (!current.domains.empty? and current.domains.include?(domain)) or - (!current.hostgroups.empty? and current.hostgroups.include?(hostgroup)) - end - end - errors.add(:base, _("You do not have permission to %s this host") % operation) - false - end - def jumpstart? operatingsystem.family == "Solaris" and architecture.name =~/Sparc/i rescue false end diff --git a/app/models/host_class.rb b/app/models/host_class.rb index 6f9b881b668..a5bac8af398 100644 --- a/app/models/host_class.rb +++ b/app/models/host_class.rb @@ -1,5 +1,5 @@ class HostClass < ActiveRecord::Base - include Authorization + include Authorizable audited :associated_with => :host, :allow_mass_assignment => true belongs_to_host :foreign_key => :host_id belongs_to :puppetclass @@ -11,18 +11,4 @@ def name "#{host} - #{puppetclass}" end - private - - def enforce_permissions operation - if operation == "edit" and new_record? - return true # We get called again with the operation being set to create - end - if User.current.allowed_to?(:edit_classes) && Host.my_hosts.pluck(:id).include?(self.host_id) - return true - else - errors.add(:base, _("You do not have permission to edit Puppet classes on this host")) - return false - end - end - end diff --git a/app/models/hostgroup.rb b/app/models/hostgroup.rb index 8f492b9215c..8b72459bea9 100644 --- a/app/models/hostgroup.rb +++ b/app/models/hostgroup.rb @@ -1,5 +1,6 @@ class Hostgroup < ActiveRecord::Base - include Authorization + has_ancestry :orphan_strategy => :restrict + include Authorizable include Taxonomix include HostCommon include NestedAncestryCommon @@ -36,6 +37,7 @@ class Hostgroup < ActiveRecord::Base scoped_search :in => :hosts, :on => :name, :complete_value => :true, :rename => "host" scoped_search :in => :puppetclasses, :on => :name, :complete_value => true, :rename => :class, :operators => ['= ', '~ '] scoped_search :in => :environment, :on => :name, :complete_value => :true, :rename => :environment + scoped_search :on => :id, :complete_value => :true if SETTINGS[:unattended] scoped_search :in => :architecture, :on => :name, :complete_value => :true, :rename => :architecture scoped_search :in => :operatingsystem, :on => :name, :complete_value => true, :rename => :os diff --git a/app/models/hostgroup_class.rb b/app/models/hostgroup_class.rb index 1eb9d9af6a6..7c37cef566c 100644 --- a/app/models/hostgroup_class.rb +++ b/app/models/hostgroup_class.rb @@ -1,5 +1,5 @@ class HostgroupClass < ActiveRecord::Base - include Authorization + include Authorizable audited :associated_with => :hostgroup, :allow_mass_assignment => true belongs_to :hostgroup belongs_to :puppetclass @@ -13,18 +13,4 @@ def name "#{hostgroup} - #{puppetclass}" end - private - - def enforce_permissions operation - if operation == "edit" and new_record? - return true # We get called again with the operation being set to create - end - if User.current.allowed_to?(:edit_classes) && Hostgroup.my_groups.pluck(:id).include?(self.hostgroup_id) - return true - else - errors.add(:base, _("You do not have permission to edit Puppet classes on this host group")) - return false - end - end - end diff --git a/app/models/image.rb b/app/models/image.rb index cdee841c5b4..ee35ccfc3a6 100644 --- a/app/models/image.rb +++ b/app/models/image.rb @@ -1,4 +1,5 @@ class Image < ActiveRecord::Base + include Authorizable audited :allow_mass_assignment => true diff --git a/app/models/lookup_key.rb b/app/models/lookup_key.rb index 843719f31de..b3acb5a7ff4 100644 --- a/app/models/lookup_key.rb +++ b/app/models/lookup_key.rb @@ -1,5 +1,5 @@ class LookupKey < ActiveRecord::Base - include Authorization + include Authorizable KEY_TYPES = %w( string boolean integer real array hash yaml json ) VALIDATOR_TYPES = %w( regexp list ) diff --git a/app/models/lookup_value.rb b/app/models/lookup_value.rb index 6c9028aa6e9..b39151d6063 100644 --- a/app/models/lookup_value.rb +++ b/app/models/lookup_value.rb @@ -1,5 +1,5 @@ class LookupValue < ActiveRecord::Base - include Authorization + include Authorizable belongs_to :lookup_key, :counter_cache => true validates :match, :presence => true, :uniqueness => {:scope => :lookup_key_id} delegate :key, :to => :lookup_key @@ -69,24 +69,4 @@ def ensure_hostgroup_exists errors.add(:match, _("%{match} does not match an existing host group") % { :match => match }) and return false end - private - - def enforce_permissions operation - # We get called again with the operation being set to create - return true if operation == "edit" and new_record? - allowed = case match - when /^fqdn=(.*)/ - # check if current fqdn is in our allowed list - Host.my_hosts.where(:name => $1).exists? || self.host_or_hostgroup.try(:new_record?) - when /^hostgroup=(.*)/ - # check if current hostgroup is in our allowed list - Hostgroup.my_groups.where(:title => $1).exists? || self.host_or_hostgroup.try(:new_record?) - else - false - end - return true if allowed - errors.add :base, _("You do not have permission to %s this Smart Variable") % operation - return false - end - end diff --git a/app/models/medium.rb b/app/models/medium.rb index ddc552e2001..5b96e86ee55 100644 --- a/app/models/medium.rb +++ b/app/models/medium.rb @@ -1,5 +1,5 @@ class Medium < ActiveRecord::Base - include Authorization + include Authorizable include Taxonomix include ValidateOsFamily audited :allow_mass_assignment => true diff --git a/app/models/model.rb b/app/models/model.rb index 75280fa43ed..6a1f289a2f9 100644 --- a/app/models/model.rb +++ b/app/models/model.rb @@ -1,5 +1,5 @@ class Model < ActiveRecord::Base - include Authorization + include Authorizable has_many_hosts has_many :trends, :as => :trendable, :class_name => "ForemanTrend" diff --git a/app/models/operatingsystem.rb b/app/models/operatingsystem.rb index c1fc884acf1..30deccfdbe0 100644 --- a/app/models/operatingsystem.rb +++ b/app/models/operatingsystem.rb @@ -2,7 +2,7 @@ require 'uri' class Operatingsystem < ActiveRecord::Base - include Authorization + include Authorizable include ValidateOsFamily before_destroy EnsureNotUsedBy.new(:hosts, :hostgroups) diff --git a/app/models/operatingsystems/archlinux.rb b/app/models/operatingsystems/archlinux.rb index 5d36158ad93..48d16714d56 100644 --- a/app/models/operatingsystems/archlinux.rb +++ b/app/models/operatingsystems/archlinux.rb @@ -19,6 +19,7 @@ def url_for_boot(file) pxedir + "/" + PXEFILES[file] end + def display_family "Arch Linux" end diff --git a/app/models/parameter.rb b/app/models/parameter.rb index 2c5a7f4acd8..7dbe9e7ffa9 100644 --- a/app/models/parameter.rb +++ b/app/models/parameter.rb @@ -1,6 +1,6 @@ class Parameter < ActiveRecord::Base belongs_to_host :foreign_key => :reference_id - include Authorization + include Authorizable validates :value, :presence => true validates :name, :presence => true, :format => {:with => /\A\S*\Z/, :message => N_("can't contain white spaces")} diff --git a/app/models/parameters/domain_parameter.rb b/app/models/parameters/domain_parameter.rb index a72fced7766..45c2b909016 100644 --- a/app/models/parameters/domain_parameter.rb +++ b/app/models/parameters/domain_parameter.rb @@ -2,21 +2,4 @@ class DomainParameter < Parameter belongs_to :domain, :foreign_key => :reference_id audited :except => [:priority], :associated_with => :domain, :allow_mass_assignment => true validates :name, :uniqueness => {:scope => :reference_id} - - private - 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}_domains".to_sym) - if current.domains.empty? or current.domains.include? domain - return true - end - end - - errors.add(:base, _("You do not have permission to %s this domain parameter") % operation) - false - end end diff --git a/app/models/parameters/group_parameter.rb b/app/models/parameters/group_parameter.rb index ce3a8de59bd..ceaedfc48d9 100644 --- a/app/models/parameters/group_parameter.rb +++ b/app/models/parameters/group_parameter.rb @@ -3,20 +3,4 @@ class GroupParameter < Parameter audited :except => [:priority], :associated_with => :hostgroup, :allow_mass_assignment => true validates :name, :uniqueness => {:scope => :reference_id} - private - 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}_params".to_sym) - if current.hostgroups.empty? or current.hostgroups.include? hostgroup - return true - end - end - - errors.add(:base, _("You do not have permission to %s this group parameter") % operation) - false - end end diff --git a/app/models/parameters/host_parameter.rb b/app/models/parameters/host_parameter.rb index 1b3fdb52c1c..165be6ae4b6 100644 --- a/app/models/parameters/host_parameter.rb +++ b/app/models/parameters/host_parameter.rb @@ -7,14 +7,4 @@ def to_s "#{host.id ? host.name : "unassociated"}: #{name} = #{value}" end - private - def enforce_permissions operation - # We get called again with the operation being set to create - return true if operation == "edit" and new_record? - - (auth = User.current.allowed_to?("#{operation}_params".to_sym)) and Host.my_hosts.include?(host) - - errors.add(:base, _("You do not have permission to %s this domain") % operation) unless auth - auth - end end diff --git a/app/models/parameters/os_parameter.rb b/app/models/parameters/os_parameter.rb index 8ba30ff8954..2e259e4d555 100644 --- a/app/models/parameters/os_parameter.rb +++ b/app/models/parameters/os_parameter.rb @@ -3,14 +3,4 @@ class OsParameter < Parameter audited :except => [:priority], :associated_with => :operatingsystem, :allow_mass_assignment => true validates :name, :uniqueness => {:scope => :reference_id} - private - def enforce_permissions operation - # We get called again with the operation being set to create - return true if operation == "edit" and new_record? - return true if User.current.allowed_to?("#{operation}_operatingsystems".to_sym) - - errors.add(:base, _("You do not have permission to %s this Operating System parameter") % operation) - false - end - end diff --git a/app/models/permission.rb b/app/models/permission.rb new file mode 100644 index 00000000000..b5f86ca04bb --- /dev/null +++ b/app/models/permission.rb @@ -0,0 +1,20 @@ +class Permission < ActiveRecord::Base + attr_accessible :name, :resource_type + + validates :name, :presence => true, :uniqueness => { :scope => :resource_type } + + has_many :filterings, :dependent => :destroy + has_many :filters, :through => :filterings + + def self.resources + @all_resources ||= Permission.uniq.order(:resource_type).pluck(:resource_type).compact + end + + def self.resources_with_translations + with_translations.sort { |a, b| a.first <=> b.first } + end + + def self.with_translations + resources.map { |r| [_(Filter.get_resource_class(r).try(:humanize_class_name) || r), r] } + end +end diff --git a/app/models/ptable.rb b/app/models/ptable.rb index ee0a5592602..461786ccd8f 100644 --- a/app/models/ptable.rb +++ b/app/models/ptable.rb @@ -3,7 +3,7 @@ # A host object may contain a reference to one of these ptables or, alternatively, it may contain a # modified version of one of these in textual form class Ptable < ActiveRecord::Base - include Authorization + include Authorizable include ValidateOsFamily audited :allow_mass_assignment => true diff --git a/app/models/puppetclass.rb b/app/models/puppetclass.rb index f953e3dc798..1fe9282ab16 100644 --- a/app/models/puppetclass.rb +++ b/app/models/puppetclass.rb @@ -1,5 +1,5 @@ class Puppetclass < ActiveRecord::Base - include Authorization + include Authorizable before_destroy EnsureNotUsedBy.new(:hosts, :hostgroups) has_many :environment_classes, :dependent => :destroy has_many :environments, :through => :environment_classes, :uniq => true diff --git a/app/models/report.rb b/app/models/report.rb index 8ea60fdc4c3..4f924f0f220 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -1,5 +1,5 @@ class Report < ActiveRecord::Base - include Authorization + include Authorizable include ReportCommon belongs_to_host @@ -33,7 +33,8 @@ class Report < ActiveRecord::Base # returns reports for hosts in the User's filter set scope :my_reports, lambda { unless User.current.admin? and Organization.current.nil? and Location.current.nil? - where(:reports => {:host_id => Host.my_hosts.select("hosts.id")}) + host_ids = Host.authorized(:view_hosts, Host).select("hosts.id").all + where(:reports => {:host_id => host_ids}) end } @@ -171,18 +172,6 @@ def summaryStatus private - def enforce_permissions operation - # No one can edit a report - return false if operation == "edit" - - # Anyone can create a report - return true if operation == "create" - return true if operation == "destroy" and User.current.allowed_to?(:destroy_reports) - - errors.add(:base, _("You do not have permission to %s this report") % operation) - false - end - # puppet report status table column name def self.report_status "status" diff --git a/app/models/role.rb b/app/models/role.rb index c24a47b295c..bfbc1e37bb0 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -31,12 +31,17 @@ class Role < ActiveRecord::Base before_destroy :check_deletable has_many :user_roles, :dependent => :destroy - has_many :users, :through => :user_roles + has_many :users, :through => :user_roles, :source => :owner, :source_type => 'User' + has_many :usergroups, :through => :user_roles, :source => :owner, :source_type => 'Usergroup' + has_many :cached_user_roles, :dependent => :destroy + has_many :cached_users, :through => :cached_user_roles, :source => :user - serialize :permissions, Array + has_many :filters, :dependent => :destroy + + has_many :permissions, :through => :filters attr_protected :builtin - validates :name, :presence => true, :uniqueness => true, :length => {:maximum => 30}, :format => {:with => /\A\w[\w\s\'\-]*\w\Z/i} + validates :name, :presence => true, :uniqueness => true, :format => {:with => /\A\w[\w\s\'\-]*\w\Z/i} validates :builtin, :inclusion => { :in => 0..2 } scoped_search :on => :name, :complete_value => true @@ -46,36 +51,13 @@ def initialize *args self.builtin = 0 end - def permissions - read_attribute(:permissions) || [] - end - - def permissions=(perms) - perms = perms.collect {|p| p.to_sym unless p.blank? }.compact.uniq if perms - write_attribute(:permissions, perms) - end - - def add_permission!(*perms) - self.permissions = [] unless permissions.is_a?(Array) - - permissions_will_change! - perms.each do |p| - p = p.to_sym - permissions << p unless permissions.include?(p) - end - save! - end - - def remove_permission!(*perms) - return unless permissions.is_a?(Array) - permissions_will_change! - perms.each { |p| permissions.delete(p.to_sym) } - save! - end - # Returns true if the role has the given permission def has_permission?(perm) - !permissions.nil? && permissions.include?(perm.to_sym) + permission_names.include?(perm.to_sym) + end + + def permission_names + @permission_names ||= permissions.map { |p| p.name.to_sym } end # Return true if the role is a builtin role @@ -94,19 +76,13 @@ def user? # * a permission Symbol (eg. :edit_project) def allowed_to?(action) if action.is_a? Hash + action[:controller] = action[:controller][1..-1] if action[:controller].starts_with?('/') allowed_actions.include? "#{action[:controller]}/#{action[:action]}" else allowed_permissions.include? action end end - # Return all the permissions that can be given to the role - def setable_permissions - setable_permissions = Foreman::AccessControl.permissions - Foreman::AccessControl.public_permissions - setable_permissions -= Foreman::AccessControl.loggedin_only_permissions if self.builtin == BUILTIN_ANONYMOUS - setable_permissions - end - # Find all the roles that can be given to a user def self.find_all_givable all(:conditions => {:builtin => 0}, :order => 'name') @@ -138,9 +114,35 @@ def self.anonymous anonymous_role end + # options can have following keys + # :search - scoped search applied to built filters + def add_permissions(permissions, options = {}) + permissions = Array(permissions) + search = options.delete(:search) + + collection = Permission.where(:name => permissions).all + raise ArgumentError, 'some permissions were not found' if collection.size != permissions.size + + collection.group_by(&:resource_type).each do |resource_type, grouped_permissions| + filter = self.filters.build(:search => search) + filter.role ||= self + + grouped_permissions.each do |permission| + filtering = filter.filterings.build + filtering.filter = filter + filtering.permission = permission + end + end + end + + def add_permissions!(*args) + add_permissions(*args) + save! + end + private def allowed_permissions - @allowed_permissions ||= permissions + Foreman::AccessControl.public_permissions.collect {|p| p.name} + @allowed_permissions ||= permission_names + Foreman::AccessControl.public_permissions.map(&:name) end def allowed_actions diff --git a/app/models/setting/general.rb b/app/models/setting/general.rb index e6a69296f8c..13f6a65e5c1 100644 --- a/app/models/setting/general.rb +++ b/app/models/setting/general.rb @@ -13,6 +13,7 @@ def self.load_defaults self.set('foreman_url', N_("URL where your Foreman instance is reachable (see also Provisioning > unattended_url)"), "#{protocol}://#{Facter.fqdn}"), self.set('email_reply_address', N_("Email reply address for emails that Foreman is sending"), "Foreman-noreply@#{domain}"), self.set('entries_per_page', N_("Number of records shown per page in Foreman"), 20), + self.set('fix_db_cache', N_('Fix DB cache on next Foreman restart'),false), self.set('authorize_login_delegation', N_("Authorize login delegation with REMOTE_USER environment variable"),false), self.set('authorize_login_delegation_api', N_("Authorize login delegation with REMOTE_USER environment variable for API calls too"),false), self.set('idle_timeout', N_("Log out idle users after a certain number of minutes"),60), diff --git a/app/models/smart_proxy.rb b/app/models/smart_proxy.rb index 3e3adc289fe..e0a45af7a3b 100644 --- a/app/models/smart_proxy.rb +++ b/app/models/smart_proxy.rb @@ -1,5 +1,5 @@ class SmartProxy < ActiveRecord::Base - include Authorization + include Authorizable include Taxonomix audited :allow_mass_assignment => true @@ -22,6 +22,8 @@ class SmartProxy < ActiveRecord::Base # There should be no problem with associating features before the proxy is saved as the whole operation is in a transaction before_save :sanitize_url, :associate_features + scoped_search :on => :name, :complete_value => :true + # with proc support, default_scope can no longer be chained # include all default scoping here default_scope lambda { @@ -30,12 +32,6 @@ class SmartProxy < ActiveRecord::Base end } - scope :my_proxies, lambda { - user = User.current - conditions = user.admin? || user.allowed_to?({ :controller => :smart_proxy, :action => :index }) ? {} : '1 = 0' - where(conditions) - } - Feature.name_map.each { |f, v| scope "#{f}_proxies".to_sym, where(:features => { :name => v }).joins(:features) } def hostname diff --git a/app/models/subnet.rb b/app/models/subnet.rb index b94cbed80f4..2ac65fdeaa9 100644 --- a/app/models/subnet.rb +++ b/app/models/subnet.rb @@ -1,6 +1,6 @@ require 'ipaddr' class Subnet < ActiveRecord::Base - include Authorization + include Authorizable include Taxonomix audited :allow_mass_assignment => true diff --git a/app/models/taxonomy.rb b/app/models/taxonomy.rb index c2b344e396d..6bbf6a5b73b 100644 --- a/app/models/taxonomy.rb +++ b/app/models/taxonomy.rb @@ -1,5 +1,6 @@ class Taxonomy < ActiveRecord::Base - include Authorization + include Authorizable + include NestedAncestryCommon serialize :ignore_types, Array diff --git a/app/models/template_combination.rb b/app/models/template_combination.rb index cf1c11e9229..090eaa9c508 100644 --- a/app/models/template_combination.rb +++ b/app/models/template_combination.rb @@ -5,8 +5,4 @@ class TemplateCombination < ActiveRecord::Base validates :environment_id, :uniqueness => {:scope => [:hostgroup_id, :config_template_id]} validates :hostgroup_id, :uniqueness => {:scope => [:environment_id, :config_template_id]} - # process_resource_error relies on presence of this method - def permission_failed? - false - end end diff --git a/app/models/user.rb b/app/models/user.rb index e9fd8baeab5..c8e0fc88e3d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,7 +1,7 @@ require 'digest/sha1' class User < ActiveRecord::Base - include Authorization + include Authorizable include Foreman::ThreadSession::UserModel include Taxonomix audited :except => [:last_login_on, :password, :password_hash, :password_salt, :password_confirmation], :allow_mass_assignment => true @@ -16,10 +16,16 @@ class User < ActiveRecord::Base has_many :auditable_changes, :class_name => '::Audit', :as => :user has_many :usergroup_member, :as => :member, :dependent => :destroy has_many :usergroups, :through => :usergroup_member + has_many :cached_usergroup_members + has_many :cached_usergroups, :through => :cached_usergroup_members, :source => :usergroup has_many :direct_hosts, :as => :owner, :class_name => "Host" has_and_belongs_to_many :notices, :join_table => 'user_notices' - has_many :user_roles, :dependent => :destroy - has_many :roles, :through => :user_roles + has_many :user_roles, :dependent => :destroy, :foreign_key => 'owner_id', :conditions => {:owner_type => self.to_s} + has_many :roles, :through => :user_roles, :dependent => :destroy + has_many :cached_user_roles, :dependent => :destroy + has_many :cached_roles, :through => :cached_user_roles, :source => :role, :uniq => true + has_many :filters, :through => :cached_roles + has_many :permissions, :through => :filters has_and_belongs_to_many :compute_resources, :join_table => "user_compute_resources" has_and_belongs_to_many :domains, :join_table => "user_domains" has_many :user_hostgroups, :dependent => :destroy @@ -28,8 +34,16 @@ class User < ActiveRecord::Base has_many :facts, :through => :user_facts, :source => :fact_name attr_name :login - scope :except_admin, lambda { where(:admin => false) } - scope :only_admin, lambda { where(:admin => true) } + scope :except_admin, lambda { + includes(:cached_usergroups). + where(["(#{self.table_name}.admin = ? OR #{self.table_name}.admin IS NULL) AND " + + "(#{Usergroup.table_name}.admin = ? OR #{Usergroup.table_name}.admin IS NULL)", + false, false]) + } + scope :only_admin, lambda { + includes(:cached_usergroups). + where(["#{self.table_name}.admin = ? OR #{Usergroup.table_name}.admin = ?", true, true]) + } accepts_nested_attributes_for :user_facts, :reject_if => lambda { |a| a[:criteria].blank? }, :allow_destroy => true @@ -57,9 +71,10 @@ class User < ActiveRecord::Base scoped_search :on => :firstname, :complete_value => :true scoped_search :on => :lastname, :complete_value => :true scoped_search :on => :mail, :complete_value => :true - scoped_search :on => :admin, :complete_value => {:true => true, :false => false} + scoped_search :on => :admin, :complete_value => { :true => true, :false => false }, :ext_method => :search_by_admin scoped_search :on => :last_login_on, :complete_value => :true, :only_explicit => true scoped_search :in => :roles, :on => :name, :rename => :role, :complete_value => true + scoped_search :in => :cached_usergroups, :on => :name, :rename => :usergroup, :complete_value => true default_scope lambda { with_taxonomy_scope do @@ -67,6 +82,35 @@ class User < ActiveRecord::Base end } + def can?(permission, subject = nil) + if self.admin? + true + else + @authorizer ||= Authorizer.new(self) + @authorizer.can?(permission, subject) + end + end + + def self.search_by_admin(key, operator, value) + value = value == 'true' + value = !value if operator == '<>' + conditions = [self.table_name, Usergroup.table_name].map do |base| + "(#{base}.admin = ?" + (value ? ')' : " OR #{base}.admin IS NULL)") + end + conditions = conditions.join(value ? ' OR ' : ' AND ') + + { + :include => :cached_usergroups, + :conditions => sanitize_sql_for_conditions([conditions, value, value]) + } + end + + # note that if you assign user new usergroups which change the admin flag you must save + # the record before #admin? will reflect this + def admin? + read_attribute(:admin) || cached_usergroups.any?(&:admin?) + end + def to_label (firstname.present? || lastname.present?) ? "#{firstname} #{lastname}" : login end @@ -195,7 +239,7 @@ def allowed_to?(action) action[:controller] = action[:controller].to_s.gsub(/::/, "_").sub(/^\//,'').underscore return true if editing_self?(action) end - roles.detect {|role| role.allowed_to?(action)}.present? + cached_roles.detect {|role| role.allowed_to?(action)}.present? end def logged? diff --git a/app/models/user_role.rb b/app/models/user_role.rb index d78d7c549b5..d2364ae4346 100644 --- a/app/models/user_role.rb +++ b/app/models/user_role.rb @@ -16,9 +16,53 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class UserRole < ActiveRecord::Base - belongs_to :user + belongs_to :owner, :polymorphic => true belongs_to :role + has_many :cached_user_roles, :dependent => :destroy + validates :role_id, :presence => true - validates :user_id, :presence => true, :uniqueness => {:scope => :role_id, :message => N_("has this role already")} + validates :owner_id, :presence => true, :uniqueness => {:scope => [:role_id, :owner_type], + :message => N_("has this role already")} + def user_role? + self.owner_type == 'User' + end + + def user_group_role? + self.owner_type == 'Usergroup' + end + + before_save :remove_cache! + after_save :cache_user_roles! + before_destroy :remove_cache! + + private + + def remove_cache! + cached_user_roles.destroy_all + end + + def cache_user_roles! + if self.user_role? + built = build_user_role_cache + elsif self.user_group_role? + built = build_user_group_role_cache(self.owner) + else + raise 'unknown UserRole owner type' + end + + built.all?(&:save!) + end + + def build_user_role_cache + [ self.cached_user_roles.build(:user => owner, :role => role) ] + end + + def build_user_group_role_cache(owner) + cache = [] + cache += owner.users.map { |m| self.cached_user_roles.build(:user => m, :role => role) } + cache += owner.usergroups.map { |g| build_user_group_role_cache(g) } + cache.flatten + end + end diff --git a/app/models/usergroup.rb b/app/models/usergroup.rb index 1ee38e41da2..84757012ef2 100644 --- a/app/models/usergroup.rb +++ b/app/models/usergroup.rb @@ -1,10 +1,19 @@ class Usergroup < ActiveRecord::Base - include Authorization audited :allow_mass_assignment => true + include Authorizable + + has_many :user_roles, :dependent => :destroy, :foreign_key => 'owner_id', :conditions => {:owner_type => self.to_s} + has_many :roles, :through => :user_roles, :dependent => :destroy has_many :usergroup_members, :dependent => :destroy - has_many :users, :through => :usergroup_members, :source => :member, :source_type => 'User' - has_many :usergroups, :through => :usergroup_members, :source => :member, :source_type => 'Usergroup' + has_many :users, :through => :usergroup_members, :source => :member, :source_type => 'User', :dependent => :destroy + has_many :usergroups, :through => :usergroup_members, :source => :member, :source_type => 'Usergroup', :dependent => :destroy + + has_many :cached_usergroup_members + has_many :usergroup_parents, :dependent => :destroy, :foreign_key => 'member_id', + :conditions => "member_type = 'Usergroup'", :class_name => 'UsergroupMember' + has_many :parents, :through => :usergroup_parents, :source => :usergroup, :dependent => :destroy + has_many_hosts :as => :owner validates :name, :uniqueness => true diff --git a/app/models/usergroup_member.rb b/app/models/usergroup_member.rb index 6fea6dd53f3..8b1f9d3191c 100644 --- a/app/models/usergroup_member.rb +++ b/app/models/usergroup_member.rb @@ -2,4 +2,112 @@ class UsergroupMember < ActiveRecord::Base belongs_to :member, :polymorphic => true belongs_to :usergroup + before_validation :ensure_no_cycle + before_update :remove_old_cache_for_old_record + after_save :add_new_cache + after_destroy :remove_old_cache + + scope :user_memberships, lambda { where("member_type = 'User'") } + scope :usergroup_memberships, lambda { where("member_type = 'Usergroup'") } + + private + + def ensure_no_cycle + current = UsergroupMember.usergroup_memberships + EnsureNoCycle.new(current, :usergroup_id, :member_id).ensure(self) + end + + def add_new_cache + find_all_affected_users.each do |user| + find_all_user_roles.each do |user_role| + CachedUserRole.create!(:user => user, :role => user_role.role, + :user_role => user_role) + end + + find_all_usergroups.each do |group| + CachedUsergroupMember.create!(:user => user, :usergroup => group) + end + end + end + + def remove_old_cache_for_old_record + klass = member_type_changed? ? self.member_type_was.constantize : self.member_type.constantize + users = member_id_changed? ? find_all_affected_users_for(klass.find(member_id_was)).flatten : find_all_affected_users + roles = usergroup_id_changed? ? find_all_user_roles_for(Usergroup.find(usergroup_id_was)).flatten : find_all_user_roles + + drop_role_cache(users, roles) + + groups = usergroup_id_changed? ? find_all_usergroups_for(Usergroup.find(usergroup_id_was)).flatten : find_all_usergroups + drop_group_cache(users, groups) + end + + def remove_old_cache + users = find_all_affected_users + drop_role_cache(users, find_all_user_roles) + drop_group_cache(users, find_all_usergroups) + + # we need to recache records that may got deleted unintentionally + # we can't detect exact records to delete since we'd have to distinguish by whole path + recache_memberships + end + + def recache_memberships + find_all_affected_memberships.each(&:save!) + end + + def drop_role_cache(users, user_roles) + CachedUserRole.where(:user_role_id => user_roles.map(&:id), :user_id => users.map(&:id)).destroy_all + end + + def drop_group_cache(users, groups) + CachedUsergroupMember.where(:user_id => users.map(&:id), :usergroup_id => groups.map(&:id)).destroy_all + end + + def find_all_affected_users + find_all_affected_users_for(member).flatten.uniq + end + + def find_all_affected_users_for(member) + if member.is_a?(User) + [member] + elsif member.is_a?(Usergroup) + [member.users + member.usergroups.map { |g| find_all_affected_users_for(g) }] + else + raise ArgumentError, "Unknown member type #{member}" + end + end + + def find_all_affected_memberships + [ + find_all_affected_memberships_for(member, :usergroups), + find_all_affected_memberships_for(usergroup, :parents) + ].flatten + end + + def find_all_affected_memberships_for(member, direction = :usergroups) + if member.is_a?(User) + [ member.usergroup_member ] + elsif member.is_a?(Usergroup) + [ member.usergroup_members.user_memberships + + member.send(direction).map { |g| find_all_affected_memberships_for(g, direction) } ] + else + raise ArgumentError, "Unknown member type #{member}" + end + end + + def find_all_user_roles + find_all_user_roles_for(usergroup).flatten + end + + def find_all_user_roles_for(usergroup) + usergroup.user_roles + usergroup.parents.map { |g| find_all_user_roles_for(g) } + end + + def find_all_usergroups + find_all_usergroups_for(usergroup).flatten + end + + def find_all_usergroups_for(usergroup) + [ usergroup ] + usergroup.parents.map { |p| find_all_usergroups_for(p) } + end end diff --git a/app/services/authorizer.rb b/app/services/authorizer.rb new file mode 100644 index 00000000000..aec2a7c1dae --- /dev/null +++ b/app/services/authorizer.rb @@ -0,0 +1,136 @@ +class Authorizer + attr_accessor :user, :base_collection, :organization_ids, :location_ids + + def initialize(user, options = {}) + + @cache = HashWithIndifferentAccess.new { |h, k| h[k] = HashWithIndifferentAccess.new } + self.user = user + self.base_collection = options.delete(:collection) + end + + def can?(permission, subject = nil) + if subject.nil? + user.permissions.where(:name => permission).present? + else + return true if user.admin? + collection = @cache[subject.class.to_s][permission] ||= find_collection(subject.class, :permission => permission) + collection.include?(subject) + end + end + + def find_collection(resource_class, options = {}) + permission = options.delete :permission + + base = user.filters.joins(:permissions).where(["#{Permission.table_name}.resource_type = ?", resource_name(resource_class)]) + all_filters = permission.nil? ? base : base.where(["#{Permission.table_name}.name = ?", permission]) + + organization_ids = allowed_organizations(resource_class) + location_ids = allowed_locations(resource_class) + + organizations, locations, values = taxonomy_conditions(organization_ids, location_ids) + all_filters = all_filters.joins(taxonomy_join).where(["#{TaxableTaxonomy.table_name}.id IS NULL " + + "OR (#{organizations}) " + + "OR (#{locations})", + *values]).uniq + + all_filters = all_filters.all # load all records, so #empty? does not call extra COUNT(*) query + return resource_class.where('1=0') if all_filters.empty? + + unless @base_collection.nil? + if @base_collection.empty? + return resource_class.where('1=0') + else + resource_class = resource_class.where(:id => base_ids) + end + end + + return resource_class.scoped if all_filters.any?(&:unlimited?) + + search_string = build_scoped_search_condition(all_filters.select(&:limited?)) + resource_class.search_for(search_string) + end + + def build_scoped_search_condition(filters) + raise ArgumentError if filters.blank? + + strings = filters.map { |f| "(#{f.search_condition.blank? ? '1=1' : f.search_condition})" } + strings.join(' OR ') + end + + private + + def allowed_organizations(resource_class) + allowed_taxonomies(resource_class, 'organization') + end + + def allowed_locations(resource_class) + allowed_taxonomies(resource_class, 'location') + end + + # return array of taxonomies that were used by default scope + # if model does not support taxonomies, we return empty array indicating + # we should not filter on taxonomies + # otherwise we fetch it from model, if it's empty + # for admin user we return empty array which means don't limit + # for normal user we allow user taxonomies only + def allowed_taxonomies(resource_class, type) + taxonomy_ids = [] + if resource_class.respond_to?("used_#{type}_ids") + taxonomy_ids = resource_class.send("used_#{type}_ids") + if taxonomy_ids.empty? && !User.current.try(:admin?) + taxonomy_ids = User.current.try("#{type}_ids") + end + end + taxonomy_ids + end + + def taxonomy_join + "LEFT JOIN #{TaxableTaxonomy.table_name} ON " + + "(#{Filter.table_name}.id = #{TaxableTaxonomy.table_name}.taxable_id AND taxable_type = 'Filter') " + + "LEFT JOIN #{Taxonomy.table_name} ON " + + "(#{Taxonomy.table_name}.id = #{TaxableTaxonomy.table_name}.taxonomy_id)" + end + + def taxonomy_conditions(organization_ids, location_ids) + values = [] + + organizations = "#{Taxonomy.table_name}.type = ?" + values.push 'Organization' + unless organization_ids.empty? + organizations += " AND #{Taxonomy.table_name}.id IN (?)" + values.push organization_ids + end + + locations = "#{Taxonomy.table_name}.type = ?" + values.push 'Location' + unless location_ids.empty? + locations += " AND #{Taxonomy.table_name}.id IN (?)" + values.push location_ids + end + + return [organizations, locations, values] + end + + # sometimes we need exceptions however we don't want to just split namespaces + def resource_name(klass) + return 'Operatingsystem' if klass <= Operatingsystem + + case name = klass.to_s + when 'Audited::Adapters::ActiveRecord::Audit' + 'Audit' + when /\AHost::.*\Z/ + 'Host' + when /\AForeman::Model::.*\Z/ + 'ComputeResource' + else + name + end + end + + def base_ids + raise ArgumentError, 'you must set base_collection to get base_ids' if @base_collection.nil? + + @base_ids ||= @base_collection.all? { |i| i.is_a?(Fixnum) } ? @base_collection : @base_collection.map(&:id) + end + +end diff --git a/app/services/cache_manager.rb b/app/services/cache_manager.rb new file mode 100644 index 00000000000..2f150977701 --- /dev/null +++ b/app/services/cache_manager.rb @@ -0,0 +1,23 @@ +class CacheManager + def self.delete_old_permission_cache + CachedUsergroupMember.delete_all + CachedUserRole.delete_all + end + + def self.create_new_permission_cache + UsergroupMember.all.map &:save! + UserRole.all.map &:save! + end + + def self.create_new_filter_cache + Filter.all.each &:save! + end + + def self.recache! + Rails.logger.warn 'Recreating the whole DB cache' + delete_old_permission_cache + create_new_permission_cache + create_new_filter_cache + Setting::General[:fix_db_cache] = false + end +end diff --git a/app/services/dashboard.rb b/app/services/dashboard.rb index 3ebb4cb27e8..5bf9748222d 100644 --- a/app/services/dashboard.rb +++ b/app/services/dashboard.rb @@ -13,7 +13,7 @@ def initialize(filter="") end def hosts - @hosts ||= Host.my_hosts.search_for(filter) + @hosts ||= Host.authorized(:view_hosts, Host).search_for(filter) end private diff --git a/app/services/foreman/access_permissions.rb b/app/services/foreman/access_permissions.rb index a52f3744899..d9315c5f594 100644 --- a/app/services/foreman/access_permissions.rb +++ b/app/services/foreman/access_permissions.rb @@ -2,6 +2,11 @@ # Permissions Foreman::AccessControl.map do |map| + map.security_block :public do |map| + map.permission :user_logout, { :users => [:logout] }, :public => true + map.permission :my_account, { :users => [:edit] }, :public => true + end + map.security_block :architectures do |map| map.permission :view_architectures, :architectures => [:index, :show, :auto_complete_search], @@ -194,6 +199,17 @@ :"api/v2/override_values" => [:create, :update, :destroy]} end + map.security_block :filters do |map| + map.permission :view_filters, {:filters => [:index, :auto_complete_search], + :'api/v2/filters' => [:index, :show]} + map.permission :create_filters, {:filters => [:new, :create], + :'api/v2/filters' => [:create]} + map.permission :edit_filters, {:filters => [:edit, :update], :permissions => [:index], + :'api/v2/filters' => [:update], :'api/v2/permissions' => [:index, :show]} + map.permission :destroy_filters, {:filters => [:destroy], + :'api/v2/filters' => [:destroy]} + end + map.security_block :global_variables do |map| map.permission :view_globals, {:common_parameters => [:index, :show, :auto_complete_search], :"api/v1/common_parameters" => [:index, :show], @@ -469,8 +485,19 @@ } end + map.security_block :roles do |map| + map.permission :view_roles, {:roles => [:index, :auto_complete_search], + :'api/v2/roles' => [:index, :show]} + map.permission :create_roles, {:roles => [:new, :create, :clone], + :'api/v2/roles' => [:create]} + map.permission :edit_roles, {:roles => [:edit, :update], + :'api/v2/roles' => [:update]} + map.permission :destroy_roles, {:roles => [:destroy], + :'api/v2/roles' => [:destroy]} + end + map.security_block :smart_proxies do |map| - map.permission :view_smart_proxies, {:smart_proxies => [:index, :ping], + map.permission :view_smart_proxies, {:smart_proxies => [:index, :ping, :auto_complete_search], :"api/v1/smart_proxies" => [:index, :show], :"api/v2/smart_proxies" => [:index, :show] } @@ -546,7 +573,7 @@ end map.security_block :usergroups do |map| - map.permission :view_usergroups, {:usergroups => [:index, :show], + map.permission :view_usergroups, {:usergroups => [:index, :show, :auto_complete_search], :"api/v1/usergroups" => [:index, :show], :"api/v2/usergroups" => [:index, :show] } diff --git a/app/services/foreman/plugin.rb b/app/services/foreman/plugin.rb index 759794544b9..e5818fc7259 100644 --- a/app/services/foreman/plugin.rb +++ b/app/services/foreman/plugin.rb @@ -164,7 +164,13 @@ def security_block(name, &block) end # Defines a permission called name for the given controller=>actions + # :options can contain :resource_type key which is the string of resource + # class to which this permissions is related, rest of options is passed + # to AccessControl def permission(name, hash, options={}) + resource_type = options.delete(:resource_type) + Permission.first rescue return false + Permission.find_or_create_by_name_and_resource_type(name, resource_type) options.merge!(:security_block => @security_block) Foreman::AccessControl.map do |map| map.permission name, hash, options @@ -175,7 +181,8 @@ def permission(name, hash, options={}) def role(name, permissions) Role.transaction do role = Role.find_or_create_by_name(name) - role.update_attribute :permissions, permissions if role.permissions.empty? + Permission.first rescue return false + role.add_permissions!(permissions) if role.permissions.empty? end end diff --git a/app/views/about/index.html.erb b/app/views/about/index.html.erb index 2bc7cfbc5c3..74bd6c76f4d 100644 --- a/app/views/about/index.html.erb +++ b/app/views/about/index.html.erb @@ -15,7 +15,7 @@
- <% if @proxies.empty? %> + <% if @smart_proxies.empty? %>

<%= _("No smart proxies to show") %>

<% else %> @@ -24,7 +24,7 @@ - <% @proxies.each do |proxy| %> + <% @smart_proxies.each do |proxy| %> diff --git a/app/views/api/v2/filters/base.json.rabl b/app/views/api/v2/filters/base.json.rabl new file mode 100644 index 00000000000..5397cbe54d6 --- /dev/null +++ b/app/views/api/v2/filters/base.json.rabl @@ -0,0 +1,3 @@ +object @filter + +attributes :id diff --git a/app/views/api/v2/filters/create.json.rabl b/app/views/api/v2/filters/create.json.rabl new file mode 100644 index 00000000000..359008c6f31 --- /dev/null +++ b/app/views/api/v2/filters/create.json.rabl @@ -0,0 +1,3 @@ +object @filter + +extends "api/v2/filters/show" diff --git a/app/views/api/v2/filters/index.json.rabl b/app/views/api/v2/filters/index.json.rabl new file mode 100644 index 00000000000..f33e6bb7d8f --- /dev/null +++ b/app/views/api/v2/filters/index.json.rabl @@ -0,0 +1,3 @@ +collection @filters + +extends "api/v2/filters/main" diff --git a/app/views/api/v2/filters/main.json.rabl b/app/views/api/v2/filters/main.json.rabl new file mode 100644 index 00000000000..fe8c68f7c86 --- /dev/null +++ b/app/views/api/v2/filters/main.json.rabl @@ -0,0 +1,5 @@ +object @filter + +extends "api/v2/filters/base" + +attributes :search, :resource_type, :role_id, :created_at, :updated_at diff --git a/app/views/api/v2/filters/show.json.rabl b/app/views/api/v2/filters/show.json.rabl new file mode 100644 index 00000000000..0849e719818 --- /dev/null +++ b/app/views/api/v2/filters/show.json.rabl @@ -0,0 +1,20 @@ +object @filter + +extends "api/v2/filters/main" + +child :permissions => :permissions do + extends "api/v2/permissions/base" +end + +# TODO: Fix when https://github.com/theforeman/foreman/pull/1208 is merged +if SETTINGS[:organizations_enabled] + child :organizations => :organizations do + attributes :id, :name + end +end + +if SETTINGS[:locations_enabled] + child :locations => :locations do + attributes :id, :name + end +end diff --git a/app/views/api/v2/permissions/base.json.rabl b/app/views/api/v2/permissions/base.json.rabl new file mode 100644 index 00000000000..725904d6483 --- /dev/null +++ b/app/views/api/v2/permissions/base.json.rabl @@ -0,0 +1,3 @@ +object @permission + +attributes :name, :id \ No newline at end of file diff --git a/app/views/api/v2/permissions/index.json.rabl b/app/views/api/v2/permissions/index.json.rabl new file mode 100644 index 00000000000..a29ab709560 --- /dev/null +++ b/app/views/api/v2/permissions/index.json.rabl @@ -0,0 +1,3 @@ +collection @permissions + +extends "api/v2/permissions/main" \ No newline at end of file diff --git a/app/views/api/v2/permissions/main.json.rabl b/app/views/api/v2/permissions/main.json.rabl new file mode 100644 index 00000000000..6e4feeebc41 --- /dev/null +++ b/app/views/api/v2/permissions/main.json.rabl @@ -0,0 +1,3 @@ +object @permission + +extends "api/v2/permissions/base" diff --git a/app/views/api/v2/permissions/show.json.rabl b/app/views/api/v2/permissions/show.json.rabl new file mode 100644 index 00000000000..251b354b35f --- /dev/null +++ b/app/views/api/v2/permissions/show.json.rabl @@ -0,0 +1,3 @@ +object @permission + +extends "api/v2/permissions/main" diff --git a/app/views/api/v2/roles/main.json.rabl b/app/views/api/v2/roles/main.json.rabl index 8b5903678ab..38b38ffd1f8 100644 --- a/app/views/api/v2/roles/main.json.rabl +++ b/app/views/api/v2/roles/main.json.rabl @@ -2,4 +2,4 @@ object @role extends "api/v2/roles/base" -attributes :builtin, :permissions, :created_at, :updated_at +attributes :builtin, :created_at, :updated_at diff --git a/app/views/api/v2/roles/show.json.rabl b/app/views/api/v2/roles/show.json.rabl index 5ceec525c6e..874afd8383a 100644 --- a/app/views/api/v2/roles/show.json.rabl +++ b/app/views/api/v2/roles/show.json.rabl @@ -1,3 +1,7 @@ object @role extends "api/v2/roles/main" + +child :filters => :filters do + extends "api/v2/filters/base" +end diff --git a/app/views/architectures/index.html.erb b/app/views/architectures/index.html.erb index 10ee5b879a8..c011662a494 100644 --- a/app/views/architectures/index.html.erb +++ b/app/views/architectures/index.html.erb @@ -9,10 +9,12 @@ <% for architecture in @architectures %> - + <% end %> diff --git a/app/views/audits/show.html.erb b/app/views/audits/show.html.erb index 478dce3cd11..0482e1bb0cf 100644 --- a/app/views/audits/show.html.erb +++ b/app/views/audits/show.html.erb @@ -1,11 +1,11 @@ <% title "#{@audit.action.camelize} #{audited_type @audit}: #{audit_title @audit}" %> <%= title_actions link_to_if_authorized(_("Host details"), - hash_for_host_path(:id => @audit.auditable.to_param), + hash_for_host_path(:id => @audit.auditable.to_param).merge(:auth_object => @audit.auditable, :auth_action => 'view'), :title => _("Host details"), :class => 'btn btn-info') if @audit.auditable_type == 'Host' && @audit.auditable %> <%= title_actions link_to 'Back', :back, :class=>'btn btn-default' %> -<% tmplt = audit_template?(@audit) %> +<% tmplt = audit_template?(@audit) %>
<%= _("Features") %> <%= _("Status") %>
<%= link_to_if_authorized proxy.name, hash_for_edit_smart_proxy_path(:id => proxy.id) %> <%=h proxy.features.to_sentence %>
<%= link_to_if_authorized(h(architecture.name), hash_for_edit_architecture_path(:id => architecture)) %><%= link_to_if_authorized(h(architecture.name), + hash_for_edit_architecture_path(:id => architecture).merge(:auth_object => architecture, :authorizer => authorizer)) %> <%=h architecture.operatingsystems.map(&:to_label).to_sentence %> - <%= display_delete_if_authorized hash_for_architecture_path(:id => architecture.name), :confirm => "Delete #{architecture.name}?" %> + <%= display_delete_if_authorized hash_for_architecture_path(:id => architecture.name).merge(:auth_object => architecture, :authorizer => authorizer), + :confirm => "Delete #{architecture.name}?" %>
@@ -12,7 +11,7 @@ <% end %> diff --git a/app/views/common_parameters/index.html.erb b/app/views/common_parameters/index.html.erb index 4d111501165..4304e0ea6ca 100644 --- a/app/views/common_parameters/index.html.erb +++ b/app/views/common_parameters/index.html.erb @@ -10,10 +10,11 @@ <% for common_parameter in @common_parameters %> - + <% end %> diff --git a/app/views/compute_profiles/index.html.erb b/app/views/compute_profiles/index.html.erb index f1c6aafc91f..1dd17e2effd 100644 --- a/app/views/compute_profiles/index.html.erb +++ b/app/views/compute_profiles/index.html.erb @@ -9,11 +9,11 @@ <% @compute_profiles.each do |compute_profile| %> - + <% end %> diff --git a/app/views/compute_profiles/show.html.erb b/app/views/compute_profiles/show.html.erb index 9485e2061f8..c390fd74c7f 100644 --- a/app/views/compute_profiles/show.html.erb +++ b/app/views/compute_profiles/show.html.erb @@ -13,7 +13,7 @@ - <% ComputeResource.my_compute_resources.each do |compute_resource| %> + <% ComputeResource.authorized(:view_compute_resources).each do |compute_resource| %> <% compute_attribute = ComputeAttribute.where(:compute_profile_id => @compute_profile.id, :compute_resource_id => compute_resource.id).first %> <% which_path = if compute_attribute.try(:id) edit_compute_profile_compute_attribute_path(@compute_profile.to_param, compute_attribute.id) diff --git a/app/views/compute_resources/index.html.erb b/app/views/compute_resources/index.html.erb index 8cb5a637128..5f83b9e44a2 100644 --- a/app/views/compute_resources/index.html.erb +++ b/app/views/compute_resources/index.html.erb @@ -13,8 +13,8 @@ <% end %> diff --git a/app/views/compute_resources/show.html.erb b/app/views/compute_resources/show.html.erb index fbc8d4800ce..580f6fa8d1b 100644 --- a/app/views/compute_resources/show.html.erb +++ b/app/views/compute_resources/show.html.erb @@ -1,8 +1,10 @@ <%= javascript 'compute_resource', 'lookup_keys'%> <% title @compute_resource.name %> -<% title_actions display_link_if_authorized(_("Associate VMs"), hash_for_associate_compute_resource_path(:compute_resource_id => @compute_resource), :title=> _("Associate VMs to Foreman hosts"), :method => :put, :class=>"btn btn-default"), - link_to(_('Edit'), edit_compute_resource_path(@compute_resource), :class => "btn btn-default") %> +<% title_actions display_link_if_authorized(_("Associate VMs"), + hash_for_associate_compute_resource_path(:compute_resource_id => @compute_resource).merge(:auth_object => @compute_resource, :permission => 'edit_compute_resources'), + :title => _("Associate VMs to Foreman hosts"), :method => :put, :class=>"btn btn-default"), + link_to_if_authorized(_('Edit'), hash_for_edit_compute_resource_path(@compute_resource).merge(:auth_object => @compute_resource), :class => "btn btn-default") %> - + diff --git a/app/views/compute_resources_vms/index/_gce.html.erb b/app/views/compute_resources_vms/index/_gce.html.erb index b2d68ca39f4..58f05dc032a 100644 --- a/app/views/compute_resources_vms/index/_gce.html.erb +++ b/app/views/compute_resources_vms/index/_gce.html.erb @@ -9,11 +9,12 @@ <% @vms.each do |vm| %> - + <% end %> diff --git a/app/views/compute_resources_vms/index/_libvirt.html.erb b/app/views/compute_resources_vms/index/_libvirt.html.erb index 307a01b77c3..287c90a7440 100644 --- a/app/views/compute_resources_vms/index/_libvirt.html.erb +++ b/app/views/compute_resources_vms/index/_libvirt.html.erb @@ -10,13 +10,13 @@ <% @vms.each do |vm| %> - + <% end %> diff --git a/app/views/compute_resources_vms/index/_ovirt.html.erb b/app/views/compute_resources_vms/index/_ovirt.html.erb index 0122e564e03..0c5a1931c52 100644 --- a/app/views/compute_resources_vms/index/_ovirt.html.erb +++ b/app/views/compute_resources_vms/index/_ovirt.html.erb @@ -10,13 +10,13 @@ <% @vms.each do |vm| %> - + diff --git a/app/views/compute_resources_vms/index/_rackspace.html.erb b/app/views/compute_resources_vms/index/_rackspace.html.erb index 0b6057df7c7..25883cefd6e 100644 --- a/app/views/compute_resources_vms/index/_rackspace.html.erb +++ b/app/views/compute_resources_vms/index/_rackspace.html.erb @@ -14,8 +14,8 @@ <% end %> diff --git a/app/views/compute_resources_vms/index/_vmware.html.erb b/app/views/compute_resources_vms/index/_vmware.html.erb index 7ae23128c66..46ab07e26af 100644 --- a/app/views/compute_resources_vms/index/_vmware.html.erb +++ b/app/views/compute_resources_vms/index/_vmware.html.erb @@ -12,15 +12,15 @@ <% @vms.each do |vm| %> - + - + diff --git a/app/views/compute_resources_vms/show.html.erb b/app/views/compute_resources_vms/show.html.erb index 522bf7eaf12..58c33e3b092 100644 --- a/app/views/compute_resources_vms/show.html.erb +++ b/app/views/compute_resources_vms/show.html.erb @@ -5,8 +5,8 @@ <% all_actions = available_actions(@vm).push( show_console_action(@vm.ready?, - link_to_if_authorized(_("Console"), hash_for_console_compute_resource_vm_path, {:disabled => @vm.nil? || !@vm.ready?, :class => "btn btn-info"})), - display_link_if_authorized(_("Associate VM"), hash_for_associate_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => @vm.identity), :title=> _("Associate VM to a Foreman host"), :method => :put, :class=>"btn"), + link_to_if_authorized(_("Console"), hash_for_console_compute_resource_vm_path.merge(:auth_object => @compute_resource), {:disabled => @vm.nil? || !@vm.ready?, :class => "btn btn-info"})), + display_link_if_authorized(_("Associate VM"), hash_for_associate_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => @vm.identity).merge(:auth_object => @compute_resource, :permission => 'edit_compute_resources'), :title=> _("Associate VM to a Foreman host"), :method => :put, :class=>"btn"), link_to(_("Back"), compute_resource_path(@compute_resource), :class=>'btn btn-default')) title_actions *all_actions %> diff --git a/app/views/config_templates/index.html.erb b/app/views/config_templates/index.html.erb index bdc320b50db..35fe4b4c8e8 100644 --- a/app/views/config_templates/index.html.erb +++ b/app/views/config_templates/index.html.erb @@ -18,11 +18,11 @@ <% for config_template in @config_templates %> - + - <% end %> diff --git a/app/views/domains/index.html.erb b/app/views/domains/index.html.erb index 21114a2503a..cbf672b5e57 100644 --- a/app/views/domains/index.html.erb +++ b/app/views/domains/index.html.erb @@ -10,9 +10,9 @@ <% for domain in @domains %> - + + <% end %>
<%= _("Name") %>
<%= h cert%> - <%= action_buttons(display_delete_if_authorized hash_for_smart_proxy_autosign_path(:smart_proxy_id => @proxy, :id => cert), :class => 'delete')%> + <%= action_buttons(display_delete_if_authorized hash_for_smart_proxy_autosign_path(:smart_proxy_id => @proxy, :id => cert).merge(:auth_object => @proxy), :class => 'delete')%>
<%= link_to_if_authorized h(common_parameter), hash_for_edit_common_parameter_path(:id => common_parameter.id)%><%= link_to_if_authorized h(common_parameter), hash_for_edit_common_parameter_path(:id => common_parameter.id).merge(:auth_object => common_parameter, :authorizer => authorizer, :permission => 'edit_globals') %> <%= trunc(common_parameter.value,80 ) %> - <%= display_delete_if_authorized hash_for_common_parameter_path(:id => common_parameter), :confirm => _("Delete %s?") % common_parameter.name %> + <%= display_delete_if_authorized hash_for_common_parameter_path(:id => common_parameter).merge(:auth_object => common_parameter, :authorizer => authorizer, :permission => 'destroy_globals'), + :confirm => _("Delete %s?") % common_parameter.name %>
<%= link_to_if_authorized h(compute_profile.name), hash_for_compute_profile_path(compute_profile)%><%= link_to_if_authorized h(compute_profile.name), hash_for_compute_profile_path(compute_profile).merge(:auth_object => compute_profile, :authorizer => authorizer, :auth_action => 'edit') %> <%= action_buttons( - display_link_if_authorized(_('Edit'), hash_for_compute_profile_path(compute_profile)), - display_link_if_authorized(_('Rename'), hash_for_edit_compute_profile_path(compute_profile)), - display_delete_if_authorized(hash_for_compute_profile_path(compute_profile), :confirm => _('Delete %s?') % compute_profile.name))%> + display_link_if_authorized(_('Edit'), hash_for_compute_profile_path(compute_profile).merge(:auth_object => compute_profile, :authorizer => authorizer, :auth_action => 'edit')), + display_link_if_authorized(_('Rename'), hash_for_edit_compute_profile_path(compute_profile).merge(:auth_object => compute_profile, :authorizer => authorizer)), + display_delete_if_authorized(hash_for_compute_profile_path(compute_profile).merge(:auth_object => compute_profile, :authorizer => authorizer), :confirm => _('Delete %s?') % compute_profile.name))%>
<%= _("Compute Resource") %> <%= _("VM Attributes (%s)") % @compute_profile.name %>
<%= link_to compute.name, compute %> <%= compute.provider_friendly_name %> - <%= action_buttons(link_to(_('Edit'), edit_compute_resource_path(compute)), - display_delete_if_authorized(hash_for_compute_resource_path(:id => compute), :confirm => _("Delete %s?") % compute.name)) %> + <%= action_buttons(link_to_if_authorized(_('Edit'), hash_for_edit_compute_resource_path(compute).merge(:auth_object => compute, :authorizer => authorizer)), + display_delete_if_authorized(hash_for_compute_resource_path(:id => compute).merge(:auth_object => compute, :authorizer => authorizer), :confirm => _("Delete %s?") % compute.name)) %>
<%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity) %><%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => authorizer) %> <%= vm.dns %> <%= vm.flavor_id %> > <%= vm_state(vm) %> <%= unless vm.state == 'terminated' or vm.state == 'pending' - action_buttons(vm_power_action(vm), display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.id))) + action_buttons(vm_power_action(vm, authorizer), + display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.id).merge(:auth_object => @compute_resource, :authorizer => authorizer))) end %>
<%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity) %><%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => authorizer) %> <%= vm.pretty_machine_type %> <%= vm.state.downcase %> - <%= action_buttons(vm_power_action(vm), display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity))) %> + <%= action_buttons(vm_power_action(vm, authorizer), + display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => authorizer))) %>
<%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.uuid) %><%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.uuid).merge(:auth_object => @compute_resource, :authorizer => authorizer) %> <%= vm.cpus %> <%= number_to_human_size vm.memory_size*1024 %> > <%= vm_state(vm) %> - <%= action_buttons(vm_power_action(vm), - display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.uuid))) %> + <%= action_buttons(vm_power_action(vm, authorizer), + display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.uuid).merge(:auth_object => @compute_resource, :authorizer => authorizer))) %>
<%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity) %><%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => authorizer) %> <%= vm.cores %> <%= number_to_human_size vm.memory %> > <%= vm_state(vm) %> - <%= action_buttons(vm_power_action(vm), - display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.id))) %> + <%= action_buttons(vm_power_action(vm, authorizer), + display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.id).merge(:auth_object => @compute_resource, :authorizer => authorizer))) %>
> <%= vm_state(vm) %> <%= action_buttons( - vm_power_action(vm), - display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.id))) %> + vm_power_action(vm, authorizer), + display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.id).merge(:auth_object => @compute_resource, :authorizer => authorizer))) %>
<%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity) %><%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => authorizer) %> <%= vm.path %> <%= vm.cpus %><%= number_to_human_size vm.memory %><%= number_to_human_size vm.memory %> > <%= vm_state(vm) %> - <%= action_buttons(vm_power_action(vm), - show_console_action(vm.ready?, display_link_if_authorized("Console", hash_for_console_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity))), - display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity))) %> + <%= action_buttons(vm_power_action(vm, authorizer), + show_console_action(vm.ready?, display_link_if_authorized("Console", hash_for_console_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => authorizer))), + display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => authorizer))) %>
<%= link_to_if_authorized h(config_template), hash_for_edit_config_template_path(:id => config_template.to_param) %><%= link_to_if_authorized h(config_template), hash_for_edit_config_template_path(:id => config_template.to_param).merge(:auth_object => config_template, :authorizer => authorizer, :permission => 'edit_templates') %> <%= combination config_template %> <%= config_template.try(:template_kind) %> <%= checked_icon config_template.snippet %><%= display_delete_if_authorized hash_for_config_template_path(:id => config_template.to_param), + <%= display_delete_if_authorized hash_for_config_template_path(:id => config_template.to_param).merge(:auth_object => config_template, :authorizer => authorizer, :permission => 'destroy_templates'), :confirm => _("Delete %s?") % config_template %>
<%= link_to_if_authorized h(domain.fullname.empty? ? domain.name : domain.fullname), hash_for_edit_domain_path(:id => domain)%><%= link_to_if_authorized h(domain.fullname.empty? ? domain.name : domain.fullname), hash_for_edit_domain_path(:id => domain).merge(:auth_object => domain, :authorizer => authorizer) %> <%= link_to @host_counter[domain.id] || 0, hosts_path(:search => "domain = #{domain}") %> - <%= display_delete_if_authorized hash_for_domain_path(:id => domain), :confirm => _("Delete %s?") % domain.name %><%= display_delete_if_authorized hash_for_domain_path(:id => domain).merge(:auth_object => domain, :authorizer => authorizer), :confirm => _("Delete %s?") % domain.name %>
diff --git a/app/views/environments/index.html.erb b/app/views/environments/index.html.erb index 8b156a800a1..cca5dda28ea 100644 --- a/app/views/environments/index.html.erb +++ b/app/views/environments/index.html.erb @@ -12,13 +12,13 @@ <% @environments.each do |environment| %> - <%= link_to_if_authorized environment.name, hash_for_edit_environment_path(:id => environment.name) %> + <%= link_to_if_authorized environment.name, hash_for_edit_environment_path(:id => environment.name).merge(:auth_object => environment, :authorizer => authorizer) %> <%= link_to @host_counter[environment.id] || 0, hosts_path(:search => "environment = #{environment}") %> - <%= action_buttons(link_to(_("Classes"), puppetclasses_path(:search => "environment = #{environment}")), + <%= action_buttons(link_to(_('Classes'), puppetclasses_path(:search => "environment = #{environment}")), import_proxy_links(hash_for_import_environments_environments_path(:env => environment.name)), - display_delete_if_authorized(hash_for_environment_path(:id => environment.name), :confirm => "Delete #{environment.name}?")) %> + display_delete_if_authorized(hash_for_environment_path(:id => environment.name).merge(:auth_object => environment, :authorizer => authorizer), :confirm => "Delete #{environment.name}?")) %> <% end %> diff --git a/app/views/filters/_form.html.erb b/app/views/filters/_form.html.erb new file mode 100644 index 00000000000..ffd4c683dea --- /dev/null +++ b/app/views/filters/_form.html.erb @@ -0,0 +1,69 @@ +<% javascript 'filters' %> + +<%= form_for @filter do |f| %> + <%= base_errors_for f.object %> + + +
+ +
+ <% if @role.present? %> + <%= field(f, :role_id, :label => _('Selected role')) do %> + <%= @role.name %> + <%= f.hidden_field :role_id, :value => f.object.role_id || @role.id %> + <% end %> + <% else %> + <%= select_f(f, :role_id, Role.scoped, :id, :name) %> + <% end %> + + <%= selectable_f(f, :resource_type, Permission.resources_with_translations, + {:include_blank => _('(Miscellaneous)')}, {:'data-url' => permissions_path}) %> + + <%= multiple_selects f, :permissions, Permission.where(:resource_type => f.object.resource_type), + f.object.permissions.map(&:id), :label => _("Permission") %> + + <%= hidden_field_tag :role_id, @role.try(:id) %> + + +
+ + <%= _("Selected resource type does not support granular filtering, therefore you can't configure granularity") %> + +
+ +
+ <%= checkbox_f f, :unlimited?, + :help_inline => _("By unchecking this you can specify filter using Foreman search syntax in search field. If filter remains unlimited (this field is checked) it applies on all resources of the selected type") %> + + <%= autocomplete_f f, :search, + :disabled => f.object.unlimited?, + :path => resource_path(f.object.resource_type), :control_group_id => 'search_group' %> +
+
+ + <% if show_location_tab? %> +
+ <% collection = User.current.locations.empty? ? Location : User.current.locations %> + <%= multiple_checkboxes f, :locations, f.object, collection, :label => _("Locations") %> +
+ <% end %> + + <% if show_organization_tab? %> +
+ <% collection = User.current.organizations.empty? ? Organization : User.current.organizations %> + <%= multiple_checkboxes f, :organizations, f.object, collection, {}, + {:label => _("Organizations")} %> +
+ <% end %> +
+ + <%= submit_or_cancel f, false, :cancel_path => :back %> +<% end %> diff --git a/app/views/filters/edit.html.erb b/app/views/filters/edit.html.erb new file mode 100644 index 00000000000..2188e33ad27 --- /dev/null +++ b/app/views/filters/edit.html.erb @@ -0,0 +1,3 @@ +<% title _("Edit Filter") %> + +<%= render 'form' %> diff --git a/app/views/filters/index.html.erb b/app/views/filters/index.html.erb new file mode 100644 index 00000000000..70fd1254903 --- /dev/null +++ b/app/views/filters/index.html.erb @@ -0,0 +1,48 @@ +<% title _("Filters") %> + +<% title_actions link_to_if_authorized(_("New filter"), hash_for_new_filter_path(:role_id => @role)) %> + + + + + <% unless params[:role_id] %> + + <% end %> + + + + + + + + <% @filters.each do |filter| %> + + <% unless params[:role_id] %> + + <% end %> + + + + + + <% end %> + +
<%= sort :role, :as => _("Role") %><%= sort :resource, :as => s_("Filter|Resource") %><%= sort :search, :as => s_("Filter|Unlimited") %><%= sort :search, :as => s_("Filter|Search") %>
+ <%= content_tag('span', link_to_if_authorized(filter.role.name, hash_for_roles_path(:search => "name = #{filter.role.name}"). + merge(:auth_object => filter.role, :authorizer => @roles_authorizer))) %> + <%= _(filter.resource_class.try(:humanize_class_name) || filter.resource_type || '(Miscellaneous)') %><%= checked_icon filter.unlimited? %> + <%= content_tag('span', link_to_if_authorized(filter.search || _('none'), + hash_for_edit_filter_path(:id => filter, :role_id => @role). + merge(:auth_object => filter, :authorizer => authorizer))) %> + + <%= action_buttons( + display_link_if_authorized(_("Edit"), hash_for_edit_filter_path(:id => filter, :role_id => @role). + merge(:auth_object => filter, :authorizer => authorizer)), + display_delete_if_authorized(hash_for_filter_path(:id => filter, :role_id => @role). + merge(:auth_object => filter, :authorizer => authorizer), + :confirm => (_("Delete filter?"))) + ) + %> +
+<%= page_entries_info @filters %> +<%= will_paginate @filters %> diff --git a/app/views/filters/new.html.erb b/app/views/filters/new.html.erb new file mode 100644 index 00000000000..f814bdfb53a --- /dev/null +++ b/app/views/filters/new.html.erb @@ -0,0 +1,3 @@ +<% title _("New Filter") %> + +<%= render 'form' %> diff --git a/app/views/hostgroups/index.html.erb b/app/views/hostgroups/index.html.erb index f72b148465e..0f7761eeb5d 100644 --- a/app/views/hostgroups/index.html.erb +++ b/app/views/hostgroups/index.html.erb @@ -9,12 +9,12 @@ <% @hostgroups.each do |hostgroup| %> - <%= label_with_link(hostgroup) %> + <%= label_with_link(hostgroup, 1000, authorizer) %> <%= action_buttons( display_link_if_authorized(_('Nest'), hash_for_nest_hostgroup_path(:id => hostgroup)), display_link_if_authorized(_('Clone'), hash_for_clone_hostgroup_path(:id => hostgroup)), - display_delete_if_authorized(hash_for_hostgroup_path(:id => hostgroup), :confirm => warning_message(hostgroup))) %> + display_delete_if_authorized(hash_for_hostgroup_path(:id => hostgroup).merge(:auth_object => hostgroup, :authorizer => authorizer), :confirm => warning_message(hostgroup))) %> <% end %> diff --git a/app/views/hosts/_form.html.erb b/app/views/hosts/_form.html.erb index dafe3ad343c..60af4466f90 100644 --- a/app/views/hosts/_form.html.erb +++ b/app/views/hosts/_form.html.erb @@ -15,7 +15,7 @@ <% if SETTINGS[:unattended] and @host.managed %>
  • <%= _('Network') %>
  • <%= _('Operating System') %>
  • - <% if authorized_for("Compute::Resources::Vms", :create) %> + <% if authorized_for(:controller => "Compute::Resources::Vms", :action => :create) %>
  • ><%= _('Virtual Machine') %>
  • <% end %> <% end %> @@ -30,7 +30,7 @@ <% if show_organization_tab? %> <%= select_f f, :organization_id, Organization.my_organizations, :id, :to_label, - { :include_blank => !@host.managed?, :selected => @organization.id}, + { :include_blank => !@host.managed?, :selected => @organization.try(:id)}, { :disabled => !@host.new_record?, :onchange => 'organization_changed(this);', :label => _("Organization"), :'data-host-id' => @host.id, :'data-url' => process_taxonomy_hosts_path, @@ -39,7 +39,7 @@ <% if show_location_tab? %> <%= select_f f, :location_id, Location.my_locations, :id, :to_label, - { :include_blank => !@host.managed?, :selected => @location.id }, + { :include_blank => !@host.managed?, :selected => @location.try(:id) }, { :disabled => !@host.new_record?, :onchange => 'location_changed(this);', :label => _("Location"), :"data-host-id" => @host.id, :'data-url' => process_taxonomy_hosts_path, :selected => Location.my_locations, @@ -52,7 +52,7 @@ :'data-url' => (@host.new_record? || @host.type_changed?) ? process_hostgroup_hosts_path : hostgroup_or_environment_selected_hosts_path, :help_inline => :indicator } %> - <%= select_f f, :compute_resource_id, ComputeResource.my_compute_resources.with_taxonomy_scope_override(@location,@organization), :id, :to_label, + <%= select_f f, :compute_resource_id, ComputeResource.with_taxonomy_scope_override(@location,@organization).authorized(:view_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);', diff --git a/app/views/hosts/_list.html.erb b/app/views/hosts/_list.html.erb index c63b53f5fb8..09a6e2fe462 100644 --- a/app/views/hosts/_list.html.erb +++ b/app/views/hosts/_list.html.erb @@ -20,13 +20,13 @@ <%= (icon(host.os, :size => "18x18") + trunc(" #{host.os.to_label}",14)).html_safe if host.os %> <%= trunc(host.try(:environment), 14) %> <%= model_name host %> - <%= label_with_link host.hostgroup, 26 %> + <%= label_with_link host.hostgroup, 26, @hostgroup_authorizer %> <%= last_report_column(host) %> <%= action_buttons( - display_link_if_authorized(_("Edit"), hash_for_edit_host_path(:id => host)), - display_link_if_authorized(_("Clone"), hash_for_clone_host_path(:id => host)), - display_delete_if_authorized(hash_for_host_path(:id => host), :confirm => _("Delete %s?") % host.name, :action => :destroy))%> + display_link_if_authorized(_("Edit"), hash_for_edit_host_path(:id => host).merge(:auth_object => host, :authorizer => authorizer)), + display_link_if_authorized(_("Clone"), hash_for_clone_host_path(:id => host).merge(:auth_object => host, :authorizer => authorizer)), + display_delete_if_authorized(hash_for_host_path(:id => host).merge(:auth_object => host, :authorizer => authorizer), :confirm => _("Delete %s?") % host.name, :action => :destroy))%> <% end %> diff --git a/app/views/hosts/_provisioning.html.erb b/app/views/hosts/_provisioning.html.erb index f53bb536460..93de4ae223a 100644 --- a/app/views/hosts/_provisioning.html.erb +++ b/app/views/hosts/_provisioning.html.erb @@ -3,7 +3,7 @@ <% templates.sort{|t,x| t.template_kind <=> x.template_kind}.each do |tmplt| %>
    <%= _("%s Template") % tmplt.template_kind %>
    - <%= link_to_if_authorized h(tmplt), hash_for_edit_config_template_path(:id => tmplt.to_param), :rel=>"external" %> + <%= link_to_if_authorized h(tmplt), hash_for_edit_config_template_path(:id => tmplt.to_param, :auth_object => tmplt, :permission => 'edit_templates'), :rel=>"external" %>
    <% end %>
    diff --git a/app/views/hosts/edit.html.erb b/app/views/hosts/edit.html.erb index a1dcd592735..3e4277a6f6f 100644 --- a/app/views/hosts/edit.html.erb +++ b/app/views/hosts/edit.html.erb @@ -1,9 +1,9 @@ <% title(_("Edit %s") % @host) %> <% if SETTINGS[:unattended] %> <% title_actions display_link_if_authorized((@host.managed? ? _("Unmanage host") : _("Manage host")), - hash_for_toggle_manage_host_path(:id => @host.name), {:method => :put}), + hash_for_toggle_manage_host_path(:id => @host.name).merge(:auth_object => @host, :permission => 'edit_hosts'), {:method => :put}), display_link_if_authorized(_("Disassociate host"), - hash_for_disassociate_host_path(:id => @host.name), :method => :put) %> + hash_for_disassociate_host_path(:id => @host.name).merge(:auth_object => @host, :permission => 'edit_hosts'), :method => :put) %> <% end %> <%= render :partial => 'hosts/form' %> diff --git a/app/views/lookup_keys/index.html.erb b/app/views/lookup_keys/index.html.erb index 94976258830..6f39177197d 100644 --- a/app/views/lookup_keys/index.html.erb +++ b/app/views/lookup_keys/index.html.erb @@ -11,11 +11,12 @@ <% @lookup_keys.each do |lookup_key| %> - <%= link_to_if_authorized h(lookup_key.key), hash_for_edit_lookup_key_path(:id => lookup_key) %> + <%= link_to_if_authorized h(lookup_key.key), hash_for_edit_lookup_key_path(:id => lookup_key).merge(:auth_object => lookup_key, :permission => 'edit_external_variables', :authorizer => authorizer) %> <% puppet_class = lookup_key.param_class %> - <%= link_to_if_authorized h(puppet_class), hash_for_edit_puppetclass_path(:id => puppet_class) if puppet_class %> + <%= link_to_if_authorized h(puppet_class), hash_for_edit_puppetclass_path(:id => puppet_class).merge(:auth_object => puppet_class, :authorizer => @puppetclass_authorizer) if puppet_class %> <%=h lookup_key.lookup_values.count %> - <%= display_delete_if_authorized hash_for_lookup_key_path(:id => lookup_key), :confirm => _("Delete %s?") % lookup_key.key %> + <%= display_delete_if_authorized hash_for_lookup_key_path(:id => lookup_key).merge(:auth_object => lookup_key, :permission => 'destroy_external_variables', :authorizer => authorizer), + :confirm => _("Delete %s?") % lookup_key.key %> <% end %> diff --git a/app/views/media/index.html.erb b/app/views/media/index.html.erb index b831f650066..54f2aa41c53 100644 --- a/app/views/media/index.html.erb +++ b/app/views/media/index.html.erb @@ -12,12 +12,13 @@ <% for medium in @media %> - <%= link_to_if_authorized medium, hash_for_edit_medium_path(:id => medium.id) %> + <%= link_to_if_authorized medium, hash_for_edit_medium_path(:id => medium.id).merge(:auth_object => medium, :authorizer => authorizer) %> <%= medium.path %> <%= lookup_family(medium.os_family) %> <%= medium.operatingsystems.map(&:to_label).to_sentence %> - <%= display_delete_if_authorized hash_for_medium_path(:id => medium), :confirm => _("Delete %s?") % medium.name %> + <%= display_delete_if_authorized hash_for_medium_path(:id => medium).merge(:auth_object => medium, :authorizer => authorizer), + :confirm => _("Delete %s?") % medium.name %> <% end %> diff --git a/app/views/models/index.html.erb b/app/views/models/index.html.erb index 4d889023f76..3da369cb3e2 100644 --- a/app/views/models/index.html.erb +++ b/app/views/models/index.html.erb @@ -12,12 +12,13 @@ <% for model in @models %> - <%=link_to_if_authorized h(model.name), hash_for_edit_model_path(:id => model)%> + <%=link_to_if_authorized h(model.name), hash_for_edit_model_path(:id => model).merge(:auth_object => model, :authorizer => authorizer) %> <%=h(model.vendor_class)%> <%=h(model.hardware_model)%> <%= link_to @host_counter[model.id] || 0, hosts_path(:search => "model = \"#{model}\"") %> - <%= display_delete_if_authorized hash_for_model_path(:id => model), :confirm => _("Delete %s?") % model.name %> + <%= display_delete_if_authorized hash_for_model_path(:id => model).merge(:auth_object => model, :authorizer => authorizer), + :confirm => _("Delete %s?") % model.name %> <% end %> diff --git a/app/views/operatingsystems/index.html.erb b/app/views/operatingsystems/index.html.erb index b5ca2cb6506..e7678653425 100644 --- a/app/views/operatingsystems/index.html.erb +++ b/app/views/operatingsystems/index.html.erb @@ -9,10 +9,11 @@ <% for operatingsystem in @operatingsystems %> - <%= link_to_if_authorized(os_name(operatingsystem), hash_for_edit_operatingsystem_path(:id => operatingsystem.id)) %> + <%= link_to_if_authorized(os_name(operatingsystem), hash_for_edit_operatingsystem_path(:id => operatingsystem.id).merge(:auth_object => operatingsystem, :authorizer => authorizer)) %> <%= link_to @host_counter[operatingsystem.id] || 0, hosts_path(:search => "os = #{operatingsystem.name}") %> - <%= display_delete_if_authorized hash_for_operatingsystem_path(:id => operatingsystem), :confirm => _("Delete %s?") % operatingsystem.fullname %> + <%= display_delete_if_authorized hash_for_operatingsystem_path(:id => operatingsystem).merge(:auth_object => operatingsystem, :authorizer => authorizer), + :confirm => _("Delete %s?") % operatingsystem.fullname %> <% end %> diff --git a/app/views/permissions/index.js.erb b/app/views/permissions/index.js.erb new file mode 100644 index 00000000000..6ebf4a74c6f --- /dev/null +++ b/app/views/permissions/index.js.erb @@ -0,0 +1,20 @@ +var permissions = $('#filter_permission_ids'); +permissions.html("<%= escape_javascript(options_for_select(@permissions.map {|p| [p.name, p.id] })) %>"); +permissions.multiSelect('refresh'); + +var search = $('#search'); +var path = '<%= escape_javascript(@search_path) %>' +search.attr('data-url', path); +search.val(''); +search.catcomplete({source: function( request, response ) { + $.getJSON( search.attr('data-url'), { search: request.term }, response ); +}}) + +<% if @granular %> + $('#granular_warning').hide(); + $('#granular_form').show(); +<% else %> + $('#granular_warning').show(); + $('#granular_form').hide(); + $('#filter_unlimited').prop('checked', true); +<% end %> diff --git a/app/views/ptables/index.html.erb b/app/views/ptables/index.html.erb index 2d87ba862d2..7df75bd8d11 100644 --- a/app/views/ptables/index.html.erb +++ b/app/views/ptables/index.html.erb @@ -10,11 +10,11 @@ <% for ptable in @ptables %> - <%= link_to_if_authorized ptable, hash_for_edit_ptable_path(:id => ptable.id) %> + <%= link_to_if_authorized ptable, hash_for_edit_ptable_path(:id => ptable.id).merge(:auth_object => ptable, :authorizer => authorizer) %> <%= lookup_family(ptable.os_family) %> <%= ptable.operatingsystems.map(&:to_label).to_sentence %> - <%= display_delete_if_authorized hash_for_ptable_path(:id => ptable), :confirm => _("Delete %s?") % ptable.name%> + <%= display_delete_if_authorized hash_for_ptable_path(:id => ptable).merge(:auth_object => ptable, :authorizer => authorizer), :confirm => _("Delete %s?") % ptable.name%> <% end %> diff --git a/app/views/puppetclasses/_class_selection.html.erb b/app/views/puppetclasses/_class_selection.html.erb index 02149f7f069..173fdcefeaa 100644 --- a/app/views/puppetclasses/_class_selection.html.erb +++ b/app/views/puppetclasses/_class_selection.html.erb @@ -8,7 +8,7 @@ <%# hidden field to ensure that classes gets removed if none are defined %> <%= hidden_field_tag obj.class.model_name.downcase + "[puppetclass_ids][]" %>
      - <% if authorized_for(:host_editing, :edit_classes) %> + <% if authorized_for(:controller => :host_editing, :action => :edit_classes) %> <%= render :partial => "puppetclasses/selectedClasses", :collection => obj.puppetclasses ,:as => :klass, :locals => { :type => obj.class.model_name.downcase, :host => obj } %> diff --git a/app/views/puppetclasses/_classes.html.erb b/app/views/puppetclasses/_classes.html.erb index 0cc36b88099..d6ca1c9e998 100644 --- a/app/views/puppetclasses/_classes.html.erb +++ b/app/views/puppetclasses/_classes.html.erb @@ -6,7 +6,7 @@
    • <%= link_to_function image_tag("bullet_toggle_plus.png") + " " + list.first, "$('#pc_#{list.first}').fadeToggle('slow')" %>
    - <%= render 'taxonomies/loc_org_tabs', :f => f, :obj => @proxy %> + <%= render 'taxonomies/loc_org_tabs', :f => f, :obj => @smart_proxy %> <%= submit_or_cancel f %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/smart_proxies/index.html.erb b/app/views/smart_proxies/index.html.erb index 69fd8e2e688..9dfaf4fd564 100644 --- a/app/views/smart_proxies/index.html.erb +++ b/app/views/smart_proxies/index.html.erb @@ -10,29 +10,29 @@ <%= _("Features") %> - <% for proxy in @proxies %> + <% for proxy in @smart_proxies %> - <%= link_to_if_authorized proxy.name, hash_for_edit_smart_proxy_path(:id => proxy.id) %> + <%= link_to_if_authorized proxy.name, hash_for_edit_smart_proxy_path(:id => proxy.id).merge(:auth_object => proxy, :authorizer => authorizer) %> <%=h proxy.url %> <%=h proxy.features.to_sentence %> <% ca = proxy.features.detect{|f| f.name == "Puppet CA"} %> <%= action_buttons( if ca - display_link_if_authorized(_("Certificates"), hash_for_smart_proxy_puppetca_index_path(:smart_proxy_id => proxy)) + display_link_if_authorized(_("Certificates"), hash_for_smart_proxy_puppetca_index_path(:smart_proxy_id => proxy).merge(:auth_object => proxy, :permission => 'view_smart_proxies_puppetca', :authorizer => authorizer)) end, if ca - display_link_if_authorized(_("Autosign"), hash_for_smart_proxy_autosign_index_path(:smart_proxy_id => proxy)) + display_link_if_authorized(_("Autosign"), hash_for_smart_proxy_autosign_index_path(:smart_proxy_id => proxy).merge(:auth_object => proxy, :permission => 'view_smart_proxies_autosign', :authorizer => authorizer)) end, if SETTINGS[:unattended] and proxy.features.detect{|f| f.name == "DHCP" } display_link_if_authorized(_("Import subnets"), hash_for_import_subnets_path(:smart_proxy_id => proxy)) end, - display_link_if_authorized(_("Refresh features"), hash_for_refresh_smart_proxy_path(:id => proxy), :method => :put), - display_delete_if_authorized(hash_for_smart_proxy_path(:id => proxy), :confirm => _("Delete %s?") % proxy.name))%> + display_link_if_authorized(_("Refresh features"), hash_for_refresh_smart_proxy_path(:id => proxy).merge(:auth_object => proxy, :permission => 'edit_smart_proxies', :authorizer => authorizer), :method => :put), + display_delete_if_authorized(hash_for_smart_proxy_path(:id => proxy).merge(:auth_object => proxy, :authorizer => authorizer), :confirm => _("Delete %s?") % proxy.name))%> <% end %> -<%= page_entries_info @proxies %> -<%= will_paginate @proxies %> +<%= page_entries_info @smart_proxies %> +<%= will_paginate @smart_proxies %> diff --git a/app/views/subnets/index.html.erb b/app/views/subnets/index.html.erb index fe9fc37ddf4..d9a5d8d4e00 100644 --- a/app/views/subnets/index.html.erb +++ b/app/views/subnets/index.html.erb @@ -13,13 +13,13 @@ <% for subnet in @subnets %> - <%=link_to_if_authorized h(subnet.name), hash_for_edit_subnet_path(:id => subnet)%> + <%=link_to_if_authorized h(subnet.name), hash_for_edit_subnet_path(:id => subnet).merge(:auth_object => subnet, :authorizer => authorizer) %> <%=subnet.network_address %> <%=subnet.domains.to_sentence %> <%=subnet.vlanid %> <%=subnet.dhcp %> - <%= display_delete_if_authorized hash_for_subnet_path(:id => subnet), :confirm => _("Delete %s?") % subnet.name %> + <%= display_delete_if_authorized hash_for_subnet_path(:id => subnet).merge(:auth_object => subnet, :authorizer => authorizer), :confirm => _("Delete %s?") % subnet.name %> <% end %> diff --git a/app/views/usergroups/_form.html.erb b/app/views/usergroups/_form.html.erb index 8d07794016c..ac367600b39 100644 --- a/app/views/usergroups/_form.html.erb +++ b/app/views/usergroups/_form.html.erb @@ -1,7 +1,24 @@ <%= form_for @usergroup do |f| %> <%= base_errors_for @usergroup %> - <%= text_f f, :name %> - <%= multiple_checkboxes f, :usergroups, @usergroup, Usergroup, :label => _("User Groups") %> - <%= multiple_checkboxes f, :users, @usergroup, User, :label => _("Users") %> + + + +
    +
    + + <%= text_f f, :name %> + <%= multiple_checkboxes f, :usergroups, @usergroup, Usergroup, :label => _("User Groups") %> + <%= multiple_checkboxes f, :users, @usergroup, User, :label => _("Users") %> +
    + +
    + <%= checkbox_f f, :admin if User.current.can_change_admin_flag? %> + <%= multiple_checkboxes f, :roles, @usergroup, Role.givable.for_current_user, {:label => _('Roles')} %> +
    +
    + <%= submit_or_cancel f %> <% end %> diff --git a/app/views/usergroups/index.html.erb b/app/views/usergroups/index.html.erb index fe1736554d8..6803fb9863c 100644 --- a/app/views/usergroups/index.html.erb +++ b/app/views/usergroups/index.html.erb @@ -11,11 +11,12 @@ <% for usergroup in @usergroups %> - <%= link_to_if_authorized h(usergroup.name), hash_for_edit_usergroup_path(:id => usergroup.id) %> + <%= link_to_if_authorized h(usergroup.name), hash_for_edit_usergroup_path(:id => usergroup.id).merge(:auth_object => usergroup, :authorizer => authorizer) %> <%= h usergroup.users.map(&:login).to_sentence %> <%= h usergroup.usergroups.map(&:name).to_sentence %> - <%= display_delete_if_authorized hash_for_usergroup_path(:id => usergroup), :confirm => (_("Delete %s?") % usergroup.name) %> + <%= display_delete_if_authorized hash_for_usergroup_path(:id => usergroup).merge(:auth_object => usergroup, :authorizer => authorizer), + :confirm => (_("Delete %s?") % usergroup.name) %> <% end %> diff --git a/app/views/users/_filters.html.erb b/app/views/users/_filters.html.erb index 49cb7836600..e289a0bfc2f 100644 --- a/app/views/users/_filters.html.erb +++ b/app/views/users/_filters.html.erb @@ -37,7 +37,7 @@ <%= f.fields_for :user_facts do |builder| %> <%= render "user_fact", :f => builder %> <% end %> - <% if authorized_for(params[:controller], params[:action]) %> + <% if authorized_for(:controller => params[:controller], :action => params[:action]) %> <%= link_to_add_fields('+ ' + _("Add Filter"), f, :user_facts, "user_fact", :title => _("Add a fact filter")) %> <% end %> diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb index 717a525c3e1..237ce644049 100644 --- a/app/views/users/_form.html.erb +++ b/app/views/users/_form.html.erb @@ -5,7 +5,6 @@
  • <%= _("User") %>
  • <% unless @editing_self %>
  • <%= _("Roles") %>
  • -
  • <%= _("Filters") %>
  • <% if show_location_tab? %>
  • <%= _("Locations") %>
  • <% end %> @@ -38,23 +37,14 @@ <%= multiple_checkboxes f, :roles, @user, Role.givable.for_current_user, {:label => _('Roles')} %> -
    - <%= render("filters", :f => f) %> -
    <% if show_location_tab? %>
    -
    - <%= f.select :locations_andor, [[_("must be"), "and"], [_("plus all"), "or"]], {}, :class => "form-control" %> -
    <%= location_selects f, @user.used_or_selected_location_ids, {:disabled => @user.used_location_ids, :label => ''} %>
    <% end %> <% if show_organization_tab? %>
    -
    - <%= f.select :organizations_andor, [[_("must be"), "and"], [_("plus all"), "or"]], {}, :class => "form-control" %> -
    <%= organization_selects f, @user.used_or_selected_organization_ids, {:disabled => @user.used_organization_ids, :label => ''} %>
    <% end %> diff --git a/app/views/users/_user_fact.html.erb b/app/views/users/_user_fact.html.erb index 7d14b12a2ee..007b540cb86 100644 --- a/app/views/users/_user_fact.html.erb +++ b/app/views/users/_user_fact.html.erb @@ -9,6 +9,6 @@
    <%= f.text_field :criteria, :class=>"form-control" %>
    - <%= authorized_for(params[:controller], params[:action]) ? link_to_remove_fields('', f, :class=>'btn') : '' %> + <%= authorized_for(:controller => params[:controller], :action => params[:action]) ? link_to_remove_fields('', f, :class=>'btn') : '' %> diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index 891e179931f..0165bc1b4b0 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb @@ -15,14 +15,15 @@ <% for user in @users %> - <%= gravatar_image_tag user.mail, :class => "gravatar" %> <%=link_to_if_authorized h(user.login), hash_for_edit_user_path(:id => user.id) %> + <%= gravatar_image_tag user.mail, :class => "gravatar" %> <%=link_to_if_authorized h(user.login), hash_for_edit_user_path(:id => user.id).merge(:auth_object => user, :authorizer => authorizer) %> <%=h user.firstname %> <%=h user.lastname %> <%=h user.mail %> <%=checked_icon user.admin? %> <%=h last_login_on_column(user)%> <%=h auth_source_column(user)%> - <%= display_delete_if_authorized hash_for_user_path(:id => user), :confirm => _("Delete %s?") % user.name %> + <%= display_delete_if_authorized hash_for_user_path(:id => user).merge(:auth_object => user, :authorizer => authorizer), + :confirm => _("Delete %s?") % user.name %> <% end %> diff --git a/bundler.d/test.rb b/bundler.d/test.rb index 5839939ab0a..37daa68250a 100644 --- a/bundler.d/test.rb +++ b/bundler.d/test.rb @@ -16,4 +16,5 @@ gem 'launchy' gem 'spork' gem 'factory_girl_rails', '~> 1.2', :require => false + gem 'oj' end diff --git a/config/application.rb b/config/application.rb index e2c2a7f785f..54e0694bdf0 100644 --- a/config/application.rb +++ b/config/application.rb @@ -37,6 +37,7 @@ SETTINGS[:openstack] = SETTINGS[:rackspace] = SETTINGS[:ec2] = !! defined?(::Fog) require File.expand_path('../../lib/timed_cached_store.rb', __FILE__) +require File.expand_path('../../lib/foreman/exception', __FILE__) require File.expand_path('../../lib/core_extensions', __FILE__) Bundler.require(:jsonp) if SETTINGS[:support_jsonp] diff --git a/config/initializers/fix_cache.rb b/config/initializers/fix_cache.rb new file mode 100644 index 00000000000..5121ac2523c --- /dev/null +++ b/config/initializers/fix_cache.rb @@ -0,0 +1,12 @@ +# if fix db cache flag is enabled and we are not running rake task, we want to +# recreate cache + +if (Setting.table_exists? rescue(false)) + flag = Setting::General.find_or_initialize_by_name('fix_db_cache', + :description => 'Fix DB cache on next Foreman restart', + :settings_type => 'boolean', :default => false) +end + +if File.basename($0) != "rake" && flag.value + CacheManager.recache! +end diff --git a/config/initializers/foreman.rb b/config/initializers/foreman.rb index 8655af1ea56..9021702373a 100644 --- a/config/initializers/foreman.rb +++ b/config/initializers/foreman.rb @@ -1,5 +1,4 @@ require 'foreman/access_permissions' -require 'foreman/default_data/loader' require 'menu/loader' require 'foreman/renderer' require 'foreman/controller' @@ -18,9 +17,6 @@ Setting.descendants.each(&:load_defaults) end -# We load the default settings for the roles if they are not already present -Foreman::DefaultData::Loader.load(false) - #load topbar Menu::Loader.load diff --git a/config/routes.rb b/config/routes.rb index 1d9d84dae7e..e489511ecd0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -171,6 +171,9 @@ resources :puppetca, :only => [:index, :update, :destroy] resources :autosign, :only => [:index, :new, :create, :destroy] end + collection do + get 'auto_complete_search' + end end resources :fact_values, :only => [:index] do @@ -187,7 +190,11 @@ end if SETTINGS[:login] - resources :usergroups, :except => [:show] + resources :usergroups, :except => [:show] do + collection do + get 'auto_complete_search' + end + end resources :users, :except => [:show] do collection do get 'login' @@ -200,13 +207,22 @@ end end resources :roles, :except => [:show] do + member do + get 'clone' + end + collection do + get 'auto_complete_search' + end + end + + resources :filters, :except => [:show] do collection do - get 'report' - post 'report' get 'auto_complete_search' end end + resources :permissions, :only => [:index] + resources :auth_source_ldaps, :except => [:show] end diff --git a/config/routes/api/v2.rb b/config/routes/api/v2.rb index e566839d88c..bf454d43a97 100644 --- a/config/routes/api/v2.rb +++ b/config/routes/api/v2.rb @@ -102,7 +102,18 @@ get :last, :on => :collection end - resources :roles, :except => [:new, :edit] + resources :roles, :except => [:new, :edit] do + resources :filters, :except => [:new, :edit] do + (resources :locations, :only => [:index, :show]) if SETTINGS[:locations_enabled] + (resources :organizations, :only => [:index, :show]) if SETTINGS[:organizations_enabled] + end + end + resources :permissions, :only => [:index, :show] + + resources :filters, :except => [:new, :edit] do + (resources :locations, :only => [:index, :show]) if SETTINGS[:locations_enabled] + (resources :organizations, :only => [:index, :show]) if SETTINGS[:organizations_enabled] + end resources :settings, :only => [:index, :show, :update] @@ -210,6 +221,7 @@ resources :compute_resources, :only => [:index, :show] resources :media, :only => [:index, :show] resources :smart_proxies, :only => [:index, :show] + resources :filters, :only => [:index, :show] resources :parameters, :except => [:new, :edit] do collection do @@ -228,6 +240,7 @@ resources :compute_resources, :only => [:index, :show] resources :media, :only => [:index, :show] resources :smart_proxies, :only => [:index, :show] + resources :filters, :only => [:index, :show] end end @@ -246,6 +259,7 @@ resources :compute_resources, :only => [:index, :show] resources :media, :only => [:index, :show] resources :smart_proxies, :only => [:index, :show] + resources :filters, :only => [:index, :show] resources :parameters, :except => [:new, :edit] do collection do @@ -264,6 +278,7 @@ resources :compute_resources, :only => [:index, :show] resources :media, :only => [:index, :show] resources :smart_proxies, :only => [:index, :show] + resources :filters, :only => [:index, :show] end end diff --git a/db/migrate/20131114084718_extend_user_role.rb b/db/migrate/20131114084718_extend_user_role.rb new file mode 100644 index 00000000000..a3426148618 --- /dev/null +++ b/db/migrate/20131114084718_extend_user_role.rb @@ -0,0 +1,23 @@ +class ExtendUserRole < ActiveRecord::Migration + def up + remove_foreign_key 'user_roles', :name => 'user_roles_user_id_fk' + add_column :user_roles, :owner_type, :string, :default => 'User', :null => false + rename_column :user_roles, :user_id, :owner_id + + add_index :user_roles, :owner_type + add_index :user_roles, :owner_id + add_index :user_roles, [:owner_id, :owner_type] + + change_column :user_roles, :owner_id, :integer, :null => false + end + + def down + remove_index :user_roles, [:owner_id, :owner_type] + remove_index :user_roles, :owner_id + remove_index :user_roles, :owner_type + + rename_column :user_roles, :owner_id, :user_id + remove_column :user_roles, :owner_type + add_foreign_key 'user_roles', 'users', :name => 'user_roles_user_id_fk' + end +end diff --git a/db/migrate/20131114094841_create_cached_user_roles.rb b/db/migrate/20131114094841_create_cached_user_roles.rb new file mode 100644 index 00000000000..7ad8c6e45a8 --- /dev/null +++ b/db/migrate/20131114094841_create_cached_user_roles.rb @@ -0,0 +1,15 @@ +class CreateCachedUserRoles < ActiveRecord::Migration + def change + create_table :cached_user_roles do |t| + t.integer :user_id, :null => false + t.integer :role_id, :null => false + t.integer :user_role_id, :null => false + + t.timestamps + end + + add_index :cached_user_roles, :user_id + add_index :cached_user_roles, :role_id + add_index :cached_user_roles, :user_role_id + end +end diff --git a/db/migrate/20131122093940_calculate_cache_for_user_role.rb b/db/migrate/20131122093940_calculate_cache_for_user_role.rb new file mode 100644 index 00000000000..03d5aafc453 --- /dev/null +++ b/db/migrate/20131122093940_calculate_cache_for_user_role.rb @@ -0,0 +1,10 @@ +class CalculateCacheForUserRole < ActiveRecord::Migration + def up + UserRole.all.each do |user_role| + user_role.role && user_role.owner ? user_role.save! : user_role.delete + end + end + + def down + end +end diff --git a/db/migrate/20131122170726_create_cached_usergroup_members.rb b/db/migrate/20131122170726_create_cached_usergroup_members.rb new file mode 100644 index 00000000000..46c710196bc --- /dev/null +++ b/db/migrate/20131122170726_create_cached_usergroup_members.rb @@ -0,0 +1,15 @@ +class CreateCachedUsergroupMembers < ActiveRecord::Migration + def change + create_table :cached_usergroup_members do |t| + t.integer :user_id + t.integer :usergroup_id + + t.timestamps + end + + add_index :cached_usergroup_members, :user_id + add_index :cached_usergroup_members, :usergroup_id + + UsergroupMember.all.each(&:save!) + end +end diff --git a/db/migrate/20131128150357_add_admin_flag_to_usergroup.rb b/db/migrate/20131128150357_add_admin_flag_to_usergroup.rb new file mode 100644 index 00000000000..7158238b6db --- /dev/null +++ b/db/migrate/20131128150357_add_admin_flag_to_usergroup.rb @@ -0,0 +1,5 @@ +class AddAdminFlagToUsergroup < ActiveRecord::Migration + def change + add_column :usergroups, :admin, :boolean, :null => false, :default => false + end +end diff --git a/db/migrate/20131202120621_create_permissions.rb b/db/migrate/20131202120621_create_permissions.rb new file mode 100644 index 00000000000..4c17336efd6 --- /dev/null +++ b/db/migrate/20131202120621_create_permissions.rb @@ -0,0 +1,12 @@ +class CreatePermissions < ActiveRecord::Migration + def change + create_table :permissions do |t| + t.string :name, :null => false + t.string :resource_type + + t.timestamps + end + + add_index :permissions, [:name, :resource_type] + end +end diff --git a/db/migrate/20131202131847_create_filters.rb b/db/migrate/20131202131847_create_filters.rb new file mode 100644 index 00000000000..5cc4e19561d --- /dev/null +++ b/db/migrate/20131202131847_create_filters.rb @@ -0,0 +1,10 @@ +class CreateFilters < ActiveRecord::Migration + def change + create_table :filters do |t| + t.text :search + t.integer :role_id + + t.timestamps + end + end +end diff --git a/db/migrate/20131202144415_create_filterings.rb b/db/migrate/20131202144415_create_filterings.rb new file mode 100644 index 00000000000..9bcd61e9882 --- /dev/null +++ b/db/migrate/20131202144415_create_filterings.rb @@ -0,0 +1,13 @@ +class CreateFilterings < ActiveRecord::Migration + def change + create_table :filterings do |t| + t.integer :filter_id + t.integer :permission_id + + t.timestamps + end + + add_index :filterings, :filter_id + add_index :filterings, :permission_id + end +end diff --git a/db/migrate/20140110164135_add_foreign_keys_to_filters_and_filterings.rb b/db/migrate/20140110164135_add_foreign_keys_to_filters_and_filterings.rb new file mode 100644 index 00000000000..64151e1f4ae --- /dev/null +++ b/db/migrate/20140110164135_add_foreign_keys_to_filters_and_filterings.rb @@ -0,0 +1,13 @@ +class AddForeignKeysToFiltersAndFilterings < ActiveRecord::Migration + def self.up + add_foreign_key "filters", "roles", :name => "filters_roles_id_fk" + add_foreign_key "filterings", "filters", :name => "filterings_filters_id_fk" + add_foreign_key "filterings", "permissions", :name => "filterings_permissions_id_fk" + end + + def self.down + remove_foreign_key "filters", :name => "filters_roles_id_fk" + remove_foreign_key "filterings", :name => "filterings_filters_id_fk" + remove_foreign_key "filterings", :name => "filterings_permissions_id_fk" + end +end diff --git a/db/migrate/20140219183343_migrate_permissions.rb b/db/migrate/20140219183343_migrate_permissions.rb new file mode 100644 index 00000000000..751fc7c58be --- /dev/null +++ b/db/migrate/20140219183343_migrate_permissions.rb @@ -0,0 +1,298 @@ +# we need permissions to be seeded already +require Rails.root + 'db/seeds.d/20-permissions' + +# Fake models to make sure that this migration can be executed even when +# original models changes later (e.g. add validation on columns that are not +# present at this moment) +class FakePermission < ActiveRecord::Base + set_table_name 'permissions' +end + +class FakeFilter < ActiveRecord::Base + set_table_name 'filters' + # we need this for polymorphic relation to work, it has class name hardcoded in AR + def self.name + 'Filter' + end + belongs_to :role, :class_name => 'FakeRole' + has_many :filterings, :dependent => :destroy, :foreign_key => 'filter_id' + has_many :permissions, :through => :filterings + + def resource_type + @resource_type ||= permissions.first.try(:resource_type) + end + + taxonomy_join_table = "taxable_taxonomies" + has_many taxonomy_join_table, :dependent => :destroy, :as => :taxable, :foreign_key => 'taxable_id' + has_many :locations, :through => taxonomy_join_table, :source => :taxonomy, + :conditions => "taxonomies.type='Location'", :validate => false + has_many :organizations, :through => taxonomy_join_table, :source => :taxonomy, + :conditions => "taxonomies.type='Organization'", :validate => false + +end + +class FakeUserRole < ActiveRecord::Base + set_table_name 'user_roles' + belongs_to :owner, :polymorphic => true + belongs_to :role, :class_name => 'FakeRole' +end + +class FakeRole < ActiveRecord::Base + set_table_name 'roles' + scope :builtin, lambda { |*args| + compare = 'not' if args.first + where("#{compare} builtin = 0") + } + + has_many :filters, :dependent => :destroy, :class_name => 'FakeFilter', :foreign_key => 'role_id' + has_many :permissions, :through => :filters, :class_name => 'FakePermission', :foreign_key => 'permission_id' +end + +class FakeFiltering < ActiveRecord::Base + set_table_name 'filterings' + belongs_to :filter, :class_name => 'FakeFilter' + belongs_to :permission, :class_name => 'FakePermission' +end + +class FakeUser < ActiveRecord::Base + set_table_name 'users' + # we need this for polymorphic relation to work, it has class name hardcoded in AR + def self.name + 'User' + end + + has_and_belongs_to_many :compute_resources, :join_table => "user_compute_resources", :foreign_key => 'user_id' + has_and_belongs_to_many :domains, :join_table => "user_domains", :foreign_key => 'user_id' + has_many :user_hostgroups, :dependent => :destroy, :foreign_key => 'user_id' + has_many :hostgroups, :through => :user_hostgroups + has_many :user_facts, :dependent => :destroy, :foreign_key => 'user_id' + has_many :facts, :through => :user_facts, :source => :fact_name + has_many :user_roles, :dependent => :destroy, :foreign_key => 'owner_id', + :conditions => {:owner_type => 'User'}, :class_name => 'FakeUserRole' + has_many :roles, :through => :user_roles, :dependent => :destroy, :class_name => 'FakeRole' + taxonomy_join_table = "taxable_taxonomies" + has_many taxonomy_join_table, :dependent => :destroy, :as => :taxable, :foreign_key => 'taxable_id' + has_many :locations, :through => taxonomy_join_table, :source => :taxonomy, + :conditions => "taxonomies.type='Location'", :validate => false + has_many :organizations, :through => taxonomy_join_table, :source => :taxonomy, + :conditions => "taxonomies.type='Organization'", :validate => false + has_many :cached_usergroup_members, :foreign_key => 'user_id' + has_many :cached_usergroups, :through => :cached_usergroup_members, :source => :usergroup +end + +class MigratePermissions < ActiveRecord::Migration + def self.up + if old_permissions_present + migrate_roles + migrate_user_filters + + flag = Setting::General.find_or_initialize_by_name('fix_db_cache', + :description => 'Fix DB cache on next Foreman restart', + :settings_type => 'boolean', :default => false) + flag.update_attributes :value => true + Rake::Task['db:migrate'].enhance nil do + Rake::Task['fix_db_cache'].invoke + end + else + say 'Skipping migration of permissions, since old permissions are not present' + end + end + + # STEP 1 - migrate roles + # for all role permissions we'll create unlimited filters + # we'll group permissions into filters by their resource + def self.migrate_roles + roles = FakeRole.all + roles.each do |role| + + # role without permissions? nothing to do then + if role.attributes['permissions'].nil? + say "no old permissions found for role '#{role.name}', skipping" + next + end + + # permissions assigned to role which we want to migrate + permission_names = YAML.load(role.attributes['permissions']) + + # role without permissions but with YAML record + if permission_names.blank? + clear_old_permission(role) + next + end + + # filter out unknown permissions, this could be leftovers from an old plugin. + role_permissions = FakePermission.where(:name => permission_names) + + # we group permissions by resource the belong to + # then create a filter per resource + # and create a new relation between mapped permission and this filter + role_permissions.group_by(&:resource_type).each do |resource, permissions| + filter = FakeFilter.new + filter.role = role + filter.save! + say "Created an unlimited filter for role '#{role.name}'" + + permissions.each do |permission| + filtering = FakeFiltering.new + filtering.filter = filter + filtering.permission = FakePermission.find_by_name(permission.name) + filtering.save! + say "... with permission '#{permission.name}'" + end + end + + # finally we clear old permissions from role so + clear_old_permission(role) + end + end + + def self.clear_old_permission(role) + say "Clearing old permissions for role '#{role.name}'" + if FakeRole.update_all("permissions = NULL", "id = #{role.id}") == 1 + say "... OK" + else + raise "could not clear old permissions for role '#{role.name}'" + end + end + + # STEP 2 - migrate user filters + # for every user having a filter we make copy of all his roles and add filtering scoped searches + # to corresponding filters + def self.migrate_user_filters + users = FakeUser.all + users.each do |user| + unless filtered?(user) + say "no filters found for user '#{user.login}', skipping" + next + end + + say "Migrating user '#{user.login}'" + say "... cloning all roles" + clones = user.roles.builtin(false).map { |r| clone_role(r, user) } + user.roles = clones + user.roles.builtin(true) + say "... done" + + filters = Hash.new { |h, k| h[k] = '' } + + # compute resources + filters[:compute_resources] = search = user.compute_resources.uniq.map { |cr| "id = #{cr.id}" }.join(' or ') + affected = clones.map(&:filters).flatten.select { |f| f.resource_type == 'ComputeResource' } + affected.each do |filter| + filter.update_attributes :search => search unless search.blank? + end + say "... compute resource filters applied" + + # domains were not limited in old system, to keep it compatible, we don't convert it and use just search string + # later for hosts + filters[:domains] = user.domains.uniq.map { |cr| "id = #{cr.id}" }.join(' or ') + + # host groups + filters[:hostgroups] = search = user.hostgroups.uniq.map { |cr| "id = #{cr.id}" }.join(' or ') + affected = clones.map(&:filters).flatten.select { |f| f.resource_type == 'Hostgroup' } + affected.each do |filter| + filter.update_attributes :search => search unless search.blank? + end + say "... hostgroups filters applied" + + # fact_values for hosts scope + filters[:facts] = user.user_facts.uniq.map { |uf| "facts.#{uf.fact_name.name} #{uf.operator} #{uf.criteria}" }.join(' or ') + + search, orgs, locs = convert_filters_to_search(filters, user) + + affected = clones.map(&:filters).flatten.select { |f| f.resource_type == 'Host' } + affected.each do |filter| + filter.organizations = orgs + filter.locations = locs + filter.update_attributes :search => search unless search.blank? + end + say "... all other filters applied" + + say "Removing old filter" + user.domains = [] + user.compute_resources = [] + user.hostgroups = [] + user.facts = [] + user.filter_on_owner = false + user.save! + say "... done" + end + end + + def self.convert_filters_to_search(filters, user) + search = '' + orgs = [] + locs = [] + + # owner_type + if user.filter_on_owner + user_cond = "owner_id = #{user.id} and owner_type = User" + group_cond = user.cached_usergroups.uniq.map { |g| "owner_id = #{g.id}" }.join(' or ') + search = "(#{user_cond})" + search += " or ((#{group_cond}) and owner_type = Usergroup)" unless group_cond.blank? + end + + # normal filters - domains, compute resource, hostgroup, facts + filter = filters[:domains].gsub('id', 'domain_id') + search = "(#{search}) #{user.domains_andor} (#{filter})" unless filter.blank? + filter = filters[:compute_resources].gsub('id', 'compute_resource_id') + search = "(#{search}) #{user.compute_resources_andor} (#{filter})" unless filter.blank? + filter = filters[:hostgroups].gsub('id', 'hostgroup_id') + search = "(#{search}) #{user.hostgroups_andor} (#{filter})" unless filter.blank? + filter = filters[:facts] + search = "(#{search}) #{user.facts_andor} (#{filter})" unless filter.blank? + + # taxonomies + if SETTINGS[:organizations_enabled] + orgs = user.organizations + end + if SETTINGS[:locations_enabled] + locs = user.locations + end + + # fix first and/or that could appear + search = search.sub(/^\(\)\s*(and|or)\s*/, '') + [ search, orgs, locs ] + end + + def self.filtered?(user) + user.compute_resources.present? || + user.domains.present? || + user.hostgroups.present? || + user.facts.present? || + user.filter_on_owner + end + + def self.clone_role(role, user) + clone = role.dup + clone.name = role.name + "_#{user.login}" + clone.save! + + role.filters.each { |f| clone_filter(f, clone) } + + clone.reload + end + + def self.clone_filter(filter, role) + clone = filter.dup + clone.permissions = filter.permissions + clone.role = role + clone.save! + end + + + # To detect whether migration is needed we use existing models + # fakes would always indicate that migration is needed + def self.old_permissions_present + user = User.new + Role.column_names.include?('permissions') && + user.respond_to?(:compute_resources) && + user.respond_to?(:domains) && + user.respond_to?(:hostgroups) && + user.respond_to?(:facts) && + user.respond_to?(:filter_on_owner) + end + + def self.down + say 'Permission data migration is impossible, skipping' + end +end diff --git a/db/migrate/20140219183345_add_taxonomy_searches_to_filter.rb b/db/migrate/20140219183345_add_taxonomy_searches_to_filter.rb new file mode 100644 index 00000000000..04d4720db4d --- /dev/null +++ b/db/migrate/20140219183345_add_taxonomy_searches_to_filter.rb @@ -0,0 +1,21 @@ +class AddTaxonomySearchesToFilter < ActiveRecord::Migration + def self.up + add_column :filters, :taxonomy_search, :text + + # to precache taxonomy search on all existing filters + # setting may not exist yet + flag = Setting::General.find_or_initialize_by_name('fix_db_cache', + :description => 'Fix DB cache on next Foreman restart', + :settings_type => 'boolean', :default => false) + flag.update_attributes :value => true + + Rake::Task['db:migrate'].enhance nil do + Filter.reset_column_information + Rake::Task['fix_db_cache'].invoke + end + end + + def self.down + remove_column :filters, :taxonomy_search + end +end diff --git a/db/seeds.d/05-architectures.rb b/db/seeds.d/05-architectures.rb new file mode 100644 index 00000000000..03de076925e --- /dev/null +++ b/db/seeds.d/05-architectures.rb @@ -0,0 +1,5 @@ +# Architectures +Architecture.without_auditing do + Architecture.find_or_create_by_name "x86_64" + Architecture.find_or_create_by_name "i386" +end diff --git a/db/seeds.d/07-config_templates.rb b/db/seeds.d/07-config_templates.rb new file mode 100644 index 00000000000..5e74d77f318 --- /dev/null +++ b/db/seeds.d/07-config_templates.rb @@ -0,0 +1,59 @@ +# Find known operating systems for associations +os_junos = Operatingsystem.find_all_by_type "Junos" || Operatingsystem.where("name LIKE ?", "junos") +os_solaris = Operatingsystem.find_all_by_type "Solaris" +os_suse = Operatingsystem.find_all_by_type "Suse" || Operatingsystem.where("name LIKE ?", "suse") +os_windows = Operatingsystem.find_all_by_type "Windows" + +# Template kinds +kinds = {} +[:PXELinux, :PXEGrub, :iPXE, :provision, :finish, :script, :user_data, :ZTP].each do |type| + kinds[type] = TemplateKind.find_by_name(type) + kinds[type] ||= TemplateKind.create :name => type + raise "Unable to create template kind: #{format_errors kinds[type]}" if kinds[type].nil? || kinds[type].errors.any? +end + +# Provisioning templates +ConfigTemplate.without_auditing do + [ + # Generic PXE files + { :name => 'PXELinux global default', :source => 'pxe/PXELinux_default.erb', :template_kind => kinds[:PXELinux] }, + { :name => 'PXELinux default local boot', :source => 'pxe/PXELinux_local.erb', :template_kind => kinds[:PXELinux] }, + { :name => 'PXEGrub default local boot', :source => 'pxe/PXEGrub_local.erb', :template_kind => kinds[:PXEGrub] }, + # OS specific files + { :name => 'AutoYaST default', :source => 'autoyast/provision.erb', :template_kind => kinds[:provision], :operatingsystems => os_suse }, + { :name => 'AutoYaST SLES default', :source => 'autoyast/provision_sles.erb', :template_kind => kinds[:provision], :operatingsystems => os_suse }, + { :name => 'AutoYaST default PXELinux', :source => 'autoyast/PXELinux.erb', :template_kind => kinds[:PXELinux], :operatingsystems => os_suse }, + { :name => 'Grubby default', :source => 'scripts/grubby.erb', :template_kind => kinds[:script] }, + { :name => 'Jumpstart default', :source => 'jumpstart/provision.erb', :template_kind => kinds[:provision], :operatingsystems => os_solaris }, + { :name => 'Jumpstart default finish', :source => 'jumpstart/finish.erb', :template_kind => kinds[:finish], :operatingsystems => os_solaris }, + { :name => 'Jumpstart default PXEGrub', :source => 'jumpstart/PXEGrub.erb', :template_kind => kinds[:PXEGrub], :operatingsystems => os_solaris }, + { :name => 'Kickstart default', :source => 'kickstart/provision.erb', :template_kind => kinds[:provision] }, + { :name => 'Kickstart RHEL default', :source => 'kickstart/provision_rhel.erb', :template_kind => kinds[:provision] }, + { :name => 'Kickstart default PXELinux', :source => 'kickstart/PXELinux.erb', :template_kind => kinds[:PXELinux] }, + { :name => 'Kickstart default iPXE', :source => 'kickstart/iPXE.erb', :template_kind => kinds[:iPXE] }, + { :name => 'Kickstart default user data', :source => 'kickstart/userdata.erb', :template_kind => kinds[:user_data] }, + { :name => 'Preseed default', :source => 'preseed/provision.erb', :template_kind => kinds[:provision] }, + { :name => 'Preseed default finish', :source => 'preseed/finish.erb', :template_kind => kinds[:finish] }, + { :name => 'Preseed default PXELinux', :source => 'preseed/PXELinux.erb', :template_kind => kinds[:PXELinux] }, + { :name => 'Preseed default iPXE', :source => 'preseed/iPXE.erb', :template_kind => kinds[:iPXE] }, + { :name => 'Preseed default user data', :source => 'preseed/userdata.erb', :template_kind => kinds[:user_data] }, + { :name => 'WAIK default PXELinux', :source => 'waik/PXELinux.erb', :template_kind => kinds[:PXELinux], :operatingsystems => os_windows }, + { :name => "Junos default SLAX", :source => 'ztp/provision.erb', :template_kind => kinds[:provision], :operatingsystems => os_junos }, + { :name => "Junos default ZTP config", :source => 'ztp/ZTP.erb', :template_kind => kinds[:ZTP], :operatingsystems => os_junos }, + { :name => "Junos default finish", :source => 'ztp/finish.erb', :template_kind => kinds[:finish], :operatingsystems => os_junos }, + # snippets + { :name => 'epel', :source => 'snippets/_epel.erb', :snippet => true }, + { :name => 'fix_hosts', :source => 'snippets/_fix_hosts.erb', :snippet => true }, + { :name => 'http_proxy', :source => 'snippets/_http_proxy.erb', :snippet => true }, + { :name => 'puppet.conf', :source => 'snippets/_puppet.conf.erb', :snippet => true }, + { :name => 'redhat_register', :source => 'snippets/_redhat_register.erb', :snippet => true } + ].each do |input| + next if ConfigTemplate.find_by_name(input[:name]) + next if audit_modified? ConfigTemplate, input[:name] + t = ConfigTemplate.create({ + :snippet => false, + :template => File.read(File.join("#{Rails.root}/app/views/unattended", input.delete(:source))) + }.merge(input)) + raise "Unable to create template #{t.name}: #{format_errors t}" if t.nil? || t.errors.any? + end +end diff --git a/db/seeds.d/08-partition_tables.rb b/db/seeds.d/08-partition_tables.rb new file mode 100644 index 00000000000..9af7504465a --- /dev/null +++ b/db/seeds.d/08-partition_tables.rb @@ -0,0 +1,21 @@ +# Partition tables +Ptable.without_auditing do + [ + { :name => 'AutoYaST entire SCSI disk', :os_family => 'Suse', :source => 'autoyast/disklayout_scsi.erb' }, + { :name => 'AutoYaST entire virtual disk', :os_family => 'Suse', :source => 'autoyast/disklayout_virtual.erb' }, + { :name => 'AutoYaST LVM', :os_family => 'Suse', :source => 'autoyast/disklayout_lvm.erb' }, + { :name => 'Jumpstart default', :os_family => 'Solaris', :source => 'jumpstart/disklayout.erb' }, + { :name => 'Jumpstart mirrored', :os_family => 'Solaris', :source => 'jumpstart/disklayout_mirrored.erb' }, + { :name => 'Kickstart default', :os_family => 'Redhat', :source => 'kickstart/disklayout.erb' }, + { :name => 'Preseed default', :os_family => 'Debian', :source => 'preseed/disklayout.erb' }, + { :name => 'Preseed custom LVM', :os_family => 'Debian', :source => 'preseed/disklayout_lvm.erb' }, + { :name => 'Junos default fake', :os_family => 'Junos', :source => 'ztp/disklayout.erb' } + ].each do |input| + next if Ptable.find_by_name(input[:name]) + next if audit_modified? Ptable, input[:name] + p = Ptable.create({ + :layout => File.read(File.join("#{Rails.root}/app/views/unattended", input.delete(:source))) + }.merge(input)) + raise "Unable to create partition table: #{format_errors p}" if p.nil? || p.errors.any? + end +end diff --git a/db/seeds.d/10-installation_media.rb b/db/seeds.d/10-installation_media.rb new file mode 100644 index 00000000000..e88a40407ef --- /dev/null +++ b/db/seeds.d/10-installation_media.rb @@ -0,0 +1,17 @@ +os_suse = Operatingsystem.find_all_by_type "Suse" || Operatingsystem.where("name LIKE ?", "suse") + +# Installation media: default mirrors +Medium.without_auditing do + [ + { :name => "CentOS mirror", :os_family => "Redhat", :path => "http://mirror.centos.org/centos/$major.$minor/os/$arch" }, + { :name => "Debian mirror", :os_family => "Debian", :path => "http://ftp.debian.org/debian/" }, + { :name => "Fedora mirror", :os_family => "Redhat", :path => "http://dl.fedoraproject.org/pub/fedora/linux/releases/$major/Fedora/$arch/os/" }, + { :name => "OpenSUSE mirror", :os_family => "Suse", :path => "http://download.opensuse.org/distribution/$major.$minor/repo/oss", :operatingsystems => os_suse }, + { :name => "Ubuntu mirror", :os_family => "Debian", :path => "http://archive.ubuntu.com/ubuntu/" } + ].each do |input| + next if Medium.where(['name = ? OR path = ?', input[:name], input[:path]]).any? + next if audit_modified? Medium, input[:name] + m = Medium.create input + raise "Unable to create medium: #{format_errors m}" if m.nil? || m.errors.any? + end +end diff --git a/db/seeds.d/11-smart_proxy_features.rb b/db/seeds.d/11-smart_proxy_features.rb new file mode 100644 index 00000000000..c80fb00ed54 --- /dev/null +++ b/db/seeds.d/11-smart_proxy_features.rb @@ -0,0 +1,5 @@ +# Proxy features +[ "TFTP", "DNS", "DHCP", "Puppet", "Puppet CA", "BMC", "Chef Proxy" ].each do |input| + f = Feature.find_or_create_by_name(input) + raise "Unable to create proxy feature: #{format_errors f}" if f.nil? || f.errors.any? +end diff --git a/db/seeds.d/12-auth_sources.rb b/db/seeds.d/12-auth_sources.rb new file mode 100644 index 00000000000..e049e1fedfe --- /dev/null +++ b/db/seeds.d/12-auth_sources.rb @@ -0,0 +1,17 @@ +AuthSource.without_auditing do + # Auth sources + src = AuthSourceInternal.find_by_type "AuthSourceInternal" + src ||= AuthSourceInternal.create :name => "Internal" + + # Users + unless User.find_by_login("admin").present? + User.without_auditing do + user = User.new(:login => "admin", :firstname => "Admin", :lastname => "User", :mail => Setting[:administrator]) + user.admin = true + user.auth_source = src + user.password = "changeme" + User.current = user + raise "Unable to create admin user: #{format_errors user}" unless user.save + end + end +end diff --git a/db/seeds.d/13-compute_profiles.rb b/db/seeds.d/13-compute_profiles.rb new file mode 100644 index 00000000000..18206e3611a --- /dev/null +++ b/db/seeds.d/13-compute_profiles.rb @@ -0,0 +1,13 @@ +# Compute Profiles - only create if there are not any +if ComputeProfile.unconfigured? + ComputeProfile.without_auditing do + [ + { :name => '1-Small' }, + { :name => '2-Medium' }, + { :name => '3-Large' }, + ].each do |input| + cp = ComputeProfile.create input + raise "Unable to create hardware profile: #{format_errors m}" if cp.nil? || cp.errors.any? + end + end +end diff --git a/db/seeds.d/15-bookmarks.rb b/db/seeds.d/15-bookmarks.rb new file mode 100644 index 00000000000..5acadcadba5 --- /dev/null +++ b/db/seeds.d/15-bookmarks.rb @@ -0,0 +1,16 @@ +# Bookmarks +Bookmark.without_auditing do + [ + { :name => "eventful", :query => "eventful = true", :controller=> "reports" }, + { :name => "active", :query => 'last_report > "35 minutes ago" and (status.applied > 0 or status.restarted > 0)', :controller=> "hosts" }, + { :name => "out of sync", :query => 'last_report < "30 minutes ago" andstatus.enabled = true', :controller=> "hosts" }, + { :name => "error", :query => 'last_report > "35 minutes ago" and (status.failed > 0 or status.failed_restarts > 0 or status.skipped > 0)', :controller=> "hosts" }, + { :name => "disabled", :query => 'status.enabled = false', :controller=> "hosts" }, + { :name => "ok hosts", :query => 'last_report > "35 minutes ago" and status.enabled = true and status.applied = 0 and status.failed = 0 and status.pending = 0', :controller=> "hosts" } + ].each do |input| + next if Bookmark.find_by_name(input[:name]) + next if audit_modified? Bookmark, input[:name] + b = Bookmark.create({ :public => true }.merge(input)) + raise "Unable to create bookmark: #{format_errors b}" if b.nil? || b.errors.any? + end +end diff --git a/db/seeds.d/20-permissions.rb b/db/seeds.d/20-permissions.rb new file mode 100644 index 00000000000..44713490a67 --- /dev/null +++ b/db/seeds.d/20-permissions.rb @@ -0,0 +1,152 @@ +permissions = [ + ['Architecture', 'view_architectures'], + ['Architecture', 'create_architectures'], + ['Architecture', 'edit_architectures'], + ['Architecture', 'destroy_architectures'], + ['Audit', 'view_audit_logs'], + ['AuthSourceLdap', 'view_authenticators'], + ['AuthSourceLdap', 'create_authenticators'], + ['AuthSourceLdap', 'edit_authenticators'], + ['AuthSourceLdap', 'destroy_authenticators'], + ['Bookmark', 'view_bookmarks'], + ['Bookmark', 'create_bookmarks'], + ['Bookmark', 'edit_bookmarks'], + ['Bookmark', 'destroy_bookmarks'], + ['ComputeProfile', 'view_compute_profiles'], + ['ComputeProfile', 'create_compute_profiles'], + ['ComputeProfile', 'edit_compute_profiles'], + ['ComputeProfile', 'destroy_compute_profiles'], + ['ComputeResource', 'view_compute_resources'], + ['ComputeResource', 'create_compute_resources'], + ['ComputeResource', 'edit_compute_resources'], + ['ComputeResource', 'destroy_compute_resources'], + ['ComputeResource', 'view_compute_resources_vms'], + ['ComputeResource', 'create_compute_resources_vms'], + ['ComputeResource', 'edit_compute_resources_vms'], + ['ComputeResource', 'destroy_compute_resources_vms'], + ['ComputeResource', 'power_compute_resources_vms'], + ['ComputeResource', 'console_compute_resources_vms'], + ['ConfigTemplate', 'view_templates'], + ['ConfigTemplate', 'create_templates'], + ['ConfigTemplate', 'edit_templates'], + ['ConfigTemplate', 'destroy_templates'], + ['ConfigTemplate', 'deploy_templates'], + [nil, 'access_dashboard'], + ['Domain', 'view_domains'], + ['Domain', 'create_domains'], + ['Domain', 'edit_domains'], + ['Domain', 'destroy_domains'], + ['Environment', 'view_environments'], + ['Environment', 'create_environments'], + ['Environment', 'edit_environments'], + ['Environment', 'destroy_environments'], + ['Environment', 'import_environments'], + ['LookupKey', 'view_external_variables'], + ['LookupKey', 'create_external_variables'], + ['LookupKey', 'edit_external_variables'], + ['LookupKey', 'destroy_external_variables'], + ['FactValue', 'view_facts'], + ['FactValue', 'upload_facts'], + ['Filter', 'view_filters'], + ['Filter', 'create_filters'], + ['Filter', 'edit_filters'], + ['Filter', 'destroy_filters'], + ['CommonParameter', 'view_globals'], + ['CommonParameter', 'create_globals'], + ['CommonParameter', 'edit_globals'], + ['CommonParameter', 'destroy_globals'], + ['HostClass', 'edit_classes'], + ['Parameter', 'create_params'], + ['Parameter', 'edit_params'], + ['Parameter', 'destroy_params'], + ['Hostgroup', 'view_hostgroups'], + ['Hostgroup', 'create_hostgroups'], + ['Hostgroup', 'edit_hostgroups'], + ['Hostgroup', 'destroy_hostgroups'], + ['Host', 'view_hosts'], + ['Host', 'create_hosts'], + ['Host', 'edit_hosts'], + ['Host', 'destroy_hosts'], + ['Host', 'build_hosts'], + ['Host', 'power_hosts'], + ['Host', 'console_hosts'], + ['Host', 'ipmi_boot'], + ['Host', 'puppetrun_hosts'], + ['Image', 'view_images'], + ['Image', 'create_images'], + ['Image', 'edit_images'], + ['Image', 'destroy_images'], + ['Location', 'view_locations'], + ['Location', 'create_locations'], + ['Location', 'edit_locations'], + ['Location', 'destroy_locations'], + ['Location', 'assign_locations'], + ['Medium', 'view_media'], + ['Medium', 'create_media'], + ['Medium', 'edit_media'], + ['Medium', 'destroy_media'], + ['Model', 'view_models'], + ['Model', 'create_models'], + ['Model', 'edit_models'], + ['Model', 'destroy_models'], + ['Operatingsystem', 'view_operatingsystems'], + ['Operatingsystem', 'create_operatingsystems'], + ['Operatingsystem', 'edit_operatingsystems'], + ['Operatingsystem', 'destroy_operatingsystems'], + ['Organization', 'view_organizations'], + ['Organization', 'create_organizations'], + ['Organization', 'edit_organizations'], + ['Organization', 'destroy_organizations'], + ['Organization', 'assign_organizations'], + ['Ptable', 'view_ptables'], + ['Ptable', 'create_ptables'], + ['Ptable', 'edit_ptables'], + ['Ptable', 'destroy_ptables'], + [nil, 'view_plugins'], + ['Puppetclass', 'view_puppetclasses'], + ['Puppetclass', 'create_puppetclasses'], + ['Puppetclass', 'edit_puppetclasses'], + ['Puppetclass', 'destroy_puppetclasses'], + ['Puppetclass', 'import_puppetclasses'], + ['Report', 'view_reports'], + ['Report', 'destroy_reports'], + ['Report', 'upload_reports'], + ['Role', 'view_roles'], + ['Role', 'create_roles'], + ['Role', 'edit_roles'], + ['Role', 'destroy_roles'], + [nil, 'access_settings'], + ['SmartProxy', 'view_smart_proxies'], + ['SmartProxy', 'create_smart_proxies'], + ['SmartProxy', 'edit_smart_proxies'], + ['SmartProxy', 'destroy_smart_proxies'], + ['SmartProxy', 'view_smart_proxies_autosign'], + ['SmartProxy', 'create_smart_proxies_autosign'], + ['SmartProxy', 'destroy_smart_proxies_autosign'], + ['SmartProxy', 'view_smart_proxies_puppetca'], + ['SmartProxy', 'edit_smart_proxies_puppetca'], + ['SmartProxy', 'destroy_smart_proxies_puppetca'], + [nil, 'view_statistics'], + ['Subnet', 'view_subnets'], + ['Subnet', 'create_subnets'], + ['Subnet', 'edit_subnets'], + ['Subnet', 'destroy_subnets'], + ['Subnet', 'import_subnets'], + [nil, 'view_tasks'], + ['Trend', 'view_trends'], + ['Trend', 'create_trends'], + ['Trend', 'edit_trends'], + ['Trend', 'destroy_trends'], + ['Trend', 'update_trends'], + ['Usergroup', 'view_usergroups'], + ['Usergroup', 'create_usergroups'], + ['Usergroup', 'edit_usergroups'], + ['Usergroup', 'destroy_usergroups'], + ['User', 'view_users'], + ['User', 'create_users'], + ['User', 'edit_users'], + ['User', 'destroy_users'], +] +permissions.each do |resource, permission| + Permission.find_or_create_by_resource_type_and_name resource, permission +end diff --git a/db/seeds.d/25-roles.rb b/db/seeds.d/25-roles.rb new file mode 100644 index 00000000000..1852e49103c --- /dev/null +++ b/db/seeds.d/25-roles.rb @@ -0,0 +1,70 @@ +# Roles +default_permissions = + { 'Manager' => [:view_architectures, :create_architectures, :edit_architectures, :destroy_architectures, + :view_authenticators, :create_authenticators, :edit_authenticators, :destroy_authenticators, + :view_bookmarks, :create_bookmarks, :edit_bookmarks, :destroy_bookmarks, + :view_compute_resources, :create_compute_resources, :edit_compute_resources, :destroy_compute_resources, + :view_compute_resources_vms, :create_compute_resources_vms, :edit_compute_resources_vms, :destroy_compute_resources_vms, :power_compute_resources_vms, :console_compute_resources_vms, + :view_templates, :create_templates, :edit_templates, :destroy_templates, :deploy_templates, + :view_domains, :create_domains, :edit_domains, :destroy_domains, + :view_environments, :create_environments, :edit_environments, :destroy_environments, :import_environments, + :view_external_variables, :create_external_variables, :edit_external_variables, :destroy_external_variables, + :view_globals, :create_globals, :edit_globals, :destroy_globals, + :view_hostgroups, :create_hostgroups, :edit_hostgroups, :destroy_hostgroups, + :view_hosts, :create_hosts, :edit_hosts, :destroy_hosts, :build_hosts, :power_hosts, :console_hosts, :ipmi_boot, :puppetrun_hosts, + :edit_classes, :create_params, :edit_params, :destroy_params, + :view_images, :create_images, :edit_images, :destroy_images, + :view_locations, :create_locations, :edit_locations, :destroy_locations, :assign_locations, + :view_media, :create_media, :edit_media, :destroy_media, + :view_models, :create_models, :edit_models, :destroy_models, + :view_operatingsystems, :create_operatingsystems, :edit_operatingsystems, :destroy_operatingsystems, + :view_ptables, :create_ptables, :edit_ptables, :destroy_ptables, + :view_puppetclasses, :create_puppetclasses, :edit_puppetclasses, :destroy_puppetclasses, :import_puppetclasses, + :view_smart_proxies, :create_smart_proxies, :edit_smart_proxies, :destroy_smart_proxies, + :view_smart_proxies_autosign, :create_smart_proxies_autosign, :destroy_smart_proxies_autosign, + :view_smart_proxies_puppetca, :edit_smart_proxies_puppetca, :destroy_smart_proxies_puppetca, + :view_subnets, :create_subnets, :edit_subnets, :destroy_subnets, :import_subnets, + :view_organizations, :create_organizations, :edit_organizations, :destroy_organizations, :assign_organizations, + :view_usergroups, :create_usergroups, :edit_usergroups, :destroy_usergroups, + :view_users, :create_users, :edit_users, :destroy_users, :access_settings, :access_dashboard, + :view_reports, :destroy_reports, :upload_reports, + :view_facts, :upload_facts, :view_audit_logs, + :view_statistics, :view_trends, :create_trends, :edit_trends, :destroy_trends, :update_trends, + :view_tasks, :view_plugins], + 'Edit partition tables' => [:view_ptables, :create_ptables, :edit_ptables, :destroy_ptables], + 'View hosts' => [:view_hosts], + 'Edit hosts' => [:view_hosts, :edit_hosts, :create_hosts, :destroy_hosts, :build_hosts], + 'Viewer' => [:view_hosts, :view_puppetclasses, :view_hostgroups, :view_domains, :view_operatingsystems, + :view_locations, :view_media, :view_models, :view_environments, :view_architectures, + :view_ptables, :view_globals, :view_external_variables, :view_authenticators, + :access_settings, :access_dashboard, :view_reports, :view_facts, :view_smart_proxies, + :view_subnets, :view_statistics, :view_organizations, :view_usergroups, :view_users, + :view_audit_logs], + 'Site manager' => [:view_architectures, :view_audit_logs, :view_authenticators, :access_dashboard, + :view_domains, :view_environments, :import_environments, :view_external_variables, + :create_external_variables, :edit_external_variables, :destroy_external_variables, + :view_facts, :view_globals, :view_hostgroups, :view_hosts, :view_smart_proxies_puppetca, + :view_smart_proxies_autosign, :create_hosts, :edit_hosts, :destroy_hosts, + :build_hosts, :view_media, :create_media, :edit_media, :destroy_media, + :view_models, :view_operatingsystems, :view_ptables, :view_puppetclasses, + :import_puppetclasses, :view_reports, :destroy_reports, :access_settings, + :view_smart_proxies, :edit_smart_proxies, :view_subnets, :edit_subnets, + :view_statistics, :view_usergroups, :create_usergroups, :edit_usergroups, + :destroy_usergroups, :view_users, :edit_users], + } + +default_user_permissions = [:view_hosts, :view_puppetclasses, :view_hostgroups, :view_domains, + :view_operatingsystems, :view_media, :view_models, :view_environments, + :view_architectures, :view_ptables, :view_globals, :view_external_variables, + :view_authenticators, :access_settings, :access_dashboard, + :view_reports, :view_subnets, :view_facts, :view_locations, + :view_organizations, :view_statistics] +anonymous_permissions = [:view_hosts, :view_bookmarks, :view_tasks] + +Role.without_auditing do + default_permissions.each do |role_name, permission_names| + create_role(role_name, permission_names, 0) + end + create_role('Default user', default_user_permissions, Role::BUILTIN_DEFAULT_USER) + create_role('Anonymous', anonymous_permissions, Role::BUILTIN_ANONYMOUS) +end diff --git a/db/seeds.rb b/db/seeds.rb index 1a9a051d0f0..8c9301103ea 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -5,6 +5,8 @@ # # Please ensure that all templates are submitted to community-templates, then they will be synced in. +# define all helpers here + def format_errors(model = nil) return '(nil found)' if model.nil? model.errors.full_messages.join(';') @@ -20,161 +22,34 @@ def audit_modified?(type, name) false end -# Architectures -Architecture.without_auditing do - Architecture.find_or_create_by_name "x86_64" - Architecture.find_or_create_by_name "i386" -end - -# Template kinds -kinds = {} -[:PXELinux, :PXEGrub, :iPXE, :provision, :finish, :script, :user_data, :ZTP].each do |type| - kinds[type] = TemplateKind.find_by_name(type) - kinds[type] ||= TemplateKind.create :name => type - raise "Unable to create template kind: #{format_errors kinds[type]}" if kinds[type].nil? || kinds[type].errors.any? -end - -# Find known operating systems for associations -os_junos = Operatingsystem.find_all_by_type "Junos" || Operatingsystem.where("name LIKE ?", "junos") -os_solaris = Operatingsystem.find_all_by_type "Solaris" -os_suse = Operatingsystem.find_all_by_type "Suse" || Operatingsystem.where("name LIKE ?", "suse") -os_windows = Operatingsystem.find_all_by_type "Windows" - -# Partition tables -Ptable.without_auditing do - [ - { :name => 'AutoYaST entire SCSI disk', :os_family => 'Suse', :source => 'autoyast/disklayout_scsi.erb' }, - { :name => 'AutoYaST entire virtual disk', :os_family => 'Suse', :source => 'autoyast/disklayout_virtual.erb' }, - { :name => 'AutoYaST LVM', :os_family => 'Suse', :source => 'autoyast/disklayout_lvm.erb' }, - { :name => 'Jumpstart default', :os_family => 'Solaris', :source => 'jumpstart/disklayout.erb' }, - { :name => 'Jumpstart mirrored', :os_family => 'Solaris', :source => 'jumpstart/disklayout_mirrored.erb' }, - { :name => 'Kickstart default', :os_family => 'Redhat', :source => 'kickstart/disklayout.erb' }, - { :name => 'Preseed default', :os_family => 'Debian', :source => 'preseed/disklayout.erb' }, - { :name => 'Preseed custom LVM', :os_family => 'Debian', :source => 'preseed/disklayout_lvm.erb' }, - { :name => 'Junos default fake', :os_family => 'Junos', :source => 'ztp/disklayout.erb' } - ].each do |input| - next if Ptable.find_by_name(input[:name]) - next if audit_modified? Ptable, input[:name] - p = Ptable.create({ - :layout => File.read(File.join("#{Rails.root}/app/views/unattended", input.delete(:source))) - }.merge(input)) - raise "Unable to create partition table: #{format_errors p}" if p.nil? || p.errors.any? - end -end - -# Provisioning templates -ConfigTemplate.without_auditing do - [ - # Generic PXE files - { :name => 'PXELinux global default', :source => 'pxe/PXELinux_default.erb', :template_kind => kinds[:PXELinux] }, - { :name => 'PXELinux default local boot', :source => 'pxe/PXELinux_local.erb', :template_kind => kinds[:PXELinux] }, - { :name => 'PXEGrub default local boot', :source => 'pxe/PXEGrub_local.erb', :template_kind => kinds[:PXEGrub] }, - # OS specific files - { :name => 'AutoYaST default', :source => 'autoyast/provision.erb', :template_kind => kinds[:provision], :operatingsystems => os_suse }, - { :name => 'AutoYaST SLES default', :source => 'autoyast/provision_sles.erb', :template_kind => kinds[:provision], :operatingsystems => os_suse }, - { :name => 'AutoYaST default PXELinux', :source => 'autoyast/PXELinux.erb', :template_kind => kinds[:PXELinux], :operatingsystems => os_suse }, - { :name => 'Grubby default', :source => 'scripts/grubby.erb', :template_kind => kinds[:script] }, - { :name => 'Jumpstart default', :source => 'jumpstart/provision.erb', :template_kind => kinds[:provision], :operatingsystems => os_solaris }, - { :name => 'Jumpstart default finish', :source => 'jumpstart/finish.erb', :template_kind => kinds[:finish], :operatingsystems => os_solaris }, - { :name => 'Jumpstart default PXEGrub', :source => 'jumpstart/PXEGrub.erb', :template_kind => kinds[:PXEGrub], :operatingsystems => os_solaris }, - { :name => 'Kickstart default', :source => 'kickstart/provision.erb', :template_kind => kinds[:provision] }, - { :name => 'Kickstart RHEL default', :source => 'kickstart/provision_rhel.erb', :template_kind => kinds[:provision] }, - { :name => 'Kickstart default PXELinux', :source => 'kickstart/PXELinux.erb', :template_kind => kinds[:PXELinux] }, - { :name => 'Kickstart default iPXE', :source => 'kickstart/iPXE.erb', :template_kind => kinds[:iPXE] }, - { :name => 'Kickstart default user data', :source => 'kickstart/userdata.erb', :template_kind => kinds[:user_data] }, - { :name => 'Preseed default', :source => 'preseed/provision.erb', :template_kind => kinds[:provision] }, - { :name => 'Preseed default finish', :source => 'preseed/finish.erb', :template_kind => kinds[:finish] }, - { :name => 'Preseed default PXELinux', :source => 'preseed/PXELinux.erb', :template_kind => kinds[:PXELinux] }, - { :name => 'Preseed default iPXE', :source => 'preseed/iPXE.erb', :template_kind => kinds[:iPXE] }, - { :name => 'Preseed default user data', :source => 'preseed/userdata.erb', :template_kind => kinds[:user_data] }, - { :name => 'WAIK default PXELinux', :source => 'waik/PXELinux.erb', :template_kind => kinds[:PXELinux], :operatingsystems => os_windows }, - { :name => "Junos default SLAX", :source => 'ztp/provision.erb', :template_kind => kinds[:provision], :operatingsystems => os_junos }, - { :name => "Junos default ZTP config", :source => 'ztp/ZTP.erb', :template_kind => kinds[:ZTP], :operatingsystems => os_junos }, - { :name => "Junos default finish", :source => 'ztp/finish.erb', :template_kind => kinds[:finish], :operatingsystems => os_junos }, - # snippets - { :name => 'epel', :source => 'snippets/_epel.erb', :snippet => true }, - { :name => 'fix_hosts', :source => 'snippets/_fix_hosts.erb', :snippet => true }, - { :name => 'http_proxy', :source => 'snippets/_http_proxy.erb', :snippet => true }, - { :name => 'puppet.conf', :source => 'snippets/_puppet.conf.erb', :snippet => true }, - { :name => 'redhat_register', :source => 'snippets/_redhat_register.erb', :snippet => true } - ].each do |input| - next if ConfigTemplate.find_by_name(input[:name]) - next if audit_modified? ConfigTemplate, input[:name] - t = ConfigTemplate.create({ - :snippet => false, - :template => File.read(File.join("#{Rails.root}/app/views/unattended", input.delete(:source))) - }.merge(input)) - raise "Unable to create template #{t.name}: #{format_errors t}" if t.nil? || t.errors.any? - end -end +def create_filters(role, collection) + collection.group_by(&:resource_type).each do |resource, permissions| + filter = Filter.new + filter.role = role -# Installation media: default mirrors -Medium.without_auditing do - [ - { :name => "CentOS mirror", :os_family => "Redhat", :path => "http://mirror.centos.org/centos/$major.$minor/os/$arch" }, - { :name => "Debian mirror", :os_family => "Debian", :path => "http://ftp.debian.org/debian/" }, - { :name => "Fedora mirror", :os_family => "Redhat", :path => "http://dl.fedoraproject.org/pub/fedora/linux/releases/$major/Fedora/$arch/os/" }, - { :name => "OpenSUSE mirror", :os_family => "Suse", :path => "http://download.opensuse.org/distribution/$major.$minor/repo/oss", :operatingsystems => os_suse }, - { :name => "Ubuntu mirror", :os_family => "Debian", :path => "http://archive.ubuntu.com/ubuntu/" } - ].each do |input| - next if Medium.where(['name = ? OR path = ?', input[:name], input[:path]]).any? - next if audit_modified? Medium, input[:name] - m = Medium.create input - raise "Unable to create medium: #{format_errors m}" if m.nil? || m.errors.any? - end -end + permissions.each do |permission| + filtering = filter.filterings.build + filtering.permission = permission + end -# Bookmarks -Bookmark.without_auditing do - [ - { :name => "eventful", :query => "eventful = true", :controller=> "reports" }, - { :name => "active", :query => 'last_report > "35 minutes ago" and (status.applied > 0 or status.restarted > 0)', :controller=> "hosts" }, - { :name => "out of sync", :query => 'last_report < "30 minutes ago" andstatus.enabled = true', :controller=> "hosts" }, - { :name => "error", :query => 'last_report > "35 minutes ago" and (status.failed > 0 or status.failed_restarts > 0 or status.skipped > 0)', :controller=> "hosts" }, - { :name => "disabled", :query => 'status.enabled = false', :controller=> "hosts" }, - { :name => "ok hosts", :query => 'last_report > "35 minutes ago" and status.enabled = true and status.applied = 0 and status.failed = 0 and status.pending = 0', :controller=> "hosts" } - ].each do |input| - next if Bookmark.find_by_name(input[:name]) - next if audit_modified? Bookmark, input[:name] - b = Bookmark.create({ :public => true }.merge(input)) - raise "Unable to create bookmark: #{format_errors b}" if b.nil? || b.errors.any? + filter.save! end end -# Proxy features -[ "TFTP", "DNS", "DHCP", "Puppet", "Puppet CA", "BMC", "Chef Proxy" ].each do |input| - f = Feature.find_or_create_by_name(input) - raise "Unable to create proxy feature: #{format_errors f}" if f.nil? || f.errors.any? -end - -AuthSource.without_auditing do - # Auth sources - src = AuthSourceInternal.find_by_type "AuthSourceInternal" - src ||= AuthSourceInternal.create :name => "Internal" +def create_role(role_name, permission_names, builtin) + return if Role.find_by_name(role_name) + return if audit_modified? Role, role_name && builtin == 0 - # Users - unless User.find_by_login("admin").present? - User.without_auditing do - user = User.new(:login => "admin", :firstname => "Admin", :lastname => "User", :mail => Setting[:administrator]) - user.admin = true - user.auth_source = src - user.password = "changeme" - User.current = user - raise "Unable to create admin user: #{format_errors user}" unless user.save - end - end + role = Role.new(:name => role_name) + role.builtin = builtin + role.save! + permissions = Permission.find_all_by_name permission_names + create_filters(role, permissions) end -# Compute Profiles - only create if there are not any -if ComputeProfile.unconfigured? - ComputeProfile.without_auditing do - [ - { :name => '1-Small' }, - { :name => '2-Medium' }, - { :name => '3-Large' }, - ].each do |input| - cp = ComputeProfile.create input - raise "Unable to create hardware profile: #{format_errors m}" if cp.nil? || cp.errors.any? - end - end +# now we load all seed files +Dir.glob(Rails.root + 'db/seeds.d/*.rb').sort.each do |seed| + puts "Seeding #{seed}" + load seed end +puts "All seed files executed" diff --git a/foreman.spec b/foreman.spec index 94d0d295a8b..a392cf84099 100644 --- a/foreman.spec +++ b/foreman.spec @@ -77,6 +77,7 @@ Requires: %{?scl_prefix}rubygem(jquery-ui-rails) Requires: %{?scl_prefix}rubygem(bootstrap-sass) >= 3.0.3.0 Requires: %{?scl_prefix}rubygem(bootstrap-sass) < 3.0.4 Requires: %{?scl_prefix}rubygem(foreigner) >= 1.4.2 +Requires: %{?scl_prefix}rubygem(deep_cloneable) BuildRequires: %{?scl_prefix}rubygem(ancestry) >= 2.0.0 BuildRequires: %{?scl_prefix}rubygem(ancestry) < 3.0.0 BuildRequires: %{?scl_prefix}rubygem(apipie-rails) >= 0.0.23 @@ -114,6 +115,7 @@ BuildRequires: %{?scl_prefix}rubygem(flot-rails) = 0.0.3 BuildRequires: %{?scl_prefix}rubygem(foreigner) >= 1.4.2 BuildRequires: %{?scl_prefix}rubygem(multi-select-rails) >= 0.9.10 BuildRequires: %{?scl_prefix}rubygem(multi-select-rails) < 0.10.0 +BuildRequires: %{?scl_prefix}rubygem(deep_cloneable) BuildRequires: %{?scl_prefix}facter BuildRequires: gettext BuildRequires: asciidoc @@ -452,12 +454,13 @@ ln -sv %{_sysconfdir}/%{name}/$i %{buildroot}%{_datadir}/%{name}/config/$i done # Put db in %{_localstatedir}/lib/%{name}/db -cp -pr db/migrate db/seeds.rb %{buildroot}%{_datadir}/%{name} +cp -pr db/migrate db/seeds.rb db/seeds.d %{buildroot}%{_datadir}/%{name} mkdir %{buildroot}%{_localstatedir}/lib/%{name}/db ln -sv %{_localstatedir}/lib/%{name}/db %{buildroot}%{_datadir}/%{name}/db ln -sv %{_datadir}/%{name}/migrate %{buildroot}%{_localstatedir}/lib/%{name}/db/migrate ln -sv %{_datadir}/%{name}/seeds.rb %{buildroot}%{_localstatedir}/lib/%{name}/db/seeds.rb +ln -sv %{_datadir}/%{name}/seeds.d %{buildroot}%{_localstatedir}/lib/%{name}/db/seeds.d # Put HTML %{_localstatedir}/lib/%{name}/public cp -pr public %{buildroot}%{_localstatedir}/lib/%{name}/ diff --git a/lib/core_extensions.rb b/lib/core_extensions.rb index 7e9934c5417..02ecc2f8a13 100644 --- a/lib/core_extensions.rb +++ b/lib/core_extensions.rb @@ -1,3 +1,4 @@ +require 'tsort' # Add an empty method to nil. Now no need for if x and x.empty?. Just x.empty? class NilClass def empty? @@ -51,6 +52,48 @@ def before_destroy(record) end end + class EnsureNoCycle + include TSort + + def initialize(base, source, target) + @source = source; @target = target + @base = base.map { |record| [record.send(@source), record.send(@target)] } + @nodes = @base.flatten.uniq + @graph = Hash.new { |h, k| h[k] = [] } + @base.each { |s, t| @graph[s]<< t } + end + + def tsort_each_node(&block) + @nodes.each(&block) + end + + def tsort_each_child(node, &block) + @graph[node].each(&block) + end + + def ensure(record) + @record = record + add_new_edges + detect_cycle + end + + private + + def add_new_edges + edges = @graph[@record.send(@source) || 0] + edges<< @record.send(@target) unless edges.include?(@record.send(@target)) + end + + def detect_cycle + if strongly_connected_components.any? { |component| component.size > 1 } + @record.errors.add :base, _("Adding would cause a cycle!") + raise ::Foreman::CyclicGraphException, @record + else + true + end + end + end + def id_and_type "#{id}-#{self.class.table_name.humanize}" end diff --git a/lib/foreman/default_data/loader.rb b/lib/foreman/default_data/loader.rb deleted file mode 100644 index 8d142964eb0..00000000000 --- a/lib/foreman/default_data/loader.rb +++ /dev/null @@ -1,166 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE See the -# GNU General Public License for more details -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - -module Foreman - module DefaultData - class DataAlreadyLoaded < Exception; end - - module Loader - class << self - # Returns true if no data is already loaded in the database - # otherwise false - def no_data? - !Role.first(:conditions => {:builtin => 0}) - end - - # Loads the default data - # Raises a RecordNotSaved exception if something goes wrong - def load(reset=false) - - # We may be executing something like rake db:migrate:reset, which destroys this table; only continue if the table exists - Role.count rescue return - Role.transaction do - # Roles - manager = Role.where(:name => "Manager").empty? ? Role.create(:name => "Manager") : Role.where(:name => "Manager")[0] - if reset or manager.permissions.empty? - manager.update_attribute :permissions, manager.setable_permissions.collect {|p| p.name} - end - - ptable_editor = Role.where(:name => "Edit partition tables").empty? ? Role.create(:name => "Edit partition tables") : Role.where(:name => "Edit partition tables")[0] - if reset or ptable_editor.permissions.empty? - ptable_editor.update_attribute :permissions, [:view_ptables, :create_ptables, :edit_ptables, :destroy_ptables] - end - - hosts_reader = Role.where(:name => "View hosts").empty? ? Role.create(:name => "View hosts") : Role.where(:name => "View hosts")[0] - if reset or hosts_reader.permissions.empty? - hosts_reader.update_attribute :permissions, [:view_hosts] - end - - hosts_editor = Role.where(:name => "Edit hosts").empty? ? Role.create(:name => "Edit hosts") : Role.where(:name => "Edit hosts")[0] - if reset or hosts_editor.permissions.empty? - hosts_editor.update_attribute :permissions, [:view_hosts, :edit_hosts, :create_hosts, :destroy_hosts, :build_hosts] - end - - viewer = Role.where(:name => "Viewer").empty? ? Role.create(:name => "Viewer") : Role.where(:name => "Viewer")[0] - if reset or viewer.permissions.empty? - viewer.update_attribute :permissions, [:view_hosts, - :view_puppetclasses, - :view_hostgroups, - :view_domains, - :view_operatingsystems, - :view_locations, - :view_media, - :view_models, - :view_environments, - :view_architectures, - :view_ptables, - :view_globals, - :view_external_variables, - :view_authenticators, - :access_settings, - :access_dashboard, - :view_reports, - :view_facts, - :view_smart_proxies, - :view_subnets, - :view_statistics, - :view_organizations, - :view_usergroups, - :view_users, - :view_audit_logs] - end - - siteman = Role.where(:name => "Site manager").empty? ? Role.create(:name => "Site manager") : Role.where(:name => "Site manager")[0] - if reset or siteman.permissions.empty? - siteman.update_attribute :permissions, [ :view_architectures, - :view_audit_logs, - :view_authenticators, - :access_dashboard, - :view_domains, - :view_environments, - :import_environments, - :view_external_variables, - :create_external_variables, - :edit_external_variables, - :destroy_external_variables, - :view_facts, - :view_globals, - :view_hostgroups, - :view_hosts, - :view_smart_proxies_puppetca, - :view_smart_proxies_autosign, - :create_hosts, - :edit_hosts, - :destroy_hosts, - :build_hosts, - :view_media, - :create_media, - :edit_media, - :destroy_media, - :view_models, - :view_operatingsystems, - :view_ptables, - :view_puppetclasses, - :import_puppetclasses, - :view_reports, - :destroy_reports, - :access_settings, - :view_smart_proxies, - :edit_smart_proxies, - :view_subnets, - :edit_subnets, - :view_statistics, - :view_usergroups, - :create_usergroups, - :edit_usergroups, - :destroy_usergroups, - :view_users, - :edit_users] - end - if reset or Role.default_user.permissions.empty? - Role.default_user.update_attribute :permissions, [:view_hosts, - :view_puppetclasses, - :view_hostgroups, - :view_domains, - :view_operatingsystems, - :view_media, - :view_models, - :view_environments, - :view_architectures, - :view_ptables, - :view_globals, - :view_external_variables, - :view_authenticators, - :access_settings, - :access_dashboard, - :view_reports, - :view_subnets, - :view_facts, - :view_locations, - :view_organizations, - :view_statistics] - end - if reset or Role.anonymous.permissions.empty? - Role.anonymous.update_attribute :permissions, [:view_hosts, :view_bookmarks, :view_tasks] - end - end - true - end - end - end - end -end diff --git a/lib/foreman/exception.rb b/lib/foreman/exception.rb index 35ef4da7db0..6f0e8f5a6e7 100644 --- a/lib/foreman/exception.rb +++ b/lib/foreman/exception.rb @@ -42,4 +42,7 @@ def fingerprint end end + class CyclicGraphException < ::ActiveRecord::RecordInvalid + end + end diff --git a/lib/tasks/backup.rake b/lib/tasks/backup.rake new file mode 100644 index 00000000000..7dbb37c047f --- /dev/null +++ b/lib/tasks/backup.rake @@ -0,0 +1,75 @@ +namespace :db do + desc "Make a dump of your database" + task :dump => :environment do + config = Rails.configuration.database_configuration[Rails.env] + backup_name = "foreman.#{Time.now.to_i}.sql" + case config['adapter'] + when 'mysql', 'mysql2' + mysql_dump(backup_name, config) + when 'postgresql' + postgres_dump(backup_name, config) + when 'sqlite' + backup_name = "foreman.#{Time.now.to_i}.sqlite_copy" + sqlite_dump(backup_name, config) + else + puts 'Your database is not supported by Foreman.' and exit(1) + end + + puts "Backup in file #{backup_name}" + end + + def mysql_dump(name, config) + cmd = "mysqldump --opt #{config['database']} -u #{config['username']} " + cmd += " -p#{config['password']} " if config['password'].present? + cmd += " -h #{config['host']} " if config['host'].present? + cmd += " -P #{config['port']} " if config['port'].present? + cmd += " > #{name}" + system(cmd) + end + + def postgres_dump(name, config) + cmd = "pg_dump -Fc #{config['database']} -U #{config['username']} " + cmd += " -h #{config['host']} " if config['host'].present? + cmd += " -p #{config['port']} " if config['port'].present? + cmd += " > #{name}" + system({'PGPASSWORD' => config['password']}, cmd) + end + + def sqlite_dump(name, config) + FileUtils.cp config['database'], name + end + + desc 'Import your database dump' + task :import_dump => :environment do + puts "Run this task with a file argument with the location of your db dump, + 'rake db:import_dump file=DBDUMPLOCATION" and return unless ENV['file'] + config = Rails.configuration.database_configuration[Rails.env] + + case config['adapter'] + when 'mysql', 'mysql2' + mysql_import(ENV['file'], config) + when 'postgresql' + postgres_import(ENV['file'], config) + else + puts 'Your database dump cannot be imported by Foreman.' and exit(1) + end + end + + def mysql_import(file, config) + cmd = "mysql #{config['database']} -u #{config['username']} " + cmd += " -p#{config['password']} " if config['password'].present? + cmd += " -h #{config['host']} " if config['host'].present? + cmd += " -P #{config['port']} " if config['port'].present? + cmd += " < #{file}" + system(cmd) + end + + def postgres_import(file, config) + cmd = "pg_restore -d #{config['database']} -U #{config['username']} " + cmd += " -h #{config['host']} " if config['host'].present? + cmd += " -p #{config['port']} " if config['port'].present? + cmd += " #{file}" + system({'PGPASSWORD' => config['password']}, cmd) + system(cmd) + end +end diff --git a/lib/tasks/fix_cache.rake b/lib/tasks/fix_cache.rake new file mode 100644 index 00000000000..8244f80e76a --- /dev/null +++ b/lib/tasks/fix_cache.rake @@ -0,0 +1,22 @@ +desc 'Fix user groups and authorization cache by removing all cached records and recreating them' +task :fix_db_cache => :environment do + puts 'Recreating cache' + CacheManager.recache! +end + +namespace :fix_db_cache do + task :delete_old_cache do + CacheManager.delete_old_permission_cache + puts "Old cached records were deleted" + end + + task :create_new_cache do + CacheManager.create_new_permission_cache + puts "New cached records were saved" + end + + task :cache_filter_searches do + CacheManager.create_new_filter_cache + puts "Filters cache saved" + end +end diff --git a/lib/tasks/load_default_data.rake b/lib/tasks/load_default_data.rake deleted file mode 100644 index 76570d6073a..00000000000 --- a/lib/tasks/load_default_data.rake +++ /dev/null @@ -1,16 +0,0 @@ -desc 'Load Foreman default configuration data.' - -namespace :foreman do - task :load_default_data => :environment do - - begin - Foreman::DefaultData::Loader.load(true) - puts "Default configuration data reloaded." - rescue Foreman::DefaultData::DataAlreadyLoaded => error - puts error - rescue => error - puts "Error: " + error - puts "Default configuration data was not loaded." - end - end -end diff --git a/test/factories/architecture.rb b/test/factories/architecture.rb new file mode 100644 index 00000000000..e49367500a4 --- /dev/null +++ b/test/factories/architecture.rb @@ -0,0 +1,5 @@ +FactoryGirl.define do + factory :architecture do + sequence(:name) {|n| "arm#{n}" } + end +end diff --git a/test/factories/domain.rb b/test/factories/domain.rb new file mode 100644 index 00000000000..0f9b0d5154f --- /dev/null +++ b/test/factories/domain.rb @@ -0,0 +1,6 @@ +FactoryGirl.define do + factory :domain do + sequence(:name) {|n| "example#{n}.com" } + fullname { |n| n.name } + end +end diff --git a/test/factories/taxonomies.rb b/test/factories/taxonomies.rb new file mode 100644 index 00000000000..afa65da8d76 --- /dev/null +++ b/test/factories/taxonomies.rb @@ -0,0 +1,9 @@ +FactoryGirl.define do + factory :organization do + sequence(:name) { |n| "org#{n}" } + end + + factory :location do + sequence(:name) { |n| "loc#{n}" } + end +end diff --git a/test/factories/user_related.rb b/test/factories/user_related.rb new file mode 100644 index 00000000000..783a6e073cd --- /dev/null +++ b/test/factories/user_related.rb @@ -0,0 +1,80 @@ +FactoryGirl.define do + factory :usergroup do + sequence(:name) {|n| "usergroup#{n}" } + end + + factory :user do + auth_source { AuthSourceInternal.first } + password 'password' + sequence(:login) {|n| "user#{n}" } + + trait :with_mail do + sequence(:mail) {|n| "email#{n}@example.com" } + end + end + + factory :permission do + sequence(:name) {|n| "view_#{n}" } + resource_type nil + + trait :host do + resource_type 'Host' + end + + trait :domain do + resource_type 'Domain' + end + + trait :architecture do + resource_type 'Architecture' + end + end + + factory :role do + sequence(:name) {|n| "role #{n}" } + builtin 0 + end + + factory :user_role do + role { FactoryGirl.create :role } + + factory :user_user_role do + owner { FactoryGirl.create :user } + end + + factory :user_group_user_role do + owner { FactoryGirl.create :usergroup } + end + end + + factory :usergroup_member do + usergroup { FactoryGirl.create :usergroup } + + factory :user_usergroup_member do + member { FactoryGirl.create :user } + end + + factory :usergroup_usergroup_member do + member { FactoryGirl.create :usergroup } + end + end + + factory :filter do + search nil + role { FactoryGirl.create :role } + permissions { [ FactoryGirl.create(:permission, :host) ] } + + trait :on_name_all do + search 'name ~ *' + end + + trait :on_name_starting_with_a do + search 'name ~ a*' + end + + trait :on_name_starting_with_b do + search 'name ~ b*' + end + end + +end diff --git a/test/factories/usergroups.rb b/test/factories/usergroups.rb deleted file mode 100644 index f5e3ac18eac..00000000000 --- a/test/factories/usergroups.rb +++ /dev/null @@ -1,5 +0,0 @@ -FactoryGirl.define do - factory :usergroup do - sequence(:name) {|n| "usergroup#{n}" } - end -end diff --git a/test/fixtures/filterings.yml b/test/fixtures/filterings.yml new file mode 100644 index 00000000000..c362ac5a897 --- /dev/null +++ b/test/fixtures/filterings.yml @@ -0,0 +1,408 @@ +manager_1_0: + filter: manager_1 + permission: view_architectures +manager_1_1: + filter: manager_1 + permission: create_architectures +manager_1_2: + filter: manager_1 + permission: edit_architectures +manager_1_3: + filter: manager_1 + permission: destroy_architectures +manager_2_0: + filter: manager_2 + permission: view_authenticators +manager_2_1: + filter: manager_2 + permission: create_authenticators +manager_2_2: + filter: manager_2 + permission: edit_authenticators +manager_2_3: + filter: manager_2 + permission: destroy_authenticators +manager_3_0: + filter: manager_3 + permission: view_environments +manager_3_1: + filter: manager_3 + permission: create_environments +manager_3_2: + filter: manager_3 + permission: edit_environments +manager_3_3: + filter: manager_3 + permission: destroy_environments +manager_3_4: + filter: manager_3 + permission: import_environments +manager_4_0: + filter: manager_4 + permission: view_external_variables +manager_4_1: + filter: manager_4 + permission: create_external_variables +manager_4_2: + filter: manager_4 + permission: edit_external_variables +manager_4_3: + filter: manager_4 + permission: destroy_external_variables +manager_5_0: + filter: manager_5 + permission: view_domains +manager_5_1: + filter: manager_5 + permission: create_domains +manager_5_2: + filter: manager_5 + permission: edit_domains +manager_5_3: + filter: manager_5 + permission: destroy_domains +manager_6_0: + filter: manager_6 + permission: view_globals +manager_6_1: + filter: manager_6 + permission: create_globals +manager_6_2: + filter: manager_6 + permission: edit_globals +manager_6_3: + filter: manager_6 + permission: destroy_globals +manager_7_0: + filter: manager_7 + permission: view_hostgroups +manager_7_1: + filter: manager_7 + permission: create_hostgroups +manager_7_2: + filter: manager_7 + permission: edit_hostgroups +manager_7_3: + filter: manager_7 + permission: destroy_hostgroups +manager_8_0: + filter: manager_8 + permission: view_hosts +manager_8_1: + filter: manager_8 + permission: create_hosts +manager_8_2: + filter: manager_8 + permission: edit_hosts +manager_8_3: + filter: manager_8 + permission: destroy_hosts +manager_9_0: + filter: manager_9 + permission: view_media +manager_9_1: + filter: manager_9 + permission: create_media +manager_9_2: + filter: manager_9 + permission: edit_media +manager_9_3: + filter: manager_9 + permission: destroy_media +manager_10_0: + filter: manager_10 + permission: view_models +manager_10_1: + filter: manager_10 + permission: create_models +manager_10_2: + filter: manager_10 + permission: edit_models +manager_10_3: + filter: manager_10 + permission: destroy_models +manager_11_0: + filter: manager_11 + permission: view_operatingsystems +manager_11_1: + filter: manager_11 + permission: create_operatingsystems +manager_11_2: + filter: manager_11 + permission: edit_operatingsystems +manager_11_3: + filter: manager_11 + permission: destroy_operatingsystems +manager_12_0: + filter: manager_12 + permission: view_ptables +manager_12_1: + filter: manager_12 + permission: create_ptables +manager_12_2: + filter: manager_12 + permission: edit_ptables +manager_12_3: + filter: manager_12 + permission: destroy_ptables +manager_13_0: + filter: manager_13 + permission: view_puppetclasses +manager_13_1: + filter: manager_13 + permission: create_puppetclasses +manager_13_2: + filter: manager_13 + permission: edit_puppetclasses +manager_13_3: + filter: manager_13 + permission: destroy_puppetclasses +manager_13_4: + filter: manager_13 + permission: import_puppetclasses +manager_14_0: + filter: manager_14 + permission: view_usergroups +manager_14_1: + filter: manager_14 + permission: create_usergroups +manager_14_2: + filter: manager_14 + permission: edit_usergroups +manager_14_3: + filter: manager_14 + permission: destroy_usergroups +manager_15_0: + filter: manager_15 + permission: view_users +manager_15_1: + filter: manager_15 + permission: create_users +manager_15_2: + filter: manager_15 + permission: edit_users +manager_15_3: + filter: manager_15 + permission: destroy_users +manager_16_0: + filter: manager_16 + permission: access_settings +manager_16_1: + filter: manager_16 + permission: access_dashboard +manager_16_2: + filter: manager_16 + permission: view_statistics +manager_17_0: + filter: manager_17 + permission: view_reports +manager_17_1: + filter: manager_17 + permission: destroy_reports +manager_18_0: + filter: manager_18 + permission: view_facts +manager_19_0: + filter: manager_19 + permission: view_audit_logs +manager_20_0: + filter: manager_20 + permission: view_locations +manager_20_1: + filter: manager_20 + permission: edit_locations +manager_20_2: + filter: manager_20 + permission: create_locations +manager_20_3: + filter: manager_20 + permission: destroy_locations +manager_21_0: + filter: manager_21 + permission: view_organizations +manager_21_1: + filter: manager_21 + permission: edit_organizations +manager_21_2: + filter: manager_21 + permission: create_organizations +manager_21_3: + filter: manager_21 + permission: destroy_organizations +manager_22_0: + filter: manager_22 + permission: edit_classes +edit_partition_tables_1_0: + filter: edit_partition_tables_1 + permission: view_ptables +edit_partition_tables_1_1: + filter: edit_partition_tables_1 + permission: create_ptables +edit_partition_tables_1_2: + filter: edit_partition_tables_1 + permission: edit_ptables +edit_partition_tables_1_3: + filter: edit_partition_tables_1 + permission: destroy_ptables +view_hosts_1_0: + filter: view_hosts_1 + permission: view_hosts +edit_hosts_1_0: + filter: edit_hosts_1 + permission: edit_hosts +viewer_1_0: + filter: viewer_1 + permission: view_architectures +viewer_2_0: + filter: viewer_2 + permission: view_audit_logs +viewer_3_0: + filter: viewer_3 + permission: view_authenticators +viewer_4_0: + filter: viewer_4 + permission: access_dashboard +viewer_4_1: + filter: viewer_4 + permission: access_settings +viewer_4_2: + filter: viewer_4 + permission: view_statistics +viewer_5_0: + filter: viewer_5 + permission: view_domains +viewer_6_0: + filter: viewer_6 + permission: view_environments +viewer_7_0: + filter: viewer_7 + permission: view_external_variables +viewer_8_0: + filter: viewer_8 + permission: view_facts +viewer_9_0: + filter: viewer_9 + permission: view_globals +viewer_10_0: + filter: viewer_10 + permission: view_hostgroups +viewer_11_0: + filter: viewer_11 + permission: view_hosts +viewer_12_0: + filter: viewer_12 + permission: view_locations +viewer_13_0: + filter: viewer_13 + permission: view_media +viewer_14_0: + filter: viewer_14 + permission: view_models +viewer_15_0: + filter: viewer_15 + permission: view_operatingsystems +viewer_16_0: + filter: viewer_16 + permission: view_ptables +viewer_17_0: + filter: viewer_17 + permission: view_puppetclasses +viewer_18_0: + filter: viewer_18 + permission: view_reports +viewer_19_0: + filter: viewer_19 + permission: view_organizations +viewer_20_0: + filter: viewer_20 + permission: view_usergroups +viewer_21_0: + filter: viewer_21 + permission: view_users +default_user_1_0: + filter: default_user_1 + permission: view_hosts +default_user_2_0: + filter: default_user_2 + permission: view_puppetclasses +default_user_3_0: + filter: default_user_3 + permission: view_hostgroups +default_user_4_0: + filter: default_user_4 + permission: view_domains +default_user_5_0: + filter: default_user_5 + permission: view_operatingsystems +default_user_6_0: + filter: default_user_6 + permission: view_media +default_user_7_0: + filter: default_user_7 + permission: view_models +default_user_8_0: + filter: default_user_8 + permission: view_environments +default_user_9_0: + filter: default_user_9 + permission: view_architectures +default_user_10_0: + filter: default_user_10 + permission: view_ptables +default_user_11_0: + filter: default_user_11 + permission: view_globals +default_user_12_0: + filter: default_user_12 + permission: view_external_variables +default_user_13_0: + filter: default_user_13 + permission: view_authenticators +default_user_14_0: + filter: default_user_14 + permission: access_settings +default_user_14_1: + filter: default_user_14 + permission: access_dashboard +default_user_14_2: + filter: default_user_14 + permission: view_statistics +default_user_15_0: + filter: default_user_15 + permission: view_reports +default_user_16_0: + filter: default_user_16 + permission: view_facts +anonymous_1_0: + filter: anonymous_1 + permission: view_hosts +destroy_hosts_1_0: + filter: destroy_hosts_1 + permission: destroy_hosts +create_hosts_1_0: + filter: create_hosts_1 + permission: create_hosts +view_compute_resources_1_0: + filter: view_compute_resources_1 + permission: view_compute_resources +view_compute_resources_1_1: + filter: view_compute_resources_1 + permission: create_compute_resources +view_compute_resources_1_2: + filter: view_compute_resources_1 + permission: edit_compute_resources +view_compute_resources_1_3: + filter: view_compute_resources_1 + permission: destroy_compute_resources +crud_hosts_1_0: + filter: crud_hosts_1 + permission: create_hosts +crud_hosts_1_1: + filter: crud_hosts_1 + permission: edit_hosts +crud_hosts_1_2: + filter: crud_hosts_1 + permission: destroy_hosts +crud_hosts_1_3: + filter: crud_hosts_1 + permission: view_hosts diff --git a/test/fixtures/filters.yml b/test/fixtures/filters.yml new file mode 100644 index 00000000000..33e6810ed0e --- /dev/null +++ b/test/fixtures/filters.yml @@ -0,0 +1,134 @@ +manager_1: + role_id: 1 +manager_2: + role_id: 1 +manager_3: + role_id: 1 +manager_4: + role_id: 1 +manager_5: + role_id: 1 +manager_6: + role_id: 1 +manager_7: + role_id: 1 +manager_8: + role_id: 1 +manager_9: + role_id: 1 +manager_10: + role_id: 1 +manager_11: + role_id: 1 +manager_12: + role_id: 1 +manager_13: + role_id: 1 +manager_14: + role_id: 1 +manager_15: + role_id: 1 +manager_16: + role_id: 1 +manager_17: + role_id: 1 +manager_18: + role_id: 1 +manager_19: + role_id: 1 +manager_20: + role_id: 1 +manager_21: + role_id: 1 +manager_22: + role_id: 1 +edit_partition_tables_1: + role_id: 2 +view_hosts_1: + role_id: 3 +edit_hosts_1: + role_id: 4 +viewer_1: + role_id: 5 +viewer_2: + role_id: 5 +viewer_3: + role_id: 5 +viewer_4: + role_id: 5 +viewer_5: + role_id: 5 +viewer_6: + role_id: 5 +viewer_7: + role_id: 5 +viewer_8: + role_id: 5 +viewer_9: + role_id: 5 +viewer_10: + role_id: 5 +viewer_11: + role_id: 5 +viewer_12: + role_id: 5 +viewer_13: + role_id: 5 +viewer_14: + role_id: 5 +viewer_15: + role_id: 5 +viewer_16: + role_id: 5 +viewer_17: + role_id: 5 +viewer_18: + role_id: 5 +viewer_19: + role_id: 5 +viewer_20: + role_id: 5 +viewer_21: + role_id: 5 +default_user_1: + role_id: 6 +default_user_2: + role_id: 6 +default_user_3: + role_id: 6 +default_user_4: + role_id: 6 +default_user_5: + role_id: 6 +default_user_6: + role_id: 6 +default_user_7: + role_id: 6 +default_user_8: + role_id: 6 +default_user_9: + role_id: 6 +default_user_10: + role_id: 6 +default_user_11: + role_id: 6 +default_user_12: + role_id: 6 +default_user_13: + role_id: 6 +default_user_14: + role_id: 6 +default_user_15: + role_id: 6 +default_user_16: + role_id: 6 +anonymous_1: + role_id: 7 +destroy_hosts_1: + role_id: 8 +create_hosts_1: + role_id: 9 +view_compute_resources_1: + role_id: 11 +crud_hosts_1: + role_id: 12 diff --git a/test/fixtures/permissions.yml b/test/fixtures/permissions.yml new file mode 100644 index 00000000000..546762cd9bb --- /dev/null +++ b/test/fixtures/permissions.yml @@ -0,0 +1,676 @@ +--- + view_architectures: + name: view_architectures + resource_type: Architecture + created_at: "2013-12-04 08:41:04.321867" + updated_at: "2013-12-04 08:41:04.321867" + create_architectures: + name: create_architectures + resource_type: Architecture + created_at: "2013-12-04 08:41:04.357689" + updated_at: "2013-12-04 08:41:04.357689" + edit_architectures: + name: edit_architectures + resource_type: Architecture + created_at: "2013-12-04 08:41:04.365371" + updated_at: "2013-12-04 08:41:04.365371" + destroy_architectures: + name: destroy_architectures + resource_type: Architecture + created_at: "2013-12-04 08:41:04.373182" + updated_at: "2013-12-04 08:41:04.373182" + view_authenticators: + name: view_authenticators + resource_type: AuthSourceLdap + created_at: "2013-12-04 08:41:04.389686" + updated_at: "2013-12-04 08:41:04.389686" + create_authenticators: + name: create_authenticators + resource_type: AuthSourceLdap + created_at: "2013-12-04 08:41:04.398376" + updated_at: "2013-12-04 08:41:04.398376" + edit_authenticators: + name: edit_authenticators + resource_type: AuthSourceLdap + created_at: "2013-12-04 08:41:04.40647" + updated_at: "2013-12-04 08:41:04.40647" + destroy_authenticators: + name: destroy_authenticators + resource_type: AuthSourceLdap + created_at: "2013-12-04 08:41:04.414794" + updated_at: "2013-12-04 08:41:04.414794" + view_bookmarks: + name: view_bookmarks + resource_type: Bookmark + created_at: "2013-12-04 08:41:04.423092" + updated_at: "2013-12-04 08:41:04.423092" + create_bookmarks: + name: create_bookmarks + resource_type: Bookmark + created_at: "2013-12-04 08:41:04.431655" + updated_at: "2013-12-04 08:41:04.431655" + edit_bookmarks: + name: edit_bookmarks + resource_type: Bookmark + created_at: "2013-12-04 08:41:04.439632" + updated_at: "2013-12-04 08:41:04.439632" + destroy_bookmarks: + name: destroy_bookmarks + resource_type: Bookmark + created_at: "2013-12-04 08:41:04.448264" + updated_at: "2013-12-04 08:41:04.448264" + view_compute_resources: + name: view_compute_resources + resource_type: ComputeResource + created_at: "2013-12-04 08:41:04.456196" + updated_at: "2013-12-04 08:41:04.456196" + create_compute_resources: + name: create_compute_resources + resource_type: ComputeResource + created_at: "2013-12-04 08:41:04.464913" + updated_at: "2013-12-04 08:41:04.464913" + edit_compute_resources: + name: edit_compute_resources + resource_type: ComputeResource + created_at: "2013-12-04 08:41:04.473288" + updated_at: "2013-12-04 08:41:04.473288" + destroy_compute_resources: + name: destroy_compute_resources + resource_type: ComputeResource + created_at: "2013-12-04 08:41:04.481549" + updated_at: "2013-12-04 08:41:04.481549" + view_templates: + name: view_templates + resource_type: ConfigTemplate + created_at: "2013-12-04 08:41:04.540648" + updated_at: "2013-12-04 08:41:04.540648" + create_templates: + name: create_templates + resource_type: ConfigTemplate + created_at: "2013-12-04 08:41:04.548631" + updated_at: "2013-12-04 08:41:04.548631" + edit_templates: + name: edit_templates + resource_type: ConfigTemplate + created_at: "2013-12-04 08:41:04.556639" + updated_at: "2013-12-04 08:41:04.556639" + destroy_templates: + name: destroy_templates + resource_type: ConfigTemplate + created_at: "2013-12-04 08:41:04.564948" + updated_at: "2013-12-04 08:41:04.564948" + deploy_templates: + name: deploy_templates + resource_type: ConfigTemplate + created_at: "2013-12-04 08:41:04.573359" + updated_at: "2013-12-04 08:41:04.573359" + access_dashboard: + name: access_dashboard + resource_type: + created_at: "2013-12-04 08:41:04.581753" + updated_at: "2013-12-04 08:41:04.581753" + view_domains: + name: view_domains + resource_type: Domain + created_at: "2013-12-04 08:41:04.590726" + updated_at: "2013-12-04 08:41:04.590726" + create_domains: + name: create_domains + resource_type: Domain + created_at: "2013-12-04 08:41:04.598517" + updated_at: "2013-12-04 08:41:04.598517" + edit_domains: + name: edit_domains + resource_type: Domain + created_at: "2013-12-04 08:41:04.606731" + updated_at: "2013-12-04 08:41:04.606731" + destroy_domains: + name: destroy_domains + resource_type: Domain + created_at: "2013-12-04 08:41:04.615227" + updated_at: "2013-12-04 08:41:04.615227" + view_environments: + name: view_environments + resource_type: Environment + created_at: "2013-12-04 08:41:04.623403" + updated_at: "2013-12-04 08:41:04.623403" + create_environments: + name: create_environments + resource_type: Environment + created_at: "2013-12-04 08:41:04.631791" + updated_at: "2013-12-04 08:41:04.631791" + edit_environments: + name: edit_environments + resource_type: Environment + created_at: "2013-12-04 08:41:04.640671" + updated_at: "2013-12-04 08:41:04.640671" + destroy_environments: + name: destroy_environments + resource_type: Environment + created_at: "2013-12-04 08:41:04.648794" + updated_at: "2013-12-04 08:41:04.648794" + import_environments: + name: import_environments + resource_type: Environment + created_at: "2013-12-04 08:41:04.656654" + updated_at: "2013-12-04 08:41:04.656654" + view_external_variables: + name: view_external_variables + resource_type: LookupKey + created_at: "2013-12-04 08:41:04.664806" + updated_at: "2013-12-04 08:41:04.664806" + create_external_variables: + name: create_external_variables + resource_type: LookupKey + created_at: "2013-12-04 08:41:04.673323" + updated_at: "2013-12-04 08:41:04.673323" + edit_external_variables: + name: edit_external_variables + resource_type: LookupKey + created_at: "2013-12-04 08:41:04.681526" + updated_at: "2013-12-04 08:41:04.681526" + destroy_external_variables: + name: destroy_external_variables + resource_type: LookupKey + created_at: "2013-12-04 08:41:04.690155" + updated_at: "2013-12-04 08:41:04.690155" + view_globals: + name: view_globals + resource_type: CommonParameter + created_at: "2013-12-04 08:41:04.782155" + updated_at: "2013-12-04 08:41:04.782155" + create_globals: + name: create_globals + resource_type: CommonParameter + created_at: "2013-12-04 08:41:04.790219" + updated_at: "2013-12-04 08:41:04.790219" + edit_globals: + name: edit_globals + resource_type: CommonParameter + created_at: "2013-12-04 08:41:04.799011" + updated_at: "2013-12-04 08:41:04.799011" + destroy_globals: + name: destroy_globals + resource_type: CommonParameter + created_at: "2013-12-04 08:41:04.806569" + updated_at: "2013-12-04 08:41:04.806569" + create_params: + name: create_params + resource_type: Parameter + created_at: "2013-12-04 08:41:04.823716" + updated_at: "2013-12-04 08:41:04.823716" + edit_params: + name: edit_params + resource_type: Parameter + created_at: "2013-12-04 08:41:04.831888" + updated_at: "2013-12-04 08:41:04.831888" + destroy_params: + name: destroy_params + resource_type: Parameter + created_at: "2013-12-04 08:41:04.84007" + updated_at: "2013-12-04 08:41:04.84007" + view_hostgroups: + name: view_hostgroups + resource_type: Hostgroup + created_at: "2013-12-04 08:41:04.848067" + updated_at: "2013-12-04 08:41:04.848067" + create_hostgroups: + name: create_hostgroups + resource_type: Hostgroup + created_at: "2013-12-04 08:41:04.857019" + updated_at: "2013-12-04 08:41:04.857019" + edit_hostgroups: + name: edit_hostgroups + resource_type: Hostgroup + created_at: "2013-12-04 08:41:04.865372" + updated_at: "2013-12-04 08:41:04.865372" + destroy_hostgroups: + name: destroy_hostgroups + resource_type: Hostgroup + created_at: "2013-12-04 08:41:04.873653" + updated_at: "2013-12-04 08:41:04.873653" + view_hosts: + name: view_hosts + resource_type: Host + created_at: "2013-12-04 08:41:04.882031" + updated_at: "2013-12-04 08:41:04.882031" + create_hosts: + name: create_hosts + resource_type: Host + created_at: "2013-12-04 08:41:04.88986" + updated_at: "2013-12-04 08:41:04.88986" + edit_hosts: + name: edit_hosts + resource_type: Host + created_at: "2013-12-04 08:41:04.898373" + updated_at: "2013-12-04 08:41:04.898373" + destroy_hosts: + name: destroy_hosts + resource_type: Host + created_at: "2013-12-04 08:41:04.907008" + updated_at: "2013-12-04 08:41:04.907008" + build_hosts: + name: build_hosts + resource_type: Host + created_at: "2013-12-04 08:41:04.915297" + updated_at: "2013-12-04 08:41:04.915297" + power_hosts: + name: power_hosts + resource_type: Host + created_at: "2013-12-04 08:41:04.923204" + updated_at: "2013-12-04 08:41:04.923204" + console_hosts: + name: console_hosts + resource_type: Host + created_at: "2013-12-04 08:41:04.931564" + updated_at: "2013-12-04 08:41:04.931564" + ipmi_boot: + name: ipmi_boot + resource_type: Host + created_at: "2013-12-04 08:41:04.940695" + updated_at: "2013-12-04 08:41:04.940695" + puppetrun_hosts: + name: puppetrun_hosts + resource_type: Host + created_at: "2013-12-04 08:41:04.962776" + updated_at: "2013-12-04 08:41:04.962776" + view_images: + name: view_images + resource_type: Image + created_at: "2013-12-04 08:41:04.982309" + updated_at: "2013-12-04 08:41:04.982309" + create_images: + name: create_images + resource_type: Image + created_at: "2013-12-04 08:41:04.990762" + updated_at: "2013-12-04 08:41:04.990762" + edit_images: + name: edit_images + resource_type: Image + created_at: "2013-12-04 08:41:04.998531" + updated_at: "2013-12-04 08:41:04.998531" + destroy_images: + name: destroy_images + resource_type: Image + created_at: "2013-12-04 08:41:05.00707" + updated_at: "2013-12-04 08:41:05.00707" + view_locations: + name: view_locations + resource_type: Location + created_at: "2013-12-04 08:41:05.015645" + updated_at: "2013-12-04 08:41:05.015645" + create_locations: + name: create_locations + resource_type: Location + created_at: "2013-12-04 08:41:05.024063" + updated_at: "2013-12-04 08:41:05.024063" + edit_locations: + name: edit_locations + resource_type: Location + created_at: "2013-12-04 08:41:05.032154" + updated_at: "2013-12-04 08:41:05.032154" + destroy_locations: + name: destroy_locations + resource_type: Location + created_at: "2013-12-04 08:41:05.040216" + updated_at: "2013-12-04 08:41:05.040216" + assign_locations: + name: assign_locations + resource_type: Location + created_at: "2013-12-04 08:41:05.048684" + updated_at: "2013-12-04 08:41:05.048684" + view_media: + name: view_media + resource_type: Medium + created_at: "2013-12-04 08:41:05.057086" + updated_at: "2013-12-04 08:41:05.057086" + create_media: + name: create_media + resource_type: Medium + created_at: "2013-12-04 08:41:05.065732" + updated_at: "2013-12-04 08:41:05.065732" + edit_media: + name: edit_media + resource_type: Medium + created_at: "2013-12-04 08:41:05.073582" + updated_at: "2013-12-04 08:41:05.073582" + destroy_media: + name: destroy_media + resource_type: Medium + created_at: "2013-12-04 08:41:05.0823" + updated_at: "2013-12-04 08:41:05.0823" + view_models: + name: view_models + resource_type: Model + created_at: "2013-12-04 08:41:05.090697" + updated_at: "2013-12-04 08:41:05.090697" + create_models: + name: create_models + resource_type: Model + created_at: "2013-12-04 08:41:05.098969" + updated_at: "2013-12-04 08:41:05.098969" + edit_models: + name: edit_models + resource_type: Model + created_at: "2013-12-04 08:41:05.107244" + updated_at: "2013-12-04 08:41:05.107244" + destroy_models: + name: destroy_models + resource_type: Model + created_at: "2013-12-04 08:41:05.11531" + updated_at: "2013-12-04 08:41:05.11531" + view_operatingsystems: + name: view_operatingsystems + resource_type: Operatingsystem + created_at: "2013-12-04 08:41:05.123697" + updated_at: "2013-12-04 08:41:05.123697" + create_operatingsystems: + name: create_operatingsystems + resource_type: Operatingsystem + created_at: "2013-12-04 08:41:05.132086" + updated_at: "2013-12-04 08:41:05.132086" + edit_operatingsystems: + name: edit_operatingsystems + resource_type: Operatingsystem + created_at: "2013-12-04 08:41:05.140537" + updated_at: "2013-12-04 08:41:05.140537" + destroy_operatingsystems: + name: destroy_operatingsystems + resource_type: Operatingsystem + created_at: "2013-12-04 08:41:05.148799" + updated_at: "2013-12-04 08:41:05.148799" + view_organizations: + name: view_organizations + resource_type: Organization + created_at: "2013-12-04 08:41:05.235498" + updated_at: "2013-12-04 08:41:05.235498" + create_organizations: + name: create_organizations + resource_type: Organization + created_at: "2013-12-04 08:41:05.248483" + updated_at: "2013-12-04 08:41:05.248483" + edit_organizations: + name: edit_organizations + resource_type: Organization + created_at: "2013-12-04 08:41:05.25688" + updated_at: "2013-12-04 08:41:05.25688" + destroy_organizations: + name: destroy_organizations + resource_type: Organization + created_at: "2013-12-04 08:41:05.26538" + updated_at: "2013-12-04 08:41:05.26538" + assign_organizations: + name: assign_organizations + resource_type: Organization + created_at: "2013-12-04 08:41:05.273221" + updated_at: "2013-12-04 08:41:05.273221" + view_ptables: + name: view_ptables + resource_type: Ptable + created_at: "2013-12-04 08:41:05.281766" + updated_at: "2013-12-04 08:41:05.281766" + create_ptables: + name: create_ptables + resource_type: Ptable + created_at: "2013-12-04 08:41:05.482882" + updated_at: "2013-12-04 08:41:05.482882" + edit_ptables: + name: edit_ptables + resource_type: Ptable + created_at: "2013-12-04 08:41:05.683037" + updated_at: "2013-12-04 08:41:05.683037" + destroy_ptables: + name: destroy_ptables + resource_type: Ptable + created_at: "2013-12-04 08:41:05.762135" + updated_at: "2013-12-04 08:41:05.762135" + view_puppetclasses: + name: view_puppetclasses + resource_type: Puppetclass + created_at: "2013-12-04 08:41:06.01639" + updated_at: "2013-12-04 08:41:06.01639" + create_puppetclasses: + name: create_puppetclasses + resource_type: Puppetclass + created_at: "2013-12-04 08:41:06.074428" + updated_at: "2013-12-04 08:41:06.074428" + edit_puppetclasses: + name: edit_puppetclasses + resource_type: Puppetclass + created_at: "2013-12-04 08:41:06.082891" + updated_at: "2013-12-04 08:41:06.082891" + destroy_puppetclasses: + name: destroy_puppetclasses + resource_type: Puppetclass + created_at: "2013-12-04 08:41:06.091247" + updated_at: "2013-12-04 08:41:06.091247" + import_puppetclasses: + name: import_puppetclasses + resource_type: Puppetclass + created_at: "2013-12-04 08:41:06.099309" + updated_at: "2013-12-04 08:41:06.099309" + view_reports: + name: view_reports + resource_type: Report + created_at: "2013-12-04 08:41:06.107515" + updated_at: "2013-12-04 08:41:06.107515" + destroy_reports: + name: destroy_reports + resource_type: Report + created_at: "2013-12-04 08:41:06.116056" + updated_at: "2013-12-04 08:41:06.116056" + upload_reports: + name: upload_reports + resource_type: Report + created_at: "2013-12-04 08:41:06.123783" + updated_at: "2013-12-04 08:41:06.123783" + access_settings: + name: access_settings + resource_type: + created_at: "2013-12-04 08:41:06.132528" + updated_at: "2013-12-04 08:41:06.132528" + view_smart_proxies: + name: view_smart_proxies + resource_type: SmartProxy + created_at: "2013-12-04 08:41:06.140564" + updated_at: "2013-12-04 08:41:06.140564" + create_smart_proxies: + name: create_smart_proxies + resource_type: SmartProxy + created_at: "2013-12-04 08:41:06.149029" + updated_at: "2013-12-04 08:41:06.149029" + edit_smart_proxies: + name: edit_smart_proxies + resource_type: SmartProxy + created_at: "2013-12-04 08:41:06.157364" + updated_at: "2013-12-04 08:41:06.157364" + destroy_smart_proxies: + name: destroy_smart_proxies + resource_type: SmartProxy + created_at: "2013-12-04 08:41:06.1657" + updated_at: "2013-12-04 08:41:06.1657" + view_smart_proxies_autosign: + name: view_smart_proxies_autosign + resource_type: SmartProxy + created_at: "2013-12-04 08:41:06.173638" + updated_at: "2013-12-04 08:41:06.173638" + create_smart_proxies_autosign: + name: create_smart_proxies_autosign + resource_type: SmartProxy + created_at: "2013-12-04 08:41:06.182425" + updated_at: "2013-12-04 08:41:06.182425" + destroy_smart_proxies_autosign: + name: destroy_smart_proxies_autosign + resource_type: SmartProxy + created_at: "2013-12-04 08:41:06.190274" + updated_at: "2013-12-04 08:41:06.190274" + view_smart_proxies_puppetca: + name: view_smart_proxies_puppetca + resource_type: SmartProxy + created_at: "2013-12-04 08:41:06.198169" + updated_at: "2013-12-04 08:41:06.198169" + edit_smart_proxies_puppetca: + name: edit_smart_proxies_puppetca + resource_type: SmartProxy + created_at: "2013-12-04 08:41:06.206812" + updated_at: "2013-12-04 08:41:06.206812" + destroy_smart_proxies_puppetca: + name: destroy_smart_proxies_puppetca + resource_type: SmartProxy + created_at: "2013-12-04 08:41:06.216154" + updated_at: "2013-12-04 08:41:06.216154" + view_statistics: + name: view_statistics + resource_type: + created_at: "2013-12-04 08:41:06.223528" + updated_at: "2013-12-04 08:41:06.223528" + view_subnets: + name: view_subnets + resource_type: Subnet + created_at: "2013-12-04 08:41:06.231467" + updated_at: "2013-12-04 08:41:06.231467" + create_subnets: + name: create_subnets + resource_type: Subnet + created_at: "2013-12-04 08:41:06.24055" + updated_at: "2013-12-04 08:41:06.24055" + edit_subnets: + name: edit_subnets + resource_type: Subnet + created_at: "2013-12-04 08:41:06.248888" + updated_at: "2013-12-04 08:41:06.248888" + destroy_subnets: + name: destroy_subnets + resource_type: Subnet + created_at: "2013-12-04 08:41:06.257199" + updated_at: "2013-12-04 08:41:06.257199" + import_subnets: + name: import_subnets + resource_type: Subnet + created_at: "2013-12-04 08:41:06.265758" + updated_at: "2013-12-04 08:41:06.265758" + view_tasks: + name: view_tasks + resource_type: + created_at: "2013-12-04 08:41:06.274449" + updated_at: "2013-12-04 08:41:06.274449" + view_trends: + name: view_trends + resource_type: Trend + created_at: "2013-12-04 08:41:06.282474" + updated_at: "2013-12-04 08:41:06.282474" + create_trends: + name: create_trends + resource_type: Trend + created_at: "2013-12-04 08:41:06.290854" + updated_at: "2013-12-04 08:41:06.290854" + edit_trends: + name: edit_trends + resource_type: Trend + created_at: "2013-12-04 08:41:06.299794" + updated_at: "2013-12-04 08:41:06.299794" + destroy_trends: + name: destroy_trends + resource_type: Trend + created_at: "2013-12-04 08:41:06.307322" + updated_at: "2013-12-04 08:41:06.307322" + update_trends: + name: update_trends + resource_type: Trend + created_at: "2013-12-04 08:41:06.315986" + updated_at: "2013-12-04 08:41:06.315986" + view_usergroups: + name: view_usergroups + resource_type: Usergroup + created_at: "2013-12-04 08:41:06.323534" + updated_at: "2013-12-04 08:41:06.323534" + create_usergroups: + name: create_usergroups + resource_type: Usergroup + created_at: "2013-12-04 08:41:06.332584" + updated_at: "2013-12-04 08:41:06.332584" + edit_usergroups: + name: edit_usergroups + resource_type: Usergroup + created_at: "2013-12-04 08:41:06.341266" + updated_at: "2013-12-04 08:41:06.341266" + destroy_usergroups: + name: destroy_usergroups + resource_type: Usergroup + created_at: "2013-12-04 08:41:06.34905" + updated_at: "2013-12-04 08:41:06.34905" + view_users: + name: view_users + resource_type: User + created_at: "2013-12-04 08:41:06.358291" + updated_at: "2013-12-04 08:41:06.358291" + create_users: + name: create_users + resource_type: User + created_at: "2013-12-04 08:41:06.366741" + updated_at: "2013-12-04 08:41:06.366741" + edit_users: + name: edit_users + resource_type: User + created_at: "2013-12-04 08:41:06.375061" + updated_at: "2013-12-04 08:41:06.375061" + destroy_users: + name: destroy_users + resource_type: User + created_at: "2013-12-04 08:41:06.38334" + updated_at: "2013-12-04 08:41:06.38334" + edit_classes: + name: edit_classes + resource_type: HostClass + created_at: "2013-12-04 08:41:04.815942" + updated_at: "2013-12-11 09:48:09.672833" + view_compute_resources_vms: + name: view_compute_resources_vms + resource_type: ComputeResource + created_at: "2013-12-11 11:23:54.965532" + updated_at: "2013-12-11 11:23:54.965532" + create_compute_resources_vms: + name: create_compute_resources_vms + resource_type: ComputeResource + created_at: "2013-12-11 11:23:54.972197" + updated_at: "2013-12-11 11:23:54.972197" + edit_compute_resources_vms: + name: edit_compute_resources_vms + resource_type: ComputeResource + created_at: "2013-12-11 11:23:54.979606" + updated_at: "2013-12-11 11:23:54.979606" + destroy_compute_resources_vms: + name: destroy_compute_resources_vms + resource_type: ComputeResource + created_at: "2013-12-11 11:23:54.988796" + updated_at: "2013-12-11 11:23:54.988796" + power_compute_resources_vms: + name: power_compute_resources_vms + resource_type: ComputeResource + created_at: "2013-12-11 11:23:54.996808" + updated_at: "2013-12-11 11:23:54.996808" + console_compute_resources_vms: + name: console_compute_resources_vms + resource_type: ComputeResource + created_at: "2013-12-11 11:23:55.004963" + updated_at: "2013-12-11 11:23:55.004963" + view_facts: + name: view_facts + resource_type: FactValue + created_at: "2013-12-11 11:23:55.027868" + updated_at: "2013-12-11 11:23:55.027868" + upload_facts: + name: upload_facts + resource_type: FactValue + created_at: "2013-12-11 11:23:55.038552" + updated_at: "2013-12-11 11:23:55.038552" + view_audit_logs: + name: view_audit_logs + resource_type: Audit + created_at: "2013-12-11 11:23:54.920553" + updated_at: "2014-01-03 15:52:15.267695" + view_plugins: + name: view_plugins + resource_type: + created_at: "2014-01-07 15:09:32.783442" + updated_at: "2014-01-07 15:09:32.783442" diff --git a/test/fixtures/roles.yml b/test/fixtures/roles.yml index 35278a406eb..d7090251bfa 100644 --- a/test/fixtures/roles.yml +++ b/test/fixtures/roles.yml @@ -3,218 +3,58 @@ manager: name: Manager id: "1" builtin: "0" - permissions: | - --- - - :view_architectures - - :create_architectures - - :edit_architectures - - :destroy_architectures - - :view_authenticators - - :create_authenticators - - :edit_authenticators - - :destroy_authenticators - - :view_environments - - :create_environments - - :edit_environments - - :destroy_environments - - :import_environments - - :view_external_variables - - :create_external_variables - - :edit_external_variables - - :destroy_external_variables - - :view_domains - - :create_domain - - :edit_domains - - :destroy_domains - - :view_globals - - :create_globals - - :edit_globals - - :destroy_globals - - :view_hostgroups - - :create_hostgroups - - :edit_hostgroups - - :destroy_hostgroups - - :view_hosts - - :create_hosts - - :edit_hosts - - :destroy_hosts - - :view_media - - :create_media - - :edit_media - - :destroy_media - - :view_models - - :create_models - - :edit_models - - :destroy_models - - :view_operatingsystems - - :create_operatingsystems - - :edit_operatingsystems - - :destroy_operatingsystems - - :view_ptables - - :create_ptables - - :edit_ptables - - :destroy_ptables - - :view_puppetclasses - - :create_puppetclasses - - :edit_puppetclasses - - :destroy_puppetclasses - - :import_puppetclasses - - :view_usergroups - - :create_usergroups - - :edit_usergroups - - :destroy_usergroups - - :view_users - - :create_users - - :edit_users - - :destroy_users - - :access_settings - - :access_dashboard - - :view_reports - - :destroy_reports - - :view_facts - - :view_audit_logs - - :view_statistics - - :view_locations - - :edit_locations - - :create_locations - - :destroy_locations - - :view_organizations - - :edit_organizations - - :create_organizations - - :destroy_organizations - - :edit_classes edit_partition_tables: name: Edit partition tables id: "2" builtin: "0" - permissions: | - --- - - :view_ptables - - :create_ptables - - :edit_ptables - - :destroy_ptables view_hosts: name: View hosts id: "3" builtin: "0" - permissions: | - --- - - :view_hosts edit_hosts: name: Edit hosts id: "4" builtin: "0" - permissions: | - --- - - :edit_hosts viewer: name: Viewer id: "5" builtin: "0" - permissions: | - --- - - :view_architectures - - :view_audit_logs - - :view_authenticators - - :access_dashboard - - :view_domains - - :view_environments - - :view_external_variables - - :view_facts - - :view_globals - - :view_hostgroups - - :view_hosts - - :view_locations - - :view_media - - :view_models - - :view_operatingsystems - - :view_ptables - - :view_puppetclasses - - :view_reports - - :access_settings - - :view_statistics - - :view_organizations - - :view_usergroups - - :view_users default_user: name: Default user id: "6" builtin: "1" - permissions: | - --- - - :view_hosts - - :view_puppetclasses - - :view_hostgroups - - :view_domains - - :view_oses - - :view_media - - :view_models - - :view_environments - - :view_architectures - - :view_ptables - - :view_globals - - :view_external_variables - - :view_authenticators - - :access_settings - - :access_dashboard - - :view_reports - - :view_facts - - :view_statistics anonymous: name: Anonymous id: "7" builtin: "2" - permissions: | - --- - - :view_hosts destroy_hosts: name: Destroy hosts id: "8" builtin: "0" - permissions: | - --- - - :destroy_hosts create_hosts: name: Create hosts id: "9" builtin: "0" - permissions: | - --- - - :create_hosts none_compute_resources: name: No rights id: "10" builtin: "0" - permissions: | - --- manage_compute_resources: name: View compute resources id: "11" builtin: "0" - permissions: | - --- - - :view_compute_resources - - :create_compute_resources - - :edit_compute_resources - - :destroy_compute_resources manage_hosts: name: CRUD hosts id: "12" builtin: "0" - permissions: | - --- - - :create_hosts - - :edit_hosts - - :destroy_hosts - - :view_hosts diff --git a/test/fixtures/user_facts.yml b/test/fixtures/user_facts.yml index dea8c48fe08..e69de29bb2d 100644 --- a/test/fixtures/user_facts.yml +++ b/test/fixtures/user_facts.yml @@ -1,8 +0,0 @@ -# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html - -one: - user: one - fact_name: ipaddress - criteria: '10.0.19.33' - operator: '=' - andor: 'and' diff --git a/test/fixtures/user_roles.yml b/test/fixtures/user_roles.yml index d4a9f7587d8..f254e879f10 100644 --- a/test/fixtures/user_roles.yml +++ b/test/fixtures/user_roles.yml @@ -1,15 +1,15 @@ user_restricted_viewer_role: - user: restricted + owner: restricted role_id: 5 user_restricted_anonymous_role: - user: restricted + owner: restricted role_id: 7 user_restricted_manage_hosts_role: - user: restricted + owner: restricted role_id: 12 user_restricted_manage_compute_resources: - user: restricted + owner: restricted role_id: 11 diff --git a/test/functional/api/v1/compute_resources_controller_test.rb b/test/functional/api/v1/compute_resources_controller_test.rb index 68755ed6ea0..230a01fe54e 100644 --- a/test/functional/api/v1/compute_resources_controller_test.rb +++ b/test/functional/api/v1/compute_resources_controller_test.rb @@ -48,59 +48,52 @@ def teardown end test "should get index of owned" do - as_user(:restricted) do - get :index, {} - end + setup_user 'view', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + get :index, {} assert_response :success assert_not_nil assigns(:compute_resources) compute_resources = ActiveSupport::JSON.decode(@response.body) ids = compute_resources.map { |hash| hash['compute_resource']['id'] } - assert !ids.include?(compute_resources(:mycompute).id) - assert ids.include?(compute_resources(:yourcompute).id) + assert_includes ids, compute_resources(:mycompute).id + refute_includes ids, compute_resources(:yourcompute).id end test "should allow access to a compute resource for owner" do - as_user(:restricted) do - get :show, { :id => compute_resources(:yourcompute).to_param } - end + setup_user 'view', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + get :show, { :id => compute_resources(:mycompute).to_param } assert_response :success end test "should update compute resource for owner" do - as_user(:restricted) do - put :update, { :id => compute_resources(:yourcompute).to_param, :compute_resource => { :description => "new_description" } } - end - assert_equal "new_description", ComputeResource.find_by_name('yourcompute').description + setup_user 'edit', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + put :update, { :id => compute_resources(:mycompute).to_param, :compute_resource => { :description => "new_description" } } + assert_equal "new_description", ComputeResource.find_by_name('mycompute').description assert_response :success end test "should destroy compute resource for owner" do assert_difference('ComputeResource.count', -1) do - as_user(:restricted) do - delete :destroy, { :id => compute_resources(:yourcompute).id } - end + setup_user 'destroy', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + delete :destroy, { :id => compute_resources(:mycompute).id } end assert_response :success end test "should not allow access to a compute resource out of users compute resources scope" do - as_user(:restricted) do - get :show, { :id => compute_resources(:one).to_param } - end + setup_user 'view', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + get :show, { :id => compute_resources(:one).to_param } assert_response :not_found end test "should not update compute resource for restricted" do - as_user(:restricted) do - put :update, { :id => compute_resources(:mycompute).to_param, :compute_resource => { :description => "new_description" } } - end + setup_user 'edit', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + put :update, { :id => compute_resources(:yourcompute).to_param, :compute_resource => { :description => "new_description" } } assert_response :not_found end test "should not destroy compute resource for restricted" do - as_user(:restricted) do - delete :destroy, { :id => compute_resources(:mycompute).id } - end + setup_user 'destroy', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + delete :destroy, { :id => compute_resources(:yourcompute).id } assert_response :not_found end diff --git a/test/functional/api/v1/config_templates_controller_test.rb b/test/functional/api/v1/config_templates_controller_test.rb index e4f1d9f4662..041609d287b 100644 --- a/test/functional/api/v1/config_templates_controller_test.rb +++ b/test/functional/api/v1/config_templates_controller_test.rb @@ -5,7 +5,7 @@ class Api::V1::ConfigTemplatesControllerTest < ActionController::TestCase test "should get index" do get :index templates = ActiveSupport::JSON.decode(@response.body) - assert !templates.empty?, "Should response with template" + assert_not_empty templates assert_response :success end @@ -13,13 +13,13 @@ class Api::V1::ConfigTemplatesControllerTest < ActionController::TestCase get :show, { :id => config_templates(:pxekickstart).to_param } assert_response :success template = ActiveSupport::JSON.decode(@response.body) - assert !template.empty? + assert_not_empty template assert_equal template["config_template"]["name"], config_templates(:pxekickstart).name end test "should not create invalid" do post :create - assert_response 422 + assert_response :unprocessable_entity end test "should create valid" do @@ -28,13 +28,13 @@ class Api::V1::ConfigTemplatesControllerTest < ActionController::TestCase post :create, { :config_template => valid_attrs } template = ActiveSupport::JSON.decode(@response.body) assert template["config_template"]["name"] == "RandomName" - assert_response 200 + assert_response :success end test "should not update invalid" do put :update, { :id => config_templates(:pxekickstart).to_param, :config_template => { :name => "" } } - assert_response 422 + assert_response :unprocessable_entity end test "should update valid" do @@ -42,13 +42,13 @@ class Api::V1::ConfigTemplatesControllerTest < ActionController::TestCase put :update, { :id => config_templates(:pxekickstart).to_param, :config_template => { :template => "blah" } } template = ActiveSupport::JSON.decode(@response.body) - assert_response :ok + assert_response :success end test "should not destroy template with associated hosts" do config_template = config_templates(:pxekickstart) delete :destroy, { :id => config_template.to_param } - assert_response 422 + assert_response :unprocessable_entity assert ConfigTemplate.exists?(config_template.id) end @@ -57,7 +57,7 @@ class Api::V1::ConfigTemplatesControllerTest < ActionController::TestCase config_template.os_default_templates.clear delete :destroy, { :id => config_template.to_param } template = ActiveSupport::JSON.decode(@response.body) - assert_response :ok + assert_response :success assert !ConfigTemplate.exists?(config_template.id) end @@ -65,7 +65,7 @@ class Api::V1::ConfigTemplatesControllerTest < ActionController::TestCase ProxyAPI::TFTP.any_instance.stubs(:create_default).returns(true) ProxyAPI::TFTP.any_instance.stubs(:fetch_boot_file).returns(true) get :build_pxe_default - assert_response 200 + assert_response :success end test "should add audit comment" do diff --git a/test/functional/api/v1/hosts_controller_test.rb b/test/functional/api/v1/hosts_controller_test.rb index dcdf964b27b..46d0b9676bd 100644 --- a/test/functional/api/v1/hosts_controller_test.rb +++ b/test/functional/api/v1/hosts_controller_test.rb @@ -21,14 +21,14 @@ def valid_attrs assert_response :success assert_not_nil assigns(:hosts) hosts = ActiveSupport::JSON.decode(@response.body) - assert !hosts.empty? + assert_not_empty hosts end test "should show individual record" do get :show, { :id => hosts(:one).to_param } assert_response :success show_response = ActiveSupport::JSON.decode(@response.body) - assert !show_response.empty? + assert_not_empty show_response end test "should create host" do @@ -74,72 +74,64 @@ def valid_attrs end test "should allow access to restricted user who owns the host" do - as_user :restricted do - get :show, { :id => hosts(:owned_by_restricted).to_param } - end + setup_user 'view', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + $debug = true + get :show, { :id => hosts(:owned_by_restricted).to_param } assert_response :success end test "should allow to update for restricted user who owns the host" do disable_orchestration - as_user :restricted do - put :update, { :id => hosts(:owned_by_restricted).to_param, :host => {} } - end + setup_user 'edit', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + put :update, { :id => hosts(:owned_by_restricted).to_param, :host => {} } assert_response :success end test "should allow destroy for restricted user who owns the hosts" do assert_difference('Host.count', -1) do - as_user :restricted do - delete :destroy, { :id => hosts(:owned_by_restricted).to_param } - end + setup_user 'destroy', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + delete :destroy, { :id => hosts(:owned_by_restricted).to_param } end assert_response :success end test "should allow show status for restricted user who owns the hosts" do - as_user :restricted do - get :status, { :id => hosts(:owned_by_restricted).to_param } - end + setup_user 'view', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + get :status, { :id => hosts(:owned_by_restricted).to_param } assert_response :success end test "should not allow access to a host out of users hosts scope" do - as_user :restricted do - get :show, { :id => hosts(:one).to_param } - end + setup_user 'view', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + get :show, { :id => hosts(:one).to_param } assert_response :not_found end test "should not list a host out of users hosts scope" do - as_user :restricted do - get :index, {} - end + setup_user 'view', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + get :index, {} assert_response :success hosts = ActiveSupport::JSON.decode(@response.body) ids = hosts.map { |hash| hash['host']['id'] } - assert !ids.include?(hosts(:one).id) - assert ids.include?(hosts(:owned_by_restricted).id) + refute_includes ids, hosts(:one).id + assert_includes ids, hosts(:owned_by_restricted).id end test "should not update host out of users hosts scope" do - as_user :restricted do - put :update, { :id => hosts(:one).to_param } - end + setup_user 'edit', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + put :update, { :id => hosts(:one).to_param } assert_response :not_found end test "should not delete hosts out of users hosts scope" do - as_user :restricted do - delete :destroy, { :id => hosts(:one).to_param } - end + setup_user 'destroy', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + delete :destroy, { :id => hosts(:one).to_param } assert_response :not_found end test "should not show status of hosts out of users hosts scope" do - as_user :restricted do - get :status, { :id => hosts(:one).to_param } - end + setup_user 'view', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + get :status, { :id => hosts(:one).to_param } assert_response :not_found end diff --git a/test/functional/api/v1/smart_proxies_controller_test.rb b/test/functional/api/v1/smart_proxies_controller_test.rb index eaef8ff1c96..8401b2fdaa4 100644 --- a/test/functional/api/v1/smart_proxies_controller_test.rb +++ b/test/functional/api/v1/smart_proxies_controller_test.rb @@ -9,7 +9,7 @@ class Api::V1::SmartProxiesControllerTest < ActionController::TestCase assert_response :success assert_not_nil assigns(:smart_proxies) smart_proxies = ActiveSupport::JSON.decode(@response.body) - assert !smart_proxies.empty? + assert_not smart_proxies.empty? end test "should get index filtered by type" do @@ -19,7 +19,7 @@ class Api::V1::SmartProxiesControllerTest < ActionController::TestCase assert_response :success assert_not_nil assigns(:smart_proxies) smart_proxies = ActiveSupport::JSON.decode(@response.body) - assert !smart_proxies.empty? + assert_not smart_proxies.empty? returned_proxy_ids = smart_proxies.map { |p| p["smart_proxy"]["id"] } expected_proxy_ids = SmartProxy.tftp_proxies.map { |p| p.id } @@ -37,7 +37,7 @@ class Api::V1::SmartProxiesControllerTest < ActionController::TestCase get :show, { :id => smart_proxies(:one).to_param } assert_response :success show_response = ActiveSupport::JSON.decode(@response.body) - assert !show_response.empty? + assert_not show_response.empty? end test "should create smart_proxy" do diff --git a/test/functional/api/v1/statistics_controller_test.rb b/test/functional/api/v1/statistics_controller_test.rb index 6fef2a4b563..8a20d570301 100644 --- a/test/functional/api/v1/statistics_controller_test.rb +++ b/test/functional/api/v1/statistics_controller_test.rb @@ -7,8 +7,12 @@ class Api::V1::StatisticsControllerTest < ActionController::TestCase get :index, { } assert_response :success response = ActiveSupport::JSON.decode(@response.body) - assert !response.empty? - assert_equal 'statistics', response.keys.first + assert_not response.empty? + expected_keys = ["arch_count", "cpu_count", "env_count", "klass_count", + "mem_free", "mem_size", "mem_totfree", "mem_totsize", + "model_count", "os_count", "swap_free", "swap_size"] + + assert_equal expected_keys, response.keys.sort end end diff --git a/test/functional/api/v1/users_controller_test.rb b/test/functional/api/v1/users_controller_test.rb index c4bd53f6a08..fafe8989f5b 100644 --- a/test/functional/api/v1/users_controller_test.rb +++ b/test/functional/api/v1/users_controller_test.rb @@ -17,14 +17,14 @@ def setup get :show, { :id => users(:one).id } assert_response :success show_response = ActiveSupport::JSON.decode(@response.body) - assert !show_response.empty? + assert_not show_response.empty? end test "should show individual record by login name" do get :show, { :id => users(:one).login } assert_response :success show_response = ActiveSupport::JSON.decode(@response.body) - assert !show_response.empty? + assert_not show_response.empty? end test "should update user" do diff --git a/test/functional/api/v2/compute_resources_controller_test.rb b/test/functional/api/v2/compute_resources_controller_test.rb index c56148f8e25..b60d0b3c65b 100644 --- a/test/functional/api/v2/compute_resources_controller_test.rb +++ b/test/functional/api/v2/compute_resources_controller_test.rb @@ -48,59 +48,52 @@ def teardown end test "should get index of owned" do - as_user(:restricted) do - get :index, {} - end + setup_user 'view', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + get :index, {} assert_response :success assert_not_nil assigns(:compute_resources) compute_resources = ActiveSupport::JSON.decode(@response.body) ids = compute_resources['results'].map { |hash| hash['id'] } - assert !ids.include?(compute_resources(:mycompute).id) - assert ids.include?(compute_resources(:yourcompute).id) + assert_includes ids, compute_resources(:mycompute).id + refute_includes ids, compute_resources(:yourcompute).id end test "should allow access to a compute resource for owner" do - as_user(:restricted) do - get :show, { :id => compute_resources(:yourcompute).to_param } - end + setup_user 'view', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + get :show, { :id => compute_resources(:mycompute).to_param } assert_response :success end test "should update compute resource for owner" do - as_user(:restricted) do - put :update, { :id => compute_resources(:yourcompute).to_param, :compute_resource => { :description => "new_description" } } - end - assert_equal "new_description", ComputeResource.find_by_name('yourcompute').description + setup_user 'edit', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + put :update, { :id => compute_resources(:mycompute).to_param, :compute_resource => { :description => "new_description" } } + assert_equal "new_description", ComputeResource.find_by_name('mycompute').description assert_response :success end test "should destroy compute resource for owner" do assert_difference('ComputeResource.count', -1) do - as_user(:restricted) do - delete :destroy, { :id => compute_resources(:yourcompute).id } - end + setup_user 'destroy', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + delete :destroy, { :id => compute_resources(:mycompute).id } end assert_response :success end test "should not allow access to a compute resource out of users compute resources scope" do - as_user(:restricted) do - get :show, { :id => compute_resources(:one).to_param } - end + setup_user 'view', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + get :show, { :id => compute_resources(:one).to_param } assert_response :not_found end test "should not update compute resource for restricted" do - as_user(:restricted) do - put :update, { :id => compute_resources(:mycompute).to_param, :compute_resource => { :description => "new_description" } } - end + setup_user 'edit', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + put :update, { :id => compute_resources(:yourcompute).to_param, :compute_resource => { :description => "new_description" } } assert_response :not_found end test "should not destroy compute resource for restricted" do - as_user(:restricted) do - delete :destroy, { :id => compute_resources(:mycompute).id } - end + setup_user 'destroy', 'compute_resources', "id = #{compute_resources(:mycompute).id}" + delete :destroy, { :id => compute_resources(:yourcompute).id } assert_response :not_found end @@ -115,7 +108,7 @@ def teardown get :available_images, { :id => compute_resources(:ec2).to_param } assert_response :success available_images = ActiveSupport::JSON.decode(@response.body) - assert !available_images.empty? + assert_not_empty available_images end test "should get available networks" do diff --git a/test/functional/api/v2/filters_controller_test.rb b/test/functional/api/v2/filters_controller_test.rb new file mode 100644 index 00000000000..448871495d4 --- /dev/null +++ b/test/functional/api/v2/filters_controller_test.rb @@ -0,0 +1,40 @@ +require 'test_helper' + +class Api::V2::FiltersControllerTest < ActionController::TestCase + + test "should get index" do + get :index + assert_response :success + assert_not_nil assigns(:filters) + filters = ActiveSupport::JSON.decode(@response.body) + assert !filters.empty? + end + + test "should show individual record" do + get :show, { :id => filters(:manager_1).to_param } + assert_response :success + show_response = ActiveSupport::JSON.decode(@response.body) + assert !show_response.empty? + end + + test "should create filter" do + valid_attrs = { :role_id => roles(:manager).id, :permission_ids => [permissions(:view_architectures).id] } + assert_difference('Filter.count') do + post :create, { :filter => valid_attrs } + end + assert_response :success + end + + test "should update filter" do + put :update, { :id => filters(:manager_1).to_param, :filter => { } } + assert_response :success + end + + test "should destroy filters" do + assert_difference('Filter.count', -1) do + delete :destroy, { :id => filters(:crud_hosts_1).to_param } + end + assert_response :success + end + +end diff --git a/test/functional/api/v2/hosts_controller_test.rb b/test/functional/api/v2/hosts_controller_test.rb index 17d368d0cc8..663e076b00c 100644 --- a/test/functional/api/v2/hosts_controller_test.rb +++ b/test/functional/api/v2/hosts_controller_test.rb @@ -74,72 +74,63 @@ def valid_attrs end test "should allow access to restricted user who owns the host" do - as_user :restricted do - get :show, { :id => hosts(:owned_by_restricted).to_param } - end + setup_user 'view', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + get :show, { :id => hosts(:owned_by_restricted).to_param } assert_response :success end test "should allow to update for restricted user who owns the host" do disable_orchestration - as_user :restricted do - put :update, { :id => hosts(:owned_by_restricted).to_param, :host => {} } - end + setup_user 'edit', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + put :update, { :id => hosts(:owned_by_restricted).to_param, :host => {} } assert_response :success end test "should allow destroy for restricted user who owns the hosts" do assert_difference('Host.count', -1) do - as_user :restricted do - delete :destroy, { :id => hosts(:owned_by_restricted).to_param } - end + setup_user 'destroy', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + delete :destroy, { :id => hosts(:owned_by_restricted).to_param } end assert_response :success end test "should allow show status for restricted user who owns the hosts" do - as_user :restricted do - get :status, { :id => hosts(:owned_by_restricted).to_param } - end + setup_user 'view', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + get :status, { :id => hosts(:owned_by_restricted).to_param } assert_response :success end test "should not allow access to a host out of users hosts scope" do - as_user :restricted do - get :show, { :id => hosts(:one).to_param } - end + setup_user 'view', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + get :show, { :id => hosts(:one).to_param } assert_response :not_found end test "should not list a host out of users hosts scope" do - as_user :restricted do - get :index, {} - end + setup_user 'view', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + get :index, {} assert_response :success hosts = ActiveSupport::JSON.decode(@response.body) ids = hosts['results'].map { |hash| hash['id'] } - assert !ids.include?(hosts(:one).id) - assert ids.include?(hosts(:owned_by_restricted).id) + refute_includes ids, hosts(:one).id + assert_includes ids, hosts(:owned_by_restricted).id end test "should not update host out of users hosts scope" do - as_user :restricted do - put :update, { :id => hosts(:one).to_param } - end + setup_user 'edit', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + put :update, { :id => hosts(:one).to_param } assert_response :not_found end test "should not delete hosts out of users hosts scope" do - as_user :restricted do - delete :destroy, { :id => hosts(:one).to_param } - end + setup_user 'destroy', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + delete :destroy, { :id => hosts(:one).to_param } assert_response :not_found end test "should not show status of hosts out of users hosts scope" do - as_user :restricted do - get :status, { :id => hosts(:one).to_param } - end + setup_user 'view', 'hosts', "owner_type = User and owner_id = #{users(:restricted).id}", :restricted + get :status, { :id => hosts(:one).to_param } assert_response :not_found end diff --git a/test/functional/api/v2/operatingsystems_controller_test.rb b/test/functional/api/v2/operatingsystems_controller_test.rb index 599df67ad21..7d284403cd5 100644 --- a/test/functional/api/v2/operatingsystems_controller_test.rb +++ b/test/functional/api/v2/operatingsystems_controller_test.rb @@ -54,7 +54,6 @@ class Api::V2::OperatingsystemsControllerTest < ActionController::TestCase test "should update associated architectures by ids" do os = operatingsystems(:redhat) - puts assert_difference('os.architectures.count') do put :update, { :id => operatingsystems(:redhat).to_param, :operatingsystem => { }, :architectures => [{ :id => architectures(:x86_64).id }, { :id => architectures(:sparc).id } ] @@ -65,7 +64,6 @@ class Api::V2::OperatingsystemsControllerTest < ActionController::TestCase test "should update associated architectures by name" do os = operatingsystems(:redhat) - puts assert_difference('os.architectures.count') do put :update, { :id => operatingsystems(:redhat).to_param, :operatingsystem => { }, :architectures => [{ :name => architectures(:x86_64).name }, { :name => architectures(:sparc).name } ] diff --git a/test/functional/api/v2/override_values_controller_test.rb b/test/functional/api/v2/override_values_controller_test.rb index da3976aa0bf..041d5ff3e56 100644 --- a/test/functional/api/v2/override_values_controller_test.rb +++ b/test/functional/api/v2/override_values_controller_test.rb @@ -9,14 +9,14 @@ class Api::V2::OverrideValuesControllerTest < ActionController::TestCase get :index, {:smart_variable_id => lookup_keys(:two).to_param } assert_response :success override_values = ActiveSupport::JSON.decode(@response.body) - assert !override_values.empty? + assert_not_empty override_values assert_equal 1, override_values["results"].length end test "should get override values for specific smart class parameter" do get :index, {:smart_class_parameter_id => lookup_keys(:complex).to_param } assert_response :success override_values = ActiveSupport::JSON.decode(@response.body) - assert !override_values.empty? + assert_not_empty override_values assert_equal 2, override_values["results"].length end @@ -37,13 +37,13 @@ class Api::V2::OverrideValuesControllerTest < ActionController::TestCase get :show, {:smart_variable_id => lookup_keys(:two).to_param, :id => lookup_values(:four).to_param } assert_response :success results = ActiveSupport::JSON.decode(@response.body) - assert !results.empty? + assert_not_empty results assert_equal "hostgroup=Common", results['match'] end test "should show specific override values for specific smart class parameter" do get :show, {:smart_class_parameter_id => lookup_keys(:complex).to_param, :id => lookup_values(:hostgroupcommon).to_param } results = ActiveSupport::JSON.decode(@response.body) - assert !results.empty? + assert_not_empty results assert_equal "hostgroup=Common", results['match'] assert_response :success end @@ -60,4 +60,4 @@ class Api::V2::OverrideValuesControllerTest < ActionController::TestCase assert_response :success end -end \ No newline at end of file +end diff --git a/test/functional/api/v2/parameters_controller_test.rb b/test/functional/api/v2/parameters_controller_test.rb index 9a1f74db7d0..7d8268f2b00 100644 --- a/test/functional/api/v2/parameters_controller_test.rb +++ b/test/functional/api/v2/parameters_controller_test.rb @@ -9,7 +9,7 @@ class Api::V2::ParametersControllerTest < ActionController::TestCase assert_response :success assert_not_nil assigns(:parameters) parameters = ActiveSupport::JSON.decode(@response.body) - assert !parameters.empty? + assert_not_empty parameters end test "should get index for specific domain" do @@ -17,7 +17,7 @@ class Api::V2::ParametersControllerTest < ActionController::TestCase assert_response :success assert_not_nil assigns(:parameters) parameters = ActiveSupport::JSON.decode(@response.body) - assert !parameters.empty? + assert_not_empty parameters end test "should get index for specific hostgroup" do @@ -25,7 +25,7 @@ class Api::V2::ParametersControllerTest < ActionController::TestCase assert_response :success assert_not_nil assigns(:parameters) parameters = ActiveSupport::JSON.decode(@response.body) - assert !parameters.empty? + assert_not_empty parameters end @@ -34,35 +34,35 @@ class Api::V2::ParametersControllerTest < ActionController::TestCase assert_response :success assert_not_nil assigns(:parameters) parameters = ActiveSupport::JSON.decode(@response.body) - assert !parameters.empty? + assert_not_empty parameters end test "should show a host parameter" do get :show, { :host_id => hosts(:one).to_param, :id => parameters(:host).to_param } assert_response :success show_response = ActiveSupport::JSON.decode(@response.body) - assert !show_response.empty? + assert_not_empty show_response end test "should show a domain parameter" do get :show, {:domain_id => domains(:mydomain).to_param, :id => parameters(:domain).to_param } assert_response :success show_response = ActiveSupport::JSON.decode(@response.body) - assert !show_response.empty? + assert_not_empty show_response end test "should show a hostgroup parameter" do get :show, {:hostgroup_id => hostgroups(:common).to_param,:id => parameters(:group).to_param } assert_response :success show_response = ActiveSupport::JSON.decode(@response.body) - assert !show_response.empty? + assert_not_empty show_response end test "should show an os parameter" do get :show, {:operatingsystem_id => operatingsystems(:redhat).to_param,:id => parameters(:os).to_param } assert_response :success show_response = ActiveSupport::JSON.decode(@response.body) - assert !show_response.empty? + assert_not_empty show_response end test "should show correct parameter if id is name even if name is not unique" do diff --git a/test/functional/api/v2/statistics_controller_test.rb b/test/functional/api/v2/statistics_controller_test.rb index e07b40a40cf..fff25a27d45 100644 --- a/test/functional/api/v2/statistics_controller_test.rb +++ b/test/functional/api/v2/statistics_controller_test.rb @@ -6,19 +6,12 @@ class Api::V2::StatisticsControllerTest < ActionController::TestCase get :index, { } assert_response :success response = ActiveSupport::JSON.decode(@response.body) - assert !response.empty? - assert response.keys.include?('os_count') - assert response.keys.include?('arch_count') - assert response.keys.include?('env_count') - assert response.keys.include?('klass_count') - assert response.keys.include?('cpu_count') - assert response.keys.include?('model_count') - assert response.keys.include?('mem_size') - assert response.keys.include?('mem_free') - assert response.keys.include?('swap_size') - assert response.keys.include?('swap_free') - assert response.keys.include?('mem_totsize') - assert response.keys.include?('mem_totfree') + assert_not response.empty? + expected_keys = ["arch_count", "cpu_count", "env_count", "klass_count", + "mem_free", "mem_size", "mem_totfree", "mem_totsize", + "model_count", "os_count", "swap_free", "swap_size"] + + assert_equal expected_keys, response.keys.sort end end diff --git a/test/functional/api/v2/users_controller_test.rb b/test/functional/api/v2/users_controller_test.rb index cf58ee57bb2..f7b8e5f336f 100644 --- a/test/functional/api/v2/users_controller_test.rb +++ b/test/functional/api/v2/users_controller_test.rb @@ -17,14 +17,14 @@ def setup get :show, { :id => users(:one).id } assert_response :success show_response = ActiveSupport::JSON.decode(@response.body) - assert !show_response.empty? + assert_not show_response.empty? end test "should show individual record by login name" do get :show, { :id => users(:one).login } assert_response :success show_response = ActiveSupport::JSON.decode(@response.body) - assert !show_response.empty? + assert_not show_response.empty? end test "should update user" do diff --git a/test/functional/compute_resources_controller_test.rb b/test/functional/compute_resources_controller_test.rb index 13c90830aa5..2ff9fa0938a 100644 --- a/test/functional/compute_resources_controller_test.rb +++ b/test/functional/compute_resources_controller_test.rb @@ -59,7 +59,7 @@ class ComputeResourcesControllerTest < ActionController::TestCase test "should not show compute resource when restricted" do setup_user "view" get :show, {:id => @your_compute_resource.to_param}, set_session_user - assert_response 403 + assert_response 404 end test "should show compute resource" do @@ -77,7 +77,7 @@ class ComputeResourcesControllerTest < ActionController::TestCase test "should not get edit when restricted" do setup_user "edit" get :edit, {:id => @your_compute_resource.to_param}, set_session_user - assert_response 403 + assert_response 404 end test "should get edit" do @@ -95,7 +95,7 @@ class ComputeResourcesControllerTest < ActionController::TestCase test "should not update compute resource when restricted" do setup_user "edit" put :update, {:id => @your_compute_resource.to_param, :compute_resource => {:name => "editing_self", :provider => "EC2"}}, set_session_user - assert_response 403 + assert_response 404 end test "should update compute resource" do @@ -119,7 +119,7 @@ class ComputeResourcesControllerTest < ActionController::TestCase delete :destroy, {:id => @your_compute_resource.to_param}, set_session_user end - assert_response 403 + assert_response 404 end test "should destroy compute resource" do @@ -154,18 +154,8 @@ def set_session_user SETTINGS[:login] ? {:user => User.current.id, :expires_at => 5.minutes.from_now} : {} end - def setup_user operation - @one = users(:one) - @request.session[:user] = @one.id - as_admin do - @one.roles = [Role.find_by_name('Anonymous'), Role.find_by_name('Viewer')] - role = Role.find_or_create_by_name :name => "#{operation}_compute_resources" - role.permissions = ["#{operation}_compute_resources".to_sym] - role.save! - @one.roles << [role] - @one.compute_resources = [@compute_resource] - @one.save! - end - User.current = @one + def setup_user operation, type = 'compute_resources' + super(operation, type, "id = #{@compute_resource.id}") end + end diff --git a/test/functional/compute_resources_vms_controller_test.rb b/test/functional/compute_resources_vms_controller_test.rb index 3ffd5b0b154..04d32bc9e88 100644 --- a/test/functional/compute_resources_vms_controller_test.rb +++ b/test/functional/compute_resources_vms_controller_test.rb @@ -12,6 +12,10 @@ class ComputeResourcesVmsControllerTest < ActionController::TestCase # Fog.unmock! end + def setup_user operation, type = 'compute_resources_vms' + super(operation, type, "id = #{@compute_resource.id}") + end + test "should not get index when not permitted" do setup_user "none" get :index, {:compute_resource_id => @compute_resource.to_param}, set_session_user @@ -34,7 +38,7 @@ class ComputeResourcesVmsControllerTest < ActionController::TestCase test "should not show vm JSON when restricted" do setup_user "view" get :show, {:id => @test_vm.uuid, :format => "json", :compute_resource_id => @your_compute_resource.to_param}, set_session_user - assert_response 403 + assert_response 404 end test "should show vm JSON" do @@ -52,7 +56,7 @@ class ComputeResourcesVmsControllerTest < ActionController::TestCase test "should not show vm when restricted" do setup_user "view" get :show, {:id => @test_vm.uuid, :compute_resource_id => @your_compute_resource.to_param}, set_session_user - assert_response 403 + assert_response 404 end test "should show vm" do @@ -73,7 +77,9 @@ class ComputeResourcesVmsControllerTest < ActionController::TestCase #Broken with Fog.mock! because lib/fog/libvirt/models/compute/volume.rb:41 calls create_volume with the wrong number of arguments #Broken before Fog 8d95d5bff223a199d33e297ea21884d8598f6921 because default pool name being "default-pool" and not "default" (with test:///default) triggers an internal bug def test_should_create_vm(name = "new_test") - setup_user "create" + setup_user "create" do |user| + user.roles.last.add_permissions! :view_compute_resources + end assert_difference('@compute_resource.vms.count', +1) do attrs = {:name => name, :memory => 128*1024*1024, :domain_type => "test", :arch => "i686"} post :create, {:vm => attrs, :compute_resource_id => @compute_resource.to_param}, set_session_user @@ -96,7 +102,7 @@ def test_should_create_vm(name = "new_test") delete :destroy, {:format => "json", :id => @test_vm.uuid, :compute_resource_id => @your_compute_resource.to_param}, set_session_user end - assert_response 403 + assert_response 404 end test "should destroy vm" do @@ -127,7 +133,7 @@ def test_should_create_vm(name = "new_test") setup_user "power" get :power, {:format => "json", :id => @test_vm.uuid, :compute_resource_id => @your_compute_resource.to_param}, set_session_user - assert_response 403 + assert_response 404 end test "should pause openstack vm" do @@ -173,18 +179,4 @@ def set_session_user SETTINGS[:login] ? {:user => User.current.id, :expires_at => 5.minutes.from_now} : {} end - def setup_user operation - @one = users(:one) - @request.session[:user] = @one.id - as_admin do - @one.roles = [Role.find_by_name('Anonymous'), Role.find_by_name('Viewer')] - role = Role.find_or_create_by_name :name => "#{operation}_compute_resources_vms" - role.permissions = ["#{operation}_compute_resources_vms".to_sym] - role.save! - @one.roles << [role] - @one.compute_resources = [@compute_resource] - @one.save! - end - User.current = @one - end end diff --git a/test/functional/hostgroups_controller_test.rb b/test/functional/hostgroups_controller_test.rb index 059297ef7d9..824b5c0f7ea 100644 --- a/test/functional/hostgroups_controller_test.rb +++ b/test/functional/hostgroups_controller_test.rb @@ -58,17 +58,8 @@ def test_destroy assert !Hostgroup.exists?(hostgroup.id) end - def setup_user operation - @request.session[:user] = users(:one).id - @one = users(:one) - as_admin do - @one.roles = [Role.find_by_name('Anonymous'), Role.find_by_name('Viewer')] - role = Role.find_or_create_by_name :name => "hostgroups" - role.permissions = ["#{operation}_hostgroups".to_sym] - role.save! - @one.roles << [role] - @one.save! - end + def setup_user operation, type = 'hostgroups' + super end test 'user with viewer rights should fail to edit a hostgroup ' do diff --git a/test/functional/hosts_controller_test.rb b/test/functional/hosts_controller_test.rb index 028304497ce..2e93d5a292b 100644 --- a/test/functional/hosts_controller_test.rb +++ b/test/functional/hosts_controller_test.rb @@ -138,144 +138,85 @@ def test_clone_empties_fields refute assigns(:host).mac end - def setup_user_and_host operation + def setup_user operation, type = 'hosts', filter = nil + super + end + + def setup_user_and_host(operation, filter = nil, &block) + setup_user operation, 'hosts', filter, &block + as_admin do - @one = users(:one) - @one.domains.destroy_all - @one.hostgroups.destroy_all - @one.user_facts.destroy_all @host1 = hosts(:one) @host1.owner = users(:admin) @host1.save! @host2 = hosts(:two) @host2.owner = users(:admin) @host2.save! - @one.roles = [Role.find_by_name('Anonymous'), Role.find_by_name("#{operation.capitalize} hosts")] end Host.per_page == 1000 @request.session[:user] = @one.id end - test 'user with edit host rights and domain is set should succeed in viewing host1' do - setup_user_and_host "Edit" + test 'user with view host rights and domain is set should succeed in viewing host1 but fail for host2' do + setup_user_and_host "view", "domain_id = #{domains(:mydomain).id}" + as_admin do - @one.domains = [domains(:mydomain)] @host1.update_attribute(:domain, domains(:mydomain)) @host2.update_attribute(:domain, domains(:yourdomain)) end get :index, {}, set_session_user.merge(:user => @one.id) assert_response :success assert_match /#{@host1.shortname}/, @response.body + refute_match /#{@host2.name}/, @response.body end - test 'user with edit host rights and domain is set should fail to view host2' do - setup_user_and_host "Edit" - as_admin do - @one.domains = [domains(:mydomain)] - @host1.domain = domains(:mydomain) - @host2.domain = domains(:yourdomain) - end - get :index, {}, set_session_user.merge(:user => @one.id) - assert_response :success - assert @response.body !~ /#{@host2.name}/ - end - - test 'user with edit host rights and ownership is set should succeed in viewing host1' do - setup_user_and_host "Edit" - as_admin do - @host1.owner = @one - @host2.owner = users(:two) - @one.filter_on_owner = true - @one.save! - @host1.save! - @host2.save! - end - get :index, {}, set_session_user.merge(:user => @one.id) - assert_response :success - assert @response.body =~ /#{@host1.name}/ - end - - test 'user with edit host rights and ownership is set should fail to view host2' do - setup_user_and_host "Edit" + test 'user with view host rights and ownership is set should succeed in viewing host1 but fail for host2' do + setup_user_and_host "view", "owner_id = #{users(:one).id} and owner_type = User" as_admin do @host1.owner = @one @host2.owner = users(:two) - @one.filter_on_owner = true - @one.save! @host1.save! @host2.save! end get :index, {}, set_session_user.merge(:user => @one.id) assert_response :success - assert @response.body !~ /#{@host2.name}/ + assert_match /#{@host1.name}/, @response.body + refute_match /#{@host2.name}/, @response.body end - test 'user with edit host rights and hostgroup is set should succeed in viewing host1' do - setup_user_and_host "Edit" + test 'user with view host rights and hostgroup is set should succeed in viewing host1 but fail for host2' do + setup_user_and_host "view", "hostgroup_id = #{hostgroups(:common).id}" as_admin do @host1.hostgroup = hostgroups(:common) @host2.hostgroup = hostgroups(:unusual) - @one.hostgroups = [hostgroups(:common)] @host1.save! @host2.save! end get :index, {}, set_session_user.merge(:user => @one.id) assert_response :success - assert @response.body =~ /#{@host1.name}/ + assert_match /#{@host1.name}/, @response.body + refute_match /#{@host2.name}/, @response.body end - test 'user with edit host rights and hostgroup is set should fail to view host2' do - setup_user_and_host "Edit" - as_admin do - @host1.hostgroup = hostgroups(:common) - @host2.hostgroup = hostgroups(:unusual) - @one.hostgroups = [hostgroups(:common)] - @host1.save! - @host2.save! - end - get :index, {}, set_session_user.merge(:user => @one.id) - assert_response :success - assert @response.body !~ /#{@host2.name}/ - end - - test 'user with edit host rights and facts are set should succeed in viewing host1' do - setup_user_and_host "Edit" + test 'user with edit host rights and facts are set should succeed in viewing host1 but fail for host2' do + setup_user_and_host "view", "facts.architecture = \"x86_64\"" as_admin do fn_id = FactName.find_or_create_by_name("architecture").id FactValue.create! :host => @host1, :fact_name_id => fn_id, :value => "x86_64" FactValue.create! :host => @host2, :fact_name_id => fn_id, :value => "i386" - UserFact.create! :user => @one, :fact_name_id => fn_id, :criteria => "x86_64", :operator => "=", :andor => "or" end get :index, {}, set_session_user.merge(:user => @one.id) assert_response :success - assert @response.body =~ /#{@host1.name}/ - end - - test 'user with edit host rights and facts are set should fail to view host2' do - setup_user_and_host "Edit" - as_admin do - fn_id = FactName.find_or_create_by_name("architecture").id - FactValue.create! :host => @host1, :fact_name_id => fn_id, :value => "x86_64" - FactValue.create! :host => @host2, :fact_name_id => fn_id, :value => "i386" - UserFact.create! :user => @one, :fact_name_id => fn_id, :criteria => "x86_64", :operator => "=", :andor => "or" - end - get :index, {}, set_session_user.merge(:user => @one.id) - assert_response :success - assert @response.body !~ /#{@host2.name}/ + assert_match /#{@host1.name}/, @response.body + refute_match /#{@host2.name}/, @response.body end test 'user with view host rights should fail to edit host' do - setup_user_and_host "View" + setup_user_and_host "view" get :edit, {:id => @host1.id}, set_session_user.merge(:user => @one.id) assert_equal @response.status, 403 end - test 'user with view host rights should should succeed in viewing hosts' do - setup_user_and_host "View" - get :index, {}, set_session_user.merge(:user => @one.id) - assert_response :success - end - test 'multiple without hosts' do post :update_multiple_hostgroup, {}, set_session_user assert_redirected_to hosts_url @@ -296,6 +237,7 @@ def setup_user_and_host operation hostgroup = hostgroups(:unusual) post :update_multiple_hostgroup, { :host_ids => hosts.map(&:id), :hostgroup => { :id => hostgroup.id } }, set_session_user + assert_response :redirect # reloads hosts hosts.map! {|h| Host.find(h.id)} @@ -315,6 +257,7 @@ def setup_user_and_host operation hostgroup = hostgroups(:common) post :update_multiple_hostgroup, { :host_names => host_names, :hostgroup => { :id => hostgroup.id} }, set_session_user + assert_response :redirect host_names.each do |name| host = Host.find_by_name name @@ -466,7 +409,7 @@ def test_submit_multiple_build def test_set_manage @request.env['HTTP_REFERER'] = edit_host_path @host assert @host.update_attribute :managed, false - assert @host.errors.empty? + assert_empty @host.errors put :toggle_manage, {:id => @host.name}, set_session_user assert_redirected_to :controller => :hosts, :action => :edit assert flash[:notice] == "Foreman now manages the build cycle for #{@host.name}" @@ -475,7 +418,7 @@ def test_set_manage def test_unset_manage @request.env['HTTP_REFERER'] = edit_host_path @host assert @host.update_attribute :managed, true - assert @host.errors.empty? + assert_empty @host.errors put :toggle_manage, {:id => @host.name}, set_session_user assert_redirected_to :controller => :hosts, :action => :edit assert flash[:notice] == "Foreman now no longer manages the build cycle for #{@host.name}" @@ -781,7 +724,7 @@ class Host::Valid < Host::Base ; end test "index returns YAML output for rundeck" do get :index, {:format => 'yaml', :rundeck => true}, set_session_user hosts = YAML.load(@response.body) - assert !hosts.empty? + assert_not_empty hosts host = Host.first assert_equal host.os.name, hosts[host.name]["osName"] # rundeck-specific field end diff --git a/test/functional/roles_controller_test.rb b/test/functional/roles_controller_test.rb index 0353e516e9c..311f80519ef 100644 --- a/test/functional/roles_controller_test.rb +++ b/test/functional/roles_controller_test.rb @@ -19,7 +19,7 @@ class RolesControllerTest < ActionController::TestCase - def test_get_index + test 'get index' do get :index, {}, set_session_user assert_response :success assert_template 'index' @@ -31,49 +31,52 @@ def test_get_index :content => 'Manager' end - def test_get_new + test 'get new' do get :new, {}, set_session_user assert_response :success assert_template 'new' end - def test_post_new_with_validaton_failure - post :create, { :role => {:name => '', - :permissions => ['add_hosts', 'edit_hosts', 'edit_ptables', ''] - }}, set_session_user + test 'empty name validation' do + post :create, { :role => {:name => ''}}, set_session_user assert_response :success assert_template 'new' end - def test_get_edit + test 'creates role' do + post :create, { :role => {:name => 'test role'}}, set_session_user + + assert_redirected_to roles_path + assert Role.find_by_name('test role') + end + + test 'get edit goes to right template' do get :edit, {:id => 1}, set_session_user assert_response :success assert_template 'edit' assert_equal Role.find(1), assigns(:role) end - def test_post_edit - put :update, {:id => 1, - :role => {:name => 'Manager', - :permissions => ['edit_hosts'] - }}, set_session_user + test 'put edit updates role' do + role = FactoryGirl.create(:role) + put :update, {:id => role.id, :role => {:name => 'masterManager'}}, set_session_user assert_redirected_to roles_path - role = Role.find(1) - assert_equal [:edit_hosts], role.permissions + role.reload + assert_equal 'masterManager', role.name end - def test_destroy - r = Role.new(:name => 'ToBeDestroyed', :permissions => [:view_ptables]) - assert r.save + test 'delete destroy removes role' do + role = FactoryGirl.build(:role, :name => 'ToBeDestroyed') + role.add_permissions! :view_ptables - delete :destroy, {:id => r}, set_session_user + delete :destroy, {:id => role}, set_session_user assert_redirected_to roles_path - assert_nil Role.find_by_id(r.id) + assert_nil Role.find_by_id(role.id) end - def test_destroy_role_in_use + test 'roles in use cannot be destroyed' do users(:one).roles = [roles(:manager)] # make user one a manager delete :destroy, {:id => roles(:manager)}, set_session_user assert_redirected_to roles_path @@ -81,29 +84,28 @@ def test_destroy_role_in_use assert_not_nil Role.find_by_id(roles(:manager).id) end - def test_get_report - get :report, {}, set_session_user - assert_response :success - assert_template 'report' - - assert_not_nil assigns(:roles) - assert_equal Role.all.sort, assigns(:roles).sort - - end - - def test_post_report - post :report, { :permissions => { '0' => '', '1' => ['edit_issues'], '3' => ['add_issues', 'delete_issues']} }, set_session_user - assert_redirected_to roles_path - - assert_equal [:edit_issues], Role.find(1).permissions - assert_equal [:add_issues, :delete_issues], Role.find(3).permissions - assert Role.find(2).permissions.empty? - end - - def test_clear_all_permissions - post :report, { :permissions => { '0' => '' } }, set_session_user - assert_redirected_to roles_path - assert Role.find(1).permissions.empty? + context 'clone' do + setup do + @role = FactoryGirl.build(:role, :name => 'ToBeDestroyed') + @role.add_permissions! :view_ptables + end + + test 'renders new page with hidden field original_role_id' do + get :clone, { :id => @role.id } , set_session_user + assert_template 'new' + end + + test 'original_role_id is used to create cloned role if set' do + params = { :role => {:name => 'clonedrole'}, + :original_role_id => @role.id, + :cloned_role => true } + post :create, params, set_session_user + assert_redirected_to roles_url + + cloned_role = Role.find_by_name('clonedrole') + assert_not_nil cloned_role + assert_equal @role.permissions, cloned_role.permissions + end end end diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb index 19b52820bae..06e702bcdf2 100644 --- a/test/functional/users_controller_test.rb +++ b/test/functional/users_controller_test.rb @@ -136,7 +136,7 @@ def test_one #"should not remove the anonymous role" do test 'user with viewer rights should fail to edit a user' do get :edit, {:id => User.first.id} - assert_response 403 + assert_response 404 end test 'user with viewer rights should succeed in viewing users' do @@ -233,16 +233,29 @@ def test_one #"should not remove the anonymous role" do assert_response :redirect end - test 'non admin user should not be able to edit another user' do + test 'user without edit permission should not be able to edit another user' do User.current = users(:one) get :edit, { :id => users(:two) } - assert_response 403 + assert_response 404 + end + + test 'user with edit permission should be able to edit another user' do + setup_user 'edit', 'users' + get :edit, { :id => users(:two) } + assert_response :success end - test 'non admin user should not be able to update another user' do + test 'user without edit permission should not be able to update another user' do User.current = users(:one) put :update, { :id => users(:two).id, :user => { :firstname => 'test' } } assert_response 403 end + test 'user with update permission should be able to update another user' do + setup_user 'edit', 'users' + put :update, { :id => users(:two).id, :user => { :firstname => 'test' } } + + assert_response :redirect + end + end diff --git a/test/integration/host_test.rb b/test/integration/host_test.rb index d78e2de8bc8..8a8ac033261 100644 --- a/test/integration/host_test.rb +++ b/test/integration/host_test.rb @@ -29,10 +29,10 @@ class HostTest < ActionDispatch::IntegrationTest end test "edit page" do - disable_orchestration # Avoid DNS errors + disable_orchestration # Avoid DNS errors visit hosts_path click_link "my5name.mydomain.net" - first(:link, "Edit").click + first(:link, "Edit").click assert page.has_link?("Cancel", :href => "/hosts/my5name.mydomain.net") fill_in "host_name", :with => "my5rename.mydomain.net" assert_submit_button("/hosts/my5rename.mydomain.net") diff --git a/test/test_helper.rb b/test/test_helper.rb index 59b689285e5..a359c5b1459 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -42,6 +42,27 @@ class ActiveSupport::TestCase set_fixture_class({ :hosts => Host::Base }) set_fixture_class :nics => Nic::BMC + setup :begin_gc_deferment + teardown :reconsider_gc_deferment + + DEFERRED_GC_THRESHOLD = (ENV['DEFER_GC'] || 1.0).to_f + + @@last_gc_run = Time.now + + def begin_gc_deferment + GC.disable if DEFERRED_GC_THRESHOLD > 0 + end + + def reconsider_gc_deferment + if DEFERRED_GC_THRESHOLD > 0 && Time.now - @@last_gc_run >= DEFERRED_GC_THRESHOLD + GC.enable + GC.start + GC.disable + + @@last_gc_run = Time.now + end + end + # for backwards compatibility to between Minitest syntax alias_method :assert_not, :refute alias_method :assert_no_match, :refute_match @@ -82,12 +103,20 @@ def setup_users user.save! end - def setup_user operation, type="" - @one = users(:one) + # if a method receieves a block it will be yielded just before user save + def setup_user operation, type="", search = nil, user = :one + @one = users(user) as_admin do + permission = Permission.find_by_name("#{operation}_#{type}") || FactoryGirl.create(:permission, :name => "#{operation}_#{type}") + filter = FactoryGirl.build(:filter, :search => search) + filter.permissions = [ permission ] role = Role.find_or_create_by_name :name => "#{operation}_#{type}" - role.permissions = ["#{operation}_#{type}".to_sym] - @one.roles = [role] + role.filters = [ filter ] + role.save! + filter.role = role + filter.save! + @one.roles = [ role ] + yield(@one) if block_given? @one.save! end User.current = @one diff --git a/test/unit/architecture_test.rb b/test/unit/architecture_test.rb index 26c0f03fceb..ff61a1d62a2 100644 --- a/test/unit/architecture_test.rb +++ b/test/unit/architecture_test.rb @@ -6,19 +6,19 @@ class ArchitectureTest < ActiveSupport::TestCase end test "should not save without a name" do architecture = Architecture.new - assert !architecture.save + assert_not architecture.save end test "name should not be blank" do architecture = Architecture.new :name => " " - assert architecture.name.strip.empty? - assert !architecture.save + assert_empty architecture.name.strip + assert_not architecture.save end test "name should not contain white spaces" do architecture = Architecture.new :name => " i38 6 " - assert !architecture.name.squeeze(" ").tr(' ', '').empty? - assert !architecture.save + assert_not_empty architecture.name.squeeze(" ").tr(' ', '') + assert_not architecture.save architecture.name.squeeze!(" ").tr!(' ', '') assert architecture.save @@ -29,7 +29,7 @@ class ArchitectureTest < ActiveSupport::TestCase assert architecture.save other_architecture = Architecture.new :name => "i386" - assert !other_architecture.save + assert_not other_architecture.save end test "to_s retrives name" do @@ -45,63 +45,7 @@ class ArchitectureTest < ActiveSupport::TestCase host.architecture = architecture host.save(:validate => false) - assert !architecture.destroy + assert_not architecture.destroy end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_architectures" - role.permissions = ["#{operation}_architectures".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create" do - setup_user "create" - record = Architecture.create :name => "dummy" - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create" do - setup_user "view" - record = Architecture.create :name => "dummy" - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = Architecture.first - as_admin do - record.hosts.delete_all - record.hostgroups.delete_all - end - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = Architecture.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = Architecture.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = Architecture.first - record.name = "renamed" - assert !record.save - end end diff --git a/test/unit/auth_source_ldap_test.rb b/test/unit/auth_source_ldap_test.rb index 3d7e587ac24..d7a0c58c8c6 100644 --- a/test/unit/auth_source_ldap_test.rb +++ b/test/unit/auth_source_ldap_test.rb @@ -175,59 +175,4 @@ def assigns_a_string_of_length_greater_than(length, method) @auth_source_ldap.send method, "this is010this is020this is030this is040this is050this is060this is070this is080this is090this is100this is110this is120this is130this is140this is150this is160this is170this is180this is190this is200this is210this is220this is230this is240this is250 and something else" end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_authenticators" - role.permissions = ["#{operation}_authenticators".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create" do - setup_user "create" - record = AuthSourceLdap.create :name => "dummy", :host => hosts(:one).name, :port => "1", :attr_login => "login" - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create" do - setup_user "view" - record = AuthSourceLdap.create :name => "dummy", :host => hosts(:one).name, :port => "1", :attr_login => "login" - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = AuthSourceLdap.first - as_admin do - record.users.delete_all - end - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = AuthSourceLdap.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = AuthSourceLdap.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = AuthSourceLdap.first - record.name = "renamed" - assert !record.save - end end diff --git a/test/unit/authorizer_test.rb b/test/unit/authorizer_test.rb new file mode 100644 index 00000000000..24635d7ee24 --- /dev/null +++ b/test/unit/authorizer_test.rb @@ -0,0 +1,248 @@ +require 'test_helper' + +class AuthorizerTest < ActiveSupport::TestCase + def setup + User.current = User.admin + + @user_role = FactoryGirl.create(:user_user_role) + @user = @user_role.owner + @role = @user_role.role + end + + # limited, unlimited, permission with resource, without resource... + test "#can?(:view_hosts) with unlimited filter" do + permission = Permission.find_by_name('view_hosts') + filter = FactoryGirl.create(:filter, :role => @role, :permissions => [permission]) + auth = Authorizer.new(@user) + + assert auth.can?(:view_hosts) + refute auth.can?(:view_domains) + end + + test "#can?(:view_hosts) with unlimited filter" do + permission = Permission.find_by_name('view_hosts') + filter = FactoryGirl.create(:filter, :on_name_all, :role => @role, :permissions => [permission]) + auth = Authorizer.new(@user) + + assert auth.can?(:view_hosts) + refute auth.can?(:view_domains) + end + + test "#can?(:view_hosts) on permission without resource" do + permission = Permission.find_by_name('view_hosts') + filter = FactoryGirl.create(:filter, :on_name_all, :role => @role, :permissions => [permission]) + auth = Authorizer.new(@user) + + assert auth.can?(:view_hosts) + refute auth.can?(:view_domains) + end + + test "#can?(:view_hosts) is limited by particular user" do + permission = Permission.find_by_name('view_hosts') + filter = FactoryGirl.create(:filter, :on_name_all, :role => @role, :permissions => [permission]) + auth = Authorizer.new(FactoryGirl.create(:user)) + + refute auth.can?(:view_hosts) + end + + test "#can?(:view_domains, @host) for unlimited filter" do + permission = Permission.find_by_name('view_domains') + filter = FactoryGirl.create(:filter, :role => @role, :permissions => [permission]) + domain = FactoryGirl.create(:domain) + auth = Authorizer.new(@user) + + assert_include auth.find_collection(Domain, :permission => :view_domains), domain + assert auth.can?(:view_domains, domain) + end + + test "#can?(:view_domains, @host) for matching limited filter" do + permission = Permission.find_by_name('view_domains') + filter = FactoryGirl.create(:filter, :role => @role, :permissions => [permission], + :search => 'name ~ example*') + domain = FactoryGirl.create(:domain) + auth = Authorizer.new(@user) + + assert_include auth.find_collection(Domain, :permission => :view_domains), domain + assert auth.can?(:view_domains, domain) + end + + test "#can?(:view_domains, @host) for matching and not matching limited filter" do + permission = Permission.find_by_name('view_domains') + not_matching_filter = FactoryGirl.create(:filter, :role => @role, :permissions => [permission], + :search => 'name ~ noexample*') + matching_filter = FactoryGirl.create(:filter, :role => @role, :permissions => [permission], + :search => 'name ~ example*') + domain = FactoryGirl.create(:domain) + auth = Authorizer.new(@user) + + assert_include auth.find_collection(Domain, :permission => :view_domains), domain + assert auth.can?(:view_domains, domain) + end + + test "#can?(:view_domains, @host) for not matching limited filter" do + permission = Permission.find_by_name('view_domains') + filter = FactoryGirl.create(:filter, :role => @role, :permissions => [permission], + :search => 'name ~ noexample*') + domain = FactoryGirl.create(:domain) + auth = Authorizer.new(@user) + + assert_not_include auth.find_collection(Domain, :permission => :view_domains), domain + refute auth.can?(:view_domains, domain) + end + + test "#can?(:view_domains, @host) filters records by matching limited filter" do + permission = Permission.find_by_name('view_domains') + filter = FactoryGirl.create(:filter, :on_name_starting_with_a, + :role => @role, :permissions => [permission]) + domain1 = FactoryGirl.create(:domain) + domain2 = FactoryGirl.create(:domain, :name => 'a-domain.to-be-found.com') + auth = Authorizer.new(@user) + + collection = auth.find_collection(Domain, :permission => :view_domains) + assert_not_include collection, domain1 + assert_include collection, domain2 + refute auth.can?(:view_domains, domain1) + assert auth.can?(:view_domains, domain2) + end + + test "#can?(:view_domains, @host) filters records by matching limited filter and permission" do + permission1 = Permission.find_by_name('view_domains') + permission2 = Permission.find_by_name('edit_domains') + filter1 = FactoryGirl.create(:filter, :on_name_starting_with_a, + :role => @role, :permissions => [permission1]) + filter2 = FactoryGirl.create(:filter, :on_name_starting_with_b, + :role => @role, :permissions => [permission2]) + domain1 = FactoryGirl.create(:domain) + domain2 = FactoryGirl.create(:domain, :name => 'a-domain.to-be-found.com') + domain3 = FactoryGirl.create(:domain, :name => 'another-domain.to-be-found.com') + domain4 = FactoryGirl.create(:domain, :name => 'be_editable.to-be-found.com') + auth = Authorizer.new(@user) + + collection = auth.find_collection(Domain, :permission => :view_domains) + assert_equal [domain2, domain3], collection + collection = auth.find_collection(Domain, :permission => :edit_domains) + assert_equal [domain4], collection + collection = auth.find_collection(Domain, :permission => :delete_domains) + assert_equal [], collection + collection = auth.find_collection(Domain) + assert_equal [domain2, domain3, domain4], collection + + refute auth.can?(:view_domains, domain1) + assert auth.can?(:view_domains, domain2) + assert auth.can?(:view_domains, domain3) + refute auth.can?(:view_domains, domain4) + refute auth.can?(:edit_domains, domain1) + refute auth.can?(:edit_domains, domain2) + refute auth.can?(:edit_domains, domain3) + assert auth.can?(:edit_domains, domain4) + + # unlimited filter on Domain permission does add the domain + filter4 = FactoryGirl.create(:filter, :role => @role, :permissions => [permission1]) + collection = auth.find_collection(Domain) + assert_include collection, domain1 + assert_include collection, domain2 + assert_include collection, domain3 + assert_include collection, domain4 + end + + test "#can?(:view_domains, @host) for user without filter" do + permission = Permission.find_by_name('view_domains') + filter = FactoryGirl.create(:filter, :role => @role, :permissions => [permission]) + domain = FactoryGirl.create(:domain) + auth = Authorizer.new(FactoryGirl.create(:user)) + + result = auth.find_collection(Domain, :permission => :view_domains) + assert_not_include result, domain + assert_kind_of ActiveRecord::Relation, result + refute auth.can?(:view_domains, domain) + end + + test "#can? caches results per permission and class" do + permission1 = Permission.find_by_name('view_domains') + filter1 = FactoryGirl.create(:filter, :on_name_starting_with_a, + :role => @role, :permissions => [permission1]) + domain1 = FactoryGirl.create(:domain, :name => 'a-domain.to-be-found.com') + domain2 = FactoryGirl.create(:domain, :name => 'x-domain.not-to-be-found.com') + permission2 = Permission.find_by_name('view_architectures') + architecture = FactoryGirl.create(:architecture) + filter2 = FactoryGirl.create(:filter, :role => @role, :permissions => [permission2]) + + auth = Authorizer.new(@user) + + auth.stubs(:find_collection).returns([domain1]).times(3) + assert auth.can?(:view_domain, domain1) + refute auth.can?('view_domain', domain2) + assert auth.can?(:edit_domain, domain1) + refute auth.can?('edit_domain', domain2) + refute auth.can?(:view_architectures, architecture) # since it's stubbed and returns domain1 only + refute auth.can?('view_architectures', architecture) + end + + test "#build_scoped_search_condition(filters) for empty set" do + auth = Authorizer.new(FactoryGirl.create(:user)) + assert_raises ArgumentError do + auth.build_scoped_search_condition([]) + end + end + + test "#build_scoped_search_condition(filters) for one filter" do + auth = Authorizer.new(FactoryGirl.create(:user)) + filters = [FactoryGirl.build(:filter, :on_name_all)] + result = auth.build_scoped_search_condition(filters) + + assert_equal '(name ~ *)', result + end + + test "#build_scoped_search_condition(filters) for more filters" do + auth = Authorizer.new(FactoryGirl.create(:user)) + filters = [FactoryGirl.build(:filter, :on_name_all), FactoryGirl.build(:filter, :on_name_starting_with_a)] + result = auth.build_scoped_search_condition(filters) + + assert_equal '(name ~ *) OR (name ~ a*)', result + end + + test "#build_scoped_search_condition(filters) for unlimited filter" do + auth = Authorizer.new(FactoryGirl.create(:user)) + filters = [FactoryGirl.build(:filter)] + result = auth.build_scoped_search_condition(filters) + + assert_equal '(1=1)', result + end + + test "#build_scoped_search_condition(filters) for limited and unlimited filter" do + auth = Authorizer.new(FactoryGirl.create(:user)) + filters = [FactoryGirl.build(:filter, :on_name_all), FactoryGirl.build(:filter)] + result = auth.build_scoped_search_condition(filters) + + assert_equal '(name ~ *) OR (1=1)', result + end + + test "#build_scoped_search_condition(filters) for empty filter" do + auth = Authorizer.new(FactoryGirl.create(:user)) + filters = [FactoryGirl.build(:filter, :search => '')] + result = auth.build_scoped_search_condition(filters) + + assert_equal '(1=1)', result + end + + test "#can? with empty base collection set" do + domain = FactoryGirl.create(:domain) + permission = Permission.find_by_name('view_domains') + filter = FactoryGirl.create(:filter, :role => @role, :permissions => [permission]) + auth = Authorizer.new(@user, :collection => []) + + refute auth.can?(:view_domains, domain) + end + + test "#can? with excluding base collection set" do + permission = Permission.find_by_name('view_domains') + filter1 = FactoryGirl.create(:filter, :on_name_starting_with_a, + :role => @role, :permissions => [permission]) + domain1 = FactoryGirl.create(:domain, :name => 'a-domain.to-be-found.com') + domain2 = FactoryGirl.create(:domain, :name => 'another-domain.to-be-found.com') + auth = Authorizer.new(@user, :collection => [domain2]) + + refute auth.can?(:view_domains, domain1) + assert auth.can?(:view_domains, domain2) + end +end diff --git a/test/unit/cached_user_role_test.rb b/test/unit/cached_user_role_test.rb new file mode 100644 index 00000000000..eb7dd466ce7 --- /dev/null +++ b/test/unit/cached_user_role_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CachedUserRoleTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/cached_usergroup_member_test.rb b/test/unit/cached_usergroup_member_test.rb new file mode 100644 index 00000000000..e3004b3907a --- /dev/null +++ b/test/unit/cached_usergroup_member_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class CachedUsergroupMemberTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/common_parameter_test.rb b/test/unit/common_parameter_test.rb index 402d11bf4c0..93cd43ed833 100644 --- a/test/unit/common_parameter_test.rb +++ b/test/unit/common_parameter_test.rb @@ -43,58 +43,4 @@ class CommonParameterTest < ActiveSupport::TestCase assert !parameter2.valid? assert parameter2.errors.full_messages[0] == "Name has already been taken" end - - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_global_variables" - role.permissions = ["#{operation}_global_variables".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create" do - setup_user "create" - record = CommonParameter.create :name => "dummy", :value => "value" - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create" do - setup_user "view" - record = CommonParameter.create :name => "dummy", :value => "value" - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = CommonParameter.first - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = CommonParameter.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = CommonParameter.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = CommonParameter.first - record.name = "renamed" - assert !record.save - end - end diff --git a/test/unit/compute_resource_test.rb b/test/unit/compute_resource_test.rb index 98deaa647b1..96f4ff297eb 100644 --- a/test/unit/compute_resource_test.rb +++ b/test/unit/compute_resource_test.rb @@ -5,87 +5,6 @@ def setup User.current = users(:admin) end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_compute_resources" - role.permissions = ["#{operation}_compute_resources".to_sym] - @one.roles = [role] - @one.compute_resources.destroy_all - @one.save! - end - User.current = @one - end - - test "user with edit permissions should be able to edit when permitted" do - setup_user "edit" - as_admin do - @one.compute_resources = [compute_resources(:mycompute)] - end - record = compute_resources(:mycompute) - assert record.update_attributes(:name => "testing") - assert record.valid? - end - - test "user with edit permissions should not be able to edit when not permitted" do - setup_user "edit" - record = compute_resources(:yourcompute) - assert !record.update_attributes(:name => "testing") - assert record.valid? - end - - test "user with edit permissions should not be able to edit when unconstrained" do - setup_user "edit" - record = compute_resources(:mycompute) - assert !record.update_attributes(:name => "testing") - assert record.valid? - end - - test "user with destroy permissions should be able to destroy when permitted" do - setup_user "destroy" - as_admin do - @one.compute_resources = [compute_resources(:mycompute)] - end - record = compute_resources(:mycompute) - assert record.destroy - end - - test "user with destroy permissions should not be able to destroy when not permitted" do - setup_user "destroy" - record = compute_resources(:yourcompute) - assert !record.destroy - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - as_admin do - @one.compute_resources = [compute_resources(:mycompute)] - end - record = compute_resources(:mycompute) - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - as_admin do - @one.compute_resources = [compute_resources(:mycompute)] - end - record = compute_resources(:mycompute) - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - as_admin do - @one.compute_resources = [compute_resources(:mycompute)] - end - record = compute_resources(:mycompute) - record.name = "renamed" - assert !record.save - end - test "password is saved encrypted when updated" do compute_resource = compute_resources(:one) compute_resource.password = "123456" diff --git a/test/unit/domain_parameter_test.rb b/test/unit/domain_parameter_test.rb index 36e0a6135da..6a8874eaf5c 100644 --- a/test/unit/domain_parameter_test.rb +++ b/test/unit/domain_parameter_test.rb @@ -26,81 +26,11 @@ class DomainParameterTest < ActiveSupport::TestCase assert parameter2.valid? end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_domains" - role.permissions = ["#{operation}_domains".to_sym] - @one.roles = [role] - @one.domains.destroy_all - @one.save! + def setup_user operation, type = 'domains' + super(operation, type) do |user| + user.domains.destroy_all end - User.current = @one end - test "user with create permissions should be able to create when permitted" do - setup_user "create" - as_admin do - @one.domains = [domains(:mydomain)] - end - record = DomainParameter.create :name => "dummy", :value => "value", :reference_id => domains(:mydomain).id - assert record.valid? - assert !record.new_record? - end - - test "user with create permissions should not be able to create when not permitted" do - setup_user "create" - as_admin do - @one.domains = [domains(:mydomain)] - end - record = DomainParameter.create :name => "dummy", :value => "value", :reference_id => domains(:yourdomain).id - assert record.valid? - assert record.new_record? - end - - test "user with create permissions should be able to create when unconstrained" do - setup_user "create" - as_admin do - @one.domains.destroy_all - end - record = DomainParameter.create :name => "dummy", :value => "value", :reference_id => domains(:mydomain).id - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create" do - setup_user "view" - record = DomainParameter.create :name => "dummy", :value => "value", :reference_id => domains(:mydomain).id - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = DomainParameter.first - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = DomainParameter.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = DomainParameter.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = DomainParameter.first - record.name = "renamed" - assert !record.save - end end diff --git a/test/unit/domain_test.rb b/test/unit/domain_test.rb index 8091f482353..2185d4ad508 100644 --- a/test/unit/domain_test.rb +++ b/test/unit/domain_test.rb @@ -72,83 +72,6 @@ def create_a_host hosts(:one) end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_domains" - role.permissions = ["#{operation}_domains".to_sym] - @one.roles = [role] - @one.domains.destroy_all - @one.save! - end - User.current = @one - end - - test "user with edit permissions should be able to edit when permitted" do - setup_user "edit" - as_admin do - @one.domains = [domains(:mydomain)] - end - record = Domain.find_by_name "mydomain.net" - assert record.update_attributes(:name => "testing") - assert record.valid? - end - - test "user with edit permissions should not be able to edit when not permitted" do - setup_user "edit" - as_admin do - @one.domains = [domains(:yourdomain)] - end - record = Domain.find_by_name "mydomain.net" - assert !record.update_attributes(:name => "testing") - assert record.valid? - end - - test "user with edit permissions should be able to edit when unconstrained" do - setup_user "edit" - record = Domain.first - assert record.update_attributes(:name => "testing") - assert record.valid? - end - - test "user with view permissions should not be able to create when not permitted" do - setup_user "view" - record = Domain.create :name => "dummy", :fullname => "dummy.com" - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = domains(:useless) - record.interfaces.clear - record.hosts.clear - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = Domain.first - record.subnets.clear - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = Domain.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = Domain.first - record.name = "renamed" - assert !record.save - end - test "should query local nameservers when enabled" do Setting['query_local_nameservers'] = true assert Domain.first.nameservers.empty? diff --git a/test/unit/ensure_no_cycle_test.rb b/test/unit/ensure_no_cycle_test.rb new file mode 100644 index 00000000000..c5fe2043f7a --- /dev/null +++ b/test/unit/ensure_no_cycle_test.rb @@ -0,0 +1,57 @@ +require 'test_helper' + +class EnsureNoCycleTest < ActiveSupport::TestCase + def setup + base = [] + base.push edge(1, 2) + base.push edge(2, 3) + base.push edge(3, 4) + base.push edge(3, 5) + base.push edge(2, 6) + @graph = ActiveRecord::Base::EnsureNoCycle.new(base, :source, :target) + end + + def edge(source, target) + OpenStruct.new(:source => source, :target => target) + end + + test "#tsort_each_node iterates over all nodes" do + found = [] + @graph.tsort_each_node { |node| found.push node } + assert_equal [1, 2, 3, 4, 5, 6], found + end + + test "#tsort_each_child(node) finds all children for node" do + found = [] + assert @graph.tsort_each_child(1) { |node| found.push node } + assert_equal [2], found + + found = [] + assert @graph.tsort_each_child(2) { |node| found.push node } + assert_equal [3, 6], found + + found = [] + assert @graph.tsort_each_child(3) { |node| found.push node } + assert_equal [4, 5], found + + found = [] + assert @graph.tsort_each_child(4) { |node| found.push node } + assert_equal [], found + end + + test "#ensure detects cycle and raises an exception" do + record = edge(6, 1) + record.errors = ActiveModel::Errors.new(record) + assert_raises Foreman::CyclicGraphException do + @graph.ensure(record) + end + assert_present record.errors[:base], 'cycle did not add error to record' + end + + test "#ensure passes when record does not create cycle" do + record = edge(2, 4) + assert_nothing_raised do + assert @graph.ensure(record) + end + end +end diff --git a/test/unit/filter_test.rb b/test/unit/filter_test.rb new file mode 100644 index 00000000000..bfb42f4ad41 --- /dev/null +++ b/test/unit/filter_test.rb @@ -0,0 +1,157 @@ +require 'test_helper' + +class FilterTest < ActiveSupport::TestCase + test "#unlimited?" do + f = Factory.build :filter + assert_nil f.search, 'default filter is not unlimited' + assert f.unlimited? + end + + test "#limited?" do + f = Factory.build :filter, :on_name_all + refute_nil f.search, 'filter is not limited' + assert f.limited? + end + + test "#limited? even for empty string" do + f = Factory.build :filter + f.search = '' + assert f.limited? + end + + test ".limited" do + f = Factory.create(:filter, :on_name_all) + assert_include Filter.limited, f + end + + test ".unlimited" do + f = Factory.create(:filter) + assert_include Filter.unlimited, f + end + + test "#resource_type for empty permissions collection" do + f = Factory.build(:filter) + f.permissions = [] + assert_nil f.resource_type + end + + test "#resource_type" do + f = Factory.build(:filter) + f.stub :permissions, [ OpenStruct.new(:resource_type => 'test') ] do + assert_equal 'test', f.resource_type + end + end + + test ".get_resource_class known" do + assert_equal Bookmark, Filter.get_resource_class('Bookmark') + end + + test ".get_resource_class unknown" do + assert_nil Filter.get_resource_class('BookmarkThatDoesNotExist') + end + + test "#resource_class" do + f = Factory.build(:filter, :resource_type => 'Bookmark') + Filter.stub :get_resource_class, Architecture do + assert_equal Architecture, f.resource_class + end + end + + test "#granular? for unknown resource type" do + f = Factory.build(:filter, :resource_type => 'BookmarkThatDoesNotExist') + refute f.granular? + end + + test "#granular?" do + f = Factory.build(:filter, :resource_type => 'Domain') + assert f.granular? + end + + test "unlimited filters have nilified search string" do + f = Factory.build(:filter, :search => 'name ~ a*', :unlimited => '1') + assert f.valid? + assert_nil f.search + + f = Factory.build(:filter, :search => '', :unlimited => '1') + assert f.valid? + assert_nil f.search + + f = Factory.build(:filter, :search => 'name ~ a*', :unlimited => '0') + assert f.valid? + assert_equal 'name ~ a*', f.search + end + + test "filter with organization set is always limited before validation" do + o = Factory.create :organization + f = Factory.build(:filter, :search => '', :unlimited => '1', :organization_ids => [o.id]) + assert f.valid? + assert f.limited? + assert_include f.taxonomy_search, "(organization_id = #{o.id})" + assert_not_include f.taxonomy_search, ' and ' + assert_not_include f.taxonomy_search, ' or ' + end + + test "filter remains unlimited when no organization assigned" do + f = Factory.build(:filter, :search => '', :unlimited => '1', :organization_ids => []) + assert f.valid? + assert f.unlimited? + assert_empty f.taxonomy_search + end + + test "filter remains set to unlimited when no taxonomy assigned and has empty search" do + f = Factory.build(:filter, :search => '', :unlimited => '0', :organization_ids => [], + :location_ids => []) + assert f.valid? + assert f.unlimited? + assert_empty f.taxonomy_search + end + + test "filter with location set is always limited before validation" do + l = Factory.create :location + f = Factory.build(:filter, :search => '', :unlimited => '1', :location_ids => [l.id]) + assert f.valid? + assert f.limited? + assert_include f.taxonomy_search, "(location_id = #{l.id})" + end + + test "filter with location set is always limited before validation" do + o1 = Factory.create :organization + o2 = Factory.create :organization + l = Factory.create :location + f = Factory.build(:filter, :search => '', :unlimited => '1', + :organization_ids => [o1.id, o2.id], :location_ids => [l.id]) + assert f.valid? + assert f.limited? + assert_include f.taxonomy_search, "(location_id = #{l.id})" + assert_include f.taxonomy_search, "organization_id = #{o1.id}" + assert_include f.taxonomy_search, "organization_id = #{o2.id}" + end + + test "removing all organizations and locations from filter nilify taxonomy search" do + o1 = Factory.create :organization + o2 = Factory.create :organization + l = Factory.create :location + f = Factory.create(:filter, :search => '', :unlimited => '1', + :organization_ids => [o1.id, o2.id], :location_ids => [l.id]) + + f.update_attributes :organization_ids => [], :location_ids => [] + assert f.valid? + assert f.unlimited? + assert_nil f.taxonomy_search + end + + test "search string composition" do + f = Factory.build :filter, :search => nil, :taxonomy_search => nil + assert_equal '', f.search_condition + + f = Factory.build :filter, :search => 'domain ~ test*', :taxonomy_search => nil + assert_equal 'domain ~ test*', f.search_condition + + f = Factory.build :filter, :search => nil, :taxonomy_search => 'organization_id = 1' + assert_equal 'organization_id = 1', f.search_condition + + f = Factory.build :filter, :search => 'domain ~ test*', :taxonomy_search => 'organization_id = 1' + assert_equal '(domain ~ test*) and (organization_id = 1)', f.search_condition + end + +end diff --git a/test/unit/group_parameter_test.rb b/test/unit/group_parameter_test.rb index 67546f9586a..a4b5fa4d568 100644 --- a/test/unit/group_parameter_test.rb +++ b/test/unit/group_parameter_test.rb @@ -28,81 +28,5 @@ class GroupParameterTest < ActiveSupport::TestCase assert parameter2.valid? end - def setup_user operation, type = "hostgroups" - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_#{type}" - role.permissions = ["#{operation}_#{type}".to_sym] - @one.roles = [role] - @one.hostgroups.destroy_all - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create when permitted" do - setup_user "create", "params" - as_admin do - @one.hostgroups = [hostgroups(:common)] - end - record = GroupParameter.create :name => "dummy", :value => "value", :reference_id => hostgroups(:common).id - assert record.valid? - assert !record.new_record? - end - - test "user with create permissions should not be able to create when not permitted" do - setup_user "create" - as_admin do - @one.hostgroups = [hostgroups(:common)] - end - record = GroupParameter.create :name => "dummy", :value => "value", :reference_id => hostgroups(:unusual).id - assert record.valid? - assert record.new_record? - end - - test "user with create permissions should be able to create when unconstrained" do - setup_user "create", "params" - as_admin do - @one.hostgroups.destroy_all - end - record = GroupParameter.create :name => "dummy", :value => "value", :reference_id => hostgroups(:common).id - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create when not permitted" do - setup_user "view" - record = GroupParameter.create :name => "dummy", :value => "value", :reference_id => hostgroups(:common).id - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy", "params" - record = GroupParameter.first - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = GroupParameter.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit", "params" - record = GroupParameter.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = GroupParameter.first - record.name = "renamed" - assert !record.save - end end diff --git a/test/unit/helpers/host_groups_helper_test.rb b/test/unit/helpers/host_groups_helper_test.rb index 20322766adc..958b7a90ef3 100644 --- a/test/unit/helpers/host_groups_helper_test.rb +++ b/test/unit/helpers/host_groups_helper_test.rb @@ -6,6 +6,7 @@ class HostGroupsHelperTest < ActionView::TestCase test "should have the full string of the parent class if the child is a substring" do test_group = Hostgroup.create(:name => "test/st") + stubs(:url_for).returns('/some/url') assert_match /test\/st/, label_with_link(test_group) refute_match /te\/st/, label_with_link(test_group) end diff --git a/test/unit/host_class_test.rb b/test/unit/host_class_test.rb index aaccddfb9c2..34ba7e80155 100644 --- a/test/unit/host_class_test.rb +++ b/test/unit/host_class_test.rb @@ -9,47 +9,4 @@ class HostClassTest < ActiveSupport::TestCase EnvironmentClass.create(:puppetclass_id => puppetclasses(:two).id, :environment_id => environments(:production).id ) end - test "non-admin user with permission :edit_classes can add puppetclass to host" do - # role "manager" has permission :edit_classes - User.current.roles << [roles(:manager)] - assert_difference('HostClass.count') do - host = hosts(:one) - puppetclass = puppetclasses(:two) - assert Host.my_hosts.include?(host) - assert host.update_attributes :puppetclass_ids => (host.puppetclass_ids + Array.wrap(puppetclass.id)) - end - end - - test "non-admin user without permission :edit_classes cannot add puppetclass to host" do - # do not assign any role to Current.user - assert_difference('HostClass.count', 0) do - host = hosts(:one) - puppetclass = puppetclasses(:two) - assert Host.my_hosts.include?(host) - assert_raises(ActiveRecord::RecordNotSaved) do - refute host.update_attributes :puppetclass_ids => (host.puppetclass_ids + Array.wrap(puppetclass.id)) - end - end - end - - test "non-admin user with permission :edit_classes can remove puppetclass from host" do - # role "manager" has permission :edit_classes - User.current.roles << [roles(:manager)] - assert_difference('HostClass.count', -1) do - host = hosts(:one) - assert Host.my_hosts.include?(host) - assert host.update_attributes :puppetclass_ids => [] - end - end - - test "non-admin user without permission :edit_classes cannot remove puppetclass from host" do - # do not assign any role to Current.user - assert_difference('HostClass.count', 0) do - host = hosts(:one) - puppetclass = puppetclasses(:two) - assert Host.my_hosts.include?(host) - refute host.update_attributes :puppetclass_ids => [] - end - end - end diff --git a/test/unit/host_parameter_test.rb b/test/unit/host_parameter_test.rb index cd21fcdcf6a..2f359dffdc8 100644 --- a/test/unit/host_parameter_test.rb +++ b/test/unit/host_parameter_test.rb @@ -35,83 +35,4 @@ class HostParameterTest < ActiveSupport::TestCase assert @parameter2.valid? end - def setup_user operation, type = "params" - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_#{type}" - role.permissions = ["#{operation}_#{type}".to_sym] - @one.roles = [role] - @one.domains.destroy_all - @one.hostgroups.destroy_all - @one.user_facts.destroy_all - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create when permitted" do - setup_user "create" - as_admin do - @one.domains = [domains(:mydomain)] - @one.save! - end - host_parameter = HostParameter.create! :name => "dummy", :value => "value", :reference_id => hosts(:one).id - assert host_parameter - end - - test "user with create permissions should not be able to create when not permitted" do - setup_user "create" - as_admin do - @one.hostgroups = [hostgroups(:common)] - @one.save! - hosts(:one).update_attribute :hostgroup, hostgroups(:unusual) - end - record = HostParameter.create :name => "dummy", :value => "value", :reference_id => hosts(:one).id - assert record.valid? - assert !record.save - end - - test "user with create permissions should be able to create when unconstrained" do - setup_user "create" - as_admin do - @one.domains.destroy_all - end - host_parameter = HostParameter.create! :name => "dummy", :value => "value", :reference_id => hosts(:one).id - assert host_parameter - end - - test "user with view permissions should not be able to create" do - setup_user "view", "hosts" - record = HostParameter.create :name => "dummy", :value => "value", :reference_id => hosts(:one).id - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = HostParameter.first - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = HostParameter.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = HostParameter.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = HostParameter.first - record.name = "renamed" - assert !record.save - end end diff --git a/test/unit/host_test.rb b/test/unit/host_test.rb index 692ea11c0cd..355e4f409af 100644 --- a/test/unit/host_test.rb +++ b/test/unit/host_test.rb @@ -351,207 +351,6 @@ class HostTest < ActiveSupport::TestCase assert host.disabled? end - def setup_user_and_host - @one = users(:one) - @one.hostgroups.destroy_all - @one.domains.destroy_all - @one.user_facts.destroy_all - @one.save! - @host = hosts(:one) - @host.owner = users(:two) - @host.save! - User.current = @one - end - - def setup_filtered_user - # Can't use `setup_user_and_host` as it deletes the UserFacts - @one = users(:one) - @one.hostgroups.destroy_all - @one.domains.destroy_all - @one.user_facts = [user_facts(:one)] - @one.facts_andor = "and" - @one.save! - User.current = @one - end - - test "host cannot be edited without permission" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Viewer")] - end - assert !@host.update_attributes(:comment => "blahblahblah") - assert_match /do not have permission/, @host.errors.full_messages.join("\n") - end - - test "any host can be edited when permitted" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Edit hosts")] - end - assert @host.update_attributes(:comment => "blahblahblah") - assert_no_match /do not have permission/, @host.errors.full_messages.join("\n") - end - - test "hosts can be edited when domains permit" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Edit hosts")] - @one.domains = [Domain.find_by_name("mydomain.net")] - end - assert @host.update_attributes(:comment => "blahblahblah") - assert_no_match /do not have permission/, @host.errors.full_messages.join("\n") - end - - test "hosts cannot be edited when domains deny" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Edit hosts")] - @one.domains = [Domain.find_by_name("yourdomain.net")] - end - assert !@host.update_attributes(:comment => "blahblahblah") - assert_match /do not have permission/, @host.errors.full_messages.join("\n") - end - - test "host cannot be created without permission" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Viewer")] - end - host = Host.create(:name => "blahblah", :mac => "aabbecddee19", :ip => "2.3.4.09", - :domain => domains(:mydomain), :operatingsystem => operatingsystems(:centos5_3), - :architecture => architectures(:x86_64), :environment => environments(:production), :puppet_proxy => smart_proxies(:puppetmaster), - :subnet => subnets(:one), :disk => "empty partition") - assert host.new_record? - assert_match /do not have permission/, host.errors.full_messages.join("\n") - end - - test "any host can be created when permitted" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Create hosts")] - end - host = Host.create(:name => "blahblah", :mac => "aabbecddee19", :ip => "2.3.4.11", - :domain => domains(:mydomain), :operatingsystem => operatingsystems(:centos5_3), :puppet_proxy => smart_proxies(:puppetmaster), - :architecture => architectures(:x86_64), :environment => environments(:production), - :subnet => subnets(:one), :disk => "empty partition") - assert !host.new_record? - assert_no_match /do not have permission/, host.errors.full_messages.join("\n") - end - - test "hosts can be created when hostgroups permit" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Create hosts")] - @one.hostgroups = [Hostgroup.find_by_name("Common")] - end - host = Host.create(:name => "blahblah", :mac => "aabbecddee19", :ip => "2.3.4.4", - :domain => domains(:mydomain), :operatingsystem => operatingsystems(:centos5_3), - :architecture => architectures(:x86_64), :environment => environments(:production), - :subnet => subnets(:one), - :disk => "empty partition", :hostgroup => hostgroups(:common)) - assert !host.new_record? - assert_no_match /do not have permission/, host.errors.full_messages.join("\n") - end - - test "hosts cannot be created when hostgroups deny" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Create hosts")] - @one.hostgroups = [Hostgroup.find_by_name("Unusual")] - end - host = Host.create(:name => "blahblah", :mac => "aabbecddee19", :ip => "2.3.4.9", - :domain => domains(:mydomain), :operatingsystem => operatingsystems(:centos5_3), - :architecture => architectures(:x86_64), :environment => environments(:production), - :subnet => subnets(:one), - :disk => "empty partition", :hostgroup => hostgroups(:common)) - assert host.new_record? - assert_match /do not have permission/, host.errors.full_messages.join("\n") - end - - test "host cannot be destroyed without permission" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Viewer")] - end - assert !@host.destroy - assert_match /do not have permission/, @host.errors.full_messages.join("\n") - end - - test "any host can be destroyed when permitted" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Destroy hosts")] - @host.host_classes.delete_all - assert @host.destroy - end - assert_no_match /do not have permission/, @host.errors.full_messages.join("\n") - end - - test "hosts can be destroyed when ownership permits" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Destroy hosts")] - @host.update_attribute :owner, users(:one) - @host.host_classes.delete_all - assert @host.destroy - end - assert_no_match /do not have permission/, @host.errors.full_messages.join("\n") - end - - test "hosts cannot be destroyed when ownership denies" do - setup_user_and_host - as_admin do - @one.roles = [Role.find_by_name("Destroy hosts")] - @one.domains = [domains(:yourdomain)] # This does not grant access but does ensure that access is constrained - @host.owner = users(:two) - @host.save! - end - assert !@host.destroy - assert_match /do not have permission/, @host.errors.full_messages.join("\n") - end - - test "fact filters restrict the my_hosts scope" do - setup_filtered_user - assert_equal 1, Host.my_hosts.count - assert_equal 'my5name.mydomain.net', Host.my_hosts.first.name - end - - test "sti types altered in memory with becomes are still contained in my_hosts scope" do - class Host::Valid < Host::Base ; belongs_to :domain ; end - h = Host::Valid.new :name => "mytestvalidhost.foo.com" - setup_user_and_host - as_admin do - @one.domains = [domains(:yourdomain)] # ensure it matches the user filters - h.update_attribute :domain, domains(:yourdomain) - end - h_new = h.becomes(Host::Managed) # change the type to break normal AR `==` method - assert Host::Base.my_hosts.include?(h_new) - end - - test "host can be edited when user fact filter permits" do - setup_filtered_user - as_admin do - @one.roles = [Role.find_by_name("Edit hosts")] - @host = hosts(:one) - @host.owner = users(:two) - @host.save! - end - assert @host.update_attributes(:comment => "blahblahblah") - assert_no_match /do not have permission/, @host.errors.full_messages.join("\n") - end - - test "host cannot be edited when user fact filter denies" do - setup_filtered_user - as_admin do - @one.roles = [Role.find_by_name("Edit hosts")] - @host = hosts(:two) - @host.owner = users(:two) - @host.save! - end - assert !@host.update_attributes(:comment => "blahblahblah") - assert_match /do not have permission/, @host.errors.full_messages.join("\n") - end - test "a fqdn Host should be assigned to a domain if such domain exists" do domain = domains(:mydomain) host = Host.create :name => "host.mydomain.net", :mac => "aabbccddeaff", :ip => "2.3.04.03", @@ -941,9 +740,13 @@ class Host::Valid < Host::Base ; belongs_to :domain ; end @one = users(:one) # add permission for user :one as_admin do + filter = FactoryGirl.build(:filter) + filter.permissions = [ Permission.find_by_name('edit_hosts') ] + filter.save! role = Role.find_or_create_by_name :name => "testing_role" - role.permissions = [:edit_hosts] - @one.roles = [role] + role.filters = [ filter ] + role.save! + @one.roles = [ role ] @one.save! end h = hosts(:one) diff --git a/test/unit/hostgroup_class_test.rb b/test/unit/hostgroup_class_test.rb index ac1ef39c1c2..337531fb69b 100644 --- a/test/unit/hostgroup_class_test.rb +++ b/test/unit/hostgroup_class_test.rb @@ -18,47 +18,4 @@ class HostgroupClassTest < ActiveSupport::TestCase end end end - - test "non-admin user with permission :edit_hostgroups can add puppetclass to hostgroup" do - # role "manager" has permission :edit_classes - User.current.roles << [roles(:manager)] - assert_difference('HostgroupClass.count') do - hostgroup = hostgroups(:common) - puppetclass = puppetclasses(:two) - assert Hostgroup.my_groups.include?(hostgroup) - assert hostgroup.update_attributes :puppetclass_ids => (hostgroup.puppetclass_ids + Array.wrap(puppetclass.id)) - end - end - - test "non-admin user without permission :edit_hostgroups cannot add puppetclass to hostgroup" do - # do not assign any role to Current.user - assert_difference('HostgroupClass.count', 0) do - hostgroup = hostgroups(:common) - puppetclass = puppetclasses(:two) - assert Hostgroup.my_groups.include?(hostgroup) - assert_raises(ActiveRecord::RecordNotSaved) do - refute hostgroup.update_attributes :puppetclass_ids => (hostgroup.puppetclass_ids + Array.wrap(puppetclass.id)) - end - end - end - - test "non-admin user with permission :edit_hostgroups can remove puppetclass from hostgroup" do - # role "manager" has permission :edit_classes - User.current.roles << [roles(:manager)] - assert_difference('HostgroupClass.count', -1) do - hostgroup = hostgroups(:common) - assert Hostgroup.my_groups.include?(hostgroup) - assert hostgroup.update_attributes :puppetclass_ids => [] - end - end - - test "non-admin user without permission :edit_hostgroups cannot remove puppetclass from hostgroup" do - # do not assign any role to Current.user - assert_difference('HostgroupClass.count', 0) do - hostgroup = hostgroups(:common) - puppetclass = puppetclasses(:two) - assert Hostgroup.my_groups.include?(hostgroup) - refute hostgroup.update_attributes :puppetclass_ids => [] - end - end end diff --git a/test/unit/hostgroup_test.rb b/test/unit/hostgroup_test.rb index e41b88d7cde..d5621516016 100644 --- a/test/unit/hostgroup_test.rb +++ b/test/unit/hostgroup_test.rb @@ -28,64 +28,7 @@ class HostgroupTest < ActiveSupport::TestCase end def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_hostgroup" - role.permissions = ["#{operation}_hostgroups".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create" do - setup_user "create" - record = Hostgroup.create :name => "dummy" - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create" do - setup_user "view" - record = Hostgroup.create :name => "dummy" - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = hostgroups(:common) - as_admin do - record.hosts.destroy_all - record.hostgroup_classes.destroy_all - assert record.destroy - end - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = hostgroups(:common) - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = Hostgroup.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = Hostgroup.first - record.name = "renamed" - as_admin do - record.hosts.destroy_all - end - assert !record.save - assert record.valid? + super operation, "hostgroups" end test "should be able to nest a group parameters" do diff --git a/test/unit/lookup_value_test.rb b/test/unit/lookup_value_test.rb index d4408a6d833..009fb0a1dc8 100644 --- a/test/unit/lookup_value_test.rb +++ b/test/unit/lookup_value_test.rb @@ -38,14 +38,15 @@ def valid_attrs3 end end - test "non-admin user cannot create lookup value if user has no matching host/hostgroup" do - # Host.my_hosts returns only hosts(:one) + test "non-admin user cannot view only his hosts restricted by filters" do + # Host.authorized(:view_hosts, Host) returns only hosts(:one) user = users(:one) + role = FactoryGirl.create(:role, :name => 'user_view_host_by_ip') + FactoryGirl.create(:filter, :role => role, :permissions => [Permission.find_by_name(:view_hosts)], :search => 'facts.ipaddress = 10.0.19.33') + user.roles<< [ role ] as_user :one do - refute Host.my_hosts.where(:name => hosts(:two).name).exists? - refute Hostgroup.my_groups.where(:name => hosts(:two).try(:hostgroup).try(:name)).exists? - lookup_value = LookupValue.new(valid_attrs2) - refute lookup_value.save + assert Host.authorized(:view_hosts, Host).where(:name => hosts(:one).name).exists? + refute Host.authorized(:view_hosts, Host).where(:name => hosts(:two).name).exists? end end @@ -67,47 +68,12 @@ def valid_attrs3 end end - test "cannot update lookup value if user has no matching host/hostgroup" do - # Host.my_hosts returns only hosts(:one) - user = users(:one) - as_user :one do - refute Host.my_hosts.where(:name => hosts(:two).name).exists? - refute Hostgroup.my_groups.where(:name => hosts(:two).try(:hostgroup).try(:name)).exists? - refute lookup_values(:hosttwo).update_attributes(:value => "9000") - end - end - - test "can create lookup value if user has matching host " do - # Host.my_hosts returns only hosts(:one) - user = users(:one) - as_user :one do - assert Host.my_hosts.where(:name => hosts(:one).name).exists? - refute Hostgroup.my_groups.where(:name => hosts(:one).try(:hostgroup).try(:name)).exists? - lookup_value = LookupValue.new(valid_attrs1) - assert_difference('LookupValue.count') do - assert lookup_value.save - end - end - end - - test "can update lookup value if user has matching host " do - # Host.my_hosts returns only hosts(:one) - user = users(:one) - as_user :one do - assert Host.my_hosts.where(:name => hosts(:one).name).exists? - refute Hostgroup.my_groups.where(:name => hosts(:one).try(:hostgroup).try(:name)).exists? - assert lookup_values(:one).update_attributes(:value => "9000") - end - end - test "can create lookup value if user has matching hostgroup " do - # Host.my_hosts returns only hosts(:one) user = users(:one) as_admin do assert user.hostgroups << hostgroups(:common) end as_user :one do - assert Hostgroup.my_groups.where(:name => "Common").exists? lookup_value = LookupValue.new(valid_attrs3) assert_difference('LookupValue.count') do assert lookup_value.save @@ -115,18 +81,6 @@ def valid_attrs3 end end - test "can update lookup value if user has matching hostgroup " do - # Host.my_hosts returns only hosts(:one) - user = users(:one) - as_admin do - assert user.hostgroups << hostgroups(:common) - end - as_user :one do - assert Hostgroup.my_groups.where(:name => "Common").exists? - assert lookup_values(:hostgroupcommon).update_attributes(:value => "9000") - end - end - test "smart class parameter accepts valid data" do as_admin do lk = LookupValue.new(:value => "---\nfoo:\n bar: baz", :match => "hostgroup=Common", :lookup_key => lookup_keys(:six)) diff --git a/test/unit/medium_test.rb b/test/unit/medium_test.rb index 7a763593879..08b3fe566a0 100644 --- a/test/unit/medium_test.rb +++ b/test/unit/medium_test.rb @@ -60,67 +60,6 @@ class MediumTest < ActiveSupport::TestCase assert !medium.destroy end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_media" - role.permissions = ["#{operation}_media".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create" do - setup_user "create" - record = Medium.create :name => "dummy", :path => "http://hello" - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create" do - setup_user "view" - record = Medium.create :name => "dummy", :path => "http://hello" - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = Medium.first - as_admin do - record.hosts.delete_all - record.hostgroups.delete_all - assert record.destroy - end - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = Medium.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = Medium.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = Medium.first - record.name = "renamed" - as_admin do - record.hosts.delete_all - end - assert !record.save - assert record.valid? - end - test "os family can be one of defined os families" do medium = Medium.new :name => "dummy", :path => "http://hello", :os_family => Operatingsystem.families[0] assert medium.valid? diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index 352e2f023a9..e1c4cb91f03 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -26,65 +26,4 @@ class ModelTest < ActiveSupport::TestCase m.hosts << host assert !m.destroy end - - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_models" - role.permissions = ["#{operation}_models".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create" do - setup_user "create" - record = Model.create :name => "dummy" - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create" do - setup_user "view" - record = Model.create :name => "dummy" - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = Model.first - as_admin do - record.hosts.destroy_all - end - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = Model.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = Model.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = Model.first - record.name = "renamed" - as_admin do - record.hosts.destroy_all - end - assert !record.save - assert record.valid? - end - end diff --git a/test/unit/operatingsystem_test.rb b/test/unit/operatingsystem_test.rb index c55aec47177..19d59c533fb 100644 --- a/test/unit/operatingsystem_test.rb +++ b/test/unit/operatingsystem_test.rb @@ -76,67 +76,6 @@ class OperatingsystemTest < ActiveSupport::TestCase assert operating_system.to_s == operating_system.to_label end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_operatingsystems" - role.permissions = ["#{operation}_operatingsystems".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create" do - setup_user "create" - record = Operatingsystem.create :name => "dummy", :major => 7 - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create" do - setup_user "view" - record = Operatingsystem.create :name => "dummy", :major => 7 - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = Operatingsystem.first - as_admin do - record.hosts.delete_all - record.hostgroups.delete_all - assert record.destroy - end - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = Operatingsystem.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = Operatingsystem.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = Operatingsystem.first - record.name = "renamed" - as_admin do - record.hosts.destroy_all - end - assert !record.save - assert record.valid? - end - test "should find by fullname string" do str = "Redhat 6.1" os = Operatingsystem.find_by_fullname(str) @@ -166,7 +105,6 @@ def setup_user operation assert_equal ["centos 5.3"], medium.operatingsystem_names end - describe "families" do let(:os) { Operatingsystem.new :name => "dummy", :major => 7 } diff --git a/test/unit/permission_test.rb b/test/unit/permission_test.rb new file mode 100644 index 00000000000..34379bdcb3b --- /dev/null +++ b/test/unit/permission_test.rb @@ -0,0 +1,18 @@ +require 'test_helper' + +class PermissionTest < ActiveSupport::TestCase + test ".resources" do + Permission.resources.each {|r| assert_kind_of String, r } + end + + test ".resources works even for undefined resource types" do + FactoryGirl.create :permission, :resource_type => 'SomethingNotExisting' + Permission.resources.each {|r| assert_not_nil r } + end + + test ".resources_with_translations are ordered by translation" do + Permission.stubs(:with_translations).returns([['Z', 'z'], ['A', 'b'], ['H', 'a']]) + assert_equal [['A', 'b'], ['H', 'a'], ['Z', 'z']], Permission.resources_with_translations + end + +end diff --git a/test/unit/ptable_test.rb b/test/unit/ptable_test.rb index dad93457086..06e245584a0 100644 --- a/test/unit/ptable_test.rb +++ b/test/unit/ptable_test.rb @@ -81,67 +81,6 @@ class PtableTest < ActiveSupport::TestCase assert !partition_table.destroy end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_ptables" - role.permissions = ["#{operation}_ptables".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create" do - setup_user "create" - record = Ptable.create :name => "dummy", :layout => "layout" - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create" do - setup_user "view" - record = Ptable.create :name => "dummy", :layout => "layout" - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = Ptable.first - as_admin do - record.hosts.delete_all - record.hostgroups.delete_all - assert record.destroy - end - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = Ptable.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = Ptable.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = Ptable.first - record.name = "renamed" - as_admin do - record.hosts.destroy_all - end - assert !record.save - assert record.valid? - end - test 'when creating a new ptable class object, an audit entry needs to be added' do as_admin do assert_difference('Audit.count') do diff --git a/test/unit/puppetclass_test.rb b/test/unit/puppetclass_test.rb index 184d2b4e2c0..2912bb8e667 100644 --- a/test/unit/puppetclass_test.rb +++ b/test/unit/puppetclass_test.rb @@ -27,84 +27,26 @@ class PuppetclassTest < ActiveSupport::TestCase assert !other_puppet_class.save end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_puppetclasses" - role.permissions = ["#{operation}_puppetclasses".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create" do - setup_user "create" - record = Puppetclass.create :name => "dummy" - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create" do - setup_user "view" - record = Puppetclass.create :name => "dummy" - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = Puppetclass.first - as_admin do - record.hosts.destroy_all - record.lookup_keys.destroy_all - end - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = Puppetclass.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = Puppetclass.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = Puppetclass.first - record.name = "renamed" - as_admin do - record.hosts.destroy_all - end - assert !record.save - assert record.valid? - end - test "looking for a nonexistent host returns no puppetclasses" do assert_equal [], Puppetclass.search_for("host = imaginaryhost.nodomain.what") end - test "user without create external_variables permission cannot create smart variable for puppetclass" do - setup_user "edit" - nested_lookup_key_params = {:new_1372154591368 => {:key=>"test_param", :key_type=>"string", :default_value => "7777", :path =>"fqdn\r\nhostgroup\r\nos\r\ndomain"}} - refute Puppetclass.first.update_attributes(:lookup_keys_attributes => nested_lookup_key_params) - end - test "user with create external_variables permission can create smart variable for puppetclass" do @one = users(:one) # add permission for user :one as_admin do + filter1 = FactoryGirl.build(:filter) + filter1.permissions = Permission.find_all_by_name(['create_external_variables']) + filter2 = FactoryGirl.build(:filter) + filter2.permissions = Permission.find_all_by_name(['edit_puppetclasses']) role = Role.find_or_create_by_name :name => "testing_role" - role.permissions = [:edit_puppetclasses, :create_external_variables] - @one.roles = [role] + role.filters = [ filter1, filter2 ] + role.save! + filter1.role = role + filter1.save! + filter2.role = role + filter2.save! + @one.roles = [ role ] @one.save! end as_user :one do diff --git a/test/unit/report_test.rb b/test/unit/report_test.rb index 9b220c323d0..8ada4476196 100644 --- a/test/unit/report_test.rb +++ b/test/unit/report_test.rb @@ -64,46 +64,4 @@ def setup assert Report.with("pending").include?(@r) end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_reports" - role.permissions = ["#{operation}_reports".to_sym] - @one.roles = [role] - @one.save! - @r.save! - end - User.current = @one - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = @r - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = @r - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should not be able to edit" do - # Reports are not an editable resource - setup_user "edit" - record = @r - record.status = {} - assert !record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = @r - record.status = {} - assert !record.save - assert record.valid? - end - end diff --git a/test/unit/role_test.rb b/test/unit/role_test.rb index ad95488e1ae..ddf5713e487 100644 --- a/test/unit/role_test.rb +++ b/test/unit/role_test.rb @@ -37,15 +37,6 @@ class RoleTest < ActiveSupport::TestCase role.wont_be :valid? end - it "should ensure length of name is at most 30" do - thirty = 'abcdefghijklmnopqrstuvwxyz1234' - thirtyone = 'abcdefghijklmnopqrstuvwxyz12345' - role = Role.new(:name => thirty) - role.must_be :valid? - role = Role.new(:name => thirtyone) - role.wont_be :valid? - end - it "should allow value 'a role name' for name" do role = Role.new(:name => "a role name") role.must_be :valid? @@ -66,25 +57,6 @@ class RoleTest < ActiveSupport::TestCase role.must_be :valid? end - def test_add_permission - role = Role.find(1) - size = role.permissions.size - role.add_permission!("apermission", "anotherpermission") - role.reload - assert role.permissions.include?(:anotherpermission) - assert_equal size + 2, role.permissions.size - end - - def test_remove_permission - role = Role.find(1) - size = role.permissions.size - perm = role.permissions[0..1] - role.remove_permission!(*perm) - role.reload - assert ! role.permissions.include?(perm[0]) - assert_equal size - 2, role.permissions.size - end - context "System roles" do should "return the anonymous role" do role = Role.anonymous @@ -97,6 +69,7 @@ def test_remove_permission role_ids = Role.where("builtin = #{Role::BUILTIN_ANONYMOUS}").pluck(:id) user_ids = UserRole.where(:role_id => role_ids) UserRole.where(:role_id => role_ids).destroy_all + Filter.where(:role_id => role_ids).destroy_all Role.where(:id => role_ids).delete_all end @@ -126,6 +99,7 @@ def test_remove_permission role_ids = Role.where("builtin = #{Role::BUILTIN_DEFAULT_USER}").pluck(:id) user_ids = UserRole.where(:role_id => role_ids) UserRole.where(:role_id => role_ids).destroy_all + Filter.where(:role_id => role_ids).destroy_all Role.where(:id => role_ids).delete_all end @@ -156,6 +130,64 @@ def test_remove_permission it { subject.must_include(first) } it { subject.wont_include(second) } end + end + + describe "#add_permissions" do + setup do + @permission1 = FactoryGirl.create(:permission, :name => 'permission1') + @permission2 = FactoryGirl.create(:permission, :architecture, :name => 'permission2') + @role = FactoryGirl.build(:role, :permissions => []) + end + + it "should build filters with assigned permission" do + @role.add_permissions [@permission1.name, @permission2.name.to_sym] + assert @role.filters.all?(&:unlimited?) + + permissions = @role.filters.map { |f| f.filterings.map(&:permission) }.flatten + assert_equal 2, @role.filters.size + assert_includes permissions, Permission.find_by_name(@permission1.name) + assert_includes permissions, Permission.find_by_name(@permission2.name) + # not saved yet + assert_empty @role.permissions + end + it "should raise error when given permission does not exist" do + assert_raises ArgumentError do + @role.add_permissions ['does_not_exist'] + end + end + + it "accespts one permissions instead of array as well" do + @role.add_permissions @permission1.name + permissions = @role.filters.map { |f| f.filterings.map(&:permission) }.flatten + + assert_equal 1, @role.filters.size + assert_includes permissions, Permission.find_by_name(@permission1.name) + end + + it "sets search filter to all filters" do + search = "id = 1" + @role.add_permissions [@permission1.name, @permission2.name.to_sym], :search => search + refute @role.filters.any?(&:unlimited?) + assert @role.filters.all? { |f| f.search == search } + end + end + + describe "#add_permissions!" do + setup do + @permission1 = FactoryGirl.create(:permission, :name => 'permission1') + @permission2 = FactoryGirl.create(:permission, :architecture, :name => 'permission2') + @role = FactoryGirl.build(:role, :permissions => []) + end + + it "persists built permissions" do + assert @role.add_permissions!([@permission1.name, @permission2.name.to_sym]) + @role.reload + + permissions = @role.permissions + assert_equal 2, @role.filters.size + assert_includes permissions, Permission.find_by_name(@permission1.name) + assert_includes permissions, Permission.find_by_name(@permission2.name) + end end end diff --git a/test/unit/subnet_test.rb b/test/unit/subnet_test.rb index 38e811bce02..1b98a175d43 100644 --- a/test/unit/subnet_test.rb +++ b/test/unit/subnet_test.rb @@ -86,70 +86,6 @@ def create_a_domain_with_the_subnet @subnet.save! end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_subnets" - role.permissions = ["#{operation}_subnets".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one - end - - test "user with create permissions should be able to create" do - setup_user "create" - record = Subnet.create :name => "dummy2", :network => "1.2.3.4", :mask => "255.255.255.0" - assert record.domain_ids = [Domain.first.id] - assert record.valid? - assert !record.new_record? - end - - test "user with view permissions should not be able to create" do - setup_user "view" - record = Subnet.new :name => "dummy", :network => "1.2.3.4", :mask => "255.255.255.0" - assert record.valid? - assert !record.save - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = subnets(:two) - as_admin do - record.domains.destroy_all - record.hosts.clear - record.interfaces.clear - end - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = Subnet.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = Subnet.first - record.name = "renamed" - assert record.save - end - - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = Subnet.first - record.name = "renamed" - as_admin do - record.domains = [domains(:unuseddomain)] - end - assert !record.save - assert record.valid? - end - test "from cant be bigger than to range" do s = subnets(:one) s.to = "2.3.4.15" diff --git a/test/unit/user_role_test.rb b/test/unit/user_role_test.rb new file mode 100644 index 00000000000..a85cb1005c8 --- /dev/null +++ b/test/unit/user_role_test.rb @@ -0,0 +1,85 @@ +require 'test_helper' + +class UserRoleTest < ActiveSupport::TestCase + + def setup + User.current = User.find_by_login "admin" + end + + test "type detection" do + user_role = FactoryGirl.create :user_user_role + assert user_role.user_role? + usergroup_role = FactoryGirl.create :user_group_user_role + assert usergroup_role.user_group_role? + end + + test "cache user roles" do + user = FactoryGirl.create :user + user_role = FactoryGirl.create :user_user_role, :owner => user + cached_user_role = user.cached_user_roles.first + + assert_equal user_role.role, cached_user_role.role + assert_equal user_role, cached_user_role.user_role + end + + test "cache usergroup roles" do + user_role = setup_admins_scenario + + users = @semiadmin_users + [@admin_user] + [@superadmin_user] + users.each do |user| + cached_user_role = user.cached_user_roles.first + assert_equal user_role.role, cached_user_role.role + assert_equal user_role, cached_user_role.user_role + end + end + + test "update role of usergroup role" do + new_role = FactoryGirl.create :role + user_role = setup_admins_scenario + user_role.role = new_role + user_role.save + + users = @semiadmin_users + [@admin_user] + [@superadmin_user] + users.each do |user| + cached_user_role = user.cached_user_roles.first + assert_equal new_role, cached_user_role.role + end + end + + test "update owner of usergroup role" do + user_role = setup_admins_scenario + user_role.owner = @admins + user_role.save + + users = [@admin_user, @superadmin_user] + users.each do |user| + cached_user_role = user.cached_user_roles.first + assert_equal user_role.role, cached_user_role.role + end + + users = @semiadmin_users + users.each do |user| + assert_empty user.cached_user_roles + end + end + + def setup_admins_scenario + @semiadmins = FactoryGirl.create :usergroup + @admins = FactoryGirl.create :usergroup + @superadmins = FactoryGirl.create :usergroup + + @semiadmins.usergroups = [@admins] + @admins.usergroups = [@superadmins] + + @semiadmin_users = [FactoryGirl.create(:user, :login => 'ur_semiadmin1'), + FactoryGirl.create(:user, :login => 'ur_semiadmin2')] + @admin_user = FactoryGirl.create(:user, :login => 'ur_admin1') + @superadmin_user = FactoryGirl.create(:user, :login => 'ur_superadmin1') + + @semiadmins.users += @semiadmin_users + @admins.users = [@admin_user] + @superadmins.users = [@superadmin_user] + + FactoryGirl.create :user_group_user_role, :owner => @semiadmins + end +end diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb index 4c0b256a2dd..b6592c7fc72 100644 --- a/test/unit/user_test.rb +++ b/test/unit/user_test.rb @@ -127,14 +127,7 @@ def setup end def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_users" - role.permissions = ["#{operation}_users".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one + super operation, "users" end test "user with create permissions should be able to create" do @@ -194,36 +187,6 @@ def setup_user operation end end - test "user with view permissions should not be able to create" do - setup_user "view" - record = User.new :login => "dummy", :mail => "j@j.com", :auth_source_id => AuthSourceInternal.first.id - record.password_hash = "asd" - assert !record.save - assert record.valid? - assert record.new_record? - end - - test "user with destroy permissions should be able to destroy" do - setup_user "destroy" - record = users(:one) - assert record.destroy - assert record.frozen? - end - - test "user with edit permissions should not be able to destroy" do - setup_user "edit" - record = User.first - assert !record.destroy - assert !record.frozen? - end - - test "user with edit permissions should be able to edit" do - setup_user "edit" - record = users(:one) - record.login = "renamed" - assert record.save - end - test "user cannot assign role he has not assigned himself" do setup_user "edit" extra_role = Role.find_or_create_by_name :name => "foobar" @@ -286,14 +249,6 @@ def setup_user operation assert record.save end - test "user with destroy permissions should not be able to edit" do - setup_user "destroy" - record = users(:two) - record.login = 'renamed' - assert !record.save - assert record.valid? - end - test "should not be able to rename the admin account" do u = User.find_by_login("admin") u.login = "root" @@ -363,6 +318,27 @@ def setup_user operation assert_equal user.role_ids_was, [foobar.id, barfoo.id] end + test "admin? detection for user admin flag" do + admin = FactoryGirl.build(:user, :admin => true) + assert admin.admin?, 'user admin flag was missed' + end + + test "admin? detection for group admin flag" do + admin = FactoryGirl.build(:user) + g1 = FactoryGirl.build(:usergroup) + g2 = FactoryGirl.build(:usergroup, :admin => true) + admin.cached_usergroups = [g1, g2] + assert admin.admin?, 'group admin flag was missed' + end + + test "admin? is false if no flag is enabled" do + admin = FactoryGirl.build(:user) + g1 = FactoryGirl.build(:usergroup) + g2 = FactoryGirl.build(:usergroup) + admin.cached_usergroups = [g1, g2] + refute admin.admin? + end + test ".find_or_create_external_user" do count = User.count # existing user @@ -443,4 +419,16 @@ def setup_user operation assert_not User.current.editing_self?(options) end + test "#can? for admin" do + Authorizer.any_instance.stubs(:can?).returns(false) + u = FactoryGirl.build(:user, :admin => true) + assert u.can?(:view_hosts_or_whatever_you_ask) + end + + test "#can? for not admin" do + Authorizer.any_instance.stubs(:can?).returns('authorizer was asked') + u = FactoryGirl.build(:user) + assert_equal 'authorizer was asked', u.can?(:view_hosts_or_whatever_you_ask) + end + end diff --git a/test/unit/usergroup_member_test.rb b/test/unit/usergroup_member_test.rb new file mode 100644 index 00000000000..466e04c226f --- /dev/null +++ b/test/unit/usergroup_member_test.rb @@ -0,0 +1,368 @@ +require 'test_helper' + +class UsergroupMemberTest < ActiveSupport::TestCase + + def setup + User.current = User.find_by_login "admin" + end + + test "remove membership of user in a group" do + setup_admins_scenario + assert_includes @superadmin_user.cached_user_roles.map(&:role), @semiadmin_role + + @superadmins.users.clear + + assert_not_include @superadmin_user.reload.cached_user_roles.map(&:role), @semiadmin_role + cached_usergroups = @superadmin_user.cached_usergroups + assert_not_include cached_usergroups, @superadmins + assert_not_include cached_usergroups, @admins + assert_not_include cached_usergroups, @semiadmins + end + + test "searching for user roles" do + setup_admins_scenario + + found = @superadmins.usergroup_members.first.send :find_all_user_roles + assert_includes found, @semiadmin_ur + assert_includes found, @admin_ur + assert_includes found, @superadmin_ur + assert_not_includes found, @role1 + assert_not_includes found, @role2 + assert_not_includes found, @role3 + end + + test "searching for user groups" do + setup_admins_scenario + + found = @admins.usergroup_members.first.send :find_all_usergroups + assert_includes found, @semiadmins + assert_includes found, @admins + assert_not_include found, @superadmins + end + + test "searching for affected users memberships" do + setup_admins_scenario + + found = @semiadmins.usergroup_members.where("member_type = 'Usergroup'").first.send :find_all_affected_users + assert_includes found, @admin_user + assert_includes found, @superadmin_user + assert_not_includes found, @semiadmin_user + + found = @superadmins.usergroup_members.where("member_type = 'User'").first.send :find_all_affected_users + assert_not_includes found, @admin_user + assert_not_includes found, @semiadmin_user + assert_includes found, @superadmin_user + end + + test "remove root member in tree" do + setup_admins_scenario + + assert_include @admin_user.cached_user_roles.map(&:role), @semiadmin_role + assert_include @superadmin_user.cached_user_roles.map(&:role), @semiadmin_role + + @semiadmins.usergroups.clear + @semiadmin_user.reload; @admin_user.reload; @superadmin_user.reload + + assert_includes @semiadmin_user.cached_user_roles.map(&:role), @semiadmin_role + assert_includes @admin_user.cached_user_roles.map(&:role), @admin_role + assert_includes @superadmin_user.cached_user_roles.map(&:role), @admin_role + assert_includes @superadmin_user.cached_user_roles.map(&:role), @superadmin_role + + assert_not_include @admin_user.cached_user_roles.map(&:role), @semiadmin_role + assert_not_include @superadmin_user.cached_user_roles.map(&:role), @semiadmin_role + + assert_includes @semiadmin_user.cached_usergroups, @semiadmins + assert_not_includes @admin_user.cached_usergroups, @semiadmins + assert_includes @admin_user.cached_usergroups, @admins + assert_not_includes @superadmin_user.cached_usergroups, @semiadmins + assert_includes @superadmin_user.cached_usergroups, @admins + assert_includes @superadmin_user.cached_usergroups, @superadmins + end + + test "remove leaf member in tree" do + setup_admins_scenario + + assert_include @semiadmin_user.cached_user_roles.map(&:role), @semiadmin_role + assert_include @admin_user.cached_user_roles.map(&:role), @semiadmin_role + assert_include @superadmin_user.cached_user_roles.map(&:role), @semiadmin_role + + @admins.usergroups.clear + @semiadmin_user.reload; @admin_user.reload; @superadmin_user.reload + + assert_includes @semiadmin_user.cached_user_roles.map(&:role), @semiadmin_role + assert_includes @admin_user.cached_user_roles.map(&:role), @admin_role + assert_includes @superadmin_user.cached_user_roles.map(&:role), @superadmin_role + assert_include @admin_user.cached_user_roles.map(&:role), @semiadmin_role + assert_not_include @superadmin_user.cached_user_roles.map(&:role), @admin_role + assert_not_include @superadmin_user.cached_user_roles.map(&:role), @semiadmin_role + + assert_includes @semiadmin_user.cached_usergroups, @semiadmins + assert_includes @admin_user.cached_usergroups, @semiadmins + assert_includes @admin_user.cached_usergroups, @admins + assert_not_includes @superadmin_user.cached_usergroups, @semiadmins + assert_not_includes @superadmin_user.cached_usergroups, @admins + assert_includes @superadmin_user.cached_usergroups, @superadmins + end + + test "add new memership to the root" do + setup_admins_scenario + + basic = FactoryGirl.create :usergroup, :name => 'um_basic' + basic_role = FactoryGirl.create :role, :name => 'um_basic_role' + basic.roles<< basic_role + basic.usergroups<< @semiadmins + @semiadmin_user.reload; @admin_user.reload; @superadmin_user.reload + + assert_includes @semiadmin_user.cached_user_roles.map(&:role), basic_role + assert_includes @admin_user.cached_user_roles.map(&:role), basic_role + assert_includes @superadmin_user.cached_user_roles.map(&:role), basic_role + + assert_includes @semiadmin_user.cached_usergroups, basic + assert_includes @admin_user.cached_usergroups, basic + assert_includes @superadmin_user.cached_usergroups, basic + end + + test "add new memership to the middle of chain" do + setup_admins_scenario + + basic = FactoryGirl.create :usergroup, :name => 'um_basic' + basic_role = FactoryGirl.create :role, :name => 'um_basic_role' + basic.roles<< basic_role + basic.usergroups<< @admins + @semiadmin_user.reload; @admin_user.reload; @superadmin_user.reload + + assert_not_include @semiadmin_user.cached_user_roles.map(&:role), basic_role + assert_includes @admin_user.cached_user_roles.map(&:role), basic_role + assert_includes @superadmin_user.cached_user_roles.map(&:role), basic_role + + assert_not_include @semiadmin_user.cached_usergroups, basic + assert_includes @admin_user.cached_usergroups, basic + assert_includes @superadmin_user.cached_usergroups, basic + end + + test "add new memership to the leaf" do + setup_admins_scenario + + basic = FactoryGirl.create :usergroup, :name => 'um_basic' + basic_role = FactoryGirl.create :role, :name => 'um_basic_role' + basic.roles<< basic_role + basic.usergroups<< @superadmins + @semiadmin_user.reload; @admin_user.reload; @superadmin_user.reload + + assert_not_includes @semiadmin_user.cached_user_roles.map(&:role), basic_role + assert_not_includes @admin_user.cached_user_roles.map(&:role), basic_role + assert_includes @superadmin_user.cached_user_roles.map(&:role), basic_role + + assert_not_include @semiadmin_user.cached_usergroups, basic + assert_not_include @admin_user.cached_usergroups, basic + assert_includes @superadmin_user.cached_usergroups, basic + end + + test "change membership (member) in the middle of chain" do + setup_admins_scenario + + membership = @semiadmins.usergroup_members.where(:member_id => @admins.id).first + membership.member = @superadmins + membership.save + @semiadmin_user.reload; @admin_user.reload; @superadmin_user.reload + + assert_includes @superadmin_user.cached_user_roles.map(&:role), @semiadmin_role + assert_includes @superadmin_user.cached_user_roles.map(&:role), @superadmin_role + assert_includes @superadmin_user.cached_user_roles.map(&:role), @admin_role + assert_not_includes @admin_user.cached_user_roles.map(&:role), @semiadmin_role + assert_includes @semiadmin_user.cached_user_roles.map(&:role), @semiadmin_role + + assert_includes @superadmin_user.cached_usergroups, @semiadmins + assert_includes @superadmin_user.cached_usergroups, @admins + assert_includes @superadmin_user.cached_usergroups, @superadmins + assert_not_include @admin_user.cached_usergroups, @semiadmins + assert_include @admin_user.cached_usergroups, @admins + assert_include @semiadmin_user.cached_usergroups, @semiadmins + end + + test "change membership (hostgroup) in the middle of chain" do + setup_admins_scenario + + membership = @admins.usergroup_members.where(:member_id => @superadmins.id).first + membership.usergroup = @semiadmins + membership.save + @semiadmin_user.reload; @admin_user.reload; @superadmin_user.reload + + assert_includes @superadmin_user.cached_user_roles.map(&:role), @semiadmin_role + assert_includes @superadmin_user.cached_user_roles.map(&:role), @superadmin_role + assert_not_includes @superadmin_user.cached_user_roles.map(&:role), @admin_role + assert_includes @admin_user.cached_user_roles.map(&:role), @semiadmin_role + assert_includes @admin_user.cached_user_roles.map(&:role), @admin_role + assert_includes @semiadmin_user.cached_user_roles.map(&:role), @semiadmin_role + + assert_includes @superadmin_user.cached_usergroups, @superadmins + assert_includes @superadmin_user.cached_usergroups, @semiadmins + assert_not_include @superadmin_user.cached_usergroups, @admins + assert_includes @admin_user.cached_usergroups, @semiadmins + assert_includes @admin_user.cached_usergroups, @admins + assert_includes @semiadmin_user.cached_usergroups, @semiadmins + end + + test "user is in two joined groups, second membership is removed" do + setup_redundant_scenario + + @admins.users = [] + assert_not_include @semiadmin_user.cached_user_roles.map(&:role), @admin_role + end + + test "user is in three two joined groups, middle membership is removed" do + setup_redundant_scenario + @superadmins = FactoryGirl.create :usergroup, :name => 'um_superadmins' + @superadmins.usergroups = [@semiadmins] + @superadmins.roles<< @admin_role + + @admins.users = [] + @semiadmin_user.reload + assert_includes @semiadmin_user.cached_user_roles.map(&:role), @admin_role + + assert_includes @semiadmin_user.cached_usergroups, @superadmins + end + + test "diamond-with-tail usergroups, one of way is removed" do + @a = FactoryGirl.create :usergroup, :name => 'um_a' + @b = FactoryGirl.create :usergroup, :name => 'um_b' + @c = FactoryGirl.create :usergroup, :name => 'um_c' + @d = FactoryGirl.create :usergroup, :name => 'um_d' + @e = FactoryGirl.create :usergroup, :name => 'um_e' + @a.usergroups = [@b, @c] + @b.usergroups = [@d] + @c.usergroups = [@d] + @d.usergroups = [@e] + + @user1 = FactoryGirl.create(:user, :login => 'um_user1') + @user2 = FactoryGirl.create(:user, :login => 'um_user2') + @user1.usergroups = [@d.reload] # @d cached #users already as [] + @user2.usergroups = [@e] + @role = FactoryGirl.create(:role, :name => 'um_role') + @role_ur = FactoryGirl.create :user_group_user_role, :owner => @a, :role => @role + + assert_includes @user1.reload.cached_user_roles.map(&:role), @role + assert_includes @user2.reload.cached_user_roles.map(&:role), @role + + assert_includes @user1.cached_usergroups, @a + assert_includes @user1.cached_usergroups, @b + assert_includes @user1.cached_usergroups, @c + assert_includes @user1.cached_usergroups, @d + assert_not_includes @user1.cached_usergroups, @e + assert_includes @user2.cached_usergroups, @a + assert_includes @user2.cached_usergroups, @b + assert_includes @user2.cached_usergroups, @c + assert_includes @user2.cached_usergroups, @d + assert_includes @user2.cached_usergroups, @e + + @c.usergroups = [] + assert_includes @user1.reload.cached_user_roles.map(&:role), @role + assert_includes @user2.reload.cached_user_roles.map(&:role), @role + + assert_includes @user1.cached_usergroups, @a + assert_includes @user1.cached_usergroups, @b + assert_not_includes @user1.cached_usergroups, @c + assert_includes @user1.cached_usergroups, @d + assert_not_includes @user1.cached_usergroups, @e + assert_includes @user2.cached_usergroups, @a + assert_includes @user2.cached_usergroups, @b + assert_not_includes @user2.cached_usergroups, @c + assert_includes @user2.cached_usergroups, @d + assert_includes @user2.cached_usergroups, @e + end + + test "user is in two joined groups, first membership is removed" do + setup_redundant_scenario + + @semiadmins.users = [] + @semiadmin_user.reload + assert_includes @semiadmin_user.cached_user_roles.map(&:role), @admin_role + assert_includes @semiadmin_user.cached_usergroups, @semiadmins + assert_includes @semiadmin_user.cached_usergroups, @admins + end + + test "user is in two joined groups, joining is removed" do + setup_redundant_scenario + + @semiadmins.usergroups = [] + @semiadmin_user.reload + + assert_includes @semiadmin_user.cached_user_roles.map(&:role), @admin_role + assert_includes @semiadmin_user.cached_usergroups, @semiadmins + assert_includes @semiadmin_user.cached_usergroups, @admins + end + + test "user is in two joined groups with redundant role, second membership is removed" do + setup_redundant_scenario + @semiadmin_ur = FactoryGirl.create :user_group_user_role, :owner => @semiadmins, :role => @admin_role + + @admins.users = [] + @semiadmin_user.reload + assert_includes @semiadmin_user.cached_user_roles.map(&:role), @admin_role + assert_includes @semiadmin_user.cached_usergroups, @semiadmins + end + + test "user is in two joined groups with redundant role, first membership is removed" do + setup_redundant_scenario + @semiadmin_ur = FactoryGirl.create :user_group_user_role, :owner => @semiadmins, :role => @admin_role + + @semiadmins.users = [] + assert_includes @semiadmin_user.cached_user_roles.map(&:role), @admin_role + end + + test "user is in two joined groups with redundant role, joining is removed" do + setup_redundant_scenario + @semiadmin_ur = FactoryGirl.create :user_group_user_role, :owner => @semiadmins, :role => @admin_role + + @semiadmins.usergroups = [] + assert_includes @semiadmin_user.cached_user_roles.map(&:role), @admin_role + end + + def setup_redundant_scenario + @semiadmins = FactoryGirl.create :usergroup, :name => 'um_semiadmins' + @admins = FactoryGirl.create :usergroup, :name => 'um_admins' + + @semiadmins.usergroups = [@admins] + + @semiadmin_user = FactoryGirl.create(:user, :login => 'um_semiadmin1') + + @semiadmins.users = [@semiadmin_user] + @admins.users = [@semiadmin_user] + + @admin_role = FactoryGirl.create(:role, :name => 'um_admin') + + @admin_ur = FactoryGirl.create :user_group_user_role, :owner => @admins, :role => @admin_role + end + + def setup_admins_scenario + @semiadmins = FactoryGirl.create :usergroup, :name => 'um_semiadmins' + @admins = FactoryGirl.create :usergroup, :name => 'um_admins' + @superadmins = FactoryGirl.create :usergroup, :name => 'um_superadmins' + + @semiadmins.usergroups = [@admins] + @admins.usergroups = [@superadmins] + + @semiadmin_user = FactoryGirl.create(:user, :login => 'um_semiadmin1') + @admin_user = FactoryGirl.create(:user, :login => 'um_admin1') + @superadmin_user = FactoryGirl.create(:user, :login => 'um_superadmin1') + + @semiadmins.users = [@semiadmin_user] + @admins.users = [@admin_user] + @superadmins.users = [@superadmin_user] + + @semiadmin_role = FactoryGirl.create(:role, :name => 'um_semiadmin') + @admin_role = FactoryGirl.create(:role, :name => 'um_admin') + @superadmin_role = FactoryGirl.create(:role, :name => 'um_superadmin') + + @semiadmin_ur = FactoryGirl.create :user_group_user_role, :owner => @semiadmins, :role => @semiadmin_role + @admin_ur = FactoryGirl.create :user_group_user_role, :owner => @admins, :role => @admin_role + @superadmin_ur = FactoryGirl.create :user_group_user_role, :owner => @superadmins, :role => @superadmin_role + + @role1 = FactoryGirl.create(:role) + @role2 = FactoryGirl.create(:role) + @role3 = FactoryGirl.create(:role) + @semiadmin_user.roles<< @role1 + @admin_user.roles<< @role2 + @superadmin_user.roles<< @role3 + end +end diff --git a/test/unit/usergroup_test.rb b/test/unit/usergroup_test.rb index c3f56130637..7031c3bb2b1 100644 --- a/test/unit/usergroup_test.rb +++ b/test/unit/usergroup_test.rb @@ -89,12 +89,13 @@ def populate_usergroups assert_equal @ug1.errors.full_messages[0], "ug1 is used by #{@h1}" end - test "cannot be destroyed when in use by another usergroup" do + test "can be destroyed when in use by another usergroup, it removes association automatically" do @ug1 = Usergroup.find_or_create_by_name :name => "ug1" @ug2 = Usergroup.find_or_create_by_name :name => "ug2" @ug1.usergroups = [@ug2] - @ug1.destroy - assert @ug1.errors.full_messages[0] == "ug1 is used by ug2" + assert @ug1.destroy + assert @ug2.reload + assert_empty UsergroupMember.where(:member_id => @ug2.id) end test "removes user join model records" do @@ -106,58 +107,29 @@ def populate_usergroups end end - def setup_user operation - @one = users(:one) - as_admin do - role = Role.find_or_create_by_name :name => "#{operation}_usergroups" - role.permissions = ["#{operation}_usergroups".to_sym] - @one.roles = [role] - @one.save! - end - User.current = @one - end + test "removes all cached_user_roles when roles are disassociated" do + user = FactoryGirl.create(:user) + record = FactoryGirl.create(:usergroup) + record.users = [user] + one = FactoryGirl.create(:role) + two = FactoryGirl.create(:role) - test "user with create permissions should be able to create" do - setup_user "create" - record = Usergroup.create :name => "dummy" - assert record.valid? - assert !record.new_record? - end + record.roles = [one, two] + assert_equal 2, user.reload.cached_user_roles.size - test "user with view permissions should not be able to create" do - setup_user "view" - record = Usergroup.create :name => "dummy" - assert record.valid? - assert record.new_record? - end + assert record.update_attributes(:role_ids => [ two.id ]) + assert_equal 1, user.reload.cached_user_roles.size - test "user with destroy permissions should be able to destroy" do - record = FactoryGirl.create(:usergroup) - setup_user "destroy" - assert record.destroy - assert record.frozen? - end + record.role_ids = [ ] + assert_equal 0, user.reload.cached_user_roles.size - test "user with edit permissions should not be able to destroy" do - record = FactoryGirl.create(:usergroup) - setup_user "edit" - assert !record.destroy - assert !record.frozen? - end + assert record.update_attribute(:role_ids, [ one.id ]) + assert_equal 1, user.reload.cached_user_roles.size - test "user with edit permissions should be able to edit" do - record = FactoryGirl.create(:usergroup) - setup_user "edit" - record.name = "renamed" - assert record.save + record.roles<< two + assert_equal 2, user.reload.cached_user_roles.size end - test "user with destroy permissions should not be able to edit" do - record = FactoryGirl.create(:usergroup) - setup_user "destroy" - record.name = "renamed" - assert !record.save - assert record.valid? - end + # TODO test who can modify usergroup roles and who can assign users!!! possible privileges escalation end