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.
- data/lib/generators/zuul/orm_helpers.rb +21 -0
- data/lib/generators/zuul/permission_generator.rb +57 -0
- data/lib/generators/zuul/permission_role_generator.rb +40 -0
- data/lib/generators/zuul/permission_subject_generator.rb +40 -0
- data/lib/generators/zuul/role_generator.rb +58 -0
- data/lib/generators/zuul/role_subject_generator.rb +40 -0
- data/lib/generators/zuul/subject_generator.rb +39 -0
- data/lib/generators/zuul/templates/permission.rb +18 -0
- data/lib/generators/zuul/templates/permission_existing.rb +25 -0
- data/lib/generators/zuul/templates/permission_role.rb +17 -0
- data/lib/generators/zuul/templates/permission_role_existing.rb +24 -0
- data/lib/generators/zuul/templates/permission_subject.rb +17 -0
- data/lib/generators/zuul/templates/permission_subject_existing.rb +24 -0
- data/lib/generators/zuul/templates/role.rb +20 -0
- data/lib/generators/zuul/templates/role_existing.rb +27 -0
- data/lib/generators/zuul/templates/role_subject.rb +17 -0
- data/lib/generators/zuul/templates/role_subject_existing.rb +24 -0
- data/lib/tasks/zuul.rake +56 -0
- data/lib/zuul.rb +14 -5
- data/lib/zuul/action_controller.rb +108 -0
- data/lib/zuul/action_controller/dsl.rb +384 -0
- data/lib/zuul/action_controller/evaluators.rb +60 -0
- data/lib/zuul/active_record.rb +338 -0
- data/lib/zuul/active_record/context.rb +38 -0
- data/lib/zuul/active_record/permission.rb +31 -0
- data/lib/zuul/active_record/permission_role.rb +29 -0
- data/lib/zuul/active_record/permission_subject.rb +29 -0
- data/lib/zuul/active_record/role.rb +117 -0
- data/lib/zuul/active_record/role_subject.rb +29 -0
- data/lib/zuul/active_record/scope.rb +71 -0
- data/lib/zuul/active_record/subject.rb +239 -0
- data/lib/zuul/configuration.rb +149 -0
- data/lib/zuul/context.rb +53 -0
- data/lib/zuul/exceptions.rb +3 -0
- data/lib/zuul/exceptions/access_denied.rb +9 -0
- data/lib/zuul/exceptions/invalid_context.rb +9 -0
- data/lib/zuul/exceptions/undefined_scope.rb +9 -0
- data/lib/zuul/railtie.rb +5 -0
- data/lib/zuul/version.rb +3 -0
- data/lib/zuul_viz.rb +195 -0
- data/spec/db/schema.rb +172 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/capture_stdout.rb +12 -0
- data/spec/support/models.rb +167 -0
- data/spec/zuul/active_record/context_spec.rb +55 -0
- data/spec/zuul/active_record/permission_role_spec.rb +84 -0
- data/spec/zuul/active_record/permission_spec.rb +174 -0
- data/spec/zuul/active_record/permission_subject_spec.rb +84 -0
- data/spec/zuul/active_record/role_spec.rb +694 -0
- data/spec/zuul/active_record/role_subject_spec.rb +84 -0
- data/spec/zuul/active_record/scope_spec.rb +75 -0
- data/spec/zuul/active_record/subject_spec.rb +1186 -0
- data/spec/zuul/active_record_spec.rb +624 -0
- data/spec/zuul/configuration_spec.rb +254 -0
- data/spec/zuul/context_spec.rb +128 -0
- data/spec/zuul_spec.rb +15 -0
- metadata +181 -70
- data/.document +0 -5
- data/.gitignore +0 -23
- data/LICENSE +0 -20
- data/README.rdoc +0 -65
- data/Rakefile +0 -54
- data/VERSION +0 -1
- data/lib/zuul/restrict_access.rb +0 -104
- data/lib/zuul/valid_roles.rb +0 -37
- data/spec/rails_root/app/controllers/application_controller.rb +0 -2
- data/spec/rails_root/app/models/user.rb +0 -8
- data/spec/rails_root/config/boot.rb +0 -110
- data/spec/rails_root/config/database.yml +0 -5
- data/spec/rails_root/config/environment.rb +0 -7
- data/spec/rails_root/config/environments/test.rb +0 -7
- data/spec/rails_root/config/initializers/session_store.rb +0 -15
- data/spec/rails_root/config/routes.rb +0 -4
- data/spec/rails_root/db/test.sqlite3 +0 -0
- data/spec/rails_root/log/test.log +0 -5388
- data/spec/rails_root/spec/controllers/require_user_spec.rb +0 -138
- data/spec/rails_root/spec/controllers/restrict_access_spec.rb +0 -64
- data/spec/rails_root/spec/models/user_spec.rb +0 -37
- data/spec/rails_root/spec/spec_helper.rb +0 -34
- data/zuul.gemspec +0 -78
@@ -0,0 +1,60 @@
|
|
1
|
+
module Zuul
|
2
|
+
module ActionController
|
3
|
+
module Evaluators
|
4
|
+
class ForTarget
|
5
|
+
def for_target(&block)
|
6
|
+
return self if @dsl.nil?
|
7
|
+
if match?
|
8
|
+
@controller.instance_eval do
|
9
|
+
yield
|
10
|
+
end if block_given?
|
11
|
+
end
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def else(&block)
|
16
|
+
return self if @dsl.nil?
|
17
|
+
if !match?
|
18
|
+
@controller.instance_eval do
|
19
|
+
yield
|
20
|
+
end if block_given?
|
21
|
+
end
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def else_for(target, context=nil, force_context=nil, &block)
|
26
|
+
return self.class.new(@controller, target, context, force_context, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def initialize(controller, target, context=nil, force_context=nil, &block)
|
32
|
+
@controller = controller
|
33
|
+
@dsl = @controller.acl_dsl
|
34
|
+
@target = target
|
35
|
+
@context = context
|
36
|
+
@force_context = force_context
|
37
|
+
for_target &block
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class ForRole < ForTarget
|
42
|
+
def match?
|
43
|
+
(@dsl.subject.nil? && @target == @dsl.logged_out) || (!@dsl.subject.nil? && (@target == @dsl.logged_in || @dsl.subject.has_role?(@target, @context, @force_context)))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class ForRoleOrHigher < ForTarget
|
48
|
+
def match?
|
49
|
+
(@dsl.subject.nil? && @target == @dsl.logged_out) || (!@dsl.subject.nil? && (@target == @dsl.logged_in || @dsl.subject.has_role_or_higher?(@target, @context, @force_context)))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class ForPermission < ForTarget
|
54
|
+
def match?
|
55
|
+
!@dsl.subject.nil? && @dsl.subject.has_permission?(@target, @context, @force_context)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,338 @@
|
|
1
|
+
require 'zuul/active_record/scope'
|
2
|
+
require 'zuul/active_record/role'
|
3
|
+
require 'zuul/active_record/permission'
|
4
|
+
require 'zuul/active_record/context'
|
5
|
+
require 'zuul/active_record/subject'
|
6
|
+
require 'zuul/active_record/role_subject'
|
7
|
+
require 'zuul/active_record/permission_role'
|
8
|
+
require 'zuul/active_record/permission_subject'
|
9
|
+
|
10
|
+
module Zuul
|
11
|
+
module ActiveRecord
|
12
|
+
def self.included(base)
|
13
|
+
base.send :extend, ClassMethods
|
14
|
+
base.send :include, InstanceMethods
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def self.extended(base)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Includes auth methods into the model and configures auth options and scopes
|
22
|
+
#
|
23
|
+
# The args parameter is an optional hash of configuration options.
|
24
|
+
def acts_as_authorization_model(args={}, &block)
|
25
|
+
include AuthorizationMethods
|
26
|
+
auth_config = Zuul.configuration.clone.configure(args, &block)
|
27
|
+
@auth_scopes ||= {}
|
28
|
+
raise "Scope already in use: #{auth_config.scope}" if @auth_scopes.has_key?(auth_config.scope)
|
29
|
+
@auth_scopes[auth_config.scope] = Scope.new(auth_config)
|
30
|
+
@auth_scopes[:default] ||= @auth_scopes[auth_config.scope]
|
31
|
+
@auth_scopes[auth_config.scope]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Configure the model to act as a zuul authorization role
|
35
|
+
#
|
36
|
+
# The args parameter is an optional hash of configuration options.
|
37
|
+
def acts_as_authorization_role(args={}, &block)
|
38
|
+
scope = acts_as_authorization_model(args.merge({:role_class => self.name}), &block)
|
39
|
+
prepare_join_classes scope.name
|
40
|
+
include Role
|
41
|
+
end
|
42
|
+
|
43
|
+
# Configure the model to act as a zuul authorization permission
|
44
|
+
#
|
45
|
+
# The args parameter is an optional hash of configuration options.
|
46
|
+
def acts_as_authorization_permission(args={}, &block)
|
47
|
+
scope = acts_as_authorization_model(args.merge({:permission_class => self.name}), &block)
|
48
|
+
prepare_join_classes scope.name
|
49
|
+
include Permission
|
50
|
+
end
|
51
|
+
|
52
|
+
# Configure the model to act as a zuul authorization subject
|
53
|
+
#
|
54
|
+
# The args parameter is an optional hash of configuration options.
|
55
|
+
def acts_as_authorization_subject(args={}, &block)
|
56
|
+
scope = acts_as_authorization_model(args.merge({:subject_class => self.name}), &block)
|
57
|
+
prepare_join_classes scope.name
|
58
|
+
include Subject
|
59
|
+
end
|
60
|
+
|
61
|
+
# Configure the model to act as a zuul authorization context (or resource)
|
62
|
+
#
|
63
|
+
# The args parameter is an optional hash of configuration options.
|
64
|
+
def acts_as_authorization_context(args={}, &block)
|
65
|
+
acts_as_authorization_model(args, &block)
|
66
|
+
include Context
|
67
|
+
end
|
68
|
+
|
69
|
+
# Sets up the join models for a newly defined scope.
|
70
|
+
#
|
71
|
+
# This is similar the the acts_as_authorization_* methods, but it handles all the joining models for a scope.
|
72
|
+
def prepare_join_classes(scope)
|
73
|
+
scope_config = auth_scope(scope).config
|
74
|
+
|
75
|
+
unless auth_scope(scope).role_subject_class.ancestors.include?(RoleSubject)
|
76
|
+
auth_scope(scope).role_subject_class.instance_eval do
|
77
|
+
acts_as_authorization_model(scope_config.to_h)
|
78
|
+
include RoleSubject
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if auth_scope(scope).config.with_permissions
|
83
|
+
unless auth_scope(scope).permission_subject_class.ancestors.include?(PermissionSubject)
|
84
|
+
auth_scope(scope).permission_subject_class.instance_eval do
|
85
|
+
acts_as_authorization_model(scope_config.to_h)
|
86
|
+
include PermissionSubject
|
87
|
+
end
|
88
|
+
end
|
89
|
+
unless auth_scope(scope).permission_role_class.ancestors.include?(PermissionRole)
|
90
|
+
auth_scope(scope).permission_role_class.instance_eval do
|
91
|
+
acts_as_authorization_model(scope_config.to_h)
|
92
|
+
include PermissionRole
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Checks if the model is setup to act as a zuul authorization role
|
99
|
+
def acts_as_authorization_role?
|
100
|
+
ancestors.include?(Zuul::ActiveRecord::Role)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Checks if the model is setup to act as a zuul authorization permission
|
104
|
+
def acts_as_authorization_permission?
|
105
|
+
ancestors.include?(Zuul::ActiveRecord::Permission)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Checks if the model is setup to act as a zuul authorization context/resource
|
109
|
+
def acts_as_authorization_context?
|
110
|
+
ancestors.include?(Zuul::ActiveRecord::Context)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Checks if the model is setup to act as a zuul authorization subject
|
114
|
+
def acts_as_authorization_subject?
|
115
|
+
ancestors.include?(Zuul::ActiveRecord::Subject)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Defines acts_as_authorization_*? methods to pass through to the class
|
120
|
+
module InstanceMethods
|
121
|
+
[:role, :permission, :subject, :context].each do |auth_type|
|
122
|
+
method_name = "acts_as_authorization_#{auth_type}?"
|
123
|
+
define_method method_name do
|
124
|
+
self.class.send method_name
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
module AuthorizationMethods
|
130
|
+
def self.included(base)
|
131
|
+
base.class.send :attr_reader, :auth_scopes
|
132
|
+
base.class.send :attr_reader, :current_auth_scope
|
133
|
+
base.send :instance_variable_set, :@current_auth_scope, :default
|
134
|
+
base.send :extend, ClassMethods
|
135
|
+
base.send :include, InstanceMethods
|
136
|
+
end
|
137
|
+
|
138
|
+
module ClassMethods
|
139
|
+
# Return the requested scope, call a method within a scope or execute an optional block within that scope
|
140
|
+
#
|
141
|
+
# If an optional block is passed, it will be executed within the provided scope. This allows
|
142
|
+
# you to call methods on the model or the auth scope without having to specify a scope
|
143
|
+
# each time. The exec_args hash can be used to pass arguments through to the block.
|
144
|
+
#
|
145
|
+
# If a block is not passed, exec_args can be used to provide a method and arguments to be called on the
|
146
|
+
# object within the requested scope.
|
147
|
+
#
|
148
|
+
# The reason this is defined separately at the class and instance level is because it uses
|
149
|
+
# instance_exec to execute the block within the scope of the object (either class or instance)
|
150
|
+
# and then uses method_missing temporarily to provide the auth scope methods.
|
151
|
+
def auth_scope(scope=nil, *exec_args, &block)
|
152
|
+
scope ||= current_auth_scope
|
153
|
+
raise ::Zuul::Exceptions::UndefinedScope unless auth_scopes.has_key?(scope)
|
154
|
+
|
155
|
+
if block_given? || (exec_args.length > 0 && exec_args[0].is_a?(Symbol) && respond_to?(exec_args[0]))
|
156
|
+
old_scope = current_auth_scope
|
157
|
+
self.current_auth_scope = scope
|
158
|
+
|
159
|
+
instance_eval do
|
160
|
+
def method_missing (meth,*args)
|
161
|
+
return auth_scopes[current_auth_scope].send(meth, *args) if auth_scopes[current_auth_scope].respond_to?(meth)
|
162
|
+
raise NoMethodError, "#{self.name}.#{meth} does not exist."
|
163
|
+
end
|
164
|
+
end
|
165
|
+
exec_result = block_given? ? instance_exec(*exec_args, &block) : send(exec_args.slice!(0), *exec_args)
|
166
|
+
instance_eval do
|
167
|
+
undef method_missing
|
168
|
+
end
|
169
|
+
|
170
|
+
self.current_auth_scope = old_scope
|
171
|
+
return exec_result
|
172
|
+
end
|
173
|
+
|
174
|
+
auth_scopes[scope]
|
175
|
+
end
|
176
|
+
|
177
|
+
# Evaluate a block within the requested scope
|
178
|
+
def auth_scope_eval(scope=nil, &block)
|
179
|
+
auth_scope(scope).instance_eval &block
|
180
|
+
end
|
181
|
+
|
182
|
+
# Set the current auth scope
|
183
|
+
#
|
184
|
+
# The current_auth_scope is the scope that is currently active on the model for all auth operations
|
185
|
+
def current_auth_scope=(scope)
|
186
|
+
@current_auth_scope = scope.to_sym
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
module InstanceMethods
|
191
|
+
def self.included(base)
|
192
|
+
# TODO figure out how to delegate tasks to self.class
|
193
|
+
end
|
194
|
+
|
195
|
+
def auth_scopes
|
196
|
+
self.class.auth_scopes
|
197
|
+
end
|
198
|
+
|
199
|
+
# Return the requested scope, call a method within a scope or execute an optional block within that scope
|
200
|
+
#
|
201
|
+
# If an optional block is passed, it will be executed within the provided scope. This allows
|
202
|
+
# you to call methods on the model or the auth scope without having to specify a scope
|
203
|
+
# each time. The exec_args hash can be used to pass arguments through to the block.
|
204
|
+
#
|
205
|
+
# If a block is not passed, exec_args can be used to provide a method and arguments to be called on the
|
206
|
+
# object within the requested scope.
|
207
|
+
#
|
208
|
+
# The reason this is defined separately at the class and instance level is because it uses
|
209
|
+
# instance_exec to execute the block within the scope of the object (either class or instance)
|
210
|
+
# and then uses method_missing temporarily to provide the auth scope methods.
|
211
|
+
def auth_scope(scope=nil, *exec_args, &block)
|
212
|
+
scope ||= current_auth_scope
|
213
|
+
raise ::Zuul::Exceptions::UndefinedScope unless auth_scopes.has_key?(scope)
|
214
|
+
|
215
|
+
if block_given? || (exec_args.length > 0 && exec_args[0].is_a?(Symbol) && respond_to?(exec_args[0]))
|
216
|
+
old_scope = current_auth_scope
|
217
|
+
self.current_auth_scope = scope
|
218
|
+
|
219
|
+
instance_eval do
|
220
|
+
def method_missing (meth,*args)
|
221
|
+
return auth_scopes[current_auth_scope].send(meth, *args) if auth_scopes[current_auth_scope].respond_to?(meth)
|
222
|
+
raise NoMethodError, "#{self.class.name}##{meth} does not exist."
|
223
|
+
end
|
224
|
+
end
|
225
|
+
exec_result = block_given? ? instance_exec(*exec_args, &block) : send(exec_args.slice!(0), *exec_args)
|
226
|
+
instance_eval do
|
227
|
+
undef method_missing
|
228
|
+
end
|
229
|
+
|
230
|
+
self.current_auth_scope = old_scope
|
231
|
+
return exec_result
|
232
|
+
end
|
233
|
+
|
234
|
+
auth_scopes[scope]
|
235
|
+
end
|
236
|
+
|
237
|
+
def auth_scope_eval(scope=nil, &block)
|
238
|
+
self.class.auth_scope_eval(scope, &block)
|
239
|
+
end
|
240
|
+
|
241
|
+
def current_auth_scope
|
242
|
+
self.class.current_auth_scope
|
243
|
+
end
|
244
|
+
|
245
|
+
def current_auth_scope=(scope)
|
246
|
+
self.class.current_auth_scope = scope
|
247
|
+
end
|
248
|
+
|
249
|
+
# Looks for the role slug with the closest contextual match, working it's way up the context chain.
|
250
|
+
#
|
251
|
+
# If the provided role is already a Role, just return it without checking for a match.
|
252
|
+
#
|
253
|
+
# This allows a way to provide a specific role that isn't necessarily the best match
|
254
|
+
# for the provided context to methods like assign_role, but still assign them in the
|
255
|
+
# provided context, letting you assign a role like ['admin', SomeThing, nil] to the
|
256
|
+
# resource SomeThing.find(1), even if you also have a ['admin', SomeThing, 1] role.
|
257
|
+
def target_role(role, context, force_context=nil)
|
258
|
+
auth_scope_eval do
|
259
|
+
return role if role.is_a?(role_class)
|
260
|
+
force_context ||= config.force_context
|
261
|
+
|
262
|
+
context = Zuul::Context.parse(context)
|
263
|
+
target_role = role_class.where(:slug => role.to_s.underscore, :context_type => context.class_name, :context_id => context.id).first
|
264
|
+
return target_role if force_context
|
265
|
+
target_role ||= role_class.where(:slug => role.to_s.underscore, :context_type => context.class_name, :context_id => nil).first unless context.id.nil?
|
266
|
+
target_role ||= role_class.where(:slug => role.to_s.underscore, :context_type => nil, :context_id => nil).first unless context.class_name.nil?
|
267
|
+
target_role
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# Looks for the permission slug with the closest contextual match, working it's way upwards.
|
272
|
+
#
|
273
|
+
# If the provided permission is already a Permission, just return it without checking for a match.
|
274
|
+
#
|
275
|
+
# This allows a way to provide a specific permission that isn't necessarily the best match
|
276
|
+
# for the provided context to metods like assign_permission, but still assign them in the
|
277
|
+
# provided context, letting you assign a permission like ['edit', SomeThing, nil] to the
|
278
|
+
# resource SomeThing.find(1), even if you also have a ['edit', SomeThing, 1] permission.
|
279
|
+
def target_permission(permission, context, force_context=nil)
|
280
|
+
auth_scope_eval do
|
281
|
+
return permission if permission.is_a?(permission_class)
|
282
|
+
force_context ||= config.force_context
|
283
|
+
|
284
|
+
context = Zuul::Context.parse(context)
|
285
|
+
target_permission = permission_class.where(:slug => permission.to_s.underscore, :context_type => context.class_name, :context_id => context.id).first
|
286
|
+
return target_permission if force_context
|
287
|
+
target_permission ||= permission_class.where(:slug => permission.to_s.underscore, :context_type => context.class_name, :context_id => nil).first unless context.id.nil?
|
288
|
+
target_permission ||= permission_class.where(:slug => permission.to_s.underscore, :context_type => nil, :context_id => nil).first unless context.class_name.nil?
|
289
|
+
target_permission
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# Verifies whether a role or permission (target) is allowed to be used within the provided context.
|
294
|
+
# The target's context must either match the one provided or be higher up the context chain.
|
295
|
+
#
|
296
|
+
# [SomeThing, 1] CANNOT be used with [SomeThing, nil] or [OtherThing, 1]
|
297
|
+
# [SomeThing, nil] CAN be used for [SomeThing, 1], [SomeThing, 2], etc.
|
298
|
+
# [nil, nil] global targets can be used for ANY context
|
299
|
+
def verify_target_context(target, context, force_context=nil)
|
300
|
+
return false if target.nil?
|
301
|
+
force_context ||= auth_scope.config.force_context
|
302
|
+
context = Zuul::Context.parse(context)
|
303
|
+
return (target.context.class_name == context.class_name && target.context.id == context.id) if force_context
|
304
|
+
(target.context.class_name.nil? && target.context.id.nil?) || (target.context.class_name == context.class_name && (target.context.id.nil? || target.context.id == context.id))
|
305
|
+
end
|
306
|
+
|
307
|
+
# Simple helper for "IS NULL" vs "= 'VALUE'" SQL syntax
|
308
|
+
# (this *must* already exist somewhere in AREL? can't find it though...)
|
309
|
+
def sql_is_or_equal(value)
|
310
|
+
value.nil? ? "IS" : "="
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
# These are included in roles & permissions objects and assigned roles & permissions objects
|
316
|
+
# to provide easy access to the context for that object.
|
317
|
+
module ContextMethods
|
318
|
+
def self.included(base)
|
319
|
+
base.send :attr_accessible, :context
|
320
|
+
end
|
321
|
+
|
322
|
+
# Return a Zuul::Context object representing the context for the role
|
323
|
+
def context
|
324
|
+
Zuul::Context.new(context_type, context_id)
|
325
|
+
end
|
326
|
+
|
327
|
+
# Parse a context into an Zuul::Context and set the type and id
|
328
|
+
def context=(context)
|
329
|
+
context = Zuul::Context.parse(context)
|
330
|
+
self.context_type = context.class_name
|
331
|
+
self.context_id = context.id
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
ActiveRecord::Base.send :include, Zuul::ActiveRecord
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Zuul
|
2
|
+
module ActiveRecord
|
3
|
+
module Context
|
4
|
+
def self.included(base)
|
5
|
+
base.send :extend, ClassMethods
|
6
|
+
base.send :include, InstanceMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def self.extended(base)
|
11
|
+
base.send :extend, RoleMethods
|
12
|
+
base.send :extend, PermissionMethods if base.auth_scope.config.with_permissions
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module InstanceMethods
|
17
|
+
def self.included(base)
|
18
|
+
base.send :include, RoleMethods
|
19
|
+
base.send :include, PermissionMethods if base.auth_scope.config.with_permissions
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module RoleMethods
|
24
|
+
# Checks whether the subject possesses the specified role within the context of self
|
25
|
+
def allowed?(subject, role)
|
26
|
+
subject.has_role?(role, self)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module PermissionMethods
|
31
|
+
# Checks whether the subject possesses the specified permission within the context of self
|
32
|
+
def allowed_to?(subject, permission)
|
33
|
+
subject.has_permission?(permission, self)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Zuul
|
2
|
+
module ActiveRecord
|
3
|
+
module Permission
|
4
|
+
def self.included(base)
|
5
|
+
base.send :extend, ClassMethods
|
6
|
+
base.send :include, ContextMethods # defined in lib/zuul/active_record.rb
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def self.extended(base)
|
11
|
+
base.send :attr_accessible, :context, :context_id, :context_type, :slug
|
12
|
+
add_validations base
|
13
|
+
add_associations base
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.add_validations(base)
|
17
|
+
base.send :validates_presence_of, :slug
|
18
|
+
base.send :validates_uniqueness_of, :slug, :scope => [:context_id, :context_type], :case_sensitive => false
|
19
|
+
base.send :validates_format_of, :slug, :with => /\A[a-z0-9_]+\Z/
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.add_associations(base)
|
23
|
+
base.send :has_many, base.auth_scope.permission_roles_table_name.to_sym
|
24
|
+
base.send :has_many, base.auth_scope.roles_table_name.to_sym, :through => base.auth_scope.permission_roles_table_name.to_sym
|
25
|
+
base.send :has_many, base.auth_scope.permission_subjects_table_name.to_sym
|
26
|
+
base.send :has_many, base.auth_scope.subjects_table_name.to_sym, :through => base.auth_scope.permission_subjects_table_name.to_sym
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|