zuul 0.2.7 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ module Zuul
2
+ module ActionController
3
+ module DSL
4
+ class Actions < Base
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,254 @@
1
+ module Zuul
2
+ module ActionController
3
+ module DSL
4
+ class Base
5
+ attr_reader :default, :context, :force_context, :mode, :default_block_allow_rules, :default_block_deny_rules, :actions, :roles, :permissions, :results, :subject_method, :scope
6
+
7
+ def actions(*actions, &block)
8
+ actions = actions[0] if actions.length == 1 && actions[0].is_a?(Array)
9
+ opts = options
10
+ opts[:actions].concat(actions)
11
+ return unless opts[:actions].map(&:to_sym).include?(@controller.params[:action].to_sym)
12
+ dsl = Actions.new(@controller, opts)
13
+ dsl.instance_eval(&block) if block_given?
14
+
15
+ @results.concat dsl.results
16
+ end
17
+
18
+ def context(ctxt, &block)
19
+ opts = options.merge(:context => ctxt)
20
+ dsl = self.class.new(@controller, opts)
21
+ dsl.instance_eval(&block) if block_given?
22
+
23
+ @results.concat dsl.results
24
+ end
25
+
26
+ def force_context(flag=true, &block)
27
+ opts = options.merge(:force_context => flag)
28
+ dsl = self.class.new(@controller, opts)
29
+ dsl.instance_eval(&block) if block_given?
30
+
31
+ @results.concat dsl.results
32
+ end
33
+
34
+ def roles(*allowed, &block)
35
+ allowed = allowed[0] if allowed.length == 1 && allowed[0].is_a?(Array)
36
+ opts = options
37
+ opts[:roles].concat(allowed)
38
+ dsl = Roles.new(@controller, opts)
39
+ dsl.instance_eval(&block) if block_given?
40
+
41
+ @results.concat dsl.results
42
+ end
43
+
44
+ def permissions(*allowed, &block)
45
+ allowed = allowed[0] if allowed.length == 1 && allowed[0].is_a?(Array)
46
+ opts = options
47
+ opts[:permissions].concat(allowed)
48
+ dsl = Permissions.new(@controller, opts)
49
+ dsl.instance_eval(&block) if block_given?
50
+
51
+ @results.concat dsl.results
52
+ end
53
+
54
+ def scope(scope, &block)
55
+ opts = options.merge(:scope => scope)
56
+ dsl = self.class.new(@controller, opts)
57
+ dsl.instance_eval(&block) if block_given?
58
+
59
+ @results.concat dsl.results
60
+ end
61
+
62
+ def allow_roles(*allowed)
63
+ allowed = allowed[0] if allowed.length == 1 && allowed[0].is_a?(Array)
64
+ roles *allowed do
65
+ allow *@actions
66
+ end
67
+ end
68
+ alias_method :allow_role, :allow_roles
69
+ alias_method :allow, :allow_roles
70
+
71
+ def allow_permissions(*allowed)
72
+ allowed = allowed[0] if allowed.length == 1 && allowed[0].is_a?(Array)
73
+ permissions *allowed do
74
+ allow *@actions
75
+ end
76
+ end
77
+ alias_method :allow_permission, :allow_permissions
78
+
79
+ def deny_roles(*denied)
80
+ denied = denied[0] if denied.length == 1 && denied[0].is_a?(Array)
81
+ roles *denied do
82
+ deny *@actions
83
+ end
84
+ end
85
+ alias_method :deny_role, :deny_roles
86
+ alias_method :deny, :deny_roles
87
+
88
+ def deny_permissions(*denied)
89
+ denied = denied[0] if denied.length == 1 && denied[0].is_a?(Array)
90
+ permissions *denied do
91
+ deny *@actions
92
+ end
93
+ end
94
+ alias_method :deny_permission, :deny_permissions
95
+
96
+ def all_actions
97
+ @controller.class.action_methods.select { |act| !act.match(/^_callback_before_[\d]*$/) }.map(&:to_sym)
98
+ end
99
+
100
+ def subject
101
+ @controller.send(@subject_method)
102
+ end
103
+
104
+ def logged_out
105
+ :_zuul_logged_out
106
+ end
107
+ alias_method :anonymous, :logged_out
108
+
109
+ def logged_in
110
+ :_zuul_logged_in
111
+ end
112
+
113
+ def anyone
114
+ [logged_in, logged_out]
115
+ end
116
+
117
+ def all_roles(context=false)
118
+ return [] if subject.nil?
119
+ context = (context == false) ? @context : parse_context(context)
120
+ found_roles = subject.auth_scope(@scope).role_class.where(:context_type => context.type, :context_id => context.id).to_a
121
+ found_roles.concat(subject.auth_scope(@scope).role_class.where(:context_type => context.type, :context_id => nil).to_a) unless context.id.nil?
122
+ found_roles.concat(subject.auth_scope(@scope).role_class.where(:context_type => nil, :context_id => nil).to_a) unless context.type.nil?
123
+ found_roles
124
+ end
125
+
126
+ def all_permissions(context=false)
127
+ return [] if subject.nil?
128
+ context = (context == false) ? @context : parse_context(context)
129
+ found_permissions = subject.auth_scope(@scope).permission_class.where(:context_type => context.type, :context_id => context.id).to_a
130
+ found_permissions.concat(subject.auth_scope(@scope).permission_class.where(:context_type => context.type, :context_id => nil).to_a) unless context.id.nil?
131
+ found_permissions.concat(subject.auth_scope(@scope).permission_class.where(:context_type => nil, :context_id => nil).to_a) unless context.type.nil?
132
+ found_permissions
133
+ end
134
+
135
+ def contextual_role(slug, context=false)
136
+ return nil if subject.nil?
137
+ context = (context == false) ? @context : parse_context(context)
138
+ return subject.auth_scope(@scope) { target_role(slug, context.to_context) }
139
+ end
140
+ alias_method :role, :contextual_role
141
+
142
+ def contextual_permission(slug, context=false)
143
+ return nil if subject.nil?
144
+ context = (context == false) ? @context : parse_context(context)
145
+ return subject.auth_scope(@scope) { target_permission(slug, context.to_context) }
146
+ end
147
+ alias_method :permission, :contextual_permission
148
+
149
+ def options
150
+ {
151
+ :default => @default,
152
+ :actions => @actions.clone,
153
+ :roles => @roles.clone,
154
+ :permissions => @permissions.clone,
155
+ :context => @context.clone,
156
+ :force_context => @force_context,
157
+ :subject_method => @subject_method,
158
+ :scope => @scope,
159
+ :mode => @mode,
160
+ :collect_results => @collect_results,
161
+ :allow => (@default_block_allow_rules.nil? ? @default_block_allow_rules : @default_block_allow_rules.clone),
162
+ :deny => (@default_block_deny_rules.nil? ? @default_block_deny_rules : @default_block_deny_rules.clone),
163
+ }
164
+ end
165
+
166
+ def set_options(opts)
167
+ [:default, :actions, :roles, :permissions, :force_context, :mode, :collect_results, :subject_method, :scope].each do |key|
168
+ instance_variable_set "@#{key.to_s}", opts[key] if opts.has_key?(key)
169
+ end
170
+ [:allow, :deny].each do |key|
171
+ instance_variable_set "@default_block_#{key.to_s}_rules", opts[key] if opts.has_key?(key)
172
+ end
173
+ @context = parse_context(opts[:context]) if opts.has_key?(:context)
174
+ self
175
+ end
176
+ alias_method :configure, :set_options
177
+
178
+ def parse_context(context=nil)
179
+ if context.is_a?(String) || context.is_a?(Symbol)
180
+ if context.to_s.match(/^@.*$/)
181
+ context = @controller.send(:instance_variable_get, context)
182
+ elsif @controller.respond_to?(context.to_sym)
183
+ context = @controller.send(context)
184
+ end
185
+ end
186
+
187
+ Zuul::Context.parse(context)
188
+ end
189
+
190
+ def execute(&block)
191
+ log_timer_start = Time.now.to_f
192
+ if block_given?
193
+ instance_eval(&block)
194
+ else
195
+ instance_eval do
196
+ [:allow, :deny].each do |auth_type|
197
+ auth_opts = instance_variable_get("@default_block_#{auth_type.to_s}_rules")
198
+ next if auth_opts.nil?
199
+
200
+ auth_actions = @actions
201
+ auth_opts[:actions] = [auth_opts[:actions]] if auth_opts.has_key?(:actions) && !auth_opts[:actions].is_a?(Array)
202
+ if !auth_opts.has_key?(:actions) || auth_opts[:actions].empty?
203
+ auth_actions << @controller.params[:action].to_sym if auth_actions.empty?
204
+ else
205
+ auth_actions.concat(auth_opts[:actions])
206
+ end
207
+
208
+ actions auth_actions do
209
+ [:roles, :permissions].each do |allowable_type|
210
+ if auth_opts.has_key?(allowable_type)
211
+ send "#{auth_type.to_s}_#{allowable_type.to_s}", auth_opts[allowable_type]
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
218
+ # only collect results if configured & there are more filters in the chain
219
+ logger.debug " \e[1;34mACL (#{((Time.now.to_f - log_timer_start) * 1000.0).round(1)}ms)\e[0m #{(authorized? ? "\e[1;32mALLOWED\e[0m" : "\e[1;31mDENIED\e[0m")} using \e[1m#{@default.to_s.upcase}\e[0m [#{results.map { |r| "\e[#{(r ? "32mallow" : "31mdeny")}\e[0m" }.join(",")}]"
220
+ collect_results if @collect_results && @controller.class.acl_filters.length > 0
221
+ end
222
+
223
+ def authorized?
224
+ if @default == :deny
225
+ !(@results.empty? || @results.any? { |result| result == false })
226
+ else
227
+ (@results.empty? || !@results.all? { |result| result == false })
228
+ end
229
+ end
230
+
231
+ def collect_results
232
+ @results = [authorized?]
233
+ end
234
+
235
+ protected
236
+
237
+ def initialize(controller, opts={})
238
+ @controller = controller
239
+ # TODO catch 22: need config for subject_method, but need subject_method to check if subject
240
+ opts = {:subject_method => Zuul.configuration.subject_method, :scope => :default}.merge(opts)
241
+ config = @controller.send(opts[:subject_method]).nil? ? Zuul.configuration : @controller.send(opts[:subject_method]).auth_scope(opts[:scope]).config
242
+ opts = {:default => config.acl_default, :force_context => config.force_context, :context => nil, :mode => config.acl_mode, :collect_results => config.acl_collect_results, :allow => nil, :deny => nil, :actions => [], :roles => [], :permissions => []}.merge(opts)
243
+ set_options opts
244
+ @results = []
245
+ end
246
+
247
+ def logger
248
+ @controller.logger
249
+ end
250
+ end
251
+
252
+ end
253
+ end
254
+ end
@@ -0,0 +1,45 @@
1
+ module Zuul
2
+ module ActionController
3
+ module DSL
4
+ class Permissions < Actionable
5
+ def match?(permission)
6
+ subject.auth_scope(@scope, @context, @force_context) { |context, force_context| has_permission?(permission, context.to_context, force_context) }
7
+ end
8
+
9
+ def allow(*actions)
10
+ log_timer_start = Time.now.to_f
11
+ actions = actions[0] if actions.length == 1 && actions[0].is_a?(Array)
12
+ actions.concat(@actions)
13
+ return if subject.nil? || @permissions.empty? || actions.empty?
14
+ if actions.map(&:to_sym).include?(@controller.params[:action].to_sym)
15
+ @permissions.each do |permission|
16
+ if allow?(permission)
17
+ logger.debug " \e[1;33mACL (#{((Time.now.to_f - log_timer_start) * 1000.0).round(1)}ms)\e[0m \e[1mMATCH\e[0m for \e[32mallow\e[0m permission \e[1m#{permission.is_a?(subject.auth_scope(@scope).role_class) ? "#{permission.slug}[#{permission.context.to_s}]" : permission}\e[0m"
18
+ @results << true
19
+ return
20
+ end
21
+ logger.debug " \e[1;33mACL (#{((Time.now.to_f - log_timer_start) * 1000.0).round(1)}ms)\e[0m \e[1mNO MATCH\e[0m for \e[32mallow\e[0m permission \e[1m#{permission.is_a?(subject.auth_scope(@scope).role_class) ? "#{permission.slug}[#{permission.context.to_s}]" : permission}\e[0m"
22
+ end
23
+ end
24
+ end
25
+
26
+ def deny(*actions)
27
+ log_timer_start = Time.now.to_f
28
+ actions = actions[0] if actions.length == 1 && actions[0].is_a?(Array)
29
+ actions.concat(@actions)
30
+ return if subject.nil? || @permissions.empty? || actions.empty?
31
+ if actions.map(&:to_sym).include?(@controller.params[:action].to_sym)
32
+ @permissions.each do |permission|
33
+ if deny?(permission)
34
+ logger.debug " \e[1;33mACL (#{((Time.now.to_f - log_timer_start) * 1000.0).round(1)}ms)\e[0m \e[1mMATCH\e[0m for \e[31mdeny\e[0m permission \e[1m#{permission.is_a?(subject.auth_scope(@scope).role_class) ? "#{permission.slug}[#{permission.context.to_s}]" : permission}\e[0m"
35
+ @results << false
36
+ return
37
+ end
38
+ logger.debug " \e[1;33mACL (#{((Time.now.to_f - log_timer_start) * 1000.0).round(1)}ms)\e[0m \e[1mNO MATCH\e[0m for \e[31mdeny\e[0m permission \e[1m#{permission.is_a?(subject.auth_scope(@scope).role_class) ? "#{permission.slug}[#{permission.context.to_s}]" : permission}\e[0m"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,77 @@
1
+ module Zuul
2
+ module ActionController
3
+ module DSL
4
+ class Roles < Actionable
5
+ def match?(role)
6
+ (@or_higher && subject.auth_scope(@scope, @context, @force_context) { |context, force_context| has_role_or_higher?(role, context.to_context, force_context) }) || (!@or_higher && subject.auth_scope(@scope, @context, @force_context) { |context, force_context| has_role?(role, context.to_context, force_context) })
7
+ end
8
+
9
+ def allow(*actions)
10
+ log_timer_start = Time.now.to_f
11
+ actions = actions[0] if actions.length == 1 && actions[0].is_a?(Array)
12
+ actions.concat(@actions)
13
+ return if @roles.empty? || actions.empty?
14
+ if actions.map(&:to_sym).include?(@controller.params[:action].to_sym)
15
+ @roles.each do |role|
16
+ if (role == logged_out && subject.nil?) ||
17
+ (role == logged_in && !subject.nil?)
18
+ @results << true
19
+ return
20
+ end
21
+
22
+ next if subject.nil? # keep going in case :_zuul_logged_out is specified
23
+
24
+ if allow?(role)
25
+ logger.debug " \e[1;33mACL (#{((Time.now.to_f - log_timer_start) * 1000.0).round(1)}ms)\e[0m \e[1mMATCH\e[0m for \e[32mallow\e[0m role \e[1m#{role.is_a?(subject.auth_scope(@scope).role_class) ? "#{role.slug}[#{role.context.to_s}]" : role}\e[0m"
26
+ @results << true
27
+ return
28
+ end
29
+ logger.debug " \e[1;33mACL (#{((Time.now.to_f - log_timer_start) * 1000.0).round(1)}ms)\e[0m \e[1mNO MATCH\e[0m for \e[32mallow\e[0m role \e[1m#{role.is_a?(subject.auth_scope(@scope).role_class) ? "#{role.slug}[#{role.context.to_s}]" : role}\e[0m"
30
+ end
31
+ end
32
+ end
33
+
34
+ def deny(*actions)
35
+ log_timer_start = Time.now.to_f
36
+ actions = actions[0] if actions.length == 1 && actions[0].is_a?(Array)
37
+ actions.concat(@actions)
38
+ return if @roles.empty? || actions.empty?
39
+ if actions.map(&:to_sym).include?(@controller.params[:action].to_sym)
40
+ @roles.each do |role|
41
+ if (role == logged_out && subject.nil?) ||
42
+ (role == logged_in && !subject.nil?)
43
+ @results << false
44
+ return
45
+ end
46
+
47
+ next if subject.nil? # keep going in case :_zuul_logged_out is specified
48
+
49
+ if deny?(role)
50
+ logger.debug " \e[1;33mACL (#{((Time.now.to_f - log_timer_start) * 1000.0).round(1)}ms)\e[0m \e[1mMATCH\e[0m for \e[31mdeny\e[0m role \e[1m#{role.is_a?(subject.auth_scope(@scope).role_class) ? "#{role.slug}[#{role.context.to_s}]" : role}\e[0m"
51
+ @results << false
52
+ return
53
+ end
54
+ logger.debug " \e[1;33mACL (#{((Time.now.to_f - log_timer_start) * 1000.0).round(1)}ms)\e[0m \e[1mNO MATCH\e[0m for \e[31mdeny\e[0m role \e[1m#{role.is_a?(subject.auth_scope(@scope).role_class) ? "#{role.slug}[#{role.context.to_s}]" : role}\e[0m"
55
+ end
56
+ end
57
+ end
58
+
59
+ def or_higher(&block)
60
+ opts = options.merge(:or_higher => true)
61
+ dsl = self.class.new(@controller, opts)
62
+ dsl.instance_eval(&block) if block_given?
63
+
64
+ @results.concat dsl.results
65
+ end
66
+
67
+ protected
68
+
69
+ def initialize(controller, opts={})
70
+ super
71
+ opts = {:or_higher => false}.merge(opts)
72
+ @or_higher = opts[:or_higher]
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,3 +1,4 @@
1
+ require 'zuul/active_record/context_accessors'
1
2
  require 'zuul/active_record/scope'
2
3
  require 'zuul/active_record/role'
3
4
  require 'zuul/active_record/permission'
@@ -96,19 +97,19 @@ module Zuul
96
97
  def prepare_join_classes(scope)
97
98
  scope_config = auth_scope(scope).config
98
99
 
99
- unless auth_scope(scope).role_subject_class.ancestors.include?(RoleSubject)
100
+ unless auth_scope(scope).role_subject_class.acts_as_authorization_role_subject?
100
101
  auth_scope(scope).role_subject_class.instance_eval do
101
102
  acts_as_authorization_role_subject(scope_config.to_h)
102
103
  end
103
104
  end
104
105
 
105
106
  if auth_scope(scope).config.with_permissions
106
- unless auth_scope(scope).permission_subject_class.ancestors.include?(PermissionSubject)
107
+ unless auth_scope(scope).permission_subject_class.acts_as_authorization_permission_subject?
107
108
  auth_scope(scope).permission_subject_class.instance_eval do
108
109
  acts_as_authorization_permission_subject(scope_config.to_h)
109
110
  end
110
111
  end
111
- unless auth_scope(scope).permission_role_class.ancestors.include?(PermissionRole)
112
+ unless auth_scope(scope).permission_role_class.acts_as_authorization_permission_role?
112
113
  auth_scope(scope).permission_role_class.instance_eval do
113
114
  acts_as_authorization_permission_role(scope_config.to_h)
114
115
  end
@@ -116,30 +117,50 @@ module Zuul
116
117
  end
117
118
  end
118
119
 
120
+
121
+ def acts_as_authorization_model?(type)
122
+ ancestors.include?("zuul/active_record/#{type}".camelize.constantize)
123
+ end
124
+
119
125
  # Checks if the model is setup to act as a zuul authorization role
120
126
  def acts_as_authorization_role?
121
- ancestors.include?(Zuul::ActiveRecord::Role)
127
+ acts_as_authorization_model? :role
122
128
  end
123
129
 
124
130
  # Checks if the model is setup to act as a zuul authorization permission
125
131
  def acts_as_authorization_permission?
126
- ancestors.include?(Zuul::ActiveRecord::Permission)
132
+ acts_as_authorization_model? :permission
127
133
  end
128
134
 
129
135
  # Checks if the model is setup to act as a zuul authorization context/resource
130
136
  def acts_as_authorization_context?
131
- ancestors.include?(Zuul::ActiveRecord::Context)
137
+ acts_as_authorization_model? :context
132
138
  end
133
139
 
134
140
  # Checks if the model is setup to act as a zuul authorization subject
135
141
  def acts_as_authorization_subject?
136
- ancestors.include?(Zuul::ActiveRecord::Subject)
142
+ acts_as_authorization_model? :subject
143
+ end
144
+
145
+ # Checks if the model is setup to act as a zuul authorization role_subject
146
+ def acts_as_authorization_role_subject?
147
+ acts_as_authorization_model? :role_subject
148
+ end
149
+
150
+ # Checks if the model is setup to act as a zuul authorization permission_subject
151
+ def acts_as_authorization_permission_subject?
152
+ acts_as_authorization_model? :permission_subject
153
+ end
154
+
155
+ # Checks if the model is setup to act as a zuul authorization permission_role
156
+ def acts_as_authorization_permission_role?
157
+ acts_as_authorization_model? :permission_role
137
158
  end
138
159
  end
139
160
 
140
- # Defines acts_as_authorization_*? methods to pass through to the class
141
161
  module InstanceMethods
142
- [:role, :permission, :subject, :context].each do |auth_type|
162
+ # Defines acts_as_authorization_*? methods to pass through to the class
163
+ [:role, :permission, :subject, :context, :role_subject, :permission_subject, :permission_role].each do |auth_type|
143
164
  method_name = "acts_as_authorization_#{auth_type}?"
144
165
  define_method method_name do
145
166
  self.class.send method_name
@@ -157,7 +178,7 @@ module Zuul
157
178
  end
158
179
 
159
180
  module ClassMethods
160
- # Return the requested scope, call a method within a scope or execute an optional block within that scope
181
+ # Return the requested scope, call a method within a scope, or execute an optional block within that scope
161
182
  #
162
183
  # If an optional block is passed, it will be executed within the provided scope. This allows
163
184
  # you to call methods on the model or the auth scope without having to specify a scope
@@ -217,7 +238,7 @@ module Zuul
217
238
  self.class.auth_scopes
218
239
  end
219
240
 
220
- # Return the requested scope, call a method within a scope or execute an optional block within that scope
241
+ # Return the requested scope, call a method within a scope, or execute an optional block within that scope
221
242
  #
222
243
  # If an optional block is passed, it will be executed within the provided scope. This allows
223
244
  # you to call methods on the model or the auth scope without having to specify a scope
@@ -321,8 +342,7 @@ module Zuul
321
342
  return false if target.nil?
322
343
  force_context ||= auth_scope.config.force_context
323
344
  context = Zuul::Context.parse(context)
324
- return (target.context.class_name == context.class_name && target.context.id == context.id) if force_context
325
- (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))
345
+ force_context ? context == target.context : context <= target.context
326
346
  end
327
347
 
328
348
  # Simple helper for "IS NULL" vs "= 'VALUE'" SQL syntax
@@ -332,28 +352,7 @@ module Zuul
332
352
  end
333
353
  end
334
354
  end
335
-
336
- # These are included in roles & permissions objects and assigned roles & permissions objects
337
- # to provide easy access to the context for that object.
338
- module ContextMethods
339
- def self.included(base)
340
- base.send :attr_accessible, :context if ::Zuul
341
- .should_whitelist?
342
- end
343
-
344
- # Return a Zuul::Context object representing the context for the role
345
- def context
346
- Zuul::Context.new(context_type, context_id)
347
- end
348
-
349
- # Parse a context into an Zuul::Context and set the type and id
350
- def context=(context)
351
- context = Zuul::Context.parse(context)
352
- self.context_type = context.class_name
353
- self.context_id = context.id
354
- end
355
- end
356
-
355
+
357
356
  end
358
357
  end
359
358