zuul 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,27 @@
1
+ class AddZuulRoleTo<%= table_name.camelize %> < ActiveRecord::Migration
2
+ def self.up
3
+ change_table(:<%= table_name %>) do |t|
4
+ <%= migration_data -%>
5
+
6
+ <% attributes.each do |attribute| -%>
7
+ t.<%= attribute.type %> :<%= attribute.name %>
8
+ <% end -%>
9
+
10
+ # Uncomment below if timestamps were not included in your original model.
11
+ # t.timestamps
12
+ end
13
+
14
+ add_index :<%= table_name %>, :slug
15
+ add_index :<%= table_name %>, :level
16
+ add_index :<%= table_name %>, :context_type
17
+ add_index :<%= table_name %>, :context_id
18
+ add_index :<%= table_name %>, [:slug, :context_type, :context_id], :unique => true
19
+ add_index :<%= table_name %>, [:level, :context_type, :context_id], :unique => true
20
+ end
21
+
22
+ def self.down
23
+ # By default, we don't want to make any assumption about how to roll back a migration when your
24
+ # model already existed. Please edit below which fields you would like to remove in this migration.
25
+ raise ActiveRecord::IrreversibleMigration
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ class ZuulRoleSubjectCreate<%= table_name.camelize %> < ActiveRecord::Migration
2
+ def change
3
+ create_table(:<%= table_name %>) do |t|
4
+ <% attributes.each do |attribute| -%>
5
+ t.<%= attribute.type %> :<%= attribute.name %>
6
+ <% end -%>
7
+
8
+ t.timestamps
9
+ end
10
+
11
+ add_index :<%= table_name %>, :<%= role_model.to_s.underscore.singularize %>_id
12
+ add_index :<%= table_name %>, :<%= subject_model.to_s.underscore.singularize %>_id
13
+ add_index :<%= table_name %>, :context_type
14
+ add_index :<%= table_name %>, :context_id
15
+ add_index :<%= table_name %>, [:<%= role_model.to_s.underscore.singularize %>_id, :<%= subject_model.to_s.underscore.singularize %>_id, :context_type, :context_id], :unique => true, :name => 'index_<%= table_name %>_on_<%= role_model.to_s.underscore.singularize %>_and_<%= subject_model.to_s.underscore.singularize %>_and_context'
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ class AddZuulRoleSubjectTo<%= table_name.camelize %> < ActiveRecord::Migration
2
+ def self.up
3
+ change_table(:<%= table_name %>) do |t|
4
+ <% attributes.each do |attribute| -%>
5
+ t.<%= attribute.type %> :<%= attribute.name %>
6
+ <% end -%>
7
+
8
+ # Uncomment below if timestamps were not included in your original model.
9
+ # t.timestamps
10
+ end
11
+
12
+ add_index :<%= table_name %>, :<%= role_model.to_s.underscore.singularize %>_id
13
+ add_index :<%= table_name %>, :<%= subject_model.to_s.underscore.singularize %>_id
14
+ add_index :<%= table_name %>, :context_type
15
+ add_index :<%= table_name %>, :context_id
16
+ add_index :<%= table_name %>, [:<%= role_model.to_s.underscore.singularize %>_id, :<%= subject_model.to_s.underscore.singularize %>_id, :context_type, :context_id], :unique => true, :name => 'index_<%= table_name %>_on_<%= role_model.to_s.underscore.singularize %>_and_<%= subject_model.to_s.underscore.singularize %>_and_context'
17
+ end
18
+
19
+ def self.down
20
+ # By default, we don't want to make any assumption about how to roll back a migration when your
21
+ # model already existed. Please edit below which fields you would like to remove in this migration.
22
+ raise ActiveRecord::IrreversibleMigration
23
+ end
24
+ end
@@ -0,0 +1,56 @@
1
+ require 'zuul_viz'
2
+ namespace :zuul do
3
+ desc "Visualize a map of all Zuul roles, permissions and subjects -- optionally pass FORMAT=format and FILENAME=filename to control output"
4
+ task :viz => :environment do |t|
5
+ format = ENV["FORMAT"] || :png
6
+ filename = ENV["FILENAME"] || "zuul_viz.#{format.to_s}"
7
+ ZuulViz.new.graph.output format.to_sym => "#{Rails.root}/tmp/#{filename}"
8
+ puts "Zuul graph saved to #{Rails.root}/tmp/#{filename}"
9
+ end
10
+
11
+ desc "Report statistics about all Zuul roles, permissions and subjects (Not Yet Implemented)"
12
+ task :stats => :environment do |t|
13
+ puts "Not Yet Implemented"
14
+ end
15
+
16
+ namespace :viz do
17
+ desc "Visualize a map of assigned roles and permissions for a specific Zuul subject -- supports FORMAT and FILENAME parameters"
18
+ task :subject, [:subject_id] => :environment do |t,args|
19
+ if args.subject_id.nil?
20
+ puts "Please provide a subject ID using the syntax `rake #{t.name}[subject_id]`"
21
+ exit
22
+ end
23
+ format = ENV["FORMAT"] || :png
24
+ filename = ENV["FILENAME"] || "zuul_viz_subject_#{args.subject_id}.#{format.to_s}"
25
+
26
+ ZuulViz.new.graph_subject(args.subject_id.to_i).output format.to_sym => "#{Rails.root}/tmp/#{filename}"
27
+ puts "Subject graph saved to #{Rails.root}/tmp/#{filename}"
28
+ end
29
+
30
+ desc "Visualize a map of subject assignments and permissions for a specific Zuul role -- supports FORMAT and FILENAME parameters"
31
+ task :role, [:role_id] => :environment do |t,args|
32
+ if args.role_id.nil?
33
+ puts "Please provide a role ID using the syntax `rake #{t.name}[role_id]`"
34
+ exit
35
+ end
36
+ format = ENV["FORMAT"] || :png
37
+ filename = ENV["FILENAME"] || "zuul_viz_subject_#{args.role_id}.#{format.to_s}"
38
+
39
+ ZuulViz.new.graph_role(args.role_id.to_i).output format.to_sym => "#{Rails.root}/tmp/#{filename}"
40
+ puts "Role graph saved to #{Rails.root}/tmp/#{filename}"
41
+ end
42
+
43
+ desc "Visualize a map of role and subject assignments for a specific Zuul permission -- supports FORMAT and FILENAME parameters"
44
+ task :permission, [:permission_id] => :environment do |t,args|
45
+ if args.permission_id.nil?
46
+ puts "Please provide a permission ID using the syntax `rake #{t.name}[permission_id]`"
47
+ exit
48
+ end
49
+ format = ENV["FORMAT"] || :png
50
+ filename = ENV["FILENAME"] || "zuul_viz_subject_#{args.permission_id}.#{format.to_s}"
51
+
52
+ ZuulViz.new.graph_permission(args.permission_id.to_i).output format.to_sym => "#{Rails.root}/tmp/#{filename}"
53
+ puts "Permission graph saved to #{Rails.root}/tmp/#{filename}"
54
+ end
55
+ end
56
+ end
data/lib/zuul.rb CHANGED
@@ -1,8 +1,17 @@
1
- require 'zuul/valid_roles'
2
- require 'zuul/restrict_access'
1
+ require 'zuul/exceptions'
2
+ require 'zuul/configuration'
3
3
 
4
- # ActiveRecord::Base.send(:include, Zuul::ValidRoles::ClassMethods)
4
+ module Zuul
5
+ mattr_reader :configuration
6
+ @@configuration = Zuul::Configuration.new
5
7
 
6
- Class.class_eval do
7
- include Zuul::ValidRoles::ClassMethods
8
+ def self.configure(&block)
9
+ @@configuration.configure &block
10
+ end
8
11
  end
12
+
13
+ require 'zuul/context'
14
+ require 'zuul/active_record'
15
+ require 'zuul/action_controller'
16
+
17
+ require 'zuul/railtie' if defined?(Rails)
@@ -0,0 +1,108 @@
1
+ require 'zuul/action_controller/dsl'
2
+ require 'zuul/action_controller/evaluators'
3
+
4
+ module Zuul
5
+ module ActionController
6
+ def self.included(base)
7
+ base.send :extend, ClassMethods
8
+ base.send :include, InstanceMethods
9
+ end
10
+
11
+ module InstanceMethods
12
+ def self.included(base)
13
+ base.send :helper_method, :authorized?
14
+ base.send :helper_method, :for_role
15
+ base.send :helper_method, :for_role_or_higher
16
+ base.send :helper_method, :for_permission
17
+ base.send :helper_method, :except_for_role
18
+ base.send :helper_method, :except_for_role_or_higher
19
+ base.send :helper_method, :except_for_permission
20
+ end
21
+
22
+ def authorized?
23
+ return true if @acl_dsl.nil?
24
+ @acl_dsl.authorized?
25
+ end
26
+
27
+ def for_role(role, context=nil, force_context=nil, &block)
28
+ return Evaluators::ForRole.new(self, role, context, force_context, &block)
29
+ end
30
+
31
+ def for_role_or_higher(role, context=nil, force_context=nil, &block)
32
+ return Evaluators::ForRoleOrHigher.new(self, role, context, force_context, &block)
33
+ end
34
+
35
+ def for_permission(permission, context=nil, force_context=nil, &block)
36
+ return Evaluators::ForPermission.new(self, permission, context, force_context, &block)
37
+ end
38
+
39
+ def except_for_role(role, context=nil, force_context=nil, &block)
40
+ return Evaluators::ForRole.new(self, role, context, force_context).else(&block)
41
+ end
42
+
43
+ def except_for_role_or_higher(role, context=nil, force_context=nil, &block)
44
+ return Evaluators::ForRoleOrHigher.new(self, role, context, force_context).else(&block)
45
+ end
46
+
47
+ def except_for_permission(permission, context=nil, force_context=nil, &block)
48
+ return Evaluators::ForPermission.new(self, permission, context, force_context).else(&block)
49
+ end
50
+ end
51
+
52
+ module ClassMethods
53
+ def self.extended(base)
54
+ base.send :cattr_accessor, :used_acl_filters
55
+ base.send :class_variable_set, :@@used_acl_filters, 0
56
+ base.send :attr_accessor, :acl_dsl
57
+ end
58
+
59
+ def access_control(*args, &block)
60
+ opts, filter_args = parse_access_control_args(*args)
61
+
62
+ callback_method = "_zuul_callback_before_#{acl_filters.length+1}".to_sym
63
+ define_method callback_method do |controller|
64
+ controller.acl_dsl ||= DSL::Base.new(controller)
65
+ controller.acl_dsl.configure opts
66
+ controller.acl_dsl.execute &block
67
+ self.class.used_acl_filters += 1
68
+
69
+ if self.class.used_acl_filters == self.class.acl_filters.length
70
+ self.class.used_acl_filters = 0
71
+ raise Exceptions::AccessDenied if !controller.acl_dsl.authorized? && controller.acl_dsl.mode != :quiet
72
+ end
73
+ end
74
+ append_before_filter "#{callback_method.to_s}(self)".to_sym, filter_args
75
+ end
76
+
77
+ def acl_filters
78
+ _process_action_callbacks.select { |f| f.kind == :before && f.filter.match(/\A_zuul_callback_before_.*/) }
79
+ end
80
+
81
+ # TODO maybe implement these to be used as simple wrappers for access_control
82
+ #def allow_roles(roles, *args, &block)
83
+ #end
84
+ #alias_method :allow_role, :allow_roles
85
+
86
+ #def allow_permissions(permissions, *args, &block)
87
+ #end
88
+ #alias_method :allow_permission, :allow_permissions
89
+
90
+ #def deny_roles(roles, *args, &block)
91
+ #end
92
+ #alias_method :deny_role, :deny_roles
93
+
94
+ #def deny_permissions(permissions, *args, &block)
95
+ #end
96
+ #alias_method :deny_permission, :deny_permissions
97
+
98
+ def parse_access_control_args(*args)
99
+ args = args[0] if args.is_a?(Array)
100
+ filter_args = args.select { |k,v| [:except, :only].include?(k) }
101
+ [:except, :only].each { |k| args.delete(k) }
102
+ return [args, filter_args]
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ ActionController::Base.send :include, Zuul::ActionController
@@ -0,0 +1,384 @@
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
+ class Actions < Base
253
+ end
254
+
255
+ class Actionable < Base
256
+ def all
257
+ all_actions
258
+ end
259
+
260
+ def allow?(role_or_perm)
261
+ match? role_or_perm
262
+ end
263
+
264
+ def deny?(role_or_perm)
265
+ match? role_or_perm
266
+ end
267
+ end
268
+
269
+ class Roles < Actionable
270
+
271
+ def match?(role)
272
+ (@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) })
273
+ end
274
+
275
+ def allow(*actions)
276
+ log_timer_start = Time.now.to_f
277
+ actions = actions[0] if actions.length == 1 && actions[0].is_a?(Array)
278
+ actions.concat(@actions)
279
+ return if @roles.empty? || actions.empty?
280
+ if actions.map(&:to_sym).include?(@controller.params[:action].to_sym)
281
+ @roles.each do |role|
282
+ if (role == logged_out && subject.nil?) ||
283
+ (role == logged_in && !subject.nil?)
284
+ @results << true
285
+ return
286
+ end
287
+
288
+ next if subject.nil? # keep going in case :_zuul_logged_out is specified
289
+
290
+ if allow?(role)
291
+ 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"
292
+ @results << true
293
+ return
294
+ end
295
+ 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"
296
+ end
297
+ end
298
+ end
299
+
300
+ def deny(*actions)
301
+ log_timer_start = Time.now.to_f
302
+ actions = actions[0] if actions.length == 1 && actions[0].is_a?(Array)
303
+ actions.concat(@actions)
304
+ return if @roles.empty? || actions.empty?
305
+ if actions.map(&:to_sym).include?(@controller.params[:action].to_sym)
306
+ @roles.each do |role|
307
+ if (role == logged_out && subject.nil?) ||
308
+ (role == logged_in && !subject.nil?)
309
+ @results << false
310
+ return
311
+ end
312
+
313
+ next if subject.nil? # keep going in case :_zuul_logged_out is specified
314
+
315
+ if deny?(role)
316
+ 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"
317
+ @results << false
318
+ return
319
+ end
320
+ 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"
321
+ end
322
+ end
323
+ end
324
+
325
+ def or_higher(&block)
326
+ opts = options.merge(:or_higher => true)
327
+ dsl = self.class.new(@controller, opts)
328
+ dsl.instance_eval(&block) if block_given?
329
+
330
+ @results.concat dsl.results
331
+ end
332
+
333
+ protected
334
+
335
+ def initialize(controller, opts={})
336
+ super
337
+ opts = {:or_higher => false}.merge(opts)
338
+ @or_higher = opts[:or_higher]
339
+ end
340
+ end
341
+
342
+ class Permissions < Actionable
343
+
344
+ def match?(permission)
345
+ subject.auth_scope(@scope, @context, @force_context) { |context, force_context| has_permission?(permission, context.to_context, force_context) }
346
+ end
347
+
348
+ def allow(*actions)
349
+ log_timer_start = Time.now.to_f
350
+ actions = actions[0] if actions.length == 1 && actions[0].is_a?(Array)
351
+ actions.concat(@actions)
352
+ return if subject.nil? || @permissions.empty? || actions.empty?
353
+ if actions.map(&:to_sym).include?(@controller.params[:action].to_sym)
354
+ @permissions.each do |permission|
355
+ if allow?(permission)
356
+ 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"
357
+ @results << true
358
+ return
359
+ end
360
+ 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"
361
+ end
362
+ end
363
+ end
364
+
365
+ def deny(*actions)
366
+ log_timer_start = Time.now.to_f
367
+ actions = actions[0] if actions.length == 1 && actions[0].is_a?(Array)
368
+ actions.concat(@actions)
369
+ return if subject.nil? || @permissions.empty? || actions.empty?
370
+ if actions.map(&:to_sym).include?(@controller.params[:action].to_sym)
371
+ @permissions.each do |permission|
372
+ if deny?(permission)
373
+ 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"
374
+ @results << false
375
+ return
376
+ end
377
+ 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"
378
+ end
379
+ end
380
+ end
381
+ end
382
+ end
383
+ end
384
+ end