lockdown 0.5.22 → 0.6.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.
@@ -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