tuersteher 0.1.4 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/tuersteher.rb +170 -91
- data/samples/access_rules.rb +15 -6
- data/spec/acces_rules_storage_spec.rb +40 -0
- data/spec/access_rules_spec.rb +170 -0
- data/spec/model_access_rule_spec.rb +42 -0
- data/spec/path_access_rule_spec.rb +129 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +6 -0
- data/tuersteher.gemspec +17 -4
- metadata +16 -6
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.1
|
data/lib/tuersteher.rb
CHANGED
@@ -53,22 +53,29 @@ module Tuersteher
|
|
53
53
|
end
|
54
54
|
|
55
55
|
|
56
|
+
def eval_rules rules_definitions
|
57
|
+
@path_rules = []
|
58
|
+
@model_rules = []
|
59
|
+
eval rules_definitions
|
60
|
+
Tuersteher::TLogger.logger.info "Tuersteher::AccessRulesStorage: #{@path_rules.size} path-rules and #{@model_rules.size} model-rules"
|
61
|
+
end
|
62
|
+
|
56
63
|
# Laden der AccesRules aus den Dateien
|
57
64
|
# config/access_rules.rb
|
58
65
|
def read_rules
|
59
66
|
@rules_config_file ||= File.join(Rails.root, 'config', DEFAULT_RULES_CONFIG_FILE)
|
60
67
|
rules_file = File.new @rules_config_file
|
61
68
|
@was_read = false
|
69
|
+
content = nil
|
62
70
|
if @last_mtime.nil? || rules_file.mtime > @last_mtime
|
63
71
|
@last_mtime = rules_file.mtime
|
64
|
-
@path_rules = []
|
65
|
-
@model_rules = []
|
66
72
|
content = rules_file.read
|
67
|
-
eval content
|
68
|
-
Tuersteher::TLogger.logger.info "Tuersteher::AccessRulesStorage: #{@path_rules.size} path-rules and #{@model_rules.size} model-rules"
|
69
73
|
end
|
70
74
|
rules_file.close
|
71
|
-
|
75
|
+
if content
|
76
|
+
eval_rules content
|
77
|
+
@was_read = true
|
78
|
+
end
|
72
79
|
rescue => ex
|
73
80
|
Tuersteher::TLogger.logger.error "Tuersteher::AccessRulesStorage - Error in rules: #{ex.message}\n\t"+ex.backtrace.join("\n\t")
|
74
81
|
end
|
@@ -77,26 +84,13 @@ module Tuersteher
|
|
77
84
|
#
|
78
85
|
# path: :all fuer beliebig, sonst String mit der http-path beginnen muss,
|
79
86
|
# wird als RegEX-Ausdruck ausgewertet
|
80
|
-
|
81
|
-
|
82
|
-
# hier ist auch ein Array von Symbolen möglich
|
83
|
-
def grant_path url_path, http_methode, *accepted_roles
|
84
|
-
@path_rules << PathAccessRule.new(url_path, http_methode, *accepted_roles)
|
85
|
-
end
|
86
|
-
|
87
|
-
# definiert HTTP-Pfad-basierende Ablehnungsregel
|
88
|
-
#
|
89
|
-
# path: :all fuer beliebig, sonst String mit der http-path beginnen muss,
|
90
|
-
# wird als RegEX-Ausdruck ausgewertet
|
91
|
-
# method: http-Methode, es sind hier erlaubt :get, :put, :delete, :post, :all
|
92
|
-
# accepted_roles: Aufzaehlung der erfoderlichen Rolen (oder-Verknuepfung), es sind nur Symbole zulaessig
|
93
|
-
# hier ist auch ein Array von Symbolen möglich
|
94
|
-
def deny_path url_path, http_methode, *accepted_roles
|
95
|
-
rule = PathAccessRule.new(url_path, http_methode, *accepted_roles)
|
96
|
-
rule.deny = true
|
87
|
+
def path url_path
|
88
|
+
rule = PathAccessRule.new(url_path)
|
97
89
|
@path_rules << rule
|
90
|
+
rule
|
98
91
|
end
|
99
92
|
|
93
|
+
|
100
94
|
# definiert Model-basierende Zugriffsregel
|
101
95
|
#
|
102
96
|
# model_class: Model-Klassenname oder :all fuer alle
|
@@ -110,30 +104,32 @@ module Tuersteher
|
|
110
104
|
# grant_model(User, :update, :all){|model,user| model.id==user.id}
|
111
105
|
# </code>
|
112
106
|
#
|
113
|
-
def
|
114
|
-
|
107
|
+
def model model_class
|
108
|
+
if block_given?
|
109
|
+
@current_model_class = model_class
|
110
|
+
yield
|
111
|
+
@current_model_class = nil
|
112
|
+
else
|
113
|
+
rule = ModelAccessRule.new(model_class)
|
114
|
+
@model_rules << rule
|
115
|
+
rule
|
116
|
+
end
|
115
117
|
end
|
116
118
|
|
117
|
-
|
118
|
-
|
119
|
-
# model_class: Model-Klassenname oder :all fuer alle
|
120
|
-
# access_type: Zugriffsart (:create, :update, :destroy, :all o.A. selbst definierte Typen)
|
121
|
-
# roles Aufzählung der erforderliche Rolen (:all für ist egal),
|
122
|
-
# hier ist auch ein Array von Symbolen möglich
|
123
|
-
# block optionaler Block, wird mit model und user aufgerufen und muss true oder false liefern
|
124
|
-
# hier ein Beispiel mit Block:
|
125
|
-
# <code>
|
126
|
-
# # Regel, in der sich jeder User selbst aendern darf
|
127
|
-
# grant_model(User, :update, :all){|model,user| model.id==user.id}
|
128
|
-
# </code>
|
129
|
-
#
|
130
|
-
def deny_model model_class, access_type, *roles, &block
|
131
|
-
rule = ModelAccessRule.new(model_class, access_type, *roles, &block)
|
132
|
-
rule.deny = true
|
119
|
+
def grant
|
120
|
+
rule = ModelAccessRule.new(@current_model_class)
|
133
121
|
@model_rules << rule
|
122
|
+
rule.grant
|
134
123
|
end
|
135
124
|
|
136
|
-
|
125
|
+
def deny
|
126
|
+
rule = ModelAccessRule.new(@current_model_class)
|
127
|
+
@model_rules << rule
|
128
|
+
rule.deny
|
129
|
+
end
|
130
|
+
|
131
|
+
end # of AccessRulesStorage
|
132
|
+
|
137
133
|
|
138
134
|
class AccessRules
|
139
135
|
|
@@ -149,14 +145,14 @@ module Tuersteher
|
|
149
145
|
if Tuersteher::TLogger.logger.debug?
|
150
146
|
if rule.nil?
|
151
147
|
s = 'denied'
|
152
|
-
elsif rule.deny
|
148
|
+
elsif rule.deny?
|
153
149
|
s = "denied with #{rule}"
|
154
150
|
else
|
155
151
|
s = "granted with #{rule}"
|
156
152
|
end
|
157
153
|
Tuersteher::TLogger.logger.debug("Tuersteher: path_access?(#{path}, #{method}) => #{s}")
|
158
154
|
end
|
159
|
-
rule!=nil && !rule.deny
|
155
|
+
rule!=nil && !rule.deny?
|
160
156
|
end
|
161
157
|
|
162
158
|
|
@@ -174,7 +170,7 @@ module Tuersteher
|
|
174
170
|
rule = AccessRulesStorage.instance.model_rules.detect do |rule|
|
175
171
|
rule.fired? model, permission, user
|
176
172
|
end
|
177
|
-
access = rule && !rule.deny
|
173
|
+
access = rule && !rule.deny?
|
178
174
|
if Tuersteher::TLogger.logger.debug?
|
179
175
|
if model.instance_of?(Class)
|
180
176
|
Tuersteher::TLogger.logger.debug("Tuersteher: model_access?(#{model}, #{permission}) => #{access || 'denied'} #{rule}")
|
@@ -192,7 +188,7 @@ module Tuersteher
|
|
192
188
|
def self.purge_collection user, collection, permission
|
193
189
|
collection.select{|model| model_access?(user, model, permission)}
|
194
190
|
end
|
195
|
-
end
|
191
|
+
end # of AccessRules
|
196
192
|
|
197
193
|
|
198
194
|
|
@@ -204,7 +200,7 @@ module Tuersteher
|
|
204
200
|
#
|
205
201
|
# Der Loginuser muss fuer die hier benoetigte Funktionalitaet
|
206
202
|
# die Methode:
|
207
|
-
# has_role?(
|
203
|
+
# has_role?(role) # role the Name of the Role as Symbol
|
208
204
|
# besitzen.
|
209
205
|
#
|
210
206
|
# Beispiel der Einbindung in den ApplicationController
|
@@ -274,10 +270,55 @@ module Tuersteher
|
|
274
270
|
|
275
271
|
end
|
276
272
|
|
273
|
+
# Astracte base class for Access-Rules
|
274
|
+
class BaseAccessRule
|
275
|
+
|
276
|
+
def initialize
|
277
|
+
@roles = []
|
278
|
+
end
|
279
|
+
|
280
|
+
# add role
|
281
|
+
def role(role_name)
|
282
|
+
raise "wrong role '#{role_name}'! Must be a symbol " unless role_name.is_a?(Symbol)
|
283
|
+
@roles << role_name
|
284
|
+
self
|
285
|
+
end
|
277
286
|
|
278
|
-
|
279
|
-
|
280
|
-
|
287
|
+
|
288
|
+
def extension method_name, methode_parameter=nil
|
289
|
+
@check_extensions ||= {}
|
290
|
+
@check_extensions[method_name] = methode_parameter
|
291
|
+
self
|
292
|
+
end
|
293
|
+
|
294
|
+
def grant
|
295
|
+
self
|
296
|
+
end
|
297
|
+
|
298
|
+
def deny
|
299
|
+
@deny = true
|
300
|
+
self
|
301
|
+
end
|
302
|
+
|
303
|
+
def deny?
|
304
|
+
@deny
|
305
|
+
end
|
306
|
+
|
307
|
+
protected
|
308
|
+
|
309
|
+
def grant_role? user
|
310
|
+
return true if @roles.empty?
|
311
|
+
return false if user.nil?
|
312
|
+
@roles.each do |role|
|
313
|
+
return true if user.has_role?(role)
|
314
|
+
end
|
315
|
+
false
|
316
|
+
end
|
317
|
+
|
318
|
+
end # of BaseAccessRule
|
319
|
+
|
320
|
+
|
321
|
+
class PathAccessRule < BaseAccessRule
|
281
322
|
|
282
323
|
METHOD_NAMES = [:get, :edit, :put, :delete, :post, :all].freeze
|
283
324
|
|
@@ -285,17 +326,10 @@ module Tuersteher
|
|
285
326
|
# Zugriffsregel
|
286
327
|
#
|
287
328
|
# path :all fuer beliebig, sonst String mit der http-path beginnen muss
|
288
|
-
# method http-Methode, es sind hier erlaubt :get, :put, :delete, :post, :all
|
289
|
-
# needed_roles Aufzaehlung der erfoderlichen Rolen (oder-Verknuepfung), es sind nur Symbole zulaessig
|
290
329
|
#
|
291
|
-
def initialize(path
|
330
|
+
def initialize(path)
|
292
331
|
raise "wrong path '#{path}'! Must be a String or :all ." unless path==:all or path.is_a?(String)
|
293
|
-
|
294
|
-
raise "needed_roles expected!" if needed_roles.empty?
|
295
|
-
@roles = needed_roles.flatten
|
296
|
-
for r in @roles
|
297
|
-
raise "wrong role '#{r}'! Must be a symbol " unless r.is_a?(Symbol)
|
298
|
-
end
|
332
|
+
super()
|
299
333
|
@path = path
|
300
334
|
if path != :all
|
301
335
|
# path in regex ^#{path} wandeln ausser bei "/",
|
@@ -307,10 +341,19 @@ module Tuersteher
|
|
307
341
|
@path = /^#{path}/
|
308
342
|
end
|
309
343
|
end
|
310
|
-
@
|
344
|
+
@http_method = :all
|
345
|
+
end
|
346
|
+
|
347
|
+
# set http-methode
|
348
|
+
# http_method http-Method, allowed is :get, :put, :delete, :post, :all
|
349
|
+
def method(http_method)
|
350
|
+
raise "wrong method '#{http_method}'! Must be #{METHOD_NAMES.join(', ')} !" unless METHOD_NAMES.include?(http_method)
|
351
|
+
@http_method = http_method
|
352
|
+
self
|
311
353
|
end
|
312
354
|
|
313
355
|
|
356
|
+
|
314
357
|
# pruefen, ob Zugriff fuer angegebenen
|
315
358
|
# path / method fuer den current_user erlaubt ist
|
316
359
|
#
|
@@ -320,35 +363,57 @@ module Tuersteher
|
|
320
363
|
#
|
321
364
|
def fired?(path, method, user)
|
322
365
|
user = nil if user==:false # manche Authenticate-System setzen den user auf :false
|
366
|
+
|
323
367
|
if @path!=:all && !(@path =~ path)
|
324
368
|
return false
|
325
369
|
end
|
326
370
|
|
327
|
-
if @
|
371
|
+
if @http_method!=:all && @http_method != method
|
328
372
|
return false
|
329
373
|
end
|
330
374
|
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
if user && user.has_role?(*@roles)
|
335
|
-
return true
|
375
|
+
if !@roles.empty? && (user.nil? || !user.has_role?(*@roles))
|
376
|
+
#Tuersteher::TLogger.logger.debug("#{to_s}.has_access? => false why #{@roles.first}!=:all && #{!user.has_role?(*@roles)}")
|
377
|
+
return false
|
336
378
|
end
|
337
|
-
|
379
|
+
|
380
|
+
return false unless grant_extension?(user)
|
381
|
+
|
382
|
+
true
|
338
383
|
end
|
339
384
|
|
340
385
|
|
341
386
|
def to_s
|
342
|
-
"PathAccesRule[#{@path}, #{@
|
387
|
+
s = "PathAccesRule[#{@deny ? 'DENY ' : ''}#{@path}, #{@http_method}, #{@roles.join(' ')}"
|
388
|
+
s << " #{@check_extensions.inspect}" if @check_extensions
|
389
|
+
s << ']'
|
390
|
+
s
|
391
|
+
end
|
392
|
+
|
393
|
+
private
|
394
|
+
|
395
|
+
def grant_extension? user
|
396
|
+
return true if @check_extensions.nil?
|
397
|
+
return false if user.nil? # check_extensions need a user
|
398
|
+
@check_extensions.each do |key, value|
|
399
|
+
unless user.respond_to?(key)
|
400
|
+
Tuersteher::TLogger.logger.warn("#{to_s}.fired? => false why user have not check-extension method '#{key}'!")
|
401
|
+
return false
|
402
|
+
end
|
403
|
+
if value
|
404
|
+
return false unless user.send(key,value)
|
405
|
+
else
|
406
|
+
return false unless user.send(key)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
true
|
343
410
|
end
|
344
411
|
|
345
412
|
end
|
346
413
|
|
347
414
|
|
348
415
|
|
349
|
-
class ModelAccessRule
|
350
|
-
attr_reader :clazz, :access_type, :roles, :block
|
351
|
-
attr_accessor :deny
|
416
|
+
class ModelAccessRule < BaseAccessRule
|
352
417
|
|
353
418
|
# erzeugt neue Object-Zugriffsregel
|
354
419
|
#
|
@@ -363,16 +428,16 @@ module Tuersteher
|
|
363
428
|
# ModelAccessRule.new(User, :update, :all){|model,user| model.id==user.id}
|
364
429
|
# </code>
|
365
430
|
#
|
366
|
-
def initialize(clazz
|
431
|
+
def initialize(clazz)
|
367
432
|
raise "wrong clazz '#{clazz}'! Must be a Class or :all ." unless clazz==:all or clazz.is_a?(Class)
|
368
|
-
|
369
|
-
@roles = roles.flatten
|
370
|
-
for r in @roles
|
371
|
-
raise "wrong role '#{r}'! Must be a symbol " unless r.is_a?(Symbol)
|
372
|
-
end
|
433
|
+
super()
|
373
434
|
@clazz = clazz.instance_of?(Symbol) ? clazz : clazz.to_s
|
374
|
-
|
375
|
-
|
435
|
+
end
|
436
|
+
|
437
|
+
|
438
|
+
def permission permission_name
|
439
|
+
@permission = permission_name
|
440
|
+
self
|
376
441
|
end
|
377
442
|
|
378
443
|
# liefert true, wenn zugriff fuer das angegebene model mit
|
@@ -388,36 +453,50 @@ module Tuersteher
|
|
388
453
|
#
|
389
454
|
def fired? model, perm, user
|
390
455
|
user = nil if user==:false # manche Authenticate-System setzen den user auf :false
|
456
|
+
debugger
|
391
457
|
m_class = model.instance_of?(Class) ? model : model.class
|
392
458
|
if @clazz!=m_class.to_s && @clazz!=:all
|
393
459
|
#Tuersteher::TLogger.logger.debug("#{to_s}.has_access? => false why #{@clazz}!=#{model.class.to_s} && #{@clazz}!=:all")
|
394
460
|
return false
|
395
461
|
end
|
396
462
|
|
397
|
-
if @
|
463
|
+
if @permission!=:all && @permission!=perm
|
398
464
|
#Tuersteher::TLogger.logger.debug("#{to_s}.has_access? => false why #{@access_type}!=:all && #{@access_type}!=#{perm}")
|
399
465
|
return false
|
400
466
|
end
|
401
467
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
468
|
+
return false unless grant_role?(user)
|
469
|
+
return false unless grant_extension?(user, model)
|
470
|
+
true
|
471
|
+
end
|
472
|
+
|
473
|
+
def to_s
|
474
|
+
s = "ModelAccessRule[#{@deny ? 'DENY ' : ''}#{@clazz}, #{@permission}, #{@roles.join(' ')}"
|
475
|
+
s << " #{@check_extensions.inspect}" if @check_extensions
|
476
|
+
s << ']'
|
477
|
+
s
|
478
|
+
end
|
479
|
+
|
480
|
+
private
|
406
481
|
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
482
|
+
def grant_extension? user, model
|
483
|
+
return true if @check_extensions.nil?
|
484
|
+
return false if model.nil? # check_extensions need a model
|
485
|
+
return false if model.instance_of?(Class) # no Extension-Call if model is a Class-Instance
|
486
|
+
@check_extensions.each do |key, value|
|
487
|
+
unless model.respond_to?(key)
|
488
|
+
Tuersteher::TLogger.logger.warn("#{to_s}.fired? => false why model-onject have not check-extension method '#{key}'!")
|
411
489
|
return false
|
412
490
|
end
|
491
|
+
if value
|
492
|
+
return false unless model.send(key,user,value)
|
493
|
+
else
|
494
|
+
return false unless model.send(key,user)
|
495
|
+
end
|
413
496
|
end
|
414
497
|
true
|
415
498
|
end
|
416
499
|
|
417
|
-
def to_s
|
418
|
-
"ModelAccessRule[#{@clazz}, #{@access_type}, #{@roles.join(' ')}#{@deny ? ' deny' : ''}]"
|
419
|
-
end
|
420
|
-
|
421
500
|
end
|
422
501
|
|
423
502
|
|
data/samples/access_rules.rb
CHANGED
@@ -12,9 +12,11 @@
|
|
12
12
|
# Methode : :all, :get, :put, :post, :delete oder :edit
|
13
13
|
# roles :Liste der berechtigten Rollen (es können mehrere Rollen durch Komma getrennt angegeben werden)
|
14
14
|
#
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
|
16
|
+
path('/').grant.method(:get)
|
17
|
+
path(:all).grant.role(:ADMIN)
|
18
|
+
path('/user/lock').deny.role(:USER).role(:APPROVER)
|
19
|
+
path('/special').grant.extension(:special?, :area1)
|
18
20
|
|
19
21
|
#
|
20
22
|
# Model-Object-Zugriffsregeln
|
@@ -24,7 +26,14 @@ deny_path '/user/lock', :user
|
|
24
26
|
# Roles : Aufzählung der Rollen
|
25
27
|
# Block : optionaler Block, diesem wird die Model-Instance und der User als Parameter bereitgestellt
|
26
28
|
|
27
|
-
grant_model String, :view, :all
|
28
|
-
grant_model String, :view, :ADMIN, :EDITOR
|
29
|
-
grant_model String, :update, :EDITOR do |model, user| model == user.name end
|
29
|
+
#grant_model String, :view, :all
|
30
|
+
#grant_model String, :view, :ADMIN, :EDITOR
|
31
|
+
#grant_model String, :update, :EDITOR do |model, user| model == user.name end
|
32
|
+
|
33
|
+
model(Dashboard).grant.permission(:view)
|
30
34
|
|
35
|
+
model(Todo) do
|
36
|
+
grant.permission(:view)
|
37
|
+
grant.permission(:full_view).role(:ADMIN)
|
38
|
+
grant.permission(:update).role(:EDITOR).extension(:owned_by?) # calls Todo.owned_by?(current_user)
|
39
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Tuersteher
|
4
|
+
|
5
|
+
class Dashboard; end
|
6
|
+
class Todo; end
|
7
|
+
|
8
|
+
describe AccessRulesStorage do
|
9
|
+
|
10
|
+
context "eval_rules" do
|
11
|
+
before(:all) do
|
12
|
+
rule_defs = <<-EOR
|
13
|
+
path('/').grant.method(:get)
|
14
|
+
path(:all).grant.role(:ADMIN)
|
15
|
+
path('/special').grant.extension(:special?, :area1)
|
16
|
+
|
17
|
+
model(Dashboard).grant.permission(:view)
|
18
|
+
model(Todo) do
|
19
|
+
grant.permission(:view)
|
20
|
+
grant.permission(:full_view).role(:ADMIN)
|
21
|
+
grant.permission(:update).role(:EDITOR).extension(:owned_by?) # calls Todo.owned_by?(current_user)
|
22
|
+
end
|
23
|
+
EOR
|
24
|
+
AccessRulesStorage.instance.eval_rules rule_defs
|
25
|
+
@path_rules = AccessRulesStorage.instance.path_rules
|
26
|
+
@model_rules = AccessRulesStorage.instance.model_rules
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should have 3 path-rules" do
|
30
|
+
@path_rules.should have(3).items
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should have 4 model-rules" do
|
34
|
+
@model_rules.should have(4).items
|
35
|
+
end
|
36
|
+
|
37
|
+
end # of context "eval_rules"
|
38
|
+
|
39
|
+
end # of describe AccessRulesStorage
|
40
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
module Tuersteher
|
6
|
+
|
7
|
+
describe AccessRules do
|
8
|
+
|
9
|
+
context 'path_access?' do
|
10
|
+
before do
|
11
|
+
rules = [
|
12
|
+
PathAccessRule.new('/'),
|
13
|
+
PathAccessRule.new('/admin').role(:admin),
|
14
|
+
PathAccessRule.new('/images').method(:get),
|
15
|
+
PathAccessRule.new('/status').method(:get).role(:system)
|
16
|
+
]
|
17
|
+
AccessRulesStorage.instance.stub(:path_rules).and_return(rules)
|
18
|
+
@user = stub('user')
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
context "User with role :user" do
|
23
|
+
before do
|
24
|
+
@user.stub(:has_role?){|role| role==:user}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be true for this paths" do
|
28
|
+
AccessRules.path_access?(@user, '/', :get).should be_true
|
29
|
+
AccessRules.path_access?(@user, '/', :post).should be_true
|
30
|
+
AccessRules.path_access?(@user, '/images', :get).should be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should not be true for this paths" do
|
34
|
+
AccessRules.path_access?(@user, '/admin', :get).should_not be_true
|
35
|
+
AccessRules.path_access?(@user, '/images', :post).should_not be_true
|
36
|
+
AccessRules.path_access?(@user, '/status', :get).should_not be_true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
context "User with role :admin" do
|
42
|
+
before do
|
43
|
+
@user.stub(:has_role?){|role| role==:admin}
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should be true for this paths" do
|
47
|
+
AccessRules.path_access?(@user, '/', :get).should be_true
|
48
|
+
AccessRules.path_access?(@user, '/admin', :post).should be_true
|
49
|
+
AccessRules.path_access?(@user, '/images', :get).should be_true
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should not be true for this paths" do
|
53
|
+
AccessRules.path_access?(@user, '/xyz', :get).should_not be_true
|
54
|
+
AccessRules.path_access?(@user, '/images', :post).should_not be_true
|
55
|
+
AccessRules.path_access?(@user, '/status', :get).should_not be_true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
context "User with role :system" do
|
61
|
+
before do
|
62
|
+
@user.stub(:has_role?){|role| role==:system}
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should be true for this paths" do
|
66
|
+
AccessRules.path_access?(@user, '/', :get).should be_true
|
67
|
+
AccessRules.path_access?(@user, '/status', :get).should be_true
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should not be true for this paths" do
|
71
|
+
AccessRules.path_access?(@user, '/xyz', :get).should_not be_true
|
72
|
+
AccessRules.path_access?(@user, '/admin', :post).should_not be_true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
context 'model_access?' do
|
79
|
+
|
80
|
+
class SampleModel1; end
|
81
|
+
class SampleModel2; end
|
82
|
+
|
83
|
+
before do
|
84
|
+
rules = [
|
85
|
+
ModelAccessRule.new(SampleModel1).grant.permission(:all),
|
86
|
+
ModelAccessRule.new(SampleModel2).grant.permission(:read),
|
87
|
+
ModelAccessRule.new(SampleModel2).grant.permission(:update).role(:user).extension(:owner?),
|
88
|
+
ModelAccessRule.new(SampleModel2).deny.permission(:create),
|
89
|
+
ModelAccessRule.new(SampleModel2).grant.permission(:all).role(:admin),
|
90
|
+
]
|
91
|
+
AccessRulesStorage.instance.stub(:model_rules).and_return(rules)
|
92
|
+
@user = stub('user')
|
93
|
+
@model1 = SampleModel1.new
|
94
|
+
@model2 = SampleModel2.new
|
95
|
+
@model2.stub(:owner?).and_return(false)
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
context "User with role :user" do
|
100
|
+
before do
|
101
|
+
@user.stub(:has_role?){|role| role==:user}
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should be true for this" do
|
105
|
+
AccessRules.model_access?(@user, @model1, :xyz).should be_true
|
106
|
+
@model2.stub(:owner?).and_return true
|
107
|
+
AccessRules.model_access?(@user, @model2, :read).should be_true
|
108
|
+
AccessRules.model_access?(@user, @model2, :update).should be_true
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should not be true for this" do
|
112
|
+
AccessRules.model_access?(@user, @model2, :update).should_not be_true
|
113
|
+
AccessRules.model_access?(@user, @model2, :delete).should_not be_true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
context "User with role :admin" do
|
119
|
+
before do
|
120
|
+
@user.stub(:has_role?){|role| role==:admin}
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should be true for this" do
|
124
|
+
AccessRules.model_access?(@user, @model1, :xyz).should be_true
|
125
|
+
AccessRules.model_access?(@user, @model2, :read).should be_true
|
126
|
+
AccessRules.model_access?(@user, @model2, :update).should be_true
|
127
|
+
AccessRules.model_access?(@user, @model2, :delete).should be_true
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should not be true for this" do
|
131
|
+
AccessRules.model_access?(@user, @model2, :create).should_not be_true
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
|
138
|
+
context 'purge_collection' do
|
139
|
+
|
140
|
+
class SampleModel
|
141
|
+
def owner? user; false; end
|
142
|
+
end
|
143
|
+
|
144
|
+
before do
|
145
|
+
rules = [
|
146
|
+
ModelAccessRule.new(SampleModel).permission(:update).role(:admin),
|
147
|
+
ModelAccessRule.new(SampleModel).permission(:update).role(:user).extension(:owner?),
|
148
|
+
]
|
149
|
+
AccessRulesStorage.instance.stub(:model_rules).and_return(rules)
|
150
|
+
@user = stub('user')
|
151
|
+
@model1 = SampleModel.new
|
152
|
+
@model2 = SampleModel.new
|
153
|
+
@model3 = SampleModel.new
|
154
|
+
@model3.stub(:owner?).and_return(true)
|
155
|
+
@collection = [@model1, @model2, @model3]
|
156
|
+
end
|
157
|
+
|
158
|
+
it "Should return [@model3] for user with role=:user" do
|
159
|
+
@user.stub(:has_role?){|role| role==:user}
|
160
|
+
AccessRules.purge_collection(@user, @collection, :update).should == [@model3]
|
161
|
+
end
|
162
|
+
|
163
|
+
it "Should return all for user with role=:admin" do
|
164
|
+
@user.stub(:has_role?){|role| role==:admin}
|
165
|
+
AccessRules.purge_collection(@user, @collection, :update).should == @collection
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Tuersteher
|
4
|
+
|
5
|
+
describe ModelAccessRule do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@rule = ModelAccessRule.new(String).grant.permission(:read).role(:sysadmin).role(:admin)
|
9
|
+
end
|
10
|
+
|
11
|
+
context "for User with role :admin" do
|
12
|
+
before do
|
13
|
+
@user = stub('user')
|
14
|
+
@user.stub(:has_role?){|role| role==:admin}
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be fired for String-Object and access-type :read" do
|
18
|
+
@rule.fired?("test", :read, @user).should be_true
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should not be fired for Non-String-Object" do
|
22
|
+
@rule.fired?(12345, :read, @user).should_not be_true
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should not be fired for String-Object and other access-type as :read" do
|
26
|
+
@rule.fired?("test", :delete, @user).should_not be_true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "for User without role :admin" do
|
31
|
+
before do
|
32
|
+
@user = stub('user')
|
33
|
+
@user.stub(:has_role?).and_return(false)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should not be fired for String-Object and access-type :read" do
|
37
|
+
@rule.fired?("test", :read, @user).should_not be_true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Tuersteher
|
4
|
+
|
5
|
+
describe PathAccessRule do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@rule = PathAccessRule.new('/admin').method(:get).role(:sysadmin).role(:admin)
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
context "for User with role :admin" do
|
13
|
+
before do
|
14
|
+
@user = stub('user')
|
15
|
+
@user.stub(:has_role?).with(:sysadmin, :admin).and_return(true)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be fired for path='/admin/xyz' and method :get" do
|
19
|
+
@rule.fired?("/admin/xyz", :get, @user).should be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should not be fired for other path" do
|
23
|
+
@rule.fired?('/todos/admin', :get, @user).should_not be_true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should not be fired for other method as :get" do
|
27
|
+
@rule.fired?("/admin/xyz", :post, @user).should_not be_true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
context "for User without role :admin" do
|
33
|
+
before do
|
34
|
+
@user = stub('user')
|
35
|
+
@user.stub(:has_role?).and_return(false)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not be fired for correct path and method" do
|
39
|
+
@rule.fired?("/admin/xyz", :get, @user).should_not be_true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
context "Rule with :all as Path-Matcher" do
|
45
|
+
before(:all) do
|
46
|
+
@rule = PathAccessRule.new(:all).method(:get).role(:sysadmin).role(:admin)
|
47
|
+
@user = stub('user')
|
48
|
+
@user.stub(:has_role?).and_return(true)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should fired for several paths" do
|
52
|
+
@rule.fired?("/admin/xyz", :get, @user).should be_true
|
53
|
+
@rule.fired?("/xyz", :get, @user).should be_true
|
54
|
+
@rule.fired?("/", :get, @user).should be_true
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should not be fired with other method" do
|
58
|
+
@rule.fired?("/admin/xyz", :post, @user).should_not be_true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
context "Rule with no Methode spezifed => all methods allowed" do
|
64
|
+
before(:all) do
|
65
|
+
@rule = PathAccessRule.new('/admin').role(:sysadmin).role(:admin)
|
66
|
+
@user = stub('user')
|
67
|
+
@user.stub(:has_role?).and_return(true)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should fired for several methods" do
|
71
|
+
@rule.fired?("/admin/xyz", :get, @user).should be_true
|
72
|
+
@rule.fired?("/admin/xyz", :post, @user).should be_true
|
73
|
+
@rule.fired?("/admin/xyz", :put, @user).should be_true
|
74
|
+
@rule.fired?("/admin/xyz", :delete, @user).should be_true
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should not be fired with other path" do
|
78
|
+
@rule.fired?("/xyz", :post, @user).should_not be_true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
context "Rule with no role spezifed => now role needed" do
|
84
|
+
before(:all) do
|
85
|
+
@rule = PathAccessRule.new('/admin').method(:get)
|
86
|
+
@user = stub('user')
|
87
|
+
@user.stub(:has_role?).and_return(false)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should fired for user with no roles" do
|
91
|
+
@rule.fired?("/admin/xyz", :get, @user).should be_true
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should not be fired with other path" do
|
95
|
+
@rule.fired?("/xyz", :get, @user).should_not be_true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
context "Rule with extension" do
|
101
|
+
before(:all) do
|
102
|
+
@rule = PathAccessRule.new('/admin').method(:get).extension(:modul_function?, :testvalue)
|
103
|
+
@rule2 = PathAccessRule.new('/admin').method(:get).extension(:modul_function2?)
|
104
|
+
@user = stub('user')
|
105
|
+
@user.stub(:has_role?).and_return(false)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should not be fired with user have not the check_extension" do
|
109
|
+
@rule.fired?("/admin", :get, @user).should_not be_true
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should fired for user with true for check-extension" do
|
113
|
+
@user.should_receive(:modul_function?).with(:testvalue).and_return(true)
|
114
|
+
@rule.fired?("/admin/xyz", :get, @user).should be_true
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should not be fired for user with false for check-extension" do
|
118
|
+
@user.should_receive(:modul_function?).with(:testvalue).and_return(false)
|
119
|
+
@rule.fired?("/admin/xyz", :get, @user).should_not be_true
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should fired for rule2 and user with true for check-extension" do
|
123
|
+
@user.should_receive(:modul_function2?).and_return(true)
|
124
|
+
@rule2.fired?("/admin/xyz", :get, @user).should be_true
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
data/tuersteher.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{tuersteher}
|
8
|
-
s.version = "0.1
|
8
|
+
s.version = "0.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Bernd Ledig"]
|
12
|
-
s.date = %q{2010-08-
|
12
|
+
s.date = %q{2010-08-28}
|
13
13
|
s.description = %q{Security-Layer for Rails-Application acts like a firewall.}
|
14
14
|
s.email = %q{bernd@ledig.info}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -26,19 +26,32 @@ Gem::Specification.new do |s|
|
|
26
26
|
"license.txt",
|
27
27
|
"samples/access_rules.rb",
|
28
28
|
"samples/application_controller.rb",
|
29
|
+
"spec/acces_rules_storage_spec.rb",
|
30
|
+
"spec/access_rules_spec.rb",
|
31
|
+
"spec/model_access_rule_spec.rb",
|
32
|
+
"spec/path_access_rule_spec.rb",
|
33
|
+
"spec/spec.opts",
|
34
|
+
"spec/spec_helper.rb",
|
29
35
|
"tuersteher.gemspec"
|
30
36
|
]
|
31
37
|
s.homepage = %q{http://github.com/bledig/tuersteher}
|
32
38
|
s.rdoc_options = ["--charset=UTF-8"]
|
33
39
|
s.require_paths = ["lib"]
|
34
|
-
s.rubygems_version = %q{1.3.
|
40
|
+
s.rubygems_version = %q{1.3.7}
|
35
41
|
s.summary = %q{Security-Layer for Rails-Application}
|
42
|
+
s.test_files = [
|
43
|
+
"spec/spec_helper.rb",
|
44
|
+
"spec/access_rules_spec.rb",
|
45
|
+
"spec/path_access_rule_spec.rb",
|
46
|
+
"spec/model_access_rule_spec.rb",
|
47
|
+
"spec/acces_rules_storage_spec.rb"
|
48
|
+
]
|
36
49
|
|
37
50
|
if s.respond_to? :specification_version then
|
38
51
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
39
52
|
s.specification_version = 3
|
40
53
|
|
41
|
-
if Gem::Version.new(Gem::
|
54
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
42
55
|
else
|
43
56
|
end
|
44
57
|
else
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tuersteher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 2
|
8
9
|
- 1
|
9
|
-
|
10
|
-
version: 0.1.4
|
10
|
+
version: 0.2.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Bernd Ledig
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-08-
|
18
|
+
date: 2010-08-28 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -38,6 +38,12 @@ files:
|
|
38
38
|
- license.txt
|
39
39
|
- samples/access_rules.rb
|
40
40
|
- samples/application_controller.rb
|
41
|
+
- spec/acces_rules_storage_spec.rb
|
42
|
+
- spec/access_rules_spec.rb
|
43
|
+
- spec/model_access_rule_spec.rb
|
44
|
+
- spec/path_access_rule_spec.rb
|
45
|
+
- spec/spec.opts
|
46
|
+
- spec/spec_helper.rb
|
41
47
|
- tuersteher.gemspec
|
42
48
|
has_rdoc: true
|
43
49
|
homepage: http://github.com/bledig/tuersteher
|
@@ -73,5 +79,9 @@ rubygems_version: 1.3.7
|
|
73
79
|
signing_key:
|
74
80
|
specification_version: 3
|
75
81
|
summary: Security-Layer for Rails-Application
|
76
|
-
test_files:
|
77
|
-
|
82
|
+
test_files:
|
83
|
+
- spec/spec_helper.rb
|
84
|
+
- spec/access_rules_spec.rb
|
85
|
+
- spec/path_access_rule_spec.rb
|
86
|
+
- spec/model_access_rule_spec.rb
|
87
|
+
- spec/acces_rules_storage_spec.rb
|