ixtlan-guard 0.7.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,8 +11,7 @@ module Ixtlan
11
11
 
12
12
  def allowed_groups(resource, action)
13
13
  if resource && action
14
- resource = resource.to_s
15
- groups = send(@load_method, resource)
14
+ groups = send(@load_method, resource.to_s)
16
15
  groups[action.to_s] || groups["defaults"] || []
17
16
  else
18
17
  []
@@ -1,74 +1,220 @@
1
1
  module Ixtlan
2
- module ActionController #:nodoc:
3
- module Guard #:nodoc:
2
+ module Guard
3
+ module ActionController
4
4
  def self.included(base)
5
5
  base.send(:include, InstanceMethods)
6
6
  base.send(:include, GroupsMethod)
7
7
  end
8
8
 
9
+ class Filter
10
+ attr_reader :block
11
+ def initialize(method, options, &block)
12
+ @only = options[:only]
13
+ @except = options[:except] || []
14
+ @reference = options[:reference]
15
+ @reference = @reference.to_sym if @reference
16
+ @block = block
17
+ @method = method.to_sym if method
18
+ raise "illegal arguments: either block or method name #{method}" if block && method
19
+ end
20
+
21
+ def proc(base, reference = nil)
22
+ if @block
23
+ if reference
24
+ Proc.new do |groups|
25
+ @block.call(groups, reference)
26
+ end
27
+ elsif @reference
28
+ Proc.new do |groups|
29
+ @block.call(groups, base.send(@reference))
30
+ end
31
+ else
32
+ @block
33
+ end
34
+ else
35
+ if base.respond_to?(@method) || base.private_methods.include?(@method.to_s)
36
+ if reference
37
+ Proc.new do |groups|
38
+ base.send(@method, groups, reference)
39
+ end
40
+ elsif @reference
41
+ Proc.new do |groups|
42
+ base.send(@method, groups, base.send(@reference))
43
+ end
44
+ else
45
+ base.method(@method)
46
+ end
47
+ else
48
+ if @reference
49
+ Proc.new do |groups|
50
+ base.class.send(@method, groups, base.send(@reference))
51
+ end
52
+ else
53
+ base.class.method(@method)
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ def allowed?(action)
60
+ action = action.to_sym
61
+ (@only && @only.member?(action)) ||
62
+ ((@only.nil? || @only.empty?) && ! @except.member?(action))
63
+ end
64
+ end
65
+
9
66
  module GroupsMethod
10
67
 
11
68
  protected
12
69
 
13
- def groups_for_current_user
14
- if respond_to?(:current_user) && current_user
15
- current_user.groups
16
- else
17
- []
18
- end
70
+ def current_groups
71
+ @current_groups ||=
72
+ if respond_to?(:current_user) && current_user
73
+ current_user.groups
74
+ else
75
+ []
76
+ end
19
77
  end
20
78
  end
21
79
 
22
80
  module RootGroup
23
81
  protected
24
82
 
25
- def groups_for_current_user
83
+ def current_groups
26
84
  ['root']
27
85
  end
28
86
  end
29
87
 
30
88
  module InstanceMethods #:nodoc:
31
89
 
90
+ def self.included(base)
91
+ base.class_eval do
92
+
93
+ def self.guard_filter(*args, &block)
94
+ method = nil#"_intern_#{guard_filters.size}"
95
+ options = {}
96
+ case args.size
97
+ when 1
98
+ if args[0].is_a? Symbol
99
+ method = args[0]
100
+ else
101
+ options = args[0]
102
+ end
103
+ when 2
104
+ method = args[0].to_sym
105
+ options = args[1]
106
+ else
107
+ raise "argument error, expected (Symbol, Hash) or (Symbol) or (Hash)"
108
+ end
109
+
110
+ guard_filters << Filter.new(method, options, &block)
111
+ end
112
+
113
+ def self.guard_filters
114
+ @_guard_filters ||= []
115
+ end
116
+
117
+ def self.guard
118
+ Rails.application.config.guard
119
+ end
120
+
121
+ def self.allowed?(action, current_groups, reference = nil)
122
+ filter = guard_filters.detect do |f|
123
+ f.allowed?(action)
124
+ end
125
+ if filter
126
+ guard.check(self.controller_name,
127
+ action,
128
+ current_groups || []) do |groups|
129
+ filter.proc(self, reference).call(groups)
130
+ end
131
+ else
132
+ # TODO maybe do something with the reference
133
+ guard.check(controller_name,
134
+ action,
135
+ current_groups || [])
136
+ end
137
+ end
138
+ end
139
+ end
140
+
32
141
  protected
33
142
 
34
143
  def guard
35
- Rails.application.config.guard
144
+ self.class.guard
36
145
  end
37
146
 
38
- def check(association = nil, &block)
39
- group_method = respond_to?(:current_user_groups) ? :current_user_groups : :groups_for_current_user
40
- unless guard.allowed?(params[:controller],
41
- params[:action],
42
- send(group_method),
43
- association,
44
- &block)
45
- if association
46
- raise ::Ixtlan::Guard::PermissionDenied.new("permission denied for '#{params[:controller]}##{params[:action]}##{association.class}(#{association.id})'")
47
- else
48
- raise ::Ixtlan::Guard::PermissionDenied.new("permission denied for '#{params[:controller]}##{params[:action]}'")
147
+ def allowed?(action_or_actions,
148
+ controller = params[:controller],
149
+ reference = nil,
150
+ &block)
151
+ case action_or_actions
152
+ when Array
153
+ action_or_actions.detect do |action|
154
+ check(action, controller, reference, &block) != nil
49
155
  end
156
+ else
157
+ check(action_or_actions, controller, reference, &block) != nil
50
158
  end
51
- true
52
159
  end
53
- alias :authorize :check
54
160
 
55
- def authorization
56
- warn "DEPRECATED: use 'authorize' instead"
57
- check
161
+ def check(action = params[:action],
162
+ controller = params[:controller],
163
+ reference = nil,
164
+ &block)
165
+ unless block
166
+ filter = self.class.guard_filters.detect do |f|
167
+ f.allowed?(action)
168
+ end
169
+ end
170
+
171
+ if filter
172
+ guard.check(controller,
173
+ action,
174
+ current_groups || []) do |groups|
175
+ filter.proc(self).call(groups)
176
+ end
177
+ else
178
+ # TODO maybe do something with the reference
179
+ guard.check(controller,
180
+ action,
181
+ current_groups || [],
182
+ &block)
183
+ end
184
+ end
185
+
186
+ def authorize
187
+ unless check
188
+ raise ::Ixtlan::Guard::PermissionDenied.new("permission denied for '#{params[:controller]}##{params[:action]}'")
189
+ end
190
+ true
58
191
  end
59
192
  end
60
193
  end
61
- end
62
194
 
63
- module Allowed #:nodoc:
64
- # Inclusion hook to make #allowed available as method
65
- def self.included(base)
66
- base.send(:include, InstanceMethods)
67
- end
195
+ module Allowed
196
+ # Inclusion hook to make #allowed available as method
197
+ def self.included(base)
198
+ base.send(:include, InstanceMethods)
199
+ end
68
200
 
69
- module InstanceMethods #:nodoc:
70
- def allowed?(resource, action)
71
- controller.send(:guard).allowed?(resource, action, controller.send(:groups_for_current_user))
201
+ module InstanceMethods #:nodoc:
202
+ def allowed?(resource, action, reference = nil)
203
+ if resource.to_s != controller.class.controller_name || reference
204
+ other = "#{resource}Controller".classify.constantize
205
+ if other.respond_to?(:allowed?)
206
+ if reference
207
+ other.send(:allowed?, action, controller.current_groups, reference)
208
+ else
209
+ other.send(:allowed?, action, controller.current_groups)
210
+ end
211
+ else
212
+ raise "can not find 'allowed?' on #{other}"
213
+ end
214
+ else
215
+ controller.send(:allowed?, action, resource)
216
+ end
217
+ end
72
218
  end
73
219
  end
74
220
  end
@@ -1,5 +1,5 @@
1
1
  require 'rails'
2
- require 'ixtlan/guard/guard_ng'
2
+ require 'ixtlan/guard/guard'
3
3
  require 'ixtlan/guard/guard_rails'
4
4
  require 'logger'
5
5
  require 'fileutils'
@@ -10,6 +10,9 @@ module Ixtlan
10
10
 
11
11
  config.before_configuration do |app|
12
12
  app.config.guards_dir = File.join(Rails.root, "app", "guards")
13
+ # needs to be here ?!?
14
+ ::ActionController::Base.send(:include, Ixtlan::Guard::ActionController)
15
+ ::ActionView::Base.send(:include, Ixtlan::Guard::Allowed)
13
16
  end
14
17
 
15
18
  config.after_initialize do |app|
@@ -20,11 +23,11 @@ module Ixtlan
20
23
  }
21
24
  options[:logger] = logger unless defined?(Slf4r)
22
25
  FileUtils.mkdir_p(app.config.guards_dir)
23
- app.config.guard = Ixtlan::Guard::GuardNG.new(options)
24
26
 
25
- ::ActionController::Base.send(:include, Ixtlan::ActionController::Guard)
26
- ::ActionController::Base.send(:before_filter, :authorize)
27
- ::ActionView::Base.send(:include, Ixtlan::Allowed)
27
+ controller = ::ApplicationController rescue ::ActionController::Base
28
+ controller.send(:before_filter, :authorize)
29
+
30
+ app.config.guard = Ixtlan::Guard::Guard.new(options)
28
31
  end
29
32
 
30
33
  config.generators do
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
- require 'ixtlan/guard/guard_ng'
2
+ require 'ixtlan/guard/guard'
3
3
  require 'logger'
4
4
  require 'fileutils'
5
5
 
@@ -12,11 +12,11 @@ def $logger.debug(&block)
12
12
  # info("\n\t[debug] " + block.call)
13
13
  end
14
14
 
15
- describe Ixtlan::Guard::GuardNG do
15
+ describe Ixtlan::Guard::Guard do
16
16
 
17
17
  context "without caching" do
18
18
  def not_cached
19
- $not_cached ||= Ixtlan::Guard::GuardNG.new(:guards_dir => File.dirname($target),
19
+ $not_cached ||= Ixtlan::Guard::Guard.new(:guards_dir => File.dirname($target),
20
20
  :logger => $logger )
21
21
  end
22
22
 
@@ -37,7 +37,7 @@ describe Ixtlan::Guard::GuardNG do
37
37
 
38
38
  context "with caching" do
39
39
  def cached
40
- $cached ||= Ixtlan::Guard::GuardNG.new(:guards_dir => File.dirname($target),
40
+ $cached ||= Ixtlan::Guard::Guard.new(:guards_dir => File.dirname($target),
41
41
  :logger => $logger,
42
42
  :cache => true)
43
43
  end
@@ -1,21 +1,38 @@
1
1
  require 'spec_helper'
2
- require 'ixtlan/guard/guard_ng'
2
+ require 'ixtlan/guard/guard'
3
3
  require 'logger'
4
4
 
5
- describe Ixtlan::Guard::GuardNG do
5
+ describe Ixtlan::Guard::Guard do
6
+
7
+ def assert(expected, perms)
8
+ map = {}
9
+ expected.each do |e|
10
+ map[e[:permission][:resource]] = e
11
+ if e[:permission][:actions]
12
+ e[:permission][:actions].sort!{ |n,m| n[:action][:name] <=> m[:action][:name] }
13
+ end
14
+ end
15
+ perms.each do |perm|
16
+ if perm[:actions]
17
+ perm[:actions].sort!{ |n,m| n.content[:name] <=> m.content[:name] }
18
+ end
19
+ map[perm[:resource].to_s].should == perm
20
+ end
21
+ end
6
22
 
7
23
  subject do
8
24
  logger = Logger.new(STDOUT)
9
25
  def logger.debug(&block)
10
26
  # info("\n\t[debug] " + block.call)
11
27
  end
12
- Ixtlan::Guard::GuardNG.new(:guards_dir => File.join(File.dirname(__FILE__), "guards"), :logger => logger )
28
+ Ixtlan::Guard::Guard.new(:guards_dir => File.join(File.dirname(__FILE__), "guards"), :logger => logger )
13
29
  end
14
30
 
15
31
  context '#permissions' do
16
32
 
17
33
  it 'should deny all without defaults but wildcard "*" actions' do
18
- subject.permissions(['unknown_group']).sort { |n,m| n[:resource] <=> m[:resource] }.should == [
34
+ perm = subject.permissions(['unknown_group'])
35
+ expected = [
19
36
  #allow nothing
20
37
  {:permission=>{:resource=>"accounts", :actions=>[], :deny=>false}},
21
38
  # allow anything but index
@@ -41,9 +58,12 @@ describe Ixtlan::Guard::GuardNG do
41
58
  {:permission=>{:resource=>"regions", :actions=>[], :deny=>false}},
42
59
  #allow nothing
43
60
  {:permission=>{:resource=>"users", :actions=>[], :deny=>false}}]
61
+
62
+ assert(expected, perm)
44
63
  end
45
64
  it 'should deny some without defaults but wildcard "*" actions' do
46
- subject.permissions(['no_admin']).sort { |n,m| n[:resource] <=> m[:resource] }.should == [
65
+ perm = subject.permissions(['no_admin'])
66
+ expected = [
47
67
  #allow nothing
48
68
  {:permission=>{:resource=>"accounts", :actions=>[], :deny=>false}},
49
69
  # allow anything but index
@@ -72,9 +92,12 @@ describe Ixtlan::Guard::GuardNG do
72
92
  {:permission=>{:resource=>"regions", :actions=>[], :deny=>false}},
73
93
  #allow nothing
74
94
  {:permission=>{:resource=>"users", :actions=>[], :deny=>false}}]
95
+
96
+ assert(expected, perm)
75
97
  end
76
98
  it 'should allow "root"' do
77
- subject.permissions(['root']).sort { |n,m| n[:resource] <=> m[:resource] }.should == [
99
+ perm = subject.permissions(['root'])
100
+ expected = [
78
101
  {:permission=>{:resource=>"accounts", :actions=>[], :deny=>true}},
79
102
  {:permission=>{:resource=>"allow_all_defaults", :actions=>[], :deny=>true}},
80
103
  {:permission=>{:resource=>"defaults", :actions=>[], :deny=>true}},
@@ -83,9 +106,13 @@ describe Ixtlan::Guard::GuardNG do
83
106
  {:permission=>{:resource=>"person", :actions=>[], :deny=>true}},
84
107
  {:permission=>{:resource=>"regions", :actions=>[], :deny=>true}},
85
108
  {:permission=>{:resource=>"users", :actions=>[], :deny=>true}}]
86
- end
109
+
110
+ assert(expected, perm)
111
+ end
112
+
87
113
  it 'should allow with default group' do
88
- subject.permissions(['_master']).sort { |n,m| n[:resource] <=> m[:resource] }.should == [
114
+ perm = subject.permissions(['_master'])
115
+ expected = [
89
116
  #allow nothing
90
117
  {:permission=>{:resource=>"accounts", :actions=>[], :deny=>false}},
91
118
  # allow anything but index
@@ -112,10 +139,13 @@ describe Ixtlan::Guard::GuardNG do
112
139
  {:permission=>{:resource=>"regions", :actions=>[], :deny=>false}},
113
140
  #allow nothing
114
141
  {:permission=>{:resource=>"users", :actions=>[], :deny=>false}}]
142
+
143
+ assert(expected, perm)
115
144
  end
116
145
 
117
146
  it 'should allow with non-default group' do
118
- subject.permissions(['_admin']).sort { |n,m| n[:resource] <=> m[:resource] }.should == [
147
+ perm = subject.permissions(['_admin'])
148
+ expected = [
119
149
  #allow nothing
120
150
  {:permission=>{:resource=>"accounts", :actions=>[], :deny=>false}},
121
151
  # allow anything but index
@@ -143,6 +173,8 @@ describe Ixtlan::Guard::GuardNG do
143
173
  {:permission=>{:resource=>"regions", :actions=>[], :deny=>false}},
144
174
  #allow nothing
145
175
  {:permission=>{:resource=>"users", :actions=>[], :deny=>false}}]
176
+
177
+ assert(expected, perm)
146
178
  end
147
179
 
148
180
  it 'should allow with association' do
@@ -150,18 +182,12 @@ describe Ixtlan::Guard::GuardNG do
150
182
  def group.name
151
183
  "region"
152
184
  end
153
- subject.permissions([group])do |resource, action, groups|
185
+ perm = subject.permissions([group])do |resource, groups|
154
186
  if resource == 'regions'
155
- case action
156
- when 'show'
157
- {:associations => [:europe, :asia]}
158
- else
159
- {}
160
- end
161
- else
162
- {}
187
+ [:europe, :asia]
163
188
  end
164
- end.sort { |n,m| n[:resource] <=> m[:resource] }.should == [
189
+ end
190
+ expected = [
165
191
  #allow nothing
166
192
  {:permission=>{:resource=>"accounts", :actions=>[], :deny=>false}},
167
193
  # allow anything but index
@@ -194,10 +220,12 @@ describe Ixtlan::Guard::GuardNG do
194
220
  {:resource=>"regions",
195
221
  :actions=>
196
222
  [{:action=>{:name=>"show", :associations=>[:europe, :asia]}},
197
- {:action=>{:name=>"create"}}],
223
+ {:action=>{:name=>"create", :associations=>[:europe, :asia]}}],
198
224
  :deny=>false}},
199
225
  #allow nothing
200
226
  {:permission=>{:resource=>"users", :actions=>[], :deny=>false}}]
227
+
228
+ assert(expected, perm)
201
229
  end
202
230
  end
203
231
  end