lockdown 0.5.22 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,22 +1,12 @@
1
+ require File.join(File.dirname(__FILE__), "rights")
2
+ require File.join(File.dirname(__FILE__), "database")
3
+
1
4
  module Lockdown
2
5
  class System
3
6
  class << self
4
- include Lockdown::ControllerInspector
7
+ include Lockdown::Rights
5
8
 
6
9
  attr_accessor :options #:nodoc:
7
-
8
- attr_accessor :permissions #:nodoc:
9
- attr_accessor :user_groups #:nodoc:
10
-
11
- # :public_access allows access to all
12
- attr_accessor :public_access #:nodoc:
13
- # :protected_access will restrict access to authenticated users.
14
- attr_accessor :protected_access #:nodoc:
15
-
16
- # Future functionality:
17
- # :private_access will restrict access to model data to their creators.
18
- # attr_accessor :private_access
19
-
20
10
  attr_accessor :controller_classes #:nodoc:
21
11
 
22
12
  def configure(&block)
@@ -24,382 +14,94 @@ module Lockdown
24
14
 
25
15
  instance_eval(&block)
26
16
 
27
- if options[:use_db_models] && options[:sync_init_rb_with_db]
28
- sync_with_db
17
+ unless Lockdown::System.fetch(:skip_db_sync_in).include?(ENV['RAILS_ENV'])
18
+ Lockdown::Database.sync_with_db
29
19
  end
30
20
  end
31
21
 
22
+ # Return option value for key
32
23
  def fetch(key)
33
24
  (@options||={})[key]
34
25
  end
35
-
36
- def set_permission(name, *method_arrays)
37
- @permissions[name] ||= []
38
- method_arrays.each{|ary| @permissions[name] += ary}
39
- end
40
-
41
- def get_permissions
42
- @permissions.keys
43
- end
44
-
45
- def permission_exists?(perm)
46
- get_permissions.include?(perm)
47
- end
48
-
49
- def set_user_group(name, *perms)
50
- @user_groups[name] ||= []
51
- perms.each do |perm|
52
- unless permission_exists?(perm)
53
- raise SecurityError, "For UserGroup (#{name}), permission is invalid: #{perm}"
54
- end
55
- @user_groups[name].push(perm)
56
- end
57
- end
58
-
59
- def get_user_groups
60
- @user_groups.keys
61
- end
62
-
63
- def permissions_for_user_group(ug)
64
- sym = lockdown_symbol(ug)
65
-
66
- if has_user_group?(sym)
67
- @user_groups[sym].each do |perm|
68
- unless permission_exists?(perm)
69
- raise SecurityError, "Permission associated to User Group is invalid: #{perm}"
70
- end
71
- yield perm
72
- end
73
- elsif ug.respond_to?(:name)
74
- # This user group was defined in the database
75
- ug.permissions.each do |perm|
76
- perm_sym = lockdown_symbol(perm.name)
77
- unless permission_exists?(perm_sym)
78
- raise SecurityError, "Permission associated to User Group is invalid: #{perm_sym}"
79
- end
80
- yield perm_sym
81
- end
82
- else
83
- raise SecurityError, "UserGroup is not known: #{ug.inspect}"
84
- end
85
- end
86
-
87
- def access_rights_for_permission(perm)
88
- sym = lockdown_symbol(perm)
89
-
90
- unless permission_exists?(sym)
91
- raise SecurityError, "Permission requested is not defined: #{sym}"
92
- end
93
- @permissions[sym]
94
- end
95
-
96
- def public_access?(perm)
97
- @public_access.include?(perm)
98
- end
99
26
 
100
- def set_public_access(*perms)
101
- perms.each{|perm| @public_access += @permissions[perm]}
27
+ # *syms is a splat of controller symbols,
28
+ # e.g all_methods(:users, :authors, :books)
29
+ def all_methods(*syms)
30
+ syms.collect{ |sym| paths_for(sym) }.flatten
102
31
  end
103
-
104
- def protected_access?(perm)
105
- @protected_access.include?(perm)
106
- end
107
-
108
- def set_protected_access(*perms)
109
- perms.each{|perm| @protected_access += @permissions[perm]}
110
- end
111
-
112
- def permission_assigned_automatically?(perm)
113
- public_access?(perm) || protected_access?(perm)
114
- end
115
-
116
- def standard_authorized_user_rights
117
- Lockdown::System.public_access + Lockdown::System.protected_access
118
- end
119
-
120
- #
121
- # Determine if the user group is defined in init.rb
32
+
33
+ # controller name (sym) and a splat of methods to
34
+ # exclude from result
122
35
  #
123
- def has_user_group?(ug)
124
- sym = lockdown_symbol(ug)
125
-
126
- return true if sym == administrator_group_symbol
127
- get_user_groups.each do |key|
128
- return true if key == sym
129
- end
130
- false
131
- end
132
-
133
- #
134
- # Delete a user group record from the database
135
- #
136
- def delete_user_group(str_sym)
137
- ug = UserGroup.find(:first, :conditions => ["name = ?",lockdown_string(str_sym)])
138
- ug.destroy unless ug.nil?
139
- end
140
-
141
- def access_rights_for_user(usr)
142
- return unless usr
143
- return :all if administrator?(usr)
144
-
145
- rights = standard_authorized_user_rights
146
-
147
- if @options[:use_db_models]
148
- usr.user_groups.each do |grp|
149
- permissions_for_user_group(grp) do |perm|
150
- rights += access_rights_for_permission(perm)
151
- end
152
- end
153
- end
154
- rights
155
- end
156
-
157
- #
158
- # Use this for the management screen to restrict user group list to the
159
- # user. This will prevent a user from creating a user with more power than
160
- # him/her self.
36
+ # All user methods except destroy:
37
+ # e.g all_except_methods(:users, :destroy)
38
+ def all_except_methods(sym, *methods)
39
+ paths_for(sym) - paths_for(sym, *methods)
40
+ end
41
+
42
+ # controller name (sym) and a splat of methods to
43
+ # to build the result
161
44
  #
162
- #
163
- def user_groups_assignable_for_user(usr)
164
- return [] if usr.nil?
165
-
166
- if administrator?(usr)
167
- UserGroup.find(:all, :order => :name)
168
- else
169
- UserGroup.find_by_sql <<-SQL
170
- select user_groups.* from user_groups, user_groups_users
171
- where user_groups.id = user_groups_users.user_group_id
172
- and user_groups_users.user_id = #{usr.id}
173
- order by user_groups.name
174
- SQL
175
- end
45
+ # Only user methods index (list), show (good for readonly access):
46
+ # e.g only_methods(:users, :index, :show)
47
+ def only_methods(sym, *methods)
48
+ paths_for(sym, *methods)
176
49
  end
177
50
 
51
+ # all controllers, all actions
178
52
  #
179
- # Similar to user_groups_assignable_for_user, this method should be
180
- # used to restrict users from creating a user group with more power than
181
- # they have been allowed.
182
- #
183
- def permissions_assignable_for_user(usr)
184
- return [] if usr.nil?
185
- if administrator?(usr)
186
- @permissions.keys.collect{|k| Permission.find_by_name(lockdown_string(k)) }.compact
187
- else
188
- groups = user_groups_assignable_for_user(usr)
189
- groups.collect{|g| g.permissions}.flatten.compact
190
- end
53
+ # This is admin access
54
+ def all_controllers_all_methods
55
+ controllers = controller_classes
56
+ controllers.collect do |str, klass|
57
+ paths_for( controller_name(klass), available_actions(klass) )
58
+ end.flatten!
191
59
  end
192
60
 
193
- def make_user_administrator(usr)
194
- unless Lockdown.database_table_exists?(UserGroup)
195
- create_administrator_user_group
196
- end
197
-
198
- usr.user_groups << UserGroup.find_or_create_by_name(administrator_group_string)
199
- end
200
-
201
- def administrator?(usr)
202
- user_has_user_group?(usr, administrator_group_symbol)
203
- end
204
-
205
- def administrator_rights
206
- all_controllers
207
- end
208
-
209
61
  def fetch_controller_class(str)
210
- @controller_classes[lockdown_class_name(str)]
62
+ controller_classes[Lockdown.controller_class_name(str)]
211
63
  end
212
-
64
+
213
65
  protected
214
66
 
215
67
  def set_defaults
216
68
  load_controller_classes
217
69
 
218
- @permissions = {}
219
- @user_groups = {}
220
-
221
- @public_access = []
222
- @protected_access = []
223
- @private_access = []
70
+ initialize_rights
224
71
 
225
72
  @options = {
226
- :use_db_models => true,
227
- :sync_init_rb_with_db => true,
228
73
  :session_timeout => (60 * 60),
229
74
  :logout_on_access_violation => false,
230
75
  :access_denied_path => "/",
231
- :successful_login_path => "/"
76
+ :successful_login_path => "/",
77
+ :subdirectory => nil,
78
+ :skip_db_sync_in => ["test"]
232
79
  }
233
80
  end
234
81
 
235
- private
236
-
237
- def create_administrator_user_group
238
- return unless @options[:use_db_models]
239
- UserGroup.create :name => administrator_group_name
240
- end
241
-
242
- def user_has_user_group?(usr, sym)
243
- usr.user_groups.each do |ug|
244
- return true if convert_reference_name(ug.name) == sym
245
- end
246
- false
247
- end
248
-
249
- def load_controller_classes
250
- @controller_classes = {}
251
-
252
- maybe_load_framework_controller_parent
253
-
254
- Dir.chdir("#{Lockdown.project_root}/app/controllers") do
255
- Dir["**/*.rb"].sort.each do |c|
256
- next if c == "application.rb"
257
- lockdown_load(c)
258
- end
259
- end
260
-
261
- if Lockdown.rails_app? && ENV['RAILS_ENV'] != 'production'
262
- if ActiveSupport.const_defined?("Dependencies")
263
- ActiveSupport::Dependencies.clear
264
- else
265
- Dependencies.clear
266
- end
267
- end
268
- end
269
-
270
- def lockdown_class_name_from_file(str)
271
- str.split(".")[0].split("/").collect{|s| camelize(s) }.join("::")
272
- end
82
+ private
273
83
 
274
- def lockdown_class_name(str)
275
- if str.include?("__")
276
- controller_class_name(str.split("__").collect{|p| camelize(p)}.join("::"))
277
- else
278
- controller_class_name(camelize(str))
84
+ def paths_for(str_sym, *methods)
85
+ str_sym = str_sym.to_s if str_sym.is_a?(Symbol)
86
+ if methods.empty?
87
+ klass = fetch_controller_class(str_sym)
88
+ methods = available_actions(klass)
279
89
  end
280
- end
90
+ path_str = str_sym.gsub("__","\/")
91
+
92
+ subdir = Lockdown::System.fetch(:subdirectory)
93
+ path_str = "#{subdir}/#{path_str}" if subdir
281
94
 
282
- def maybe_load_framework_controller_parent
283
- if Lockdown.rails_app?
284
- if ActiveSupport.const_defined?("Dependencies")
285
- ActiveSupport::Dependencies.require_or_load("application.rb")
286
- else
287
- Dependencies.require_or_load("application.rb")
288
- end
289
- else
290
- load("application.rb") unless const_defined?("Application")
291
- end
292
- end
293
-
294
- def lockdown_load(file)
295
- klass = lockdown_class_name_from_file(file)
296
- if Lockdown.rails_app?
297
- if ActiveSupport.const_defined?("Dependencies")
298
- ActiveSupport::Dependencies.require_or_load(file)
299
- else
300
- Dependencies.require_or_load(file)
301
- end
302
- else
303
- load(file) unless qualified_const_defined?(klass)
304
- end
305
- @controller_classes[klass] = qualified_const_get(klass)
306
- end
95
+ controller_actions = methods.flatten
96
+ returning = controller_actions.collect{|meth| "#{path_str}/#{meth.to_s}" }
307
97
 
308
- def qualified_const_defined?(klass)
309
- if klass =~ /::/
310
- namespace, klass = klass.split("::")
311
- eval("#{namespace}.const_defined?(#{klass})") if const_defined?(namespace)
312
- else
313
- const_defined?(klass)
98
+ if controller_actions.include?("index")
99
+ returning += [path_str]
314
100
  end
315
- end
316
101
 
317
- def qualified_const_get(klass)
318
- if klass =~ /::/
319
- namespace, klass = klass.split("::")
320
- eval(namespace).const_get(klass)
321
- else
322
- const_get(klass)
323
- end
102
+ returning
324
103
  end
325
104
 
326
- #
327
- # This is very basic and could be handled better using orm specific
328
- # functionality, but I wanted to keep it generic to avoid creating
329
- # an interface for each the different orm implementations.
330
- # We'll see how it works...
331
- #
332
- def sync_with_db
333
- # Create permissions not found in the database
334
- get_permissions.each do |key|
335
- next if permission_assigned_automatically?(key)
336
- str = lockdown_string(key)
337
- p = Permission.find(:first, :conditions => ["name = ?", str])
338
- unless p
339
- puts ">> Lockdown: Permission not found in db: #{str}, creating."
340
- Permission.create(:name => str)
341
- end
342
- end
343
-
344
- #
345
- # Delete the permissions not found in init.rb
346
- #
347
- db_perms = Permission.find(:all).dup
348
- perm_keys = get_permissions
349
- db_perms.each do |dbp|
350
- unless perm_keys.include?(lockdown_symbol(dbp.name))
351
- puts ">> Lockdown: Permission no longer in init.rb: #{dbp.name}, deleting."
352
- Lockdown.database_execute("delete from permissions_user_groups where permission_id = #{dbp.id}")
353
- dbp.destroy
354
- end
355
- end
356
-
357
- # Create user groups not found in the database
358
- get_user_groups.each do |key|
359
- str = lockdown_string(key)
360
- ug = UserGroup.find(:first, :conditions => ["name = ?", str])
361
- unless ug
362
- puts ">> Lockdown: UserGroup not in the db: #{str}, creating."
363
- ug = UserGroup.create(:name => str)
364
- #Inefficient, definitely, but shouldn't have any issues across orms.
365
- permissions_for_user_group(key) do |perm|
366
- p = Permission.find(:first, :conditions => ["name = ?", lockdown_string(perm)])
367
- Lockdown.database_execute <<-SQL
368
- insert into permissions_user_groups(permission_id, user_group_id)
369
- values(#{p.id}, #{ug.id})
370
- SQL
371
- end
372
- else
373
- # Remove permissions from user group not found in init.rb
374
- ug.permissions.each do |perm|
375
- perm_sym = lockdown_symbol(perm)
376
- perm_string = lockdown_string(perm)
377
- unless @user_groups[key].include?(perm_sym)
378
- puts ">> Lockdown: Permission: #{perm_string} no longer associated to User Group: #{ug.name}, deleting."
379
- ug.permissions.delete(perm)
380
- end
381
- end
382
-
383
- # Add in permissions from init.rb not found in database
384
- @user_groups[key].each do |perm|
385
- perm_string = lockdown_string(perm)
386
- found = false
387
- # see if permission exists
388
- ug.permissions.each do |p|
389
- found = true if lockdown_string(p) == perm_string
390
- end
391
- # if not found, add it
392
- unless found
393
- puts ">> Lockdown: Permission: #{perm_string} not found for User Group: #{ug.name}, adding it."
394
- p = Permission.find(:first, :conditions => ["name = ?", perm_string])
395
- ug.permissions << p
396
- end
397
- end
398
- end
399
- end
400
- rescue Exception => e
401
- puts ">> Lockdown sync failed: #{e}"
402
- end
403
105
  end # class block
404
106
  end # System class
405
107
  end # Lockdown
@@ -1,8 +1,8 @@
1
1
  module Lockdown #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 5
5
- TINY = 22
4
+ MINOR = 6
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/lib/lockdown.rb CHANGED
@@ -1,151 +1,40 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
1
+ require File.join(File.dirname(__FILE__), "lockdown", "classy-inheritance")
2
+ require File.join(File.dirname(__FILE__), "lockdown", "helper")
3
3
 
4
4
  module Lockdown
5
5
  class << self
6
- def format_controller_action(url)
7
- new_url = url.split("/").delete_if{|p| p.to_i > 0 || p.length == 0}.join("/")
8
- new_url += "/index" unless new_url =~ /\//
9
- new_url
10
- end
11
-
12
- def format_controller(ctr)
13
- ctr.split("/").delete_if{|p| p.length == 0}.join("/")
14
- end
15
-
16
- def project_root
17
- project_related_value("Merb.root", "RAILS_ROOT")
18
- end
19
-
20
- def merb_app?
21
- Object.const_defined?("Merb") && Merb.const_defined?("AbstractController")
22
- end
23
-
24
- def rails_app?
25
- Object.const_defined?("ActionController") && ActionController.const_defined?("Base")
26
- end
27
-
28
- def controller_parent
29
- project_related_value("Merb::Controller", "ActionController::Base")
30
- end
31
-
32
- def datamapper_orm?
33
- Object.const_defined?("DataMapper") && DataMapper.const_defined?("Base")
34
- end
35
-
36
- def active_record_orm?
37
- Object.const_defined?("ActiveRecord") && ActiveRecord.const_defined?("Base")
38
- end
39
-
40
- def orm_parent
41
- if datamapper_orm?
42
- DataMapper::Base
43
- elsif active_record_orm?
44
- ActiveRecord::Base
45
- else
46
- raise NotImplementedError, "ORM unknown to Lockdown! Lockdown recognizes DataMapper and ActiveRecord"
47
- end
48
- end
49
-
50
- def database_execute(query)
51
- if active_record_orm?
52
- ActiveRecord::Base.connection.execute(query)
53
- elsif datamapper_orm?
54
- DataMapper.database.execute(query)
55
- else
56
- raise NotImplementedError, "ORM unknown to Lockdown! Lockdown recognizes DataMapper and ActiveRecord"
57
- end
58
- end
6
+ include Lockdown::Helper
59
7
 
60
- def database_query(query)
61
- if active_record_orm?
62
- ActiveRecord::Base.connection.execute(query)
63
- elsif datamapper_orm?
64
- DataMapper.database.query(query)
8
+ def mixin
9
+ if mixin_resource?("frameworks")
10
+ unless mixin_resource?("orms")
11
+ raise NotImplementedError, "ORM unknown to Lockdown!"
12
+ end
65
13
  else
66
- raise NotImplementedError, "ORM unknown to Lockdown! Lockdown recognizes DataMapper and ActiveRecord"
14
+ raise NotImplementedError, "Framework unknown to Lockdown!"
67
15
  end
68
16
  end
69
17
 
70
- def database_table_exists?(klass)
71
- if active_record_orm?
72
- klass.table_exists?
73
- elsif datamapper_orm?
74
- DataMapper.database.table_exists?(klass)
75
- else
76
- raise NotImplementedError, "ORM unknown to Lockdown! Lockdown recognizes DataMapper and ActiveRecord"
77
- end
78
- end
79
18
  private
80
19
 
81
- def project_related_value(merb_val, rails_val)
82
- if merb_app?
83
- eval(merb_val)
84
- elsif rails_app?
85
- eval(rails_val)
86
- else
87
- raise NotImplementedError, "Project type unkown to Lockdown"
88
- end
89
-
90
- end
91
- end # class block
92
-
93
- require File.join("lockdown", "helper.rb")
94
- require File.join("lockdown", "controller_inspector.rb")
95
- require File.join("lockdown", "system.rb")
96
- require File.join("lockdown", "controller.rb")
97
- require File.join("lockdown", "model.rb")
98
- require File.join("lockdown", "view.rb")
99
-
100
- module Session
101
- include Lockdown::Helper
102
-
103
- def nil_lockdown_values
104
- [:expiry_time, :user_id, :user_name, :user_profile_id, :access_rights].each do |val|
105
- session[val] = nil if session[val]
106
- end
107
- end
108
-
109
- #
110
- # Does the current user have access to at least one permission
111
- # in the user group?
112
- #
113
- def current_user_access_in_group?(grp)
114
- return true if current_user_is_admin?
115
- Lockdown::System.user_groups[grp].each do |perm|
116
- return true if access_in_perm?(perm)
20
+ def mixin_resource?(str)
21
+ Dir["#{File.dirname(__FILE__)}/lockdown/#{str}/*.rb"].each do |f|
22
+ require "#{f}"
23
+ mod = File.basename(f).split(".")[0]
24
+ mklass = eval("Lockdown::#{str.capitalize}::#{Lockdown.camelize(mod)}")
25
+ if mklass.use_me?
26
+ include mklass
27
+ return true
117
28
  end
29
+ end
118
30
  false
119
31
  end
32
+ end # class block
33
+ end # Lockdown
120
34
 
121
- def current_user_is_admin?
122
- session[:access_rights] == :all
123
- end
124
-
125
- private
126
-
127
- #
128
- # session[:access_rights] are the keys to Lockdown.
129
- #
130
- # session[:access_rights] holds the array of "controller/action" strings
131
- # allowed for the user.
132
- #
133
- #
134
- def add_lockdown_session_values(user)
135
- session[:access_rights] = Lockdown::System.access_rights_for_user(user)
136
- end
137
-
138
- def access_in_perm?(perm)
139
- Lockdown::System.permissions[perm].each do |ar|
140
- return true if session_access_rights_include?(ar)
141
- end unless Lockdown::System.permissions[perm].nil?
142
- false
143
- end
144
35
 
145
- def session_access_rights_include?(str)
146
- return false unless session[:access_rights]
147
- session[:access_rights].include?(str)
148
- end
149
- end
150
- end
36
+ require File.join(File.dirname(__FILE__), "lockdown", "system")
37
+ require File.join(File.dirname(__FILE__), "lockdown", "controller")
38
+ require File.join(File.dirname(__FILE__), "lockdown", "session")
151
39
 
40
+ Lockdown.mixin