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