hone-lockdown 1.2.1
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/.gitignore +6 -0
- data/History.txt +195 -0
- data/README.txt +36 -0
- data/Rakefile +14 -0
- data/VERSION +1 -0
- data/lib/lockdown.rb +73 -0
- data/lib/lockdown/context.rb +48 -0
- data/lib/lockdown/database.rb +117 -0
- data/lib/lockdown/frameworks/rails.rb +105 -0
- data/lib/lockdown/frameworks/rails/controller.rb +163 -0
- data/lib/lockdown/frameworks/rails/view.rb +50 -0
- data/lib/lockdown/helper.rb +101 -0
- data/lib/lockdown/orms/active_record.rb +68 -0
- data/lib/lockdown/permission.rb +240 -0
- data/lib/lockdown/rules.rb +378 -0
- data/lib/lockdown/session.rb +57 -0
- data/lib/lockdown/system.rb +52 -0
- data/rails_generators/lockdown/lockdown_generator.rb +273 -0
- data/rails_generators/lockdown/templates/app/controllers/permissions_controller.rb +22 -0
- data/rails_generators/lockdown/templates/app/controllers/sessions_controller.rb +39 -0
- data/rails_generators/lockdown/templates/app/controllers/user_groups_controller.rb +122 -0
- data/rails_generators/lockdown/templates/app/controllers/users_controller.rb +117 -0
- data/rails_generators/lockdown/templates/app/helpers/permissions_helper.rb +2 -0
- data/rails_generators/lockdown/templates/app/helpers/user_groups_helper.rb +2 -0
- data/rails_generators/lockdown/templates/app/helpers/users_helper.rb +2 -0
- data/rails_generators/lockdown/templates/app/models/permission.rb +13 -0
- data/rails_generators/lockdown/templates/app/models/profile.rb +10 -0
- data/rails_generators/lockdown/templates/app/models/user.rb +95 -0
- data/rails_generators/lockdown/templates/app/models/user_group.rb +15 -0
- data/rails_generators/lockdown/templates/app/views/permissions/index.html.erb +16 -0
- data/rails_generators/lockdown/templates/app/views/permissions/show.html.erb +26 -0
- data/rails_generators/lockdown/templates/app/views/sessions/new.html.erb +12 -0
- data/rails_generators/lockdown/templates/app/views/user_groups/edit.html.erb +33 -0
- data/rails_generators/lockdown/templates/app/views/user_groups/index.html.erb +20 -0
- data/rails_generators/lockdown/templates/app/views/user_groups/new.html.erb +31 -0
- data/rails_generators/lockdown/templates/app/views/user_groups/show.html.erb +29 -0
- data/rails_generators/lockdown/templates/app/views/users/edit.html.erb +51 -0
- data/rails_generators/lockdown/templates/app/views/users/index.html.erb +22 -0
- data/rails_generators/lockdown/templates/app/views/users/new.html.erb +50 -0
- data/rails_generators/lockdown/templates/app/views/users/show.html.erb +33 -0
- data/rails_generators/lockdown/templates/config/initializers/lockit.rb +1 -0
- data/rails_generators/lockdown/templates/db/migrate/create_admin_user.rb +17 -0
- data/rails_generators/lockdown/templates/db/migrate/create_permissions.rb +19 -0
- data/rails_generators/lockdown/templates/db/migrate/create_profiles.rb +26 -0
- data/rails_generators/lockdown/templates/db/migrate/create_user_groups.rb +19 -0
- data/rails_generators/lockdown/templates/db/migrate/create_users.rb +17 -0
- data/rails_generators/lockdown/templates/lib/lockdown/README +42 -0
- data/rails_generators/lockdown/templates/lib/lockdown/init.rb +131 -0
- data/spec/lockdown/database_spec.rb +158 -0
- data/spec/lockdown/frameworks/rails/controller_spec.rb +224 -0
- data/spec/lockdown/frameworks/rails/view_spec.rb +87 -0
- data/spec/lockdown/frameworks/rails_spec.rb +175 -0
- data/spec/lockdown/permission_spec.rb +166 -0
- data/spec/lockdown/rules_spec.rb +109 -0
- data/spec/lockdown/session_spec.rb +89 -0
- data/spec/lockdown/system_spec.rb +59 -0
- data/spec/lockdown_spec.rb +19 -0
- data/spec/rcov.opts +5 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +1 -0
- metadata +131 -0
@@ -0,0 +1,240 @@
|
|
1
|
+
module Lockdown
|
2
|
+
class InvalidRuleContext < StandardError; end
|
3
|
+
class PermissionScopeCollision < StandardError; end
|
4
|
+
|
5
|
+
class Controller
|
6
|
+
attr_accessor :name, :access_methods, :only_methods, :except_methods
|
7
|
+
|
8
|
+
def initialize(name)
|
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 if @except_methods.length > 0
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def apply_exceptions
|
26
|
+
exceptions = paths_for(@name, *@except_methods)
|
27
|
+
@access_methods = @access_methods - exceptions
|
28
|
+
end
|
29
|
+
|
30
|
+
def paths_for(str_sym, *methods)
|
31
|
+
Lockdown::System.paths_for(str_sym, *methods)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Model
|
36
|
+
attr_accessor :name, :controller_method, :model_method, :association, :param, :proc_object
|
37
|
+
|
38
|
+
def initialize(name, param = :id)
|
39
|
+
@name = name
|
40
|
+
@param = param
|
41
|
+
end
|
42
|
+
|
43
|
+
def class_name
|
44
|
+
self.name.to_s.camelize
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
class Permission
|
50
|
+
attr_reader :name, :controllers, :models
|
51
|
+
|
52
|
+
# A Permission is a set of rules that are, through UserGroups, assigned
|
53
|
+
# to users to allow access to system resources.
|
54
|
+
#
|
55
|
+
# ==== Summary of controller oriented methods:
|
56
|
+
#
|
57
|
+
# # defines which controller we're talking about
|
58
|
+
# .with_controller(:controller_name) #all_methods is the default
|
59
|
+
#
|
60
|
+
# # only these methods on the controller
|
61
|
+
# .only_methods(:meth1, :meth2)
|
62
|
+
#
|
63
|
+
# # all controller methods except these
|
64
|
+
# .except_methods(:meth1, :meth2)
|
65
|
+
#
|
66
|
+
# ==== Summary of model oriented methods:
|
67
|
+
#
|
68
|
+
# # defines which model we're talking about
|
69
|
+
# .to_model(:model)
|
70
|
+
#
|
71
|
+
# # model_method is simply a public method on :model
|
72
|
+
# .where(:model_method)
|
73
|
+
#
|
74
|
+
# # controller_method must equal model_method
|
75
|
+
# .equals(:controller_method)
|
76
|
+
#
|
77
|
+
# # controller_method.include?(model_method)
|
78
|
+
# .is_in(:controller_method)
|
79
|
+
#
|
80
|
+
#
|
81
|
+
# ==== Example:
|
82
|
+
#
|
83
|
+
# # Define a permission called 'Manage Users' that allows users access
|
84
|
+
# # all methods on the users_controller
|
85
|
+
#
|
86
|
+
# set_permission(:manage_users).
|
87
|
+
# with_controller(:users)
|
88
|
+
#
|
89
|
+
# # Define a permission called "My Account" that only allows a user access
|
90
|
+
# # to methods show and update and the current_user_id must match the id
|
91
|
+
# # of the user being modified
|
92
|
+
#
|
93
|
+
# set_permission(:my_account).
|
94
|
+
# with_controller(:users).
|
95
|
+
# only_methods(:show, :update).
|
96
|
+
# to_model(:user).
|
97
|
+
# where(:current_user_id).
|
98
|
+
# equals(:id)
|
99
|
+
#
|
100
|
+
def initialize(name_symbol)
|
101
|
+
@name = name_symbol
|
102
|
+
@controllers = {}
|
103
|
+
@models = {}
|
104
|
+
@current_context = Lockdown::RootContext.new(name_symbol)
|
105
|
+
end
|
106
|
+
|
107
|
+
def with_controller(name_symbol)
|
108
|
+
validate_context
|
109
|
+
|
110
|
+
controller = Controller.new(name_symbol)
|
111
|
+
@controllers[name_symbol] = controller
|
112
|
+
@current_context = Lockdown::ControllerContext.new(name_symbol)
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
alias_method :and_controller, :with_controller
|
117
|
+
|
118
|
+
def only_methods(*methods)
|
119
|
+
validate_context
|
120
|
+
|
121
|
+
current_controller.only_methods = methods
|
122
|
+
@current_context = Lockdown::RootContext.new(@name)
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
def except_methods(*methods)
|
127
|
+
validate_context
|
128
|
+
|
129
|
+
current_controller.except_methods = methods
|
130
|
+
|
131
|
+
@current_context = Lockdown::RootContext.new(@name)
|
132
|
+
self
|
133
|
+
end
|
134
|
+
|
135
|
+
def to_model(name_symbol, param = :id)
|
136
|
+
validate_context
|
137
|
+
|
138
|
+
@models[name_symbol] = Model.new(name_symbol, param)
|
139
|
+
@current_context = Lockdown::ModelContext.new(name_symbol)
|
140
|
+
self
|
141
|
+
end
|
142
|
+
|
143
|
+
def where(model_method)
|
144
|
+
validate_context
|
145
|
+
|
146
|
+
current_model.model_method = model_method
|
147
|
+
@current_context = Lockdown::ModelWhereContext.new(current_context.name)
|
148
|
+
self
|
149
|
+
end
|
150
|
+
|
151
|
+
def equals(controller_method)
|
152
|
+
validate_context
|
153
|
+
|
154
|
+
associate_controller_method(controller_method, :==)
|
155
|
+
@current_context = Lockdown::RootContext.new(@name)
|
156
|
+
self
|
157
|
+
end
|
158
|
+
|
159
|
+
def is_in(controller_method)
|
160
|
+
validate_context
|
161
|
+
|
162
|
+
associate_controller_method(controller_method, :include?)
|
163
|
+
@current_context = Lockdown::RootContext.new(@name)
|
164
|
+
self
|
165
|
+
end
|
166
|
+
|
167
|
+
# allows you to pass in a proc object to do complex authorization control
|
168
|
+
# it is called from a +to_model+ method. the +to_model+'s model
|
169
|
+
# and the +with_controller+'s controller
|
170
|
+
# i.e. set_permission(:permission).
|
171
|
+
# with_controller(:controller).
|
172
|
+
# to_model(:model).
|
173
|
+
# with_proc do |model, controller|
|
174
|
+
# ...do stuff here
|
175
|
+
# end
|
176
|
+
def with_proc(&block)
|
177
|
+
validate_context
|
178
|
+
|
179
|
+
current_model.proc_object = Proc.new(&block)
|
180
|
+
@current_context = Lockdown::ModelWithProcContext.new(current_context.name)
|
181
|
+
self
|
182
|
+
end
|
183
|
+
|
184
|
+
alias_method :includes, :is_in
|
185
|
+
|
186
|
+
def public_access?
|
187
|
+
@public_access
|
188
|
+
end
|
189
|
+
|
190
|
+
def protected_access?
|
191
|
+
@protected_access
|
192
|
+
end
|
193
|
+
|
194
|
+
def set_as_public_access
|
195
|
+
if protected_access?
|
196
|
+
raise PermissionScopeCollision, "Permission: #{name} already marked as protected and trying to set as public."
|
197
|
+
end
|
198
|
+
@public_access = true
|
199
|
+
end
|
200
|
+
|
201
|
+
def set_as_protected_access
|
202
|
+
if public_access?
|
203
|
+
raise PermissionScopeCollision, "Permission: #{name} already marked as public and trying to set as protected."
|
204
|
+
end
|
205
|
+
@protected_access = true
|
206
|
+
end
|
207
|
+
|
208
|
+
def current_context
|
209
|
+
@current_context
|
210
|
+
end
|
211
|
+
|
212
|
+
def current_controller
|
213
|
+
@controllers[current_context.name]
|
214
|
+
end
|
215
|
+
|
216
|
+
def current_model
|
217
|
+
@models[current_context.name]
|
218
|
+
end
|
219
|
+
|
220
|
+
def ==(other)
|
221
|
+
name == other.name
|
222
|
+
end
|
223
|
+
|
224
|
+
private
|
225
|
+
|
226
|
+
def associate_controller_method(controller_method, association)
|
227
|
+
current_model.controller_method = controller_method
|
228
|
+
current_model.association = association
|
229
|
+
@current_context = Lockdown::RootContext.new(@name)
|
230
|
+
end
|
231
|
+
|
232
|
+
def validate_context
|
233
|
+
method_trace = caller.first;
|
234
|
+
calling_method = caller.first[/#{__FILE__}:(\d+):in `(.*)'/,2]
|
235
|
+
unless current_context.allows?(calling_method)
|
236
|
+
raise InvalidRuleContext, "Method: #{calling_method} was called on wrong context #{current_context}. Allowed methods are: #{current_context.allowed_methods.join(',')}."
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,378 @@
|
|
1
|
+
module Lockdown
|
2
|
+
class InvalidRuleAssignment < StandardError; end
|
3
|
+
|
4
|
+
module Rules
|
5
|
+
attr_accessor :options
|
6
|
+
attr_accessor :permissions
|
7
|
+
attr_accessor :user_groups
|
8
|
+
|
9
|
+
attr_reader :protected_access
|
10
|
+
attr_reader :public_access
|
11
|
+
|
12
|
+
attr_reader :permission_objects
|
13
|
+
|
14
|
+
def set_defaults
|
15
|
+
@permissions = {}
|
16
|
+
@user_groups = {}
|
17
|
+
@options = {}
|
18
|
+
|
19
|
+
@permission_objects = {}
|
20
|
+
|
21
|
+
@controller_classes = []
|
22
|
+
@public_access = []
|
23
|
+
@protected_access = []
|
24
|
+
|
25
|
+
@options = {
|
26
|
+
:session_timeout => (60 * 60),
|
27
|
+
:who_did_it => :current_user_id,
|
28
|
+
:default_who_did_it => 1,
|
29
|
+
:logout_on_access_violation => false,
|
30
|
+
:access_denied_path => "/",
|
31
|
+
:successful_login_path => "/",
|
32
|
+
:subdirectory => nil,
|
33
|
+
:skip_db_sync_in => ["test"],
|
34
|
+
:link_separator => ' | '
|
35
|
+
}
|
36
|
+
|
37
|
+
begin
|
38
|
+
@options[:user_group_model] = "UserGroup"
|
39
|
+
rescue NameError
|
40
|
+
end
|
41
|
+
|
42
|
+
begin
|
43
|
+
@options[:user_model] = "User"
|
44
|
+
rescue NameError
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
50
|
+
# =Rule defining methods. e.g. Methods used in lib/lockdown/init.rb
|
51
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
52
|
+
|
53
|
+
# Creates new permission object
|
54
|
+
# Refer to the Permission object for the full functionality
|
55
|
+
def set_permission(name)
|
56
|
+
@permission_objects[name] = Lockdown::Permission.new(name)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Defines public access by the permission symbols
|
60
|
+
#
|
61
|
+
# ==== Example
|
62
|
+
# set_public_access(:permission_one, :permission_two)
|
63
|
+
#
|
64
|
+
def set_public_access(*perms)
|
65
|
+
perms.each do |perm_symbol|
|
66
|
+
perm = permission_objects.find{|name, pobj| pobj.name == perm_symbol}
|
67
|
+
if perm
|
68
|
+
perm[1].set_as_public_access
|
69
|
+
else
|
70
|
+
msg = "Permission not found: #{perm_symbol}"
|
71
|
+
raise InvalidRuleAssigment, msg
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Defines protected access by the permission symbols
|
77
|
+
#
|
78
|
+
# ==== Example
|
79
|
+
# set_public_access(:permission_one, :permission_two)
|
80
|
+
#
|
81
|
+
def set_protected_access(*perms)
|
82
|
+
perms.each do |perm_symbol|
|
83
|
+
perm = permission_objects.find{|name, pobj| pobj.name == perm_symbol}
|
84
|
+
if perm
|
85
|
+
perm[1].set_as_protected_access
|
86
|
+
else
|
87
|
+
msg = "Permission not found: #{perm_symbol}"
|
88
|
+
raise InvalidRuleAssigment, msg
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Define a user groups by name and permission symbol(s)
|
94
|
+
#
|
95
|
+
# ==== Example
|
96
|
+
# set_user_group(:managment_group, :permission_one, :permission_two)
|
97
|
+
#
|
98
|
+
def set_user_group(name, *perms)
|
99
|
+
user_groups[name] ||= []
|
100
|
+
perms.each do |perm|
|
101
|
+
user_groups[name].push(perm)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
106
|
+
# =Convenience methods for permissions and user groups
|
107
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
108
|
+
|
109
|
+
# Returns array of permission names as symbols
|
110
|
+
def get_permissions
|
111
|
+
permissions.keys
|
112
|
+
end
|
113
|
+
|
114
|
+
# Is the permission defined?
|
115
|
+
def permission_exists?(permission_symbol)
|
116
|
+
get_permissions.include?(permission_symbol)
|
117
|
+
end
|
118
|
+
|
119
|
+
alias_method :has_permission?, :permission_exists?
|
120
|
+
|
121
|
+
# returns true if the permission is public
|
122
|
+
def public_access?(permmision_symbol)
|
123
|
+
public_access.include?(permmision_symbol)
|
124
|
+
end
|
125
|
+
|
126
|
+
# returns true if the permission is public
|
127
|
+
def protected_access?(permmision_symbol)
|
128
|
+
protected_access.include?(permmision_symbol)
|
129
|
+
end
|
130
|
+
|
131
|
+
# These permissions are assigned by the system
|
132
|
+
def permission_assigned_automatically?(permmision_symbol)
|
133
|
+
public_access?(permmision_symbol) || protected_access?(permmision_symbol)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns array of user group names as symbols
|
137
|
+
def get_user_groups
|
138
|
+
user_groups.keys
|
139
|
+
end
|
140
|
+
|
141
|
+
# Is the user group defined?
|
142
|
+
# The :administrators user group always exists
|
143
|
+
def user_group_exists?(user_group_symbol)
|
144
|
+
return true if user_group_symbol == Lockdown.administrator_group_symbol
|
145
|
+
get_user_groups.include?(user_group_symbol)
|
146
|
+
end
|
147
|
+
|
148
|
+
alias_method :has_user_group?, :user_group_exists?
|
149
|
+
|
150
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
151
|
+
# =Convenience methods for permissions and user groups
|
152
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
153
|
+
|
154
|
+
# Pass in a user object to be associated to the administrator user group
|
155
|
+
# The group will be created if it doesn't exist
|
156
|
+
def make_user_administrator(usr)
|
157
|
+
user_groups = usr.send(Lockdown.user_groups_hbtm_reference)
|
158
|
+
user_groups << Lockdown.user_group_class.
|
159
|
+
find_or_create_by_name(Lockdown.administrator_group_string)
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
# Returns array of controller/action values all logged in users can access.
|
164
|
+
def standard_authorized_user_rights
|
165
|
+
public_access + protected_access
|
166
|
+
end
|
167
|
+
|
168
|
+
# Return array of controller/action values user can access.
|
169
|
+
def access_rights_for_user(usr)
|
170
|
+
return unless usr
|
171
|
+
return :all if administrator?(usr)
|
172
|
+
|
173
|
+
rights = standard_authorized_user_rights
|
174
|
+
|
175
|
+
user_groups = usr.send(Lockdown.user_groups_hbtm_reference)
|
176
|
+
user_groups.each do |grp|
|
177
|
+
permissions_for_user_group(grp).each do |perm|
|
178
|
+
rights += access_rights_for_permission(perm)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
rights
|
182
|
+
end
|
183
|
+
|
184
|
+
# Return array of controller/action for a permission
|
185
|
+
def access_rights_for_permission(perm)
|
186
|
+
sym = Lockdown.get_symbol(perm)
|
187
|
+
|
188
|
+
permissions[sym]
|
189
|
+
rescue
|
190
|
+
raise SecurityError, "Permission requested is not defined: #{sym}"
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
# Test user for administrator rights
|
195
|
+
def administrator?(usr)
|
196
|
+
user_has_user_group?(usr, Lockdown.administrator_group_symbol)
|
197
|
+
end
|
198
|
+
|
199
|
+
# Pass in user object and symbol for name of user group
|
200
|
+
def user_has_user_group?(usr, sym)
|
201
|
+
user_groups = usr.send(Lockdown.user_groups_hbtm_reference)
|
202
|
+
user_groups.any? do |ug|
|
203
|
+
Lockdown.convert_reference_name(ug.name) == sym
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Use this for the management screen to restrict user group list to the
|
208
|
+
# user. This will prevent a user from creating a user with more power than
|
209
|
+
# him/her self.
|
210
|
+
def user_groups_assignable_for_user(usr)
|
211
|
+
return [] if usr.nil?
|
212
|
+
ug_table = Lockdown.user_groups_hbtm_reference.to_s
|
213
|
+
if administrator?(usr)
|
214
|
+
Lockdown.user_group_class.find_by_sql <<-SQL
|
215
|
+
select #{ug_table}.* from #{ug_table} order by #{ug_table}.name
|
216
|
+
SQL
|
217
|
+
else
|
218
|
+
usr_table = Lockdown.users_hbtm_reference.to_s
|
219
|
+
if usr_table < ug_table
|
220
|
+
join_table = "#{usr_table}_#{ug_table}"
|
221
|
+
else
|
222
|
+
join_table = "#{ug_table}_#{usr_table}"
|
223
|
+
end
|
224
|
+
Lockdown.user_group_class.find_by_sql <<-SQL
|
225
|
+
select #{ug_table}.* from #{ug_table}, #{join_table}
|
226
|
+
where #{ug_table}.id = #{join_table}.#{Lockdown.user_group_id_reference}
|
227
|
+
and #{join_table}.#{Lockdown.user_id_reference} = #{usr.id}
|
228
|
+
order by #{ug_table}.name
|
229
|
+
SQL
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Similar to user_groups_assignable_for_user, this method should be
|
234
|
+
# used to restrict users from creating a user group with more power than
|
235
|
+
# they have been allowed.
|
236
|
+
def permissions_assignable_for_user(usr)
|
237
|
+
return [] if usr.nil?
|
238
|
+
if administrator?(usr)
|
239
|
+
get_permissions.collect do |k|
|
240
|
+
::Permission.find_by_name(Lockdown.get_string(k))
|
241
|
+
end.compact
|
242
|
+
else
|
243
|
+
user_groups_assignable_for_user(usr).collect do |g|
|
244
|
+
g.permissions
|
245
|
+
end.flatten.compact
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# Returns and array of permission symbols for the user group
|
250
|
+
def permissions_for_user_group(ug)
|
251
|
+
sym = Lockdown.get_symbol(ug)
|
252
|
+
perm_array = []
|
253
|
+
|
254
|
+
if has_user_group?(sym)
|
255
|
+
permissions = user_groups[sym] || []
|
256
|
+
else
|
257
|
+
permissions = ug.permissions
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
permissions.each do |perm|
|
262
|
+
perm_sym = Lockdown.get_symbol(perm)
|
263
|
+
|
264
|
+
unless permission_exists?(perm_sym)
|
265
|
+
msg = "Permission associated to User Group is invalid: #{perm}"
|
266
|
+
raise SecurityError, msg
|
267
|
+
end
|
268
|
+
|
269
|
+
perm_array << perm_sym
|
270
|
+
end
|
271
|
+
|
272
|
+
perm_array
|
273
|
+
end
|
274
|
+
|
275
|
+
def process_rules
|
276
|
+
parse_permissions
|
277
|
+
validate_user_groups
|
278
|
+
end
|
279
|
+
|
280
|
+
private
|
281
|
+
|
282
|
+
def validate_user_groups
|
283
|
+
user_groups.each do |user_group, perms|
|
284
|
+
perms.each do |perm|
|
285
|
+
unless permission_exists?(perm)
|
286
|
+
msg ="User Group: #{user_group}, permission not found: #{perm}"
|
287
|
+
raise InvalidRuleAssignment, msg
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def parse_permissions
|
294
|
+
permission_objects.each do |name, perm|
|
295
|
+
@permissions[perm.name] ||= []
|
296
|
+
set_controller_access(perm)
|
297
|
+
end
|
298
|
+
|
299
|
+
set_model_access
|
300
|
+
end
|
301
|
+
|
302
|
+
def set_controller_access(perm)
|
303
|
+
perm.controllers.each do |name, controller|
|
304
|
+
controller.set_access_methods
|
305
|
+
|
306
|
+
@permissions[perm.name] |= controller.access_methods
|
307
|
+
|
308
|
+
if perm.public_access?
|
309
|
+
@public_access |= controller.access_methods
|
310
|
+
elsif perm.protected_access?
|
311
|
+
@protected_access |= controller.access_methods
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def set_model_access
|
317
|
+
method_definition = "\tdef check_model_authorization\n\t#This method will check for access to model resources\n"
|
318
|
+
|
319
|
+
permission_objects.each do |name, perm|
|
320
|
+
next if perm.models.empty?
|
321
|
+
|
322
|
+
#Set filter for each controller
|
323
|
+
perm.controllers.each do |controller_name, controller|
|
324
|
+
#Set filter for each model on controller
|
325
|
+
perm.models.each do |model_name, model|
|
326
|
+
method_definition << define_restrict_model_access(controller, model)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
method_definition << "\n\tend"
|
332
|
+
|
333
|
+
#puts "method_definition:\n #{method_definition}"
|
334
|
+
|
335
|
+
Lockdown.add_controller_method method_definition
|
336
|
+
end
|
337
|
+
|
338
|
+
def define_restrict_model_access(controller, model)
|
339
|
+
controller_class = Lockdown.fetch_controller_class(controller.name)
|
340
|
+
|
341
|
+
methods = controller.
|
342
|
+
access_methods.
|
343
|
+
collect do |am|
|
344
|
+
am[am.index('/') + 1..-1].to_sym if am.index('/')
|
345
|
+
end.compact.inspect
|
346
|
+
|
347
|
+
return <<-RUBY
|
348
|
+
if controller_name == "#{controller.name}"
|
349
|
+
if #{methods}.include?(action_name.to_sym)
|
350
|
+
unless instance_variable_defined?(:@#{model.name})
|
351
|
+
@#{model.name} = #{model.class_name}.find(params[#{model.param.inspect}])
|
352
|
+
end
|
353
|
+
#{generate_proc_string(model)}
|
354
|
+
# Need to make sure we find the model first before checking admin status.
|
355
|
+
return true if current_user_is_admin?
|
356
|
+
unless @#{model.name}.#{model.model_method}.#{model.association}(#{model.controller_method})
|
357
|
+
raise SecurityError, "Access to #\{action_name\} denied to #{model.name}.id #\{@#{model.name}.id\}"
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
RUBY
|
362
|
+
end
|
363
|
+
|
364
|
+
# generates the metaprogram string for allowing +with_proc+ in the lib/lockdown/init.rb
|
365
|
+
def generate_proc_string(model)
|
366
|
+
# spaces need to properly format the code
|
367
|
+
spaces = (1..12).to_a.collect { " " }.join
|
368
|
+
|
369
|
+
if model.proc_object
|
370
|
+
<<PROC_STRING
|
371
|
+
unless #{model.proc_object.to_ruby.gsub("\n", "\n#{spaces}")}.call(@#{model.name}, self)
|
372
|
+
raise SecurityError, "Access to #\{action_name\} denied to #{model.name}.id #\{@#{model.name}.id\}"
|
373
|
+
end
|
374
|
+
PROC_STRING
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|