lockdown 0.9.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/lockdown/frameworks/rails/controller.rb +6 -7
- data/lib/lockdown/frameworks/rails.rb +40 -81
- data/lib/lockdown/helper.rb +0 -18
- data/lib/lockdown/permission.rb +47 -29
- data/lib/lockdown/rules.rb +53 -33
- data/lib/lockdown/system.rb +1 -9
- data/lib/lockdown.rb +1 -1
- metadata +3 -3
@@ -4,11 +4,7 @@ module Lockdown
|
|
4
4
|
module Controller
|
5
5
|
|
6
6
|
def available_actions(klass)
|
7
|
-
|
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
|
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
|
-
|
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
|
-
|
35
|
+
klass.helper_method :authorized?
|
36
|
+
|
37
|
+
klass.hide_action(:set_current_user, :configure_lockdown, :check_request_authorization)
|
24
38
|
|
25
|
-
|
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
|
-
|
32
|
-
:password_confirmation
|
46
|
+
klass.filter_parameter_logging :password, :password_confirmation
|
33
47
|
|
34
|
-
|
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
|
-
::
|
69
|
+
if ::Rails.env == 'development'
|
70
|
+
ActionController::Base
|
71
|
+
else
|
72
|
+
ApplicationController
|
73
|
+
end
|
59
74
|
end
|
60
75
|
|
61
|
-
|
62
|
-
|
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
|
data/lib/lockdown/helper.rb
CHANGED
@@ -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)
|
data/lib/lockdown/permission.rb
CHANGED
@@ -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
|
21
|
-
|
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(:
|
68
|
+
# .to_model(:model)
|
46
69
|
#
|
47
|
-
# #
|
48
|
-
# .where(:
|
70
|
+
# # model_method is simply a public method on :model
|
71
|
+
# .where(:model_method)
|
49
72
|
#
|
50
|
-
# #
|
51
|
-
# .equals(:
|
73
|
+
# # controller_method must equal model_method
|
74
|
+
# .equals(:controller_method)
|
52
75
|
#
|
53
|
-
# #
|
54
|
-
# .is_in(:
|
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.
|
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.
|
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(
|
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(
|
150
|
+
def equals(controller_method)
|
129
151
|
validate_context
|
130
152
|
|
131
|
-
|
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(
|
158
|
+
def is_in(controller_method)
|
137
159
|
validate_context
|
138
160
|
|
139
|
-
|
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
|
187
|
-
current_model.
|
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
|
data/lib/lockdown/rules.rb
CHANGED
@@ -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
|
286
|
-
|
287
|
-
|
288
|
-
|
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
|
-
|
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
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
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
|
-
|
338
|
+
RUBY
|
319
339
|
end
|
320
340
|
end
|
321
341
|
end
|
data/lib/lockdown/system.rb
CHANGED
@@ -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
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.
|
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-
|
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.
|
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
|