zuul 0.1.1 → 0.2.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 (80) hide show
  1. data/lib/generators/zuul/orm_helpers.rb +21 -0
  2. data/lib/generators/zuul/permission_generator.rb +57 -0
  3. data/lib/generators/zuul/permission_role_generator.rb +40 -0
  4. data/lib/generators/zuul/permission_subject_generator.rb +40 -0
  5. data/lib/generators/zuul/role_generator.rb +58 -0
  6. data/lib/generators/zuul/role_subject_generator.rb +40 -0
  7. data/lib/generators/zuul/subject_generator.rb +39 -0
  8. data/lib/generators/zuul/templates/permission.rb +18 -0
  9. data/lib/generators/zuul/templates/permission_existing.rb +25 -0
  10. data/lib/generators/zuul/templates/permission_role.rb +17 -0
  11. data/lib/generators/zuul/templates/permission_role_existing.rb +24 -0
  12. data/lib/generators/zuul/templates/permission_subject.rb +17 -0
  13. data/lib/generators/zuul/templates/permission_subject_existing.rb +24 -0
  14. data/lib/generators/zuul/templates/role.rb +20 -0
  15. data/lib/generators/zuul/templates/role_existing.rb +27 -0
  16. data/lib/generators/zuul/templates/role_subject.rb +17 -0
  17. data/lib/generators/zuul/templates/role_subject_existing.rb +24 -0
  18. data/lib/tasks/zuul.rake +56 -0
  19. data/lib/zuul.rb +14 -5
  20. data/lib/zuul/action_controller.rb +108 -0
  21. data/lib/zuul/action_controller/dsl.rb +384 -0
  22. data/lib/zuul/action_controller/evaluators.rb +60 -0
  23. data/lib/zuul/active_record.rb +338 -0
  24. data/lib/zuul/active_record/context.rb +38 -0
  25. data/lib/zuul/active_record/permission.rb +31 -0
  26. data/lib/zuul/active_record/permission_role.rb +29 -0
  27. data/lib/zuul/active_record/permission_subject.rb +29 -0
  28. data/lib/zuul/active_record/role.rb +117 -0
  29. data/lib/zuul/active_record/role_subject.rb +29 -0
  30. data/lib/zuul/active_record/scope.rb +71 -0
  31. data/lib/zuul/active_record/subject.rb +239 -0
  32. data/lib/zuul/configuration.rb +149 -0
  33. data/lib/zuul/context.rb +53 -0
  34. data/lib/zuul/exceptions.rb +3 -0
  35. data/lib/zuul/exceptions/access_denied.rb +9 -0
  36. data/lib/zuul/exceptions/invalid_context.rb +9 -0
  37. data/lib/zuul/exceptions/undefined_scope.rb +9 -0
  38. data/lib/zuul/railtie.rb +5 -0
  39. data/lib/zuul/version.rb +3 -0
  40. data/lib/zuul_viz.rb +195 -0
  41. data/spec/db/schema.rb +172 -0
  42. data/spec/spec_helper.rb +25 -0
  43. data/spec/support/capture_stdout.rb +12 -0
  44. data/spec/support/models.rb +167 -0
  45. data/spec/zuul/active_record/context_spec.rb +55 -0
  46. data/spec/zuul/active_record/permission_role_spec.rb +84 -0
  47. data/spec/zuul/active_record/permission_spec.rb +174 -0
  48. data/spec/zuul/active_record/permission_subject_spec.rb +84 -0
  49. data/spec/zuul/active_record/role_spec.rb +694 -0
  50. data/spec/zuul/active_record/role_subject_spec.rb +84 -0
  51. data/spec/zuul/active_record/scope_spec.rb +75 -0
  52. data/spec/zuul/active_record/subject_spec.rb +1186 -0
  53. data/spec/zuul/active_record_spec.rb +624 -0
  54. data/spec/zuul/configuration_spec.rb +254 -0
  55. data/spec/zuul/context_spec.rb +128 -0
  56. data/spec/zuul_spec.rb +15 -0
  57. metadata +181 -70
  58. data/.document +0 -5
  59. data/.gitignore +0 -23
  60. data/LICENSE +0 -20
  61. data/README.rdoc +0 -65
  62. data/Rakefile +0 -54
  63. data/VERSION +0 -1
  64. data/lib/zuul/restrict_access.rb +0 -104
  65. data/lib/zuul/valid_roles.rb +0 -37
  66. data/spec/rails_root/app/controllers/application_controller.rb +0 -2
  67. data/spec/rails_root/app/models/user.rb +0 -8
  68. data/spec/rails_root/config/boot.rb +0 -110
  69. data/spec/rails_root/config/database.yml +0 -5
  70. data/spec/rails_root/config/environment.rb +0 -7
  71. data/spec/rails_root/config/environments/test.rb +0 -7
  72. data/spec/rails_root/config/initializers/session_store.rb +0 -15
  73. data/spec/rails_root/config/routes.rb +0 -4
  74. data/spec/rails_root/db/test.sqlite3 +0 -0
  75. data/spec/rails_root/log/test.log +0 -5388
  76. data/spec/rails_root/spec/controllers/require_user_spec.rb +0 -138
  77. data/spec/rails_root/spec/controllers/restrict_access_spec.rb +0 -64
  78. data/spec/rails_root/spec/models/user_spec.rb +0 -37
  79. data/spec/rails_root/spec/spec_helper.rb +0 -34
  80. data/zuul.gemspec +0 -78
data/spec/db/schema.rb ADDED
@@ -0,0 +1,172 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :dummies do |t|
3
+ end
4
+
5
+ create_table :users do |t|
6
+ t.string :name
7
+ end
8
+
9
+ create_table :roles do |t|
10
+ t.string :name
11
+ t.string :slug
12
+ t.integer :level
13
+ t.string :context_type
14
+ t.integer :context_id
15
+ end
16
+
17
+ create_table :permissions do |t|
18
+ t.string :name
19
+ t.string :slug
20
+ t.string :context_type
21
+ t.integer :context_id
22
+ end
23
+
24
+ create_table :role_users do |t|
25
+ t.integer :user_id
26
+ t.integer :role_id
27
+ t.string :context_type
28
+ t.integer :context_id
29
+ end
30
+
31
+ create_table :permission_users do |t|
32
+ t.integer :user_id
33
+ t.integer :permission_id
34
+ t.string :context_type
35
+ t.integer :context_id
36
+ end
37
+
38
+ create_table :permission_roles do |t|
39
+ t.integer :role_id
40
+ t.integer :permission_id
41
+ t.string :context_type
42
+ t.integer :context_id
43
+ end
44
+
45
+ create_table :contexts do |t|
46
+ t.string :name
47
+ end
48
+
49
+ create_table :levels do |t|
50
+ t.string :name
51
+ t.string :slug
52
+ t.integer :level
53
+ t.string :context_type
54
+ t.integer :context_id
55
+ end
56
+
57
+ create_table :abilities do |t|
58
+ t.string :name
59
+ t.string :slug
60
+ t.string :context_type
61
+ t.integer :context_id
62
+ end
63
+
64
+ create_table :level_users do |t|
65
+ t.integer :user_id
66
+ t.integer :level_id
67
+ t.string :context_type
68
+ t.integer :context_id
69
+ end
70
+
71
+ create_table :ability_users do |t|
72
+ t.integer :user_id
73
+ t.integer :ability_id
74
+ t.string :context_type
75
+ t.integer :context_id
76
+ end
77
+
78
+ create_table :ability_levels do |t|
79
+ t.integer :level_id
80
+ t.integer :ability_id
81
+ t.string :context_type
82
+ t.integer :context_id
83
+ end
84
+
85
+ create_table :soldiers do |t|
86
+ t.string :name
87
+ end
88
+
89
+ create_table :ranks do |t|
90
+ t.string :name
91
+ t.string :slug
92
+ t.integer :level
93
+ t.string :context_type
94
+ t.integer :context_id
95
+ end
96
+
97
+ create_table :skills do |t|
98
+ t.string :name
99
+ t.string :slug
100
+ t.string :context_type
101
+ t.integer :context_id
102
+ end
103
+
104
+ create_table :rank_soldiers do |t|
105
+ t.integer :soldier_id
106
+ t.integer :rank_id
107
+ t.string :context_type
108
+ t.integer :context_id
109
+ end
110
+
111
+ create_table :skill_soldiers do |t|
112
+ t.integer :soldier_id
113
+ t.integer :skill_id
114
+ t.string :context_type
115
+ t.integer :context_id
116
+ end
117
+
118
+ create_table :rank_skills do |t|
119
+ t.integer :rank_id
120
+ t.integer :skill_id
121
+ t.string :context_type
122
+ t.integer :context_id
123
+ end
124
+
125
+ create_table :weapons do |t|
126
+ t.string :name
127
+ end
128
+
129
+ create_table :zuul_models_users do |t|
130
+ t.string :name
131
+ end
132
+
133
+ create_table :zuul_models_roles do |t|
134
+ t.string :name
135
+ t.string :slug
136
+ t.integer :level
137
+ t.string :context_type
138
+ t.integer :context_id
139
+ end
140
+
141
+ create_table :zuul_models_permissions do |t|
142
+ t.string :name
143
+ t.string :slug
144
+ t.string :context_type
145
+ t.integer :context_id
146
+ end
147
+
148
+ create_table :zuul_models_role_users do |t|
149
+ t.integer :user_id
150
+ t.integer :role_id
151
+ t.string :context_type
152
+ t.integer :context_id
153
+ end
154
+
155
+ create_table :zuul_models_permission_users do |t|
156
+ t.integer :user_id
157
+ t.integer :permission_id
158
+ t.string :context_type
159
+ t.integer :context_id
160
+ end
161
+
162
+ create_table :zuul_models_permission_roles do |t|
163
+ t.integer :role_id
164
+ t.integer :permission_id
165
+ t.string :context_type
166
+ t.integer :context_id
167
+ end
168
+
169
+ create_table :zuul_models_contexts do |t|
170
+ t.string :name
171
+ end
172
+ end
@@ -0,0 +1,25 @@
1
+ require 'active_support'
2
+ require 'active_record'
3
+ require 'action_controller'
4
+ require 'zuul'
5
+ require 'rspec'
6
+
7
+ Dir[File.join(File.dirname(__FILE__), '..', "spec/support/**/*.rb")].each { |f| require f }
8
+
9
+ RSpec.configure do |config|
10
+ config.before(:suite) do
11
+ ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
12
+ capture_stdout { load "db/schema.rb" }
13
+ end
14
+
15
+ config.before(:each) do
16
+ load 'support/models.rb'
17
+ end
18
+
19
+ config.around(:each) do |example|
20
+ ActiveRecord::Base.transaction do
21
+ example.run
22
+ raise ActiveRecord::Rollback
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ require 'stringio'
2
+
3
+ module Kernel
4
+ def capture_stdout
5
+ out = StringIO.new
6
+ $stdout = out
7
+ yield
8
+ return out
9
+ ensure
10
+ $stdout = STDOUT
11
+ end
12
+ end
@@ -0,0 +1,167 @@
1
+ # Default Subject, Role, Permission and Context models
2
+ Object.send(:remove_const, :User) if defined?(User) # we do this to undefine the model and start fresh, without any of the authorization stuff applied by tests
3
+ class User < ActiveRecord::Base
4
+ attr_accessible :name
5
+ end
6
+
7
+ Object.send(:remove_const, :Role) if defined?(Role)
8
+ class Role < ActiveRecord::Base
9
+ attr_accessible :name, :slug, :level, :context_type, :context_id
10
+ end
11
+
12
+ Object.send(:remove_const, :Permission) if defined?(Permission)
13
+ class Permission < ActiveRecord::Base
14
+ attr_accessible :name, :slug, :context_type, :context_id
15
+ end
16
+
17
+ Object.send(:remove_const, :Context) if defined?(Context)
18
+ class Context < ActiveRecord::Base
19
+ end
20
+
21
+ # Default association models
22
+ Object.send(:remove_const, :RoleUser) if defined?(RoleUser)
23
+ class RoleUser < ActiveRecord::Base
24
+ belongs_to :user
25
+ belongs_to :role
26
+ end
27
+
28
+ Object.send(:remove_const, :SpecialRoleUser) if defined?(SpecialRoleUser)
29
+ class SpecialRoleUser < ActiveRecord::Base
30
+ belongs_to :user
31
+ belongs_to :role
32
+ end
33
+
34
+ Object.send(:remove_const, :PermissionUser) if defined?(PermissionUser)
35
+ class PermissionUser < ActiveRecord::Base
36
+ belongs_to :user
37
+ belongs_to :permission
38
+ end
39
+
40
+ Object.send(:remove_const, :PermissionRole) if defined?(PermissionRole)
41
+ class PermissionRole < ActiveRecord::Base
42
+ belongs_to :role
43
+ belongs_to :permission
44
+ end
45
+
46
+ # Additional models to test scoping
47
+ Object.send(:remove_const, :Level) if defined?(Level)
48
+ class Level < ActiveRecord::Base
49
+ attr_accessible :name, :slug, :level, :context_type, :context_id
50
+ end
51
+
52
+ Object.send(:remove_const, :Ability) if defined?(Ability)
53
+ class Ability < ActiveRecord::Base
54
+ attr_accessible :name, :slug, :context_type, :context_id
55
+ end
56
+
57
+ Object.send(:remove_const, :AbilityLevel) if defined?(AbilityLevel)
58
+ class AbilityLevel < ActiveRecord::Base
59
+ belongs_to :ability
60
+ belongs_to :level
61
+ end
62
+
63
+ Object.send(:remove_const, :AbilityUser) if defined?(AbilityUser)
64
+ class AbilityUser < ActiveRecord::Base
65
+ belongs_to :ability
66
+ belongs_to :user
67
+ end
68
+
69
+ Object.send(:remove_const, :LevelUser) if defined?(LevelUser)
70
+ class LevelUser < ActiveRecord::Base
71
+ belongs_to :level
72
+ belongs_to :user
73
+ end
74
+
75
+
76
+ # Dummy model without any configuration for generic tests
77
+ Object.send(:remove_const, :Dummy) if defined?(Dummy)
78
+ class Dummy < ActiveRecord::Base
79
+ end
80
+
81
+ # Custom named Subject, Role, Permission and Context models
82
+ Object.send(:remove_const, :Soldier) if defined?(Soldier)
83
+ class Soldier < ActiveRecord::Base
84
+ attr_accessible :name
85
+ end
86
+
87
+ Object.send(:remove_const, :Rank) if defined?(Rank)
88
+ class Rank < ActiveRecord::Base
89
+ attr_accessible :name, :slug, :level, :context_type, :context_id
90
+ end
91
+
92
+ Object.send(:remove_const, :Skill) if defined?(Skill)
93
+ class Skill < ActiveRecord::Base
94
+ attr_accessible :name, :slug, :context_type, :context_id
95
+ end
96
+
97
+ Object.send(:remove_const, :Weapon) if defined?(Weapon)
98
+ class Weapon < ActiveRecord::Base
99
+ end
100
+
101
+ Object.send(:remove_const, :RankSoldier) if defined?(RankSoldier)
102
+ class RankSoldier < ActiveRecord::Base
103
+ belongs_to :soldier
104
+ belongs_to :rank
105
+ end
106
+
107
+ Object.send(:remove_const, :SkillSoldier) if defined?(SkillSoldier)
108
+ class SkillSoldier < ActiveRecord::Base
109
+ belongs_to :soldier
110
+ belongs_to :skill
111
+ end
112
+
113
+ Object.send(:remove_const, :CustomSkillSoldier) if defined?(CustomSkillSoldier)
114
+ class CustomSkillSoldier < ActiveRecord::Base
115
+ belongs_to :soldier
116
+ belongs_to :skill
117
+ end
118
+
119
+ Object.send(:remove_const, :RankSkill) if defined?(RankSkill)
120
+ class RankSkill < ActiveRecord::Base
121
+ belongs_to :rank
122
+ belongs_to :skill
123
+ end
124
+
125
+ # Namespaced Subject, Role, Permission and Context models
126
+ module ZuulModels
127
+ def self.table_name_prefix
128
+ 'zuul_models_'
129
+ end
130
+
131
+ send(:remove_const, :User) if defined?(ZuulModels::User)
132
+ class User < ActiveRecord::Base
133
+ attr_accessible :name
134
+ end
135
+
136
+ send(:remove_const, :Role) if defined?(ZuulModels::Role)
137
+ class Role < ActiveRecord::Base
138
+ attr_accessible :name, :slug, :level, :context_type, :context_id
139
+ end
140
+
141
+ send(:remove_const, :Permission) if defined?(ZuulModels::Permission)
142
+ class Permission < ActiveRecord::Base
143
+ attr_accessible :name, :slug, :context_type, :context_id
144
+ end
145
+
146
+ send(:remove_const, :Context) if defined?(ZuulModels::Context)
147
+ class Context < ActiveRecord::Base
148
+ end
149
+
150
+ send(:remove_const, :RoleUser) if defined?(ZuulModels::RoleUser)
151
+ class RoleUser < ActiveRecord::Base
152
+ belongs_to :user
153
+ belongs_to :role
154
+ end
155
+
156
+ send(:remove_const, :PermissionUser) if defined?(ZuulModels::PermissionUser)
157
+ class PermissionUser < ActiveRecord::Base
158
+ belongs_to :user
159
+ belongs_to :permission
160
+ end
161
+
162
+ send(:remove_const, :PermissionRole) if defined?(ZuulModels::PermissionRole)
163
+ class PermissionRole < ActiveRecord::Base
164
+ belongs_to :role
165
+ belongs_to :permission
166
+ end
167
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Zuul::ActiveRecord::Context" do
4
+ before(:each) do
5
+ User.acts_as_authorization_subject
6
+ Role.acts_as_authorization_role
7
+ Permission.acts_as_authorization_permission
8
+ Context.acts_as_authorization_context
9
+ end
10
+
11
+ describe "allowed?" do
12
+ it "should require a subject and a role object or slug" do
13
+ context = Context.create(:name => "Test Context")
14
+ user = User.create(:name => "Test User")
15
+ expect { context.allowed? }.to raise_exception
16
+ expect { context.allowed?(user) }.to raise_exception
17
+ end
18
+
19
+ it "should wrap Subect#has_role?" do
20
+ context = Context.create(:name => "Test Context")
21
+ user = User.create(:name => "Test User")
22
+ role = Role.create(:name => "Admin", :slug => "admin", :level => 100)
23
+ context.allowed?(user, role).should be_false
24
+ context.allowed?(user, role).should == user.has_role?(role, context)
25
+ user.assign_role(role, context)
26
+ context.allowed?(user, role).should be_true
27
+ context.allowed?(user, role).should == user.has_role?(role, context)
28
+ end
29
+ end
30
+
31
+ describe "allowed_to?" do
32
+ it "should not be available if permissions are disabled" do
33
+ Weapon.acts_as_authorization_context :with_permissions => false
34
+ Weapon.new.should_not respond_to(:allowed_to?)
35
+ end
36
+
37
+ it "should require a subject and a permission object or slug" do
38
+ context = Context.create(:name => "Test Context")
39
+ user = User.create(:name => "Test User")
40
+ expect { context.allowed_to? }.to raise_exception
41
+ expect { context.allowed_to?(user) }.to raise_exception
42
+ end
43
+
44
+ it "should wrap Subect#has_permission?" do
45
+ context = Context.create(:name => "Test Context")
46
+ user = User.create(:name => "Test User")
47
+ permission = Permission.create(:name => "Edit", :slug => "edit")
48
+ context.allowed_to?(user, permission).should be_false
49
+ context.allowed_to?(user, permission).should == user.has_permission?(permission, context)
50
+ user.assign_permission(permission, context)
51
+ context.allowed_to?(user, permission).should be_true
52
+ context.allowed_to?(user, permission).should == user.has_permission?(permission, context)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Zuul::ActiveRecord::PermissionRole" do
4
+ before(:each) do
5
+ Permission.acts_as_authorization_permission
6
+ end
7
+
8
+ describe "accessible attributes" do
9
+ it "should allow mass assignment of permission class foreign key" do
10
+ pu = PermissionRole.new(:permission_id => 1)
11
+ pu.permission_id.should == 1
12
+ end
13
+
14
+ it "should allow mass assignment of role class foreign key" do
15
+ pu = PermissionRole.new(:role_id => 1)
16
+ pu.role_id.should == 1
17
+ end
18
+
19
+ it "should allow mass assignment of :context" do
20
+ context = Context.create(:name => "Test Context")
21
+ pu = PermissionRole.new(:context => context)
22
+ pu.context_type.should == 'Context'
23
+ pu.context_id.should == context.id
24
+ end
25
+
26
+ it "should allow mass assignment of :context_type" do
27
+ pu = PermissionRole.new(:context_type => 'Context')
28
+ pu.context_type.should == 'Context'
29
+ end
30
+
31
+ it "should allow mass assignment of :context_id" do
32
+ pu = PermissionRole.new(:context_id => 1)
33
+ pu.context_id.should == 1
34
+ end
35
+ end
36
+
37
+ context "validations for core permission fields" do
38
+ it "should validate presence of permission class foreign key" do
39
+ pu = PermissionRole.new()
40
+ pu.valid?.should be_false
41
+ pu.errors.keys.should include(:permission_id)
42
+ end
43
+
44
+ it "should validate presence of role class foreign key" do
45
+ pu = PermissionRole.new()
46
+ pu.valid?.should be_false
47
+ pu.errors.keys.should include(:role_id)
48
+ end
49
+
50
+ it "should validate uniqueness of permission class foreign key scoped to context_type, context_id and the role class foreign key" do
51
+ PermissionRole.create(:permission_id => 1, :role_id => 1)
52
+ pu = PermissionRole.create(:permission_id => 1, :role_id => 1)
53
+ pu.valid?.should be_false
54
+ pu.errors.keys.should include(:permission_id)
55
+
56
+ PermissionRole.create(:permission_id => 1, :role_id => 1, :context_type => 'Context').valid?.should be_true
57
+ pu = PermissionRole.create(:permission_id => 1, :role_id => 1, :context_type => 'Context')
58
+ pu.valid?.should be_false
59
+ pu.errors.keys.should include(:permission_id)
60
+
61
+ PermissionRole.create(:permission_id => 1, :role_id => 1, :context_type => 'Context', :context_id => 1).valid?.should be_true
62
+ pu = PermissionRole.create(:permission_id => 1, :role_id => 1, :context_type => 'Context', :context_id => 1)
63
+ pu.valid?.should be_false
64
+ pu.errors.keys.should include(:permission_id)
65
+ end
66
+
67
+ it "should validate numericality of permission class foreign key with integers only" do
68
+ pu = PermissionRole.new(:permission_id => 'a', :role_id => 1)
69
+ pu.valid?.should be_false
70
+ pu.errors.keys.should include(:permission_id)
71
+ pu.permission_id = 1.3
72
+ pu.valid?.should be_false
73
+ pu.errors.keys.should include(:permission_id)
74
+ end
75
+ end
76
+
77
+ it "should provide the model with belongs_to associations for permissions and roles" do
78
+ PermissionRole.reflections.keys.should include(:permission)
79
+ PermissionRole.reflections.keys.should include(:role)
80
+ pu = PermissionRole.create(:permission_id => 1, :use_id => 1)
81
+ pu.should respond_to(:permission)
82
+ pu.should respond_to(:role)
83
+ end
84
+ end