cjbottaro-aegis 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. data/.gitignore +3 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +182 -0
  4. data/Rakefile +37 -0
  5. data/VERSION +1 -0
  6. data/aegis.gemspec +117 -0
  7. data/lib/aegis.rb +11 -0
  8. data/lib/aegis/constants.rb +6 -0
  9. data/lib/aegis/has_role.rb +156 -0
  10. data/lib/aegis/meta_class.rb +13 -0
  11. data/lib/aegis/normalization.rb +26 -0
  12. data/lib/aegis/permission_error.rb +5 -0
  13. data/lib/aegis/permission_evaluator.rb +41 -0
  14. data/lib/aegis/permissions.rb +108 -0
  15. data/lib/aegis/role.rb +57 -0
  16. data/lib/aegis/role_assignments.rb +10 -0
  17. data/lib/rails/active_record.rb +5 -0
  18. data/test/app_root/app/controllers/application_controller.rb +2 -0
  19. data/test/app_root/app/models/account.rb +3 -0
  20. data/test/app_root/app/models/forum.rb +8 -0
  21. data/test/app_root/app/models/permissions.rb +70 -0
  22. data/test/app_root/app/models/post.rb +7 -0
  23. data/test/app_root/app/models/soldier.rb +5 -0
  24. data/test/app_root/app/models/user.rb +7 -0
  25. data/test/app_root/config/boot.rb +114 -0
  26. data/test/app_root/config/database.yml +21 -0
  27. data/test/app_root/config/environment.rb +14 -0
  28. data/test/app_root/config/environments/in_memory.rb +0 -0
  29. data/test/app_root/config/environments/mysql.rb +0 -0
  30. data/test/app_root/config/environments/postgresql.rb +0 -0
  31. data/test/app_root/config/environments/sqlite.rb +0 -0
  32. data/test/app_root/config/environments/sqlite3.rb +0 -0
  33. data/test/app_root/config/routes.rb +4 -0
  34. data/test/app_root/db/migrate/20090408115228_create_users.rb +15 -0
  35. data/test/app_root/db/migrate/20090429075648_create_soldiers.rb +16 -0
  36. data/test/app_root/db/migrate/20090903234709_create_role_assignments.rb +16 -0
  37. data/test/app_root/db/migrate/20090903234759_create_accounts.rb +11 -0
  38. data/test/app_root/db/migrate/20090903234821_create_forums.rb +12 -0
  39. data/test/app_root/db/migrate/20090903234828_create_posts.rb +12 -0
  40. data/test/app_root/lib/console_with_fixtures.rb +4 -0
  41. data/test/app_root/log/.gitignore +1 -0
  42. data/test/app_root/script/console +7 -0
  43. data/test/fixtures/accounts.yml +5 -0
  44. data/test/fixtures/forums.yml +11 -0
  45. data/test/fixtures/posts.yml +23 -0
  46. data/test/fixtures/role_assignments.yml +0 -0
  47. data/test/fixtures/users.yml +2 -0
  48. data/test/has_role_options_test.rb +33 -0
  49. data/test/has_role_test.rb +88 -0
  50. data/test/permissions_test.rb +117 -0
  51. data/test/test_helper.rb +44 -0
  52. data/test/validation_test.rb +49 -0
  53. metadata +130 -0
@@ -0,0 +1,21 @@
1
+ in_memory:
2
+ adapter: sqlite3
3
+ database: ":memory:"
4
+ verbosity: quiet
5
+ sqlite:
6
+ adapter: sqlite
7
+ dbfile: plugin_test.sqlite.db
8
+ sqlite3:
9
+ adapter: sqlite3
10
+ dbfile: plugin_test.sqlite3.db
11
+ postgresql:
12
+ adapter: postgresql
13
+ username: postgres
14
+ password: postgres
15
+ database: plugin_test
16
+ mysql:
17
+ adapter: mysql
18
+ host: localhost
19
+ username: root
20
+ password:
21
+ database: plugin_test
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), 'boot')
2
+
3
+ Rails::Initializer.run do |config|
4
+ config.cache_classes = false
5
+ config.whiny_nils = true
6
+ config.action_controller.session = { :key => "_myapp_session", :secret => "gwirofjweroijger8924rt2zfwehfuiwehb1378rifowenfoqwphf23" }
7
+ config.plugin_locators.unshift(
8
+ Class.new(Rails::Plugin::Locator) do
9
+ def plugins
10
+ [Rails::Plugin.new(File.expand_path('.'))]
11
+ end
12
+ end
13
+ ) unless defined?(PluginTestHelper::PluginLocator)
14
+ end
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,4 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.connect ':controller/:action/:id'
3
+ map.connect ':controller/:action/:id.:format'
4
+ end
@@ -0,0 +1,15 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ create_table :users do |t|
5
+ t.string "role_name"
6
+ t.boolean "is_admin", :null => false, :default => false
7
+ t.timestamps
8
+ end
9
+ end
10
+
11
+ def self.down
12
+ drop_table :users
13
+ end
14
+
15
+ end
@@ -0,0 +1,16 @@
1
+ class CreateSoldiers < ActiveRecord::Migration
2
+
3
+ def self.up
4
+
5
+ create_table :soldiers do |t|
6
+ t.string :rank
7
+ t.timestamps
8
+ end
9
+
10
+ end
11
+
12
+ def self.down
13
+ drop_table :soldiers
14
+ end
15
+
16
+ end
@@ -0,0 +1,16 @@
1
+ class CreateRoleAssignments < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :role_assignments do |t|
4
+ t.string :actor_type, :null => false
5
+ t.integer :actor_id, :null => false
6
+ t.string :role_name, :null => false
7
+ t.string :context_type, :null => false
8
+ t.integer :context_id, :null => false
9
+ t.timestamps
10
+ end
11
+ end
12
+
13
+ def self.down
14
+ drop_table :role_assignments
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ class CreateAccounts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :accounts do |t|
4
+ t.string :name, :null => false
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :accounts
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ class CreateForums < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :forums do |t|
4
+ t.integer :account_id, :null => false
5
+ t.string :name, :null => false
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :forums
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ class CreatePosts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :posts do |t|
4
+ t.integer :forum_id, :null => false
5
+ t.string :title, :null => false
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :posts
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ # Loads fixtures into the database when running the test app via the console
2
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(Rails.root, '../fixtures/*.{yml,csv}'))).each do |fixture_file|
3
+ Fixtures.create_fixtures(File.join(Rails.root, '../fixtures'), File.basename(fixture_file, '.*'))
4
+ end
@@ -0,0 +1 @@
1
+ *.log
@@ -0,0 +1,7 @@
1
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
2
+ libs = " -r irb/completion"
3
+ libs << " -r test/test_helper"
4
+ libs << " -r console_app"
5
+ libs << " -r console_with_helpers"
6
+ libs << " -r console_with_fixtures"
7
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,5 @@
1
+ google:
2
+ name: google.com
3
+
4
+ yahoo:
5
+ name: yahoo.com
@@ -0,0 +1,11 @@
1
+ searching:
2
+ account: google
3
+ name: searching
4
+
5
+ crawling:
6
+ account: google
7
+ name: crawling
8
+
9
+ advertising:
10
+ account: google
11
+ name: advertising
@@ -0,0 +1,23 @@
1
+ searching101:
2
+ forum: searching
3
+ title: searching101
4
+
5
+ searching102:
6
+ forum: searching
7
+ title: searching102
8
+
9
+ crawling101:
10
+ forum: crawling
11
+ title: crawling101
12
+
13
+ crawling102:
14
+ forum: crawling
15
+ title: crawling102
16
+
17
+ advertising101:
18
+ forum: advertising
19
+ title: advertising101
20
+
21
+ advertising102:
22
+ forum: advertising
23
+ title: advertising102
File without changes
@@ -0,0 +1,2 @@
1
+ with_hierarchy:
2
+ role_name: guest
@@ -0,0 +1,33 @@
1
+ require "test/test_helper"
2
+
3
+ class HasRoleOptionsTest < ActiveSupport::TestCase
4
+
5
+ context "A record with a custom role field" do
6
+
7
+ setup do
8
+ @soldier = Soldier.new
9
+ end
10
+
11
+ should "allow its role to be written and read" do
12
+ @soldier.role = "guest"
13
+ assert "guest", @soldier.role.name
14
+ end
15
+
16
+ should "store the role name in the custom field" do
17
+ assert "guest", @soldier.rank
18
+ end
19
+
20
+ should "still work with permissions" do
21
+ @soldier.role = "guest"
22
+ assert @soldier.may_hug?
23
+ assert !@soldier.may_update_users?
24
+ end
25
+
26
+ end
27
+
28
+ def test_setting_hierarchy
29
+ assert_equal "forum", User.aegis_role_hierarchy["Post"]
30
+ assert_equal "account", User.aegis_role_hierarchy["Forum"]
31
+ end
32
+
33
+ end
@@ -0,0 +1,88 @@
1
+ require "test/test_helper"
2
+
3
+ class HasRoleTest < ActiveSupport::TestCase
4
+
5
+ context "Objects that have an aegis role" do
6
+
7
+ setup do
8
+ @guest = User.new(:role_name => "guest")
9
+ @student = User.new(:role_name => "student")
10
+ @admin = User.new(:role_name => "admin")
11
+ end
12
+
13
+ should "know their role" do
14
+ assert :guest, @guest.role.name
15
+ assert :student, @student.role.name
16
+ assert :admin, @admin.role.name
17
+ end
18
+
19
+ should "know if they belong to a role" do
20
+ assert @guest.guest?
21
+ assert !@guest.student?
22
+ assert !@guest.admin?
23
+ assert !@student.guest?
24
+ assert @student.student?
25
+ assert !@student.admin?
26
+ assert !@admin.guest?
27
+ assert !@admin.student?
28
+ assert @admin.admin?
29
+ end
30
+
31
+ should "still behave as usual when a method ending in a '?' does not map to a role query" do
32
+ assert_raise NoMethodError do
33
+ @guest.nonexisting_method?
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ def test_role_in
40
+ create_role_assignments
41
+ user = users(:with_hierarchy)
42
+ do_test_role_in(user)
43
+ end
44
+
45
+ def test_role_in_using_hierarchy_accessor
46
+ create_role_assignments
47
+ saved_role_heirarchy = User.aegis_role_hierarchy
48
+
49
+ assert_not_nil User.aegis_role_hierarchy
50
+ User.instance_variable_set("@aegis_role_hierarchy", nil)
51
+ assert_nil User.aegis_role_hierarchy
52
+
53
+ User.instance_variable_set("@aegis_role_hierarchy_accessor", "parent")
54
+ assert_equal "parent", User.aegis_role_hierarchy_accessor
55
+
56
+ do_test_role_in(users(:with_hierarchy))
57
+
58
+ # So the rest of the tests don't break.
59
+ User.instance_variable_set("@aegis_role_hierarchy", saved_role_heirarchy)
60
+ User.instance_variable_set("@aegis_role_hierarchy_accessor", nil)
61
+ end
62
+
63
+ def test_forced_role
64
+ create_role_assignments
65
+ user = users(:with_hierarchy)
66
+ user.update_attribute(:is_admin, true)
67
+ assert_equal "superuser", user.role
68
+ assert_equal "superuser", user.role_in(accounts(:google))
69
+ assert_equal "superuser", user.role_in(forums(:searching))
70
+ assert_equal "superuser", user.role_in(posts(:searching101))
71
+ assert_equal "superuser", user.role_in(posts(:searching102))
72
+ end
73
+
74
+ private
75
+
76
+ def do_test_role_in(user)
77
+ assert_equal :admin, user.role_in(accounts(:google)).name
78
+
79
+ assert_equal :writer, user.role_in(forums(:searching)).name
80
+ assert_equal :writer, user.role_in(posts(:searching101)).name
81
+ assert_equal :reader, user.role_in(posts(:searching102)).name
82
+
83
+ assert_equal :admin, user.role_in(forums(:crawling)).name
84
+ assert_equal :admin, user.role_in(posts(:crawling101)).name
85
+ assert_equal :admin, user.role_in(posts(:crawling102)).name
86
+ end
87
+
88
+ end
@@ -0,0 +1,117 @@
1
+ require "test/test_helper"
2
+
3
+ class PermissionsTest < ActiveSupport::TestCase
4
+
5
+ context "Aegis permissions" do
6
+
7
+ setup do
8
+ @guest = User.new(:role_name => "guest")
9
+ @student = User.new(:role_name => "student")
10
+ @admin = User.new(:role_name => "admin")
11
+ end
12
+
13
+ should "use the default permission for actions without any allow or grant directives" do
14
+ assert !@guest.may_use_empty?
15
+ assert !@student.may_use_empty?
16
+ assert @admin.may_use_empty?
17
+ end
18
+
19
+ should "understand simple allow and deny directives" do
20
+ assert !@guest.may_use_simple?
21
+ assert @student.may_use_simple?
22
+ assert !@admin.may_use_simple?
23
+ end
24
+
25
+ should 'raise exceptions when a denied action is queried with an exclamation mark' do
26
+ assert_raise Aegis::PermissionError do
27
+ @guest.may_use_simple!
28
+ end
29
+ assert_raise Aegis::PermissionError do
30
+ @admin.may_use_simple!
31
+ end
32
+ end
33
+
34
+ should 'do nothing if an allowed action is queried with an exclamation mark' do
35
+ assert_nothing_raised do
36
+ @student.may_use_simple!
37
+ end
38
+ end
39
+
40
+ should "implicate the singular form of an action described in plural form" do
41
+ assert !@guest.may_update_users?
42
+ assert !@guest.may_update_user?("foo")
43
+ assert @student.may_update_users?
44
+ assert @student.may_update_user?("foo")
45
+ assert !@admin.may_update_users?
46
+ assert !@admin.may_update_user?("foo")
47
+ end
48
+
49
+ should 'implicate create, read, update and destroy forms for actions named "crud_..."' do
50
+ assert @student.may_create_projects?
51
+ assert @student.may_read_projects?
52
+ assert @student.may_update_projects?
53
+ assert @student.may_destroy_projects?
54
+ end
55
+
56
+ should 'perform normalization of CRUD verbs (e.g. "edit" and "update")' do
57
+ assert !@guest.may_edit_drinks?
58
+ assert @student.may_edit_drinks?
59
+ assert !@admin.may_edit_drinks?
60
+ assert !@guest.may_update_drinks?
61
+ assert @student.may_update_drinks?
62
+ assert !@admin.may_update_drinks?
63
+ end
64
+
65
+ should "be able to grant or deny actions to all roles using :everyone" do
66
+ assert @guest.may_hug?
67
+ assert @student.may_hug?
68
+ assert @admin.may_hug?
69
+ end
70
+
71
+ should "allow the definition of parametrized actions" do
72
+ assert !@guest.may_divide?(10, 2)
73
+ assert @student.may_divide?(10, 2)
74
+ assert !@student.may_divide?(10, 0)
75
+ assert @admin.may_divide?(10, 2)
76
+ assert @admin.may_divide?(10, 0)
77
+ end
78
+
79
+ should 'use default permissions for undefined actions' do
80
+ !@student.may_do_undefined_stuff?("foo")
81
+ @admin.may_do_undefined_stuff?("foo")
82
+ end
83
+
84
+ should 'overshadow previous action definitions with the same name' do
85
+ assert @guest.may_draw?
86
+ assert !@student.may_draw?
87
+ assert !@admin.may_draw?
88
+ end
89
+
90
+ end
91
+
92
+ def test_hierarchical_permissions
93
+ create_role_assignments
94
+ user = users(:with_hierarchy)
95
+
96
+ assert user.may_edit_post_in?(posts(:searching101))
97
+ assert !user.may_edit_post_in?(posts(:searching102))
98
+
99
+ assert user.may_view_post_in?(posts(:searching101))
100
+ assert user.may_view_post_in?(posts(:searching102))
101
+
102
+ assert user.may_create_post_in?(forums(:searching))
103
+ assert user.may_create_post_in?(forums(:crawling))
104
+
105
+ assert user.may_create_forum_in?(accounts(:google))
106
+ assert !user.may_create_forum_in?(accounts(:yahoo))
107
+ end
108
+
109
+ def test_invalid_permission_context
110
+ create_role_assignments
111
+ user = users(:with_hierarchy)
112
+
113
+ assert_nothing_raised{ user.may_create_post_in?(forums(:searching)) }
114
+ assert_raise(Aegis::PermissionError){ user.may_create_post_in?(posts(:searching101)) }
115
+ end
116
+
117
+ end