ixtlan-guard 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +104 -0
- data/lib/ixtlan/guard.rb +1 -1
- data/lib/ixtlan/guard/{guard_ng.rb → guard.rb} +50 -34
- data/lib/ixtlan/guard/guard.rb~ +195 -0
- data/lib/ixtlan/guard/guard_config.rb +1 -2
- data/lib/ixtlan/guard/guard_rails.rb +181 -35
- data/lib/ixtlan/guard/railtie.rb +8 -5
- data/spec/guard_cache_spec.rb +4 -4
- data/spec/guard_export_spec.rb +48 -20
- data/spec/guard_rails_spec.rb +150 -0
- data/spec/guard_rails_spec.rb~ +150 -0
- data/spec/guard_spec.rb +17 -11
- data/spec/guard_with_associations_spec.rb +91 -75
- data/spec/guards/re_users_guard.yaml~ +4 -0
- metadata +10 -8
- data/features/step_definitions/ruby_maven.rb +0 -170
@@ -11,8 +11,7 @@ module Ixtlan
|
|
11
11
|
|
12
12
|
def allowed_groups(resource, action)
|
13
13
|
if resource && action
|
14
|
-
|
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
|
3
|
-
module
|
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
|
14
|
-
|
15
|
-
current_user
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
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
|
-
|
144
|
+
self.class.guard
|
36
145
|
end
|
37
146
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
56
|
-
|
57
|
-
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
-
|
70
|
-
|
71
|
-
|
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
|
data/lib/ixtlan/guard/railtie.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'rails'
|
2
|
-
require 'ixtlan/guard/
|
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
|
-
::
|
26
|
-
|
27
|
-
|
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
|
data/spec/guard_cache_spec.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'ixtlan/guard/
|
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::
|
15
|
+
describe Ixtlan::Guard::Guard do
|
16
16
|
|
17
17
|
context "without caching" do
|
18
18
|
def not_cached
|
19
|
-
$not_cached ||= Ixtlan::Guard::
|
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::
|
40
|
+
$cached ||= Ixtlan::Guard::Guard.new(:guards_dir => File.dirname($target),
|
41
41
|
:logger => $logger,
|
42
42
|
:cache => true)
|
43
43
|
end
|
data/spec/guard_export_spec.rb
CHANGED
@@ -1,21 +1,38 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'ixtlan/guard/
|
2
|
+
require 'ixtlan/guard/guard'
|
3
3
|
require 'logger'
|
4
4
|
|
5
|
-
describe Ixtlan::Guard::
|
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::
|
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'])
|
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'])
|
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'])
|
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
|
-
|
109
|
+
|
110
|
+
assert(expected, perm)
|
111
|
+
end
|
112
|
+
|
87
113
|
it 'should allow with default group' do
|
88
|
-
subject.permissions(['_master'])
|
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'])
|
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,
|
185
|
+
perm = subject.permissions([group])do |resource, groups|
|
154
186
|
if resource == 'regions'
|
155
|
-
|
156
|
-
when 'show'
|
157
|
-
{:associations => [:europe, :asia]}
|
158
|
-
else
|
159
|
-
{}
|
160
|
-
end
|
161
|
-
else
|
162
|
-
{}
|
187
|
+
[:europe, :asia]
|
163
188
|
end
|
164
|
-
end
|
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
|