This is still preliminary, as there are a few things missing: 1) no support for using these permissions in the controllers 2) no UI to manipulate permission records 3) The roles would ideally be loaded via a yml file rather than in the migration, since they are theoretically dynamic values -- changes over time would be allowed without changes to the underlying code. 4) No fixtures/tests for any of this yet. I'll update this patch with fixtures, etc. before pushing, but I wanted to get this out there while the recent model decisions were still in my mind.
Signed-off-by: Scott Seago sseago@redhat.com --- src/app/models/base_portal_object.rb | 33 ++++++ src/app/models/cloud_account.rb | 4 + src/app/models/permission.rb | 43 ++++++++ src/app/models/portal_pool.rb | 4 + src/app/models/privilege.rb | 76 +++++++++++++ src/app/models/provider.rb | 4 + src/app/models/role.rb | 34 ++++++ src/db/migrate/20091008153046_create_privileges.rb | 49 +++++++++ src/db/migrate/20091008153058_create_roles.rb | 112 ++++++++++++++++++++ .../migrate/20091008153106_create_permissions.rb | 37 +++++++ .../20091019215838_create_base_portal_objects.rb | 14 +++ src/test/fixtures/base_portal_objects.yml | 7 ++ src/test/fixtures/permissions.yml | 7 ++ src/test/fixtures/privileges.yml | 7 ++ src/test/fixtures/roles.yml | 7 ++ src/test/unit/base_portal_object_test.rb | 8 ++ src/test/unit/permission_test.rb | 8 ++ src/test/unit/privilege_test.rb | 8 ++ src/test/unit/role_test.rb | 8 ++ 19 files changed, 470 insertions(+), 0 deletions(-) create mode 100644 src/app/models/base_portal_object.rb create mode 100644 src/app/models/permission.rb create mode 100644 src/app/models/privilege.rb create mode 100644 src/app/models/role.rb create mode 100644 src/db/migrate/20091008153046_create_privileges.rb create mode 100644 src/db/migrate/20091008153058_create_roles.rb create mode 100644 src/db/migrate/20091008153106_create_permissions.rb create mode 100644 src/db/migrate/20091019215838_create_base_portal_objects.rb create mode 100644 src/test/fixtures/base_portal_objects.yml create mode 100644 src/test/fixtures/permissions.yml create mode 100644 src/test/fixtures/privileges.yml create mode 100644 src/test/fixtures/roles.yml create mode 100644 src/test/unit/base_portal_object_test.rb create mode 100644 src/test/unit/permission_test.rb create mode 100644 src/test/unit/privilege_test.rb create mode 100644 src/test/unit/role_test.rb
diff --git a/src/app/models/base_portal_object.rb b/src/app/models/base_portal_object.rb new file mode 100644 index 0000000..e96dd44 --- /dev/null +++ b/src/app/models/base_portal_object.rb @@ -0,0 +1,33 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Scott Seago sseago@redhat.com +# +# 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; version 2 of the License. +# +# 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. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class BasePortalObject < ActiveRecord::Base + has_many :permissions, :as => :permission_object, :dependent => :destroy, + :include => [:role], + :order => "permissions.id ASC" + + validates_presence_of :name + validates_uniqueness_of :name + + GENERAL_PERMISSION_SCOPE = "general_permission_scope" + + def self.general_permission_scope + self.find_by_name(GENERAL_PERMISSION_SCOPE) + end +end diff --git a/src/app/models/cloud_account.rb b/src/app/models/cloud_account.rb index db213b0..afb4623 100644 --- a/src/app/models/cloud_account.rb +++ b/src/app/models/cloud_account.rb @@ -35,6 +35,10 @@ class CloudAccount < ActiveRecord::Base validates_uniqueness_of :username, :scope => :provider_id validates_presence_of :password
+ has_many :permissions, :as => :permission_object, :dependent => :destroy, + :include => [:role], + :order => "permissions.id ASC" + def connect begin return DeltaCloud.new(username, password, provider.url) diff --git a/src/app/models/permission.rb b/src/app/models/permission.rb new file mode 100644 index 0000000..7c2bd9c --- /dev/null +++ b/src/app/models/permission.rb @@ -0,0 +1,43 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Scott Seago sseago@redhat.com +# +# 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; version 2 of the License. +# +# 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. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class Permission < ActiveRecord::Base + belongs_to :pool + + belongs_to :role + + validates_presence_of :pool_id + validates_presence_of :role_id + + validates_presence_of :user_id + validates_uniqueness_of :user_id, :scope => [:permission_object_id, + :permission_object_type] + + belongs_to :permission_object, :polymorphic => true + # type-specific associations + belongs_to :portal_pool, :class_name => "PortalPool", + :foreign_key => "permission_object_id" + belongs_to :provider, :class_name => "Provider", + :foreign_key => "permission_object_id" + belongs_to :cloud_account, :class_name => "CloudAccount", + :foreign_key => "permission_object_id" + belongs_to :base_portal_object, :class_name => "BasePortalObject", + :foreign_key => "permission_object_id" + +end diff --git a/src/app/models/portal_pool.rb b/src/app/models/portal_pool.rb index 6c30a67..6f4084b 100644 --- a/src/app/models/portal_pool.rb +++ b/src/app/models/portal_pool.rb @@ -30,6 +30,10 @@ class PortalPool < ActiveRecord::Base validates_presence_of :name validates_uniqueness_of :name, :scope => :cloud_account_id
+ has_many :permissions, :as => :permission_object, :dependent => :destroy, + :include => [:role], + :order => "permissions.id ASC" + def populate_realms_and_images client = cloud_account.connect realms = client.realms diff --git a/src/app/models/privilege.rb b/src/app/models/privilege.rb new file mode 100644 index 0000000..06dd18e --- /dev/null +++ b/src/app/models/privilege.rb @@ -0,0 +1,76 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Scott Seago sseago@redhat.com +# +# 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; version 2 of the License. +# +# 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. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class Privilege < ActiveRecord::Base + has_and_belongs_to_many :roles + + validates_presence_of :name + validates_uniqueness_of :name + + #default privileges + PERM_SET = "set_perms" # can create/modify/delete permission + # records on this object + PERM_VIEW = "view_perms" # can view permission records on this + # object + + # instance privileges normally checked at the pool level, although + # instance-specific overrides could be a future enhancement. + INSTANCE_MODIFY = "instance_modify" # can create, modify, delete, or + # control (start, stop, etc) instances + INSTANCE_CONTROL = "instance_control" # can control (start, stop, etc) + # instances + INSTANCE_VIEW = "instance_view" # can view instance metadata + # do we need a separate "connect" privilege? + + # stats privileges normally checked at the pool level, although + # instance-specific overrides could be a future enhancement. + STATS_VIEW = "stats_view" # can view monitoring data for + # instances + + # account privileges normally checked at the provider level, although + # account-specific overrides could be a future enhancement. + ACCOUNT_MODIFY = "account_modify" # can create or modify cloud accounts + ACCOUNT_VIEW = "account_view" # can create or modify cloud accounts + + # pool privileges normally checked at the provider level + # (and at the account level for choosing which accounts are visible on the + # new pool form), although + # pool-specific overrides could be a future enhancement. + POOL_MODIFY = "pool_modify" # can create or modify a pool + POOL_VIEW = "pool_view" # can view a pool + + # quota privileges normally checked at the pool or account level, + # depending on which quota level we're dealing with + # (account level for cloud-imposed quota, pool level for portal quota) + QUOTA_MODIFY = "quota_modify" # can create or modify a quota + QUOTA_VIEW = "quota_view" # can view a quota + + # provider privileges normally checked at the provider level, although + # 'new provider' action requires this privilege at the SystemPermission level + PROVIDER_MODIFY = "provider_modify" # can create or modify a provider + PROVIDER_VIEW = "provider_view" # can view a provider + + # normally checked at the SystemPermission level + USER_MODIFY = "user_modify" # can create a new user (other than + # self-registration) or modify another + # user's metadata (for admin-level + # actions) + USER_VIEW = "user_view" # can view a user's profile data + +end diff --git a/src/app/models/provider.rb b/src/app/models/provider.rb index b7a071a..dab9fee 100644 --- a/src/app/models/provider.rb +++ b/src/app/models/provider.rb @@ -34,6 +34,10 @@ class Provider < ActiveRecord::Base validates_presence_of :cloud_type validates_presence_of :url
+ has_many :permissions, :as => :permission_object, :dependent => :destroy, + :include => [:role], + :order => "permissions.id ASC" + def connect begin return DeltaCloud.new(nil, nil, url) diff --git a/src/app/models/role.rb b/src/app/models/role.rb new file mode 100644 index 0000000..ed7aaf4 --- /dev/null +++ b/src/app/models/role.rb @@ -0,0 +1,34 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Scott Seago sseago@redhat.com +# +# 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; version 2 of the License. +# +# 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. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class Role < ActiveRecord::Base + has_many :permissions + has_and_belongs_to_many :privileges, :uniq => true + + validates_presence_of :name + validates_uniqueness_of :name + + + #default roles + SUPER_ADMIN = "Super Admin" + ADMIN = "Administrator" + USER = "User" + MONITOR = "Monitor" + CLOUD_USER = "Cloud User" +end diff --git a/src/db/migrate/20091008153046_create_privileges.rb b/src/db/migrate/20091008153046_create_privileges.rb new file mode 100644 index 0000000..53817f8 --- /dev/null +++ b/src/db/migrate/20091008153046_create_privileges.rb @@ -0,0 +1,49 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Scott Seago sseago@redhat.com +# +# 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; version 2 of the License. +# +# 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. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class CreatePrivileges < ActiveRecord::Migration + def self.up + create_table :privileges do |t| + t.string :name, :null => false + t.integer :lock_version, :default => 0 + + t.timestamps + end + + #create default privileges + privileges = ["set_perms", "view_perms", + "instance_modify", "instance_control", "instance_view", + "instance_console", "stats_view", + "account_modify", "account_view", + "pool_modify", "pool_view", + "quota_modify", "quota_view", + "provider_modify", "provider_view", + "user_modify", "user_view"] + Privilege.transaction do + privileges.each do |priv_name| + privilege = Privilege.new({:name => priv_name}) + privilege.save! + end + end + end + + def self.down + drop_table :privileges + end +end diff --git a/src/db/migrate/20091008153058_create_roles.rb b/src/db/migrate/20091008153058_create_roles.rb new file mode 100644 index 0000000..15e91c5 --- /dev/null +++ b/src/db/migrate/20091008153058_create_roles.rb @@ -0,0 +1,112 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Scott Seago sseago@redhat.com +# +# 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; version 2 of the License. +# +# 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. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class CreateRoles < ActiveRecord::Migration + def self.up + create_table :roles do |t| + t.string :name, :null => false + t.string :scope, :null => false + t.integer :lock_version, :default => 0 + + t.timestamps + end + create_table :privileges_roles, :id => false do |t| + t.integer :privilege_id, :null => false + t.integer :role_id, :null => false + end + + #create default roles + roles = {"Instance Controller" => + {:role_scope => "PortalPool", + :privileges => ["instance_console", + "instance_control", + "instance_view", + "pool_view"]}, + "Instance Controller With Monitoring" => + {:role_scope => "PortalPool", + :privileges => ["instance_console", + "instance_control", + "instance_view", + "pool_view", + "stats_view"]}, + "Instance Creator and User" => + {:role_scope => "PortalPool", + :privileges => ["instance_console", + "instance_control", + "instance_view", + "pool_view", + "stats_view", + "instance_modify", + "quota_view", + "set_perms", + "view_perms"]}, + "Pool Creator" => + {:role_scope => "Provider", + :privileges => ["provider_view", + "pool_modify", + "pool_view", + "quota_view"]}, + "Pool Administrator" => + {:role_scope => "Provider", + :privileges => ["provider_view", + "pool_modify", + "pool_view", + "quota_view", + "quota_modify", + "account_view", + "account_modify"]}, + "Account Administrator" => + {:role_scope => "CloudAccount", + :privileges => ["set_perms", + "view_perms", + "account_view", + "account_modify"]}, + "Account User" => + {:role_scope => "CloudAccount", + :privileges => ["account_view"]}, + "Provider Administrator" => + {:role_scope => "BasePortalObject", + :privileges => ["provider_modify", + "provider_view"]}, + "Administrator" => + {:role_scope => "BasePortalObject", + :privileges => ["provider_modify", + "provider_view", + "user_modify", + "user_view", + "view_perms", + "set_perms"]} + + } + Role.transaction do + roles.each do |role_name, role_hash| + role = Role.new({:name => role_name, :scope => role_hash[:role_scope]}) + role.save! + role.privileges = role_hash[:privileges].collect do |priv_name| + Privilege.find_by_name(priv_name) + end + role.save! + end + end + end + + def self.down + drop_table :roles + end +end diff --git a/src/db/migrate/20091008153106_create_permissions.rb b/src/db/migrate/20091008153106_create_permissions.rb new file mode 100644 index 0000000..6e5a7a5 --- /dev/null +++ b/src/db/migrate/20091008153106_create_permissions.rb @@ -0,0 +1,37 @@ +# +# Copyright (C) 2009 Red Hat, Inc. +# Written by Scott Seago sseago@redhat.com +# +# 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; version 2 of the License. +# +# 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. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +class CreatePermissions < ActiveRecord::Migration + def self.up + create_table :permissions do |t| + t.integer :role_id, :null => false + t.integer :user_id, :null => false + t.integer :permission_object_id + t.string :permission_object_type + t.integer :pool_id + t.integer :lock_version, :default => 0 + + t.timestamps + end + end + + def self.down + drop_table :permissions + end +end diff --git a/src/db/migrate/20091019215838_create_base_portal_objects.rb b/src/db/migrate/20091019215838_create_base_portal_objects.rb new file mode 100644 index 0000000..badea5d --- /dev/null +++ b/src/db/migrate/20091019215838_create_base_portal_objects.rb @@ -0,0 +1,14 @@ +class CreateBasePortalObjects < ActiveRecord::Migration + def self.up + create_table :base_portal_objects do |t| + t.string :name, :null => false + t.timestamps + end + + BasePortalObject.new({:name => "general_permission_scope"}).save! + end + + def self.down + drop_table :base_portal_objects + end +end diff --git a/src/test/fixtures/base_portal_objects.yml b/src/test/fixtures/base_portal_objects.yml new file mode 100644 index 0000000..5bf0293 --- /dev/null +++ b/src/test/fixtures/base_portal_objects.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +# one: +# column: value +# +# two: +# column: value diff --git a/src/test/fixtures/permissions.yml b/src/test/fixtures/permissions.yml new file mode 100644 index 0000000..5bf0293 --- /dev/null +++ b/src/test/fixtures/permissions.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +# one: +# column: value +# +# two: +# column: value diff --git a/src/test/fixtures/privileges.yml b/src/test/fixtures/privileges.yml new file mode 100644 index 0000000..5bf0293 --- /dev/null +++ b/src/test/fixtures/privileges.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +# one: +# column: value +# +# two: +# column: value diff --git a/src/test/fixtures/roles.yml b/src/test/fixtures/roles.yml new file mode 100644 index 0000000..5bf0293 --- /dev/null +++ b/src/test/fixtures/roles.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +# one: +# column: value +# +# two: +# column: value diff --git a/src/test/unit/base_portal_object_test.rb b/src/test/unit/base_portal_object_test.rb new file mode 100644 index 0000000..e6e4b9d --- /dev/null +++ b/src/test/unit/base_portal_object_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class BasePortalObjectTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end diff --git a/src/test/unit/permission_test.rb b/src/test/unit/permission_test.rb new file mode 100644 index 0000000..08fcc0b --- /dev/null +++ b/src/test/unit/permission_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class PermissionTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end diff --git a/src/test/unit/privilege_test.rb b/src/test/unit/privilege_test.rb new file mode 100644 index 0000000..459d805 --- /dev/null +++ b/src/test/unit/privilege_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class PrivilegeTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end diff --git a/src/test/unit/role_test.rb b/src/test/unit/role_test.rb new file mode 100644 index 0000000..b0374ce --- /dev/null +++ b/src/test/unit/role_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class RoleTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end
deltacloud-devel@lists.fedorahosted.org