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(a)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(a)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 90d9b2b..c55e3e1 100644
--- a/src/app/models/cloud_account.rb
+++ b/src/app/models/cloud_account.rb
@@ -14,6 +14,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(a)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 a8df0d5..0e2b036 100644
--- a/src/app/models/portal_pool.rb
+++ b/src/app/models/portal_pool.rb
@@ -9,6 +9,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(a)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 5b6fb2e..f770d9f 100644
--- a/src/app/models/provider.rb
+++ b/src/app/models/provider.rb
@@ -13,6 +13,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(a)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(a)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(a)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(a)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
--
1.6.2.5