zuul 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|