tuersteher 0.3.0 → 0.3.3

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 CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.3.3
data/lib/tuersteher.rb CHANGED
@@ -37,30 +37,35 @@ module Tuersteher
37
37
 
38
38
  DEFAULT_RULES_CONFIG_FILE = 'access_rules.rb' # in config-dir
39
39
 
40
+ # private initializer why this class is a singleton
40
41
  def initialize
41
42
  @path_rules = []
42
43
  @model_rules = []
43
44
  end
44
45
 
46
+ # get all path_rules as array of PathAccessRule-Instances
45
47
  def path_rules
46
48
  read_rules unless @was_read
47
49
  @path_rules
48
50
  end
49
51
 
52
+ # get all model_rules as array of ModelAccessRule-Instances
50
53
  def model_rules
51
54
  read_rules unless @was_read
52
55
  @model_rules
53
56
  end
54
57
 
55
58
 
59
+ # evaluated rules_definitions and create path-/model-rules
56
60
  def eval_rules rules_definitions
57
61
  @path_rules = []
58
62
  @model_rules = []
59
63
  eval rules_definitions
64
+ @was_read = true
60
65
  Tuersteher::TLogger.logger.info "Tuersteher::AccessRulesStorage: #{@path_rules.size} path-rules and #{@model_rules.size} model-rules"
61
66
  end
62
67
 
63
- # Laden der AccesRules aus den Dateien
68
+ # Load AccesRules from file
64
69
  # config/access_rules.rb
65
70
  def read_rules
66
71
  @rules_config_file ||= File.join(Rails.root, 'config', DEFAULT_RULES_CONFIG_FILE)
@@ -74,7 +79,6 @@ module Tuersteher
74
79
  rules_file.close
75
80
  if content
76
81
  eval_rules content
77
- @was_read = true
78
82
  end
79
83
  rescue => ex
80
84
  Tuersteher::TLogger.logger.error "Tuersteher::AccessRulesStorage - Error in rules: #{ex.message}\n\t"+ex.backtrace.join("\n\t")
@@ -106,12 +110,16 @@ module Tuersteher
106
110
  end
107
111
  end
108
112
 
113
+ # create new rule as grant-rule
114
+ # and add this to the model_rules array
109
115
  def grant
110
116
  rule = ModelAccessRule.new(@current_model_class)
111
117
  @model_rules << rule
112
118
  rule.grant
113
119
  end
114
120
 
121
+ # create new rule as deny-rule
122
+ # and add this to the model_rules array
115
123
  def deny
116
124
  rule = ModelAccessRule.new(@current_model_class)
117
125
  @model_rules << rule
@@ -122,62 +130,67 @@ module Tuersteher
122
130
 
123
131
 
124
132
  class AccessRules
125
-
126
- # Pruefen Zugriff fuer eine Web-action
127
- # user User, für den der Zugriff geprüft werden soll (muss Methode has_role? haben)
128
- # path Pfad der Webresource (String)
129
- # method http-Methode (:get, :put, :delete, :post), default ist :get
130
- #
131
- def self.path_access?(user, path, method = :get)
132
- rule = AccessRulesStorage.instance.path_rules.detect do |r|
133
- r.fired?(path, method, user)
134
- end
135
- if Tuersteher::TLogger.logger.debug?
136
- if rule.nil?
137
- s = 'denied'
138
- elsif rule.deny?
139
- s = "denied with #{rule}"
140
- else
141
- s = "granted with #{rule}"
133
+ class << self
134
+ # Pruefen Zugriff fuer eine Web-action
135
+ # user User, für den der Zugriff geprüft werden soll (muss Methode has_role? haben)
136
+ # path Pfad der Webresource (String)
137
+ # method http-Methode (:get, :put, :delete, :post), default ist :get
138
+ #
139
+ def path_access?(user, path, method = :get)
140
+ rule = AccessRulesStorage.instance.path_rules.detect do |r|
141
+ r.fired?(path, method, user)
142
142
  end
143
- Tuersteher::TLogger.logger.debug("Tuersteher: path_access?(#{path}, #{method}) => #{s}")
143
+ if Tuersteher::TLogger.logger.debug?
144
+ if rule.nil?
145
+ s = 'denied'
146
+ elsif rule.deny?
147
+ s = "denied with #{rule}"
148
+ else
149
+ s = "granted with #{rule}"
150
+ end
151
+ usr_id = user.respond_to?(:id) ? user.id : user.object_id
152
+ Tuersteher::TLogger.logger.debug("Tuersteher: path_access?(user.id=#{usr_id}, path=#{path}, method=#{method}) => #{s}")
153
+ end
154
+ !(rule.nil? || rule.deny?)
144
155
  end
145
- !(rule.nil? || rule.deny?)
146
- end
147
156
 
148
157
 
149
- # Pruefen Zugriff auf ein Model-Object
150
- #
151
- # user User, für den der Zugriff geprüft werden soll (muss Methode has_role? haben)
152
- # model das Model-Object
153
- # permission das geforderte Zugriffsrecht (:create, :update, :destroy, :get)
154
- #
155
- # liefert true/false
156
- def self.model_access? user, model, permission
157
- raise "Wrong call! Use: model_access(model-instance-or-class, permission)" unless permission.is_a? Symbol
158
- return false unless model
158
+ # Pruefen Zugriff auf ein Model-Object
159
+ #
160
+ # user User, für den der Zugriff geprüft werden soll (muss Methode has_role? haben)
161
+ # model das Model-Object
162
+ # permission das geforderte Zugriffsrecht (:create, :update, :destroy, :get)
163
+ #
164
+ # liefert true/false
165
+ def model_access? user, model, permission
166
+ raise "Wrong call! Use: model_access(model-instance-or-class, permission)" unless permission.is_a? Symbol
167
+ return false unless model
159
168
 
160
- rule = AccessRulesStorage.instance.model_rules.detect do |rule|
161
- rule.fired? model, permission, user
162
- end
163
- access = rule && !rule.deny?
164
- if Tuersteher::TLogger.logger.debug?
165
- if model.instance_of?(Class)
166
- Tuersteher::TLogger.logger.debug("Tuersteher: model_access?(#{model}, #{permission}) => #{access || 'denied'} #{rule}")
167
- else
168
- Tuersteher::TLogger.logger.debug("Tuersteher: model_access?(#{model.class}(#{model.respond_to?(:id) ? model.id : model.object_id }), #{permission}) => #{access || 'denied'} #{rule}")
169
+ rule = AccessRulesStorage.instance.model_rules.detect do |rule|
170
+ rule.fired? model, permission, user
171
+ end
172
+ access = rule && !rule.deny?
173
+ if Tuersteher::TLogger.logger.debug?
174
+ usr_id = user.respond_to?(:id) ? user.id : user.object_id
175
+ if model.instance_of?(Class)
176
+ Tuersteher::TLogger.logger.debug(
177
+ "Tuersteher: model_access?(user.id=#{usr_id}, model=#{model}, permission=#{permission}) => #{access || 'denied'} #{rule}")
178
+ else
179
+ Tuersteher::TLogger.logger.debug(
180
+ "Tuersteher: model_access?(user.id=#{usr_id}, model=#{model.class}(#{model.respond_to?(:id) ? model.id : model.object_id }), permission=#{permission}) => #{access || 'denied'} #{rule}")
181
+ end
169
182
  end
183
+ access
170
184
  end
171
- access
172
- end
173
185
 
174
- # Bereinigen (entfernen) aller Objecte aus der angebenen Collection,
175
- # wo der angegebene User nicht das angegebene Recht hat
176
- #
177
- # liefert ein neues Array mit den Objecten, wo der spez. Zugriff arlaubt ist
178
- def self.purge_collection user, collection, permission
179
- collection.select{|model| model_access?(user, model, permission)}
180
- end
186
+ # Bereinigen (entfernen) aller Objecte aus der angebenen Collection,
187
+ # wo der angegebene User nicht das angegebene Recht hat
188
+ #
189
+ # liefert ein neues Array mit den Objecten, wo der spez. Zugriff arlaubt ist
190
+ def purge_collection user, collection, permission
191
+ collection.select{|model| model_access?(user, model, permission)}
192
+ end
193
+ end # of Class-Methods
181
194
  end # of AccessRules
182
195
 
183
196
 
@@ -224,7 +237,7 @@ module Tuersteher
224
237
  # wo der akt. User nicht das angegebene Recht hat
225
238
  #
226
239
  # liefert ein neues Array mit den Objecten, wo der spez. Zugriff arlaubt ist
227
- def self.purge_collection collection, permission
240
+ def purge_collection collection, permission
228
241
  AccessRules.purge_collection(current_user, collection, permission)
229
242
  end
230
243
 
@@ -248,10 +261,14 @@ module Tuersteher
248
261
  # Rails3 hat andere url-path-methode
249
262
  @@url_path_method ||= Rails.version[0..1]=='3.' ? :fullpath : :request_uri
250
263
 
264
+ # bind current_user on the current thread
265
+ Thread.current[:user] = current_user
266
+
251
267
  req_method = request.method.downcase.to_sym
252
268
  url_path = request.send(@@url_path_method)
253
269
  unless path_access?(url_path, req_method)
254
- msg = "Tuersteher#check_access: access denied for #{request.request_uri} :#{req_method}"
270
+ usr_id = current_user.respond_to?(:id) ? current_user.id : current_user.object_id
271
+ msg = "Tuersteher#check_access: access denied for #{request.request_uri} :#{req_method} user.id=#{usr_id}"
255
272
  Tuersteher::TLogger.logger.warn msg
256
273
  logger.warn msg # log message also for Rails-Default logger
257
274
  access_denied # Methode aus dem authenticated_system, welche ein redirect zum login auslöst
@@ -261,6 +278,55 @@ module Tuersteher
261
278
  end
262
279
 
263
280
 
281
+
282
+ # Module for include in Model-Object-Classes
283
+ #
284
+ # The module get the current-user from Thread.current[:user]
285
+ #
286
+ # Sample for ActiveRecord-Class
287
+ # class Sample < ActiveRecord::Base
288
+ # include Tuersteher::ModelExtensions
289
+ #
290
+ # def transfer_to account
291
+ # check_model_access :transfer # raise a exception if not allowed
292
+ # ....
293
+ # end
294
+ #
295
+ #
296
+ module ModelExtensions
297
+
298
+ # Check permission for the Model-Object
299
+ #
300
+ # permission the requested permission (sample :create, :update, :destroy, :get)
301
+ #
302
+ # raise a SecurityError-Exception if access denied
303
+ def check_access permission
304
+ user = Thread.current[:user]
305
+ unless AccessRules.model_access? user, self, permission
306
+ raise SecurityError, "Access denied! Current user have no permission '#{permission}' on Model-Object #{self}."
307
+ end
308
+ end
309
+
310
+ def self.included(base)
311
+ base.extend ClassMethods
312
+ end
313
+
314
+ module ClassMethods
315
+
316
+ # Bereinigen (entfernen) aller Objecte aus der angebenen Collection,
317
+ # wo der akt. User nicht das angegebene Recht hat
318
+ #
319
+ # liefert ein neues Array mit den Objecten, wo der spez. Zugriff arlaubt ist
320
+ def purge_collection collection, permission
321
+ user = Thread.current[:user]
322
+ AccessRules.purge_collection(user, collection, permission)
323
+ end
324
+ end # of ClassMethods
325
+
326
+ end # of module ModelExtensions
327
+
328
+
329
+
264
330
  # Astracte base class for Access-Rules
265
331
  class BaseAccessRule
266
332
 
@@ -275,26 +341,33 @@ module Tuersteher
275
341
  self
276
342
  end
277
343
 
278
-
279
- def extension method_name, methode_parameter=nil
344
+ # add extension-definition
345
+ # parmaters:
346
+ # method_name: Symbol with the name of the method to call for addional check
347
+ # expected_value: optional expected value for the result of the with metho_name specified method, defalt is true
348
+ def extension method_name, expected_value=nil
280
349
  @check_extensions ||= {}
281
- @check_extensions[method_name] = methode_parameter
350
+ @check_extensions[method_name] = expected_value
282
351
  self
283
352
  end
284
353
 
354
+ # mark this rule as grant-rule
285
355
  def grant
286
356
  self
287
357
  end
288
358
 
359
+ # mark this rule as deny-rule
289
360
  def deny
290
361
  @deny = true
291
362
  self
292
363
  end
293
364
 
365
+ # is this rule a deny-rule
294
366
  def deny?
295
367
  @deny
296
368
  end
297
369
 
370
+ # negate role-membership
298
371
  def not
299
372
  @not = true
300
373
  self
@@ -302,6 +375,7 @@ module Tuersteher
302
375
 
303
376
  protected
304
377
 
378
+ # check, if this rule granted for specified user
305
379
  def grant_role? user
306
380
  return true if @roles.empty?
307
381
  return false if user.nil?
@@ -384,6 +458,7 @@ module Tuersteher
384
458
 
385
459
  private
386
460
 
461
+ # check, if this rule grant the defined extension (if exist)
387
462
  def grant_extension? user
388
463
  return true if @check_extensions.nil?
389
464
  return false if user.nil? # check_extensions need a user
@@ -426,7 +501,7 @@ module Tuersteher
426
501
  @clazz = clazz.instance_of?(Symbol) ? clazz : clazz.to_s
427
502
  end
428
503
 
429
-
504
+ # set the permission-name
430
505
  def permission permission_name
431
506
  @permission = permission_name
432
507
  self
@@ -445,7 +520,6 @@ module Tuersteher
445
520
  #
446
521
  def fired? model, perm, user
447
522
  user = nil if user==:false # manche Authenticate-System setzen den user auf :false
448
- debugger
449
523
  m_class = model.instance_of?(Class) ? model : model.class
450
524
  if @clazz!=m_class.to_s && @clazz!=:all
451
525
  #Tuersteher::TLogger.logger.debug("#{to_s}.has_access? => false why #{@clazz}!=#{model.class.to_s} && #{@clazz}!=:all")
@@ -471,6 +545,7 @@ module Tuersteher
471
545
 
472
546
  private
473
547
 
548
+ # check, if this rule grant the defined extension (if exist)
474
549
  def grant_extension? user, model
475
550
  return true if @check_extensions.nil?
476
551
  return false if model.nil? # check_extensions need a model
@@ -491,5 +566,4 @@ module Tuersteher
491
566
 
492
567
  end
493
568
 
494
-
495
569
  end
@@ -35,7 +35,7 @@ module Tuersteher
35
35
  @user.stub(:has_role?).and_return(false)
36
36
  end
37
37
 
38
- it "should not be fired for String-Object and access-type :read" do
38
+ specify do
39
39
  @rule.fired?("test", :read, @user).should_not be_true
40
40
  end
41
41
  end
@@ -0,0 +1,58 @@
1
+ require "spec_helper"
2
+
3
+ module Tuersteher
4
+
5
+ describe ModelExtensions do
6
+
7
+ class SampleModel
8
+ include ModelExtensions
9
+
10
+ def deactived
11
+ check_access :deactived
12
+ end
13
+ end
14
+
15
+
16
+ before do
17
+ rules = [ModelAccessRule.new(SampleModel).grant.permission(:deactived).role(:admin)]
18
+ AccessRulesStorage.instance.stub(:model_rules).and_return(rules)
19
+ @user = stub('user')
20
+ Thread.current[:user] = @user
21
+ end
22
+
23
+
24
+ context "check_access" do
25
+
26
+ it "should not raise a Error for user with role :admin" do
27
+ @user.stub(:has_role?){|role| role==:admin}
28
+ model = SampleModel.new
29
+ model.deactived
30
+ end
31
+
32
+ it "should raise a SecurityError for user with not role :admin" do
33
+ @user.stub(:has_role?){|role| role==:user}
34
+ model = SampleModel.new
35
+ expect{ model.deactived }.to raise_error(SecurityError)
36
+ end
37
+
38
+ end # of context "grant with roles"
39
+
40
+
41
+ context "purge_collection" do
42
+
43
+ it "should purge nothing for user with role :admin" do
44
+ @user.stub(:has_role?){|role| role==:admin}
45
+ list = [SampleModel.new]
46
+ SampleModel.purge_collection(list, :deactived).should == list
47
+ end
48
+
49
+ it "should purge all for user with not role :admin" do
50
+ @user.stub(:has_role?){|role| role==:user}
51
+ list = [SampleModel.new]
52
+ SampleModel.purge_collection(list, :deactived).should == []
53
+ end
54
+
55
+ end # of context "purge_collection"
56
+ end
57
+ end
58
+
data/spec/spec_helper.rb CHANGED
@@ -4,3 +4,4 @@ require File.expand_path(File.dirname(__FILE__) + "/../lib/tuersteher")
4
4
 
5
5
  # Logger auf stdout stellen
6
6
  Tuersteher::TLogger.logger = Logger.new(STDOUT)
7
+ Tuersteher::TLogger.logger.level = Logger::ERROR
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.3.0"
8
+ s.version = "0.3.3"
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-30}
12
+ s.date = %q{2010-09-01}
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 = [
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
29
29
  "spec/acces_rules_storage_spec.rb",
30
30
  "spec/access_rules_spec.rb",
31
31
  "spec/model_access_rule_spec.rb",
32
+ "spec/model_extensions_spec.rb",
32
33
  "spec/path_access_rule_spec.rb",
33
34
  "spec/spec.opts",
34
35
  "spec/spec_helper.rb",
@@ -40,11 +41,12 @@ Gem::Specification.new do |s|
40
41
  s.rubygems_version = %q{1.3.7}
41
42
  s.summary = %q{Security-Layer for Rails-Application}
42
43
  s.test_files = [
43
- "spec/acces_rules_storage_spec.rb",
44
- "spec/path_access_rule_spec.rb",
44
+ "spec/path_access_rule_spec.rb",
45
45
  "spec/model_access_rule_spec.rb",
46
- "spec/access_rules_spec.rb",
47
- "spec/spec_helper.rb"
46
+ "spec/model_extensions_spec.rb",
47
+ "spec/acces_rules_storage_spec.rb",
48
+ "spec/spec_helper.rb",
49
+ "spec/access_rules_spec.rb"
48
50
  ]
49
51
 
50
52
  if s.respond_to? :specification_version then
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: 19
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 0
10
- version: 0.3.0
9
+ - 3
10
+ version: 0.3.3
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-30 00:00:00 +02:00
18
+ date: 2010-09-01 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -41,6 +41,7 @@ files:
41
41
  - spec/acces_rules_storage_spec.rb
42
42
  - spec/access_rules_spec.rb
43
43
  - spec/model_access_rule_spec.rb
44
+ - spec/model_extensions_spec.rb
44
45
  - spec/path_access_rule_spec.rb
45
46
  - spec/spec.opts
46
47
  - spec/spec_helper.rb
@@ -80,8 +81,9 @@ signing_key:
80
81
  specification_version: 3
81
82
  summary: Security-Layer for Rails-Application
82
83
  test_files:
83
- - spec/acces_rules_storage_spec.rb
84
84
  - spec/path_access_rule_spec.rb
85
85
  - spec/model_access_rule_spec.rb
86
- - spec/access_rules_spec.rb
86
+ - spec/model_extensions_spec.rb
87
+ - spec/acces_rules_storage_spec.rb
87
88
  - spec/spec_helper.rb
89
+ - spec/access_rules_spec.rb