lockdown 0.9.8 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,11 +4,7 @@ module Lockdown
4
4
  module Controller
5
5
 
6
6
  def available_actions(klass)
7
- if klass.respond_to?(:action_methods)
8
- klass.action_methods
9
- else
10
- klass.public_instance_methods - klass.hidden_actions
11
- end
7
+ klass.action_methods
12
8
  end
13
9
 
14
10
  def controller_name(klass)
@@ -17,6 +13,7 @@ module Lockdown
17
13
 
18
14
  # Locking methods
19
15
  module Lock
16
+
20
17
  def configure_lockdown
21
18
  check_session_expiry
22
19
  store_location
@@ -32,9 +29,11 @@ module Lockdown
32
29
 
33
30
  def check_request_authorization
34
31
  unless authorized?(path_from_hash(params))
35
- raise SecurityError, "Authorization failed for params #{params.inspect}"
32
+ raise SecurityError, "Authorization failed! \nparams: #{params.inspect}\nsession: #{session.inspect}"
36
33
  end
37
34
  end
35
+
36
+ protected
38
37
 
39
38
  def path_allowed?(url)
40
39
  session[:access_rights] ||= Lockdown::System.public_access
@@ -76,7 +75,7 @@ module Lockdown
76
75
  begin
77
76
  hash = ActionController::Routing::Routes.recognize_path(path, :method => method)
78
77
  return path_allowed?(path_from_hash(hash)) if hash
79
- rescue Exception
78
+ rescue Exception => e
80
79
  # continue on
81
80
  end
82
81
 
@@ -13,34 +13,39 @@ module Lockdown
13
13
  mod.extend Lockdown::Frameworks::Rails::Environment
14
14
  mixin
15
15
  end
16
-
16
+
17
17
  def mixin
18
- Lockdown.controller_parent.class_eval do
18
+ mixin_controller
19
+
20
+ Lockdown.view_helper.class_eval do
21
+ include Lockdown::Frameworks::Rails::View
22
+ end
23
+
24
+ Lockdown::System.class_eval do
25
+ extend Lockdown::Frameworks::Rails::System
26
+ end
27
+ end
28
+
29
+ def mixin_controller(klass = Lockdown.controller_parent)
30
+ klass.class_eval do
19
31
  include Lockdown::Session
20
32
  include Lockdown::Frameworks::Rails::Controller::Lock
21
33
  end
22
34
 
23
- Lockdown.controller_parent.helper_method :authorized?
35
+ klass.helper_method :authorized?
36
+
37
+ klass.hide_action(:set_current_user, :configure_lockdown, :check_request_authorization)
24
38
 
25
- Lockdown.controller_parent.before_filter do |c|
39
+ klass.before_filter do |c|
26
40
  c.set_current_user
27
41
  c.configure_lockdown
28
42
  c.check_request_authorization
43
+ c.check_model_authorization
29
44
  end
30
45
 
31
- Lockdown.controller_parent.filter_parameter_logging :password,
32
- :password_confirmation
46
+ klass.filter_parameter_logging :password, :password_confirmation
33
47
 
34
- Lockdown.controller_parent.rescue_from SecurityError,
35
- :with => proc{|e| access_denied(e)}
36
-
37
- Lockdown.view_helper.class_eval do
38
- include Lockdown::Frameworks::Rails::View
39
- end
40
-
41
- Lockdown::System.class_eval do
42
- extend Lockdown::Frameworks::Rails::System
43
- end
48
+ klass.rescue_from SecurityError, :with => proc{|e| access_denied(e)}
44
49
  end
45
50
  end # class block
46
51
 
@@ -54,12 +59,24 @@ module Lockdown
54
59
  "#{project_root}/lib/lockdown/init.rb"
55
60
  end
56
61
 
62
+ def view_helper
63
+ ::ActionView::Base
64
+ end
65
+
66
+ # cache_classes is true in production and testing, need to
67
+ # modify the ApplicationController
57
68
  def controller_parent
58
- ::ActionController::Base
69
+ if ::Rails.env == 'development'
70
+ ActionController::Base
71
+ else
72
+ ApplicationController
73
+ end
59
74
  end
60
75
 
61
- def view_helper
62
- ::ActionView::Base
76
+ # cache_classes is true in production and testing, need to
77
+ # do an instance eval instead
78
+ def add_controller_method(code)
79
+ Lockdown.controller_parent.class_eval code, __FILE__,__LINE__ +1
63
80
  end
64
81
 
65
82
  def controller_class_name(str)
@@ -70,6 +87,10 @@ module Lockdown
70
87
  Lockdown.camelize(str)
71
88
  end
72
89
  end
90
+
91
+ def fetch_controller_class(str)
92
+ eval("::#{controller_class_name(str)}")
93
+ end
73
94
  end
74
95
 
75
96
  module System
@@ -78,68 +99,6 @@ module Lockdown
78
99
  def skip_sync?
79
100
  Lockdown::System.fetch(:skip_db_sync_in).include?(ENV['RAILS_ENV'])
80
101
  end
81
-
82
- def load_controller_classes
83
- @controller_classes = {}
84
-
85
- maybe_load_framework_controller_parent
86
-
87
- ApplicationController.helper_method :authorized?
88
-
89
- ApplicationController.before_filter do |c|
90
- c.set_current_user
91
- c.configure_lockdown
92
- c.check_request_authorization
93
- end
94
-
95
- ApplicationController.filter_parameter_logging :password,
96
- :password_confirmation
97
-
98
- ApplicationController.rescue_from SecurityError,
99
- :with => proc{|e| access_denied(e)}
100
-
101
-
102
- Dir.chdir("#{Lockdown.project_root}/app/controllers") do
103
- Dir["**/*.rb"].sort.each do |c|
104
- next if c == "application.rb"
105
- lockdown_load(c)
106
- end
107
- end
108
-
109
- if ENV['RAILS_ENV'] != 'production'
110
- if ActiveSupport.const_defined?("Dependencies")
111
- ActiveSupport::Dependencies.clear
112
- else
113
- Dependencies.clear
114
- end
115
- end
116
- end
117
-
118
- def maybe_load_framework_controller_parent
119
- if ::Rails::VERSION::MAJOR >= 2 && ::Rails::VERSION::MINOR >= 3
120
- filename = "application_controller.rb"
121
- else
122
- filename = "application.rb"
123
- end
124
-
125
- require_or_load(filename)
126
- end
127
-
128
- def lockdown_load(filename)
129
- klass = Lockdown.class_name_from_file(filename)
130
-
131
- require_or_load(filename)
132
-
133
- @controller_classes[klass] = Lockdown.qualified_const_get(klass)
134
- end
135
-
136
- def require_or_load(filename)
137
- if ActiveSupport.const_defined?("Dependencies")
138
- ActiveSupport::Dependencies.require_or_load(filename)
139
- else
140
- Dependencies.require_or_load(filename)
141
- end
142
- end
143
102
  end # System
144
103
  end # Rails
145
104
  end # Frameworks
@@ -49,24 +49,6 @@ module Lockdown
49
49
  :administrators
50
50
  end
51
51
 
52
- def qualified_const_defined?(klass)
53
- if klass =~ /::/
54
- namespace, klass = klass.split("::")
55
- eval("#{namespace}.const_defined?(#{klass})") if const_defined?(namespace)
56
- else
57
- const_defined?(klass)
58
- end
59
- end
60
-
61
- def qualified_const_get(klass)
62
- if klass =~ /::/
63
- namespace, klass = klass.split("::")
64
- eval(namespace).const_get(klass)
65
- else
66
- const_get(klass)
67
- end
68
- end
69
-
70
52
  private
71
53
 
72
54
  def string_name(str_sym)
@@ -3,23 +3,46 @@ module Lockdown
3
3
  class PermissionScopeCollision < StandardError; end
4
4
 
5
5
  class Controller
6
- attr_accessor :name, :access_methods
6
+ attr_accessor :name, :access_methods, :only_methods, :except_methods
7
7
 
8
8
  def initialize(name)
9
9
  @name = name
10
+ @except_methods = []
11
+ end
12
+
13
+ def set_access_methods
14
+ if @only_methods
15
+ @access_methods = paths_for(@name, *@only_methods)
16
+ else
17
+ @access_methods = paths_for(@name)
18
+ end
19
+
20
+ apply_exceptions
21
+ end
22
+
23
+ private
24
+
25
+ def apply_exceptions
26
+ @access_methods = @access_methods - @except_methods
27
+ end
28
+
29
+ def paths_for(str_sym, *methods)
30
+ Lockdown::System.paths_for(str_sym, *methods)
10
31
  end
11
32
  end
12
33
 
13
34
  class Model
14
- attr_accessor :name, :controller_method, :model_method, :association
35
+ attr_accessor :name, :controller_method, :model_method, :association, :param
15
36
 
16
- def initialize(name)
37
+ def initialize(name, param = :id)
17
38
  @name = name
39
+ @param = :id
18
40
  end
19
41
 
20
- def association=(type)
21
- @assocation = type
42
+ def class_name
43
+ self.name.to_s.camelize
22
44
  end
45
+
23
46
  end
24
47
 
25
48
  class Permission
@@ -42,16 +65,16 @@ module Lockdown
42
65
  # ==== Summary of model oriented methods:
43
66
  #
44
67
  # # defines which model we're talking about
45
- # .to_model(:model_name)
68
+ # .to_model(:model)
46
69
  #
47
- # # data_method must be available to the controller
48
- # .where(:data_method)
70
+ # # model_method is simply a public method on :model
71
+ # .where(:model_method)
49
72
  #
50
- # # model_name.value_method must equal data_method
51
- # .equals(:value_method)
73
+ # # controller_method must equal model_method
74
+ # .equals(:controller_method)
52
75
  #
53
- # # model_name.values_method.include?(data_method)
54
- # .is_in(:values_method)
76
+ # # controller_method.include?(model_method)
77
+ # .is_in(:controller_method)
55
78
  #
56
79
  #
57
80
  # ==== Example:
@@ -84,7 +107,6 @@ module Lockdown
84
107
  validate_context
85
108
 
86
109
  controller = Controller.new(name_symbol)
87
- controller.access_methods = paths_for(name_symbol)
88
110
  @controllers[name_symbol] = controller
89
111
  @current_context = Lockdown::ControllerContext.new(name_symbol)
90
112
  self
@@ -95,8 +117,7 @@ module Lockdown
95
117
  def only_methods(*methods)
96
118
  validate_context
97
119
 
98
- current_controller.access_methods = paths_for(current_controller.name,
99
- *methods)
120
+ current_controller.only_methods = methods
100
121
  @current_context = Lockdown::RootContext.new(@name)
101
122
  self
102
123
  end
@@ -104,39 +125,40 @@ module Lockdown
104
125
  def except_methods(*methods)
105
126
  validate_context
106
127
 
107
- current_controller.access_methods = current_controller.access_methods - paths_for(current_controller.name, *methods)
128
+ current_controller.except_methods = methods
108
129
 
109
130
  @current_context = Lockdown::RootContext.new(@name)
110
131
  self
111
132
  end
112
133
 
113
- def to_model(name_symbol)
134
+ def to_model(name_symbol, param = :id)
114
135
  validate_context
115
136
 
116
- @models[name_symbol] = Model.new(name_symbol)
137
+ @models[name_symbol] = Model.new(name_symbol, param)
117
138
  @current_context = Lockdown::ModelContext.new(name_symbol)
118
139
  self
119
140
  end
120
141
 
121
- def where(controller_method)
142
+ def where(model_method)
122
143
  validate_context
123
144
 
145
+ current_model.model_method = model_method
124
146
  @current_context = Lockdown::ModelWhereContext.new(current_context.name)
125
147
  self
126
148
  end
127
149
 
128
- def equals(model_method)
150
+ def equals(controller_method)
129
151
  validate_context
130
152
 
131
- associate_model_method(model_method, :equals)
153
+ associate_controller_method(controller_method, :==)
132
154
  @current_context = Lockdown::RootContext.new(@name)
133
155
  self
134
156
  end
135
157
 
136
- def is_in(model_method)
158
+ def is_in(controller_method)
137
159
  validate_context
138
160
 
139
- associate_model_method(model_method, :includes)
161
+ associate_controller_method(controller_method, :include?)
140
162
  @current_context = Lockdown::RootContext.new(@name)
141
163
  self
142
164
  end
@@ -183,8 +205,8 @@ module Lockdown
183
205
 
184
206
  private
185
207
 
186
- def associate_model_method(model_method, association)
187
- current_model.model_method = model_method
208
+ def associate_controller_method(controller_method, association)
209
+ current_model.controller_method = controller_method
188
210
  current_model.association = association
189
211
  @current_context = Lockdown::RootContext.new(@name)
190
212
  end
@@ -196,9 +218,5 @@ module Lockdown
196
218
  raise InvalidRuleContext, "Method: #{calling_method} was called on wrong context #{current_context}. Allowed methods are: #{current_context.allowed_methods.join(',')}."
197
219
  end
198
220
  end
199
-
200
- def paths_for(controller, *methods)
201
- Lockdown::System.paths_for(controller, *methods)
202
- end
203
221
  end
204
222
  end
@@ -5,7 +5,6 @@ module Lockdown
5
5
  attr_accessor :options
6
6
  attr_accessor :permissions
7
7
  attr_accessor :user_groups
8
- attr_accessor :controller_classes
9
8
 
10
9
  attr_reader :protected_access
11
10
  attr_reader :public_access
@@ -254,24 +253,36 @@ module Lockdown
254
253
  end
255
254
 
256
255
  def process_rules
257
- parse_permissions
258
256
  validate_user_groups
257
+ parse_permissions
259
258
  end
260
259
 
261
260
  private
262
261
 
262
+ def validate_user_groups
263
+ user_groups.each do |user_group, perms|
264
+ perms.each do |perm|
265
+ unless permission_exists?(perm)
266
+ msg ="User Group: #{user_group}, permission not found: #{perm}"
267
+ raise InvalidRuleAssignment, msg
268
+ end
269
+ end
270
+ end
271
+ end
272
+
263
273
  def parse_permissions
264
274
  permission_objects.each do |name, perm|
265
275
  @permissions[perm.name] ||= []
266
-
267
276
  set_controller_access(perm)
268
-
269
- set_model_access(perm)
270
277
  end
278
+
279
+ set_model_access
271
280
  end
272
281
 
273
282
  def set_controller_access(perm)
274
283
  perm.controllers.each do |name, controller|
284
+ controller.set_access_methods
285
+
275
286
  @permissions[perm.name] |= controller.access_methods
276
287
 
277
288
  if perm.public_access?
@@ -282,40 +293,49 @@ module Lockdown
282
293
  end
283
294
  end
284
295
 
285
- def set_model_access(perm)
286
- perm.models.each do |model|
287
- # Create inherited method on Lockdown.orm_parent that
288
- # will create a list of controller/actions the model
296
+ def set_model_access
297
+ method_definition = "\tdef check_model_authorization\n\t#This method will check for access to model resources\n"
298
+
299
+ permission_objects.each do |name, perm|
300
+ next if perm.models.empty?
301
+
302
+ #Set filter for each controller
303
+ perm.controllers.each do |controller_name, controller|
304
+ #Set filter for each model on controller
305
+ perm.models.each do |model_name, model|
306
+ method_definition << define_restrict_model_access(controller, model)
307
+ end
308
+ end
289
309
  end
290
310
 
291
- # Create method to access that list for link_to call validation
292
- #Lockdown.orm_parent.instance_eval <<-RUBY, __FILE__,__LINE__ + 1
293
- # def self.inherited(klass)
294
- # super
295
- #
296
- # end
297
- #RUBY
298
-
299
- # Create inherited method on Lockdown.controller_parent that
300
- # will setup before_filter
301
- #Lockdown.controller_parent.instance_eval <<-RUBY, __FILE__,__LINE__ + 1
302
- # def self.inherited(klass)
303
- # super
304
- #
305
- # end
306
- #RUBY
307
- end
311
+ method_definition << "\n\tend"
308
312
 
313
+ #puts "method_definition:\n #{method_definition}"
309
314
 
310
- def validate_user_groups
311
- user_groups.each do |user_group, perms|
312
- perms.each do |perm|
313
- unless permission_exists?(perm)
314
- msg ="User Group: #{user_group}, permission not found: #{perm}"
315
- raise InvalidRuleAssignment, msg
315
+ Lockdown.add_controller_method method_definition
316
+ end
317
+
318
+ def define_restrict_model_access(controller, model)
319
+ controller_class = Lockdown.fetch_controller_class(controller.name)
320
+
321
+ methods = controller.
322
+ access_methods.
323
+ collect{|am| am[am.index('/') + 1..-1].to_sym}.inspect
324
+
325
+ return <<-RUBY
326
+ if controller_name == "#{controller.name}"
327
+ if #{methods}.include?(action_name.to_sym)
328
+ unless instance_variable_defined?(:@#{model.name})
329
+ @#{model.name} = #{model.class_name}.find(params[#{model.param.inspect}])
330
+ end
331
+ # Need to make sure we find the model first before checking admin status.
332
+ return true if current_user_is_admin?
333
+ unless #{model.controller_method}.#{model.association}(@#{model.name}.#{model.model_method})
334
+ raise SecurityError, "Access to #\{action_name\} denied to #{model.name}.id #\{@#{model.name}.id\}"
335
+ end
316
336
  end
317
337
  end
318
- end
338
+ RUBY
319
339
  end
320
340
  end
321
341
  end
@@ -5,9 +5,6 @@ module Lockdown
5
5
  def self.configure(&block)
6
6
  set_defaults
7
7
 
8
- # Defined by the framework
9
- load_controller_classes
10
-
11
8
  # Lockdown::Rules defines the methods that are used inside block
12
9
  instance_eval(&block)
13
10
 
@@ -33,7 +30,7 @@ module Lockdown
33
30
  def self.paths_for(str_sym, *methods)
34
31
  str_sym = str_sym.to_s if str_sym.is_a?(Symbol)
35
32
  if methods.empty?
36
- klass = fetch_controller_class(str_sym)
33
+ klass = Lockdown.fetch_controller_class(str_sym)
37
34
  methods = available_actions(klass)
38
35
  end
39
36
  path_str = str_sym.gsub("__","\/")
@@ -51,10 +48,5 @@ module Lockdown
51
48
 
52
49
  paths
53
50
  end
54
-
55
- def self.fetch_controller_class(str)
56
- controller_classes[Lockdown.controller_class_name(str)]
57
- end
58
-
59
51
  end # System class
60
52
  end # Lockdown
data/lib/lockdown.rb CHANGED
@@ -3,7 +3,7 @@ require File.join(File.dirname(__FILE__), "lockdown", "helper")
3
3
  module Lockdown
4
4
  extend Lockdown::Helper
5
5
 
6
- VERSION = '0.9.8'
6
+ VERSION = '1.0.0'
7
7
 
8
8
  # Returns the version string for the library.
9
9
  def self.version
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lockdown
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.8
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Stone
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-07 00:00:00 -04:00
12
+ date: 2009-07-08 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -128,7 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
128
  requirements: []
129
129
 
130
130
  rubyforge_project: lockdown
131
- rubygems_version: 1.3.3
131
+ rubygems_version: 1.3.4
132
132
  signing_key:
133
133
  specification_version: 3
134
134
  summary: Lockdown is an authorization system for RubyOnRails (ver >= 2