zuul 0.2.7 → 0.2.8

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.
@@ -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