tuersteher 0.1.4 → 0.2.1
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/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
|