ucb_rails_security 2.0.7
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/CHANGELOG +6 -0
- data/Manifest +56 -0
- data/README +195 -0
- data/Rakefile +21 -0
- data/TODO +3 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/base_controller.rb +17 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/ldap_search_controller.rb +10 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/role_users_controller.rb +27 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/roles_controller.rb +52 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/user_roles_controller.rb +29 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/users_controller.rb +59 -0
- data/generators/ucb_rails_security/templates/db/migrate/xxx_create_ucb_rails_security_tables.rb +31 -0
- data/generators/ucb_rails_security/templates/helpers/ucb_security/base_helper.rb +23 -0
- data/generators/ucb_rails_security/templates/helpers/ucb_security/builder.rb +25 -0
- data/generators/ucb_rails_security/templates/helpers/ucb_security/roles_helper.rb +2 -0
- data/generators/ucb_rails_security/templates/helpers/ucb_security/users_helper.rb +2 -0
- data/generators/ucb_rails_security/templates/initializers/ucb_security_config.rb +20 -0
- data/generators/ucb_rails_security/templates/javascripts/ucb_security.js +99 -0
- data/generators/ucb_rails_security/templates/models/ldap_search.rb +48 -0
- data/generators/ucb_rails_security/templates/models/role.rb +32 -0
- data/generators/ucb_rails_security/templates/models/user.rb +106 -0
- data/generators/ucb_rails_security/templates/models/user_roles.rb +3 -0
- data/generators/ucb_rails_security/templates/stylesheets/ucb_security.css +347 -0
- data/generators/ucb_rails_security/templates/views/layouts/ucb_security/_main_navigation.html.erb +10 -0
- data/generators/ucb_rails_security/templates/views/layouts/ucb_security/application.html.erb +24 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/ldap_search/index.html.erb +62 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/role_users/_new.html.erb +11 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/role_users/edit.html.erb +37 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/roles/_users.html.erb +14 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/roles/edit.html.erb +19 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/roles/index.html.erb +34 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/roles/new.html.erb +19 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/roles/show.html.erb +27 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/user_roles/edit.html.erb +17 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/users/edit.html.erb +23 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/users/index.html.erb +43 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/users/new.html.erb +29 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/users/show.html.erb +43 -0
- data/generators/ucb_rails_security/ucb_rails_security_generator.rb +191 -0
- data/init.rb +9 -0
- data/lib/helpers/rspec_helpers.rb +119 -0
- data/lib/tasks/ucb_rails_security.rake +22 -0
- data/lib/ucb_rails_security.rb +60 -0
- data/lib/ucb_rails_security_casauthentication.rb +117 -0
- data/lib/ucb_rails_security_logger.rb +33 -0
- data/lib/ucb_rs_controller_methods.rb +496 -0
- data/rdoc_includes/application_controller_rb.txt +9 -0
- data/rspec/_all_specs.rb +5 -0
- data/rspec/_setup.rb +36 -0
- data/rspec/filter_ldap_spec.rb +87 -0
- data/rspec/filter_role_spec.rb +56 -0
- data/rspec/filter_spec.rb +37 -0
- data/rspec/filter_user_spec.rb +55 -0
- data/rspec/logged_in_status_spec.rb +226 -0
- data/rspec/ucb_rails_security_casauthentication_spec.rb +83 -0
- data/rspec/ucb_rails_security_spec.rb +34 -0
- data/test/test_rails-2.0.x/test/test_helper.rb +38 -0
- data/test/test_rails-2.1.x/test/test_helper.rb +38 -0
- data/ucb_rails_security.gemspec +41 -0
- metadata +147 -0
@@ -0,0 +1,496 @@
|
|
1
|
+
module UCB #:nodoc:
|
2
|
+
module Rails #:nodoc:
|
3
|
+
module Security
|
4
|
+
# == Overview
|
5
|
+
# These methods are added to ActionController::Base
|
6
|
+
# so they are available to all of your application's controllers.
|
7
|
+
#
|
8
|
+
# Most of the time you will be using the various <tt>filter_*</tt>
|
9
|
+
# methods. Note that most of these methods are implemented via method_missing
|
10
|
+
# and are not explicitly listed in the "methods" section of this document.
|
11
|
+
# For details see examples below as well as method_missing, filter_ldap and
|
12
|
+
# filter_db_role.
|
13
|
+
#
|
14
|
+
# There are several methods used primarily by the filter methods, but you
|
15
|
+
# may find use for these in your controllers. Many of these methods
|
16
|
+
# are marked as "helper methods" and are available for use in your
|
17
|
+
# views (*.rhtml templates) and helpers. See ApplicationHelper for
|
18
|
+
# more information.
|
19
|
+
#
|
20
|
+
# == How Does This Work?
|
21
|
+
# Take a look at the following controller: +RAILS_ROOT/app/controllers/ucb_security/base_controller.rb+
|
22
|
+
#
|
23
|
+
# You should see the following:
|
24
|
+
#
|
25
|
+
# class UcbSecurity::BaseController < ApplicationController
|
26
|
+
# # Move this include into your ApplicationController to add security to your entire application
|
27
|
+
# include UCB::Rails::Security::ControllerMethods
|
28
|
+
#
|
29
|
+
# layout 'layouts/ucb_security/application'
|
30
|
+
# before_filter :filter_role_security, :except => [:not_authorized, :logout]
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# The +include+ line adds several methods to this base controller, many
|
34
|
+
# of which are filters. The line <tt>before_filter :filter_role_security, :except => [:not_authorized, :logout]</tt>
|
35
|
+
# tells this controller to only allow a user with the
|
36
|
+
# security role access to the actions in this controller. Since all
|
37
|
+
# of the ucb_security controllers extend this base controller, that has
|
38
|
+
# the requires the user to have the security role for all actions
|
39
|
+
# in the ucb_security module (with the exception of not_authorized and
|
40
|
+
# logout)
|
41
|
+
#
|
42
|
+
# When you add one of these filters to your controller, behind the scenes
|
43
|
+
# CAS authentication is handled for you: if the user has not yet authenticated
|
44
|
+
# they will be directed to CAS otherwise your filter will be run.
|
45
|
+
#
|
46
|
+
# You may want to add this filter to your application controller. If your
|
47
|
+
# entire site requires authentication then that is definitely the way to go.
|
48
|
+
# If only a handful of controllers require auth, then only add these filter
|
49
|
+
# methods to those specific controllers.
|
50
|
+
#
|
51
|
+
#
|
52
|
+
# ==Explicit Filters
|
53
|
+
#
|
54
|
+
# User must be logged in:
|
55
|
+
#
|
56
|
+
# class MyController < ActionController::Base
|
57
|
+
# before_filter :filter_logged_in
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# User must be in user table (assumes your application has
|
61
|
+
# a +User+ table -- see UCB::Rails::Security):
|
62
|
+
#
|
63
|
+
# class MyController < ActionController::Base
|
64
|
+
# before_filter :filter_in_user_table
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# ==LDAP Filters
|
68
|
+
#
|
69
|
+
# Any LDAP attribute can be used in a dynamic LDAP filter. More accurately, any method
|
70
|
+
# that an instance of UCB::LDAP::Person responds to can be used in a filter.
|
71
|
+
#
|
72
|
+
# To satisfy the filter, the method must return a broader-than-normal
|
73
|
+
# definition of <tt>true</tt>: strings containing only spaces and empty arrays
|
74
|
+
# are considered <tt>false</tt>.
|
75
|
+
#
|
76
|
+
# Since UCB::LDAP::Person has <tt>employee?</tt> and <tt>student?</tt> methods,
|
77
|
+
# we can do the following:
|
78
|
+
#
|
79
|
+
# class MyController < ActionController::Base
|
80
|
+
# before_filter :filter_ldap_employee?
|
81
|
+
# before_filter :filter_ldap_student?
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# You can use any valid UCB::LDAP::Person method or LDAP attribute as the
|
85
|
+
# "method" part of :filter_ldap_method. Just keep in mind what constitutes
|
86
|
+
# "true".
|
87
|
+
#
|
88
|
+
# Since there is no "bogus" attribute, the following raises a <tt>NoMethodError</tt>
|
89
|
+
# exception:
|
90
|
+
#
|
91
|
+
# class MyController < ActionController::Base
|
92
|
+
# before_filter :filter_ldap_bogus
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# You can filter based on the value of a particular attribute.
|
96
|
+
# Currently supported operators are "eq" and "ne":
|
97
|
+
#
|
98
|
+
# class MyController < ActionController::Base
|
99
|
+
# before_filter :filter_ldap_deptid__eq__JKASD
|
100
|
+
# before_filter :filter_ldap_lastname__ne__Badenov
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# === Note
|
104
|
+
#
|
105
|
+
# LDAP filters call the filter_logged_in filter.
|
106
|
+
#
|
107
|
+
# == User Filters
|
108
|
+
#
|
109
|
+
# If your application has a user table you can do controller filtering
|
110
|
+
# based on your user table:
|
111
|
+
#
|
112
|
+
# The following only allows people who can update to access the controller:
|
113
|
+
#
|
114
|
+
# class User < ActiveRecord::Base
|
115
|
+
# def can_update?
|
116
|
+
# <complicated logic>
|
117
|
+
# end
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
# class UpdateController < ActionController::Base
|
121
|
+
# before_filter :filter_user_can_update?
|
122
|
+
# end
|
123
|
+
#
|
124
|
+
# Filters of the form <tt>:filter_user_method</tt> are passed/failed
|
125
|
+
# based on the return value of <tt>User#method</tt>.
|
126
|
+
#
|
127
|
+
# === Non-boolean User Filters
|
128
|
+
#
|
129
|
+
# You can filter based on the value of a particular +User+ table
|
130
|
+
# method. Currently supported operators are "eq" and "ne":
|
131
|
+
#
|
132
|
+
# class DoeNotJohnController < ActionController::Base
|
133
|
+
# before_filter :filter_user_lastname__eq__Doe
|
134
|
+
# before_filter :filter_user_firstname__ne__John
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# === Note
|
138
|
+
#
|
139
|
+
# All User filters call the filter_logged_in and filter_in_user_table filters.
|
140
|
+
#
|
141
|
+
# ==Role Filters
|
142
|
+
#
|
143
|
+
# If your application has both a user and
|
144
|
+
# a roles table (see UCB::Rails::Security)
|
145
|
+
# you can use dynamic database role filters.
|
146
|
+
#
|
147
|
+
# Your user class must repond to the "roles" message
|
148
|
+
# by returning an Array of objects that respond to the "name"
|
149
|
+
# message.
|
150
|
+
#
|
151
|
+
# The following verifies the user has the "admin" role:
|
152
|
+
#
|
153
|
+
# class MyController < ActionController::Base
|
154
|
+
# before_filter :filter_role_admin
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# In general, the ":filter_role_rolename" filter verifies that the
|
158
|
+
# user holds the "rolename" role.
|
159
|
+
#
|
160
|
+
# The following verifies the user has the "admin" <b>and</b> "super_user" roles:
|
161
|
+
#
|
162
|
+
# class MyController < ActionController::Base
|
163
|
+
# before_filter :filter_role_has_all_of_admin_and_super_user
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# The following verifies the user has either the "guest" <b>or</b> "user" roles:
|
167
|
+
#
|
168
|
+
# class MyController < ActionController::Base
|
169
|
+
# before_filter :filter_role_has_one_of_guest_or_user
|
170
|
+
# end
|
171
|
+
#
|
172
|
+
# === Note
|
173
|
+
#
|
174
|
+
# Role filters call the filter_logged_in and filter_in_user_table filters.
|
175
|
+
#
|
176
|
+
# == Helper Methods
|
177
|
+
#
|
178
|
+
# Several of the methods in this module are exposed as helper methods
|
179
|
+
# that you can use in your views (<tt>../app/views/<controller>/*.rhtml</tt>)
|
180
|
+
# and helpers (<tt>../app/helpers/<controller>_helper.rb</tt>).
|
181
|
+
#
|
182
|
+
# # in your view
|
183
|
+
#
|
184
|
+
# <% if logged_in? %>
|
185
|
+
# Logged in as: <%= "#{ldap_user.firstname} #{ldap_user.lastname}"%>
|
186
|
+
# <% end %>
|
187
|
+
#
|
188
|
+
# Or even better, used in a helper method you write:
|
189
|
+
#
|
190
|
+
# # in your view
|
191
|
+
#
|
192
|
+
# <%= logged_in_html %>
|
193
|
+
#
|
194
|
+
# # in your controller's helper
|
195
|
+
#
|
196
|
+
# def logged_in_html
|
197
|
+
# logged_in? ? "" : "Logged in as #{ldap_user.firstname} #{ldap_user.lastname}"
|
198
|
+
# end
|
199
|
+
#
|
200
|
+
# See the HELPER_METHODS constant below for a list of the methods.
|
201
|
+
#
|
202
|
+
module ControllerMethods
|
203
|
+
|
204
|
+
# These methods are available has helpers in your views and helpers.
|
205
|
+
HELPER_METHODS = [
|
206
|
+
:in_user_table?,
|
207
|
+
:ldap_user,
|
208
|
+
:logged_in,
|
209
|
+
:role_names,
|
210
|
+
:roles,
|
211
|
+
:ldap_uid,
|
212
|
+
:user_table_user,
|
213
|
+
:user_table_id,
|
214
|
+
:using_user_table?,
|
215
|
+
:logout,
|
216
|
+
]
|
217
|
+
|
218
|
+
# Operators available for non-boolean LDAP and User filters.
|
219
|
+
OPERATOR_METHODS = {
|
220
|
+
"eq" => "==",
|
221
|
+
"ne" => "!=",
|
222
|
+
}
|
223
|
+
|
224
|
+
def not_authorized
|
225
|
+
render :text => "Not Authorized", :status => 401
|
226
|
+
end
|
227
|
+
|
228
|
+
# Logs user out of application
|
229
|
+
def logout
|
230
|
+
application_logout
|
231
|
+
protocol = request.ssl? ? 'https://' : 'http://'
|
232
|
+
url = UCB::Rails::Security::CASAuthentication.home_url
|
233
|
+
logout_url = UCB::Rails::Security::CASAuthentication.logout_url
|
234
|
+
redirect_to("#{logout_url}?url=#{protocol}#{request.host_with_port}/#{url}")
|
235
|
+
end
|
236
|
+
|
237
|
+
private unless $TESTING
|
238
|
+
|
239
|
+
def application_logout()
|
240
|
+
[ :cas_user, :ldap_user, :user_table_id, :casfilterpgt,
|
241
|
+
:casfilterreceipt, :caslastticket, :casfiltergateway ].each{ |k| session[k] = nil }
|
242
|
+
end
|
243
|
+
|
244
|
+
# CAS authentication before_filter. Use this filter to ensure
|
245
|
+
# users have logged in, i.e. authenticated with CAS.
|
246
|
+
def filter_logged_in() #:doc:
|
247
|
+
_logger.debug("In filter_logged_in")
|
248
|
+
if logged_in?
|
249
|
+
_logger.debug("\tlogged_in? returned true")
|
250
|
+
return true
|
251
|
+
elsif !UCB::Rails::Security::CASAuthentication.filter(self)
|
252
|
+
_logger.debug("\tUCB::Rails::Security::CASAuthentication.filter returned false")
|
253
|
+
return false
|
254
|
+
end
|
255
|
+
application_login
|
256
|
+
true
|
257
|
+
end
|
258
|
+
|
259
|
+
# Logs ldap_uid into application.
|
260
|
+
#
|
261
|
+
# * get LDAP entry (available via ActionController::Base#ldap_user)
|
262
|
+
# * check for user in User table (if using_user_table?)
|
263
|
+
# * update User table columns with LDAP values
|
264
|
+
#
|
265
|
+
# This happens upon successful CAS authentication. You can login
|
266
|
+
# a particular user to your application by calling this method
|
267
|
+
# with the corresponding ldap_uid.
|
268
|
+
def application_login(ldap_uid=ldap_uid) #:doc:
|
269
|
+
_logger.debug("In application_login")
|
270
|
+
UCB::LDAP::Person.include_test_entries = UCB::Rails::Security::CASAuthentication.allow_test_entries?
|
271
|
+
_logger.debug("\tLDAP test entries will #{UCB::LDAP::Person.include_test_entries? || "NOT"} be included")
|
272
|
+
_logger.debug("Looking for authenticated user in LDAP: #{ldap_uid}")
|
273
|
+
self.ldap_user = UCB::LDAP::Person.find_by_uid(ldap_uid)
|
274
|
+
if ldap_user().nil?
|
275
|
+
_logger.debug("Unable to find user in LDAP.")
|
276
|
+
redirect_to(not_authorized_url())
|
277
|
+
return false
|
278
|
+
end
|
279
|
+
_logger.debug("Found user in LDAP.")
|
280
|
+
look_for_user_in_user_table(ldap_uid) if using_user_table?
|
281
|
+
end
|
282
|
+
|
283
|
+
# Check if user is in user table. If found, update columns
|
284
|
+
# with LDAP attributes of same name.
|
285
|
+
def look_for_user_in_user_table(ldap_uid)
|
286
|
+
_logger.debug("Looking for user in user table.")
|
287
|
+
if ar_user = User.find_by_ldap_uid(ldap_uid)
|
288
|
+
_logger.debug("Found user.")
|
289
|
+
self.user_table_id = ar_user.id
|
290
|
+
update_user_table(ldap_user, ar_user)
|
291
|
+
return true
|
292
|
+
else
|
293
|
+
_logger.debug("User NOT found.")
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# Update User table entry with values from UCB::LDAP::Person instance.
|
298
|
+
# This happens automatically when a user logs in and is found in
|
299
|
+
# the User table.
|
300
|
+
#
|
301
|
+
# Applications can call this to update user table entries with
|
302
|
+
# (presumably more current) LDAP information. Each column name that
|
303
|
+
# has a corresponding LDAP attribute or alias will be updated.
|
304
|
+
def update_user_table(ldap_user, ar_user) #:doc:
|
305
|
+
_logger.debug("Updating users attributes to match LDAP.")
|
306
|
+
User.content_columns.each do |col|
|
307
|
+
begin
|
308
|
+
ar_user.send("#{col.name}=", ldap_user.send(col.name.to_sym) )
|
309
|
+
rescue NoMethodError
|
310
|
+
# It's okay. Don't have LDAP attribute for given column.
|
311
|
+
end
|
312
|
+
end
|
313
|
+
ar_user.save
|
314
|
+
end
|
315
|
+
|
316
|
+
# Returns +true+ if using a User table.
|
317
|
+
# Gets value from UCB::Rails::Security::using_user_table?.
|
318
|
+
def using_user_table?() #:doc:
|
319
|
+
UCB::Rails::Security::using_user_table?
|
320
|
+
end
|
321
|
+
|
322
|
+
# Returns LDAP_UID of logged in user
|
323
|
+
def ldap_uid() #:doc:
|
324
|
+
session[:cas_user]
|
325
|
+
end
|
326
|
+
|
327
|
+
# Returns UCB::LDAP::Person instance of logged in user.
|
328
|
+
def ldap_user() #:doc:
|
329
|
+
session[:ldap_user]
|
330
|
+
end
|
331
|
+
|
332
|
+
# Returns +id+ column from User table for logged in user.
|
333
|
+
def user_table_id() #:doc:
|
334
|
+
session[:user_table_id]
|
335
|
+
end
|
336
|
+
|
337
|
+
# Returns the User table instance for the logged in user.
|
338
|
+
def user_table_user() #:doc:
|
339
|
+
user_table_id && (@user_table_user ||= User.find(user_table_id))
|
340
|
+
end
|
341
|
+
|
342
|
+
# Returns +true+ if user is logged in. Does <b>not</b>
|
343
|
+
# attempt to authenticate.
|
344
|
+
def logged_in?() #:doc:
|
345
|
+
ldap_user ? true : false
|
346
|
+
end
|
347
|
+
|
348
|
+
# Returns +true+ if user is logged in and was found in User table.
|
349
|
+
# At authentication time. Does <b>not</b> attempt to find user.
|
350
|
+
def in_user_table?() #:doc:
|
351
|
+
user_table_id ? true : false
|
352
|
+
end
|
353
|
+
|
354
|
+
# Setter for ldap_user.
|
355
|
+
def ldap_user=(ldap_user)
|
356
|
+
session[:ldap_user] = ldap_user
|
357
|
+
end
|
358
|
+
|
359
|
+
# Setter for user_table_id.
|
360
|
+
def user_table_id=(user_table_id)
|
361
|
+
session[:user_table_id] = user_table_id
|
362
|
+
end
|
363
|
+
|
364
|
+
# Setter for user_table_user.
|
365
|
+
def user_table_user=(user_table_instance)
|
366
|
+
@user_table_user = user_table_instance
|
367
|
+
end
|
368
|
+
|
369
|
+
# Dynamic filter implementation.
|
370
|
+
def method_missing(method, *args)
|
371
|
+
return super unless method.to_s =~ /^filter_(ldap|user|role)_(.+)$/
|
372
|
+
|
373
|
+
_logger.debug("#{method} dispatched to method_missing()")
|
374
|
+
|
375
|
+
_logger.debug("before filter_logged_in")
|
376
|
+
filter_logged_in or return false
|
377
|
+
_logger.debug("after filter_logged_in")
|
378
|
+
|
379
|
+
_logger.debug("Beginning Authorization")
|
380
|
+
return true if case
|
381
|
+
when $1 == "ldap": filter_ldap($2)
|
382
|
+
when $1 == "user": filter_user($2)
|
383
|
+
when $1 == "role": filter_role($2)
|
384
|
+
end
|
385
|
+
|
386
|
+
redirect_to(not_authorized_url)
|
387
|
+
_logger.debug("Authorization Failed")
|
388
|
+
return false
|
389
|
+
end
|
390
|
+
|
391
|
+
# Processes LDAP filters.
|
392
|
+
def filter_ldap(method)
|
393
|
+
_logger.debug("In filter_ldap(): processing LDAP based authorization filters")
|
394
|
+
(method =~ /(.+)__(.+)__(.+)/) ? filter_extended(ldap_user.send($1), $2, $3) : ldap_boolean(ldap_user.send(method))
|
395
|
+
end
|
396
|
+
|
397
|
+
# Implements a special definition of truth for the purposes
|
398
|
+
# of the ldap filters. Empty strings, empty arrays,
|
399
|
+
# and arrays that only have nil/empty elements are all false.
|
400
|
+
def ldap_boolean(ldap_attribute_value)
|
401
|
+
( ldap_attribute_value && ("#{ldap_attribute_value}".strip != '') ) ? true : false
|
402
|
+
end
|
403
|
+
|
404
|
+
# +eval+ a boolean expression
|
405
|
+
def filter_extended(left, operator, right)
|
406
|
+
return eval("'#{left}' #{OPERATOR_METHODS[operator]} '#{right}'")
|
407
|
+
end
|
408
|
+
|
409
|
+
# Returns +true+ if user in user table. If not logged in, user
|
410
|
+
# is redirected to CAS authentication.
|
411
|
+
def filter_in_user_table() #:doc:
|
412
|
+
filter_logged_in or return false
|
413
|
+
user_table_id ? true : false
|
414
|
+
end
|
415
|
+
|
416
|
+
# Prcoess User-based filters
|
417
|
+
def filter_user(method)
|
418
|
+
_logger.debug("In filter_user(): processing user based authorization filters")
|
419
|
+
unless UCB::Rails::Security.using_user_table?
|
420
|
+
_logger.debug("User table not enabled.")
|
421
|
+
raise(Exception, "You must enable the user table to use user based filters")
|
422
|
+
return false
|
423
|
+
end
|
424
|
+
filter_in_user_table or return false
|
425
|
+
return filter_extended(user_table_user.send($1), $2, $3) if method =~ /(.+)__(.+)__(.+)/
|
426
|
+
user_table_user.send(method)
|
427
|
+
end
|
428
|
+
|
429
|
+
# Process Role-based filters
|
430
|
+
def filter_role(method)
|
431
|
+
_logger.debug("In filter_role(): processing role based authorization filters")
|
432
|
+
unless UCB::Rails::Security.using_user_table?
|
433
|
+
_logger.debug("User table not enabled.")
|
434
|
+
raise(Exception, "You must enable the user table to use role based filters")
|
435
|
+
return false
|
436
|
+
end
|
437
|
+
filter_in_user_table or return false
|
438
|
+
return roles_has_one_of($1) if method =~ /^has_one_of_(.+)$/
|
439
|
+
return roles_has_all_of($1) if method =~ /^has_all_of_(.+)$/
|
440
|
+
role_names.include?(method.downcase)
|
441
|
+
end
|
442
|
+
|
443
|
+
# Returns +true+ if user has one of specified roles.
|
444
|
+
#
|
445
|
+
# Called like:
|
446
|
+
#
|
447
|
+
# before_filter filter_role_has_one_of_role1_or_role2_or_role3
|
448
|
+
#
|
449
|
+
def roles_has_one_of(roles_string)
|
450
|
+
(roles_array(roles_string) & role_names).size > 0
|
451
|
+
end
|
452
|
+
|
453
|
+
# Returns +true+ if user has all specified roles.
|
454
|
+
#
|
455
|
+
# Called like:
|
456
|
+
#
|
457
|
+
# before_filter filter_role_has_all_of_role1_and_role2_and_role3
|
458
|
+
#
|
459
|
+
def roles_has_all_of(roles_string)
|
460
|
+
(roles_array(roles_string) - role_names).size == 0
|
461
|
+
end
|
462
|
+
|
463
|
+
# Parse role string.
|
464
|
+
def roles_array(roles_string)
|
465
|
+
roles_string.downcase.split(/_and_|_or_/)
|
466
|
+
end
|
467
|
+
|
468
|
+
# Returns +Array+ of +Role+ for logged in user.
|
469
|
+
def roles() #:doc:
|
470
|
+
user_table_user && user_table_user.roles
|
471
|
+
end
|
472
|
+
|
473
|
+
# Returns +Array+ of user's role names, lowercased. Returns
|
474
|
+
# +nil+ if user is not in user table (or not logged in).
|
475
|
+
def role_names() #:doc:
|
476
|
+
roles && roles.map{|r| r.name.downcase}
|
477
|
+
end
|
478
|
+
|
479
|
+
# Returns url where user is redirected upon failed authorization.
|
480
|
+
def not_authorized_url() #:doc:
|
481
|
+
UCB::Rails::Security.not_authorized_url
|
482
|
+
end
|
483
|
+
|
484
|
+
# Add HELPER_METHODS to controller classes including this module.
|
485
|
+
def self.included(base)
|
486
|
+
base.send(:helper_method, HELPER_METHODS)
|
487
|
+
end
|
488
|
+
|
489
|
+
def _logger
|
490
|
+
UCB::Rails::Security.logger
|
491
|
+
end
|
492
|
+
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
|
2
|
+
You also neet to <tt>include<tt> UCB::Rails::Security::ControllerMethods</tt>
|
3
|
+
in your controller class. This can be done in each controller, but should probably be done in <tt>application.rb</tt>:
|
4
|
+
|
5
|
+
# ../app/controllers/application.rb
|
6
|
+
|
7
|
+
class ApplicationController < ActionController::Base
|
8
|
+
include UCB::Rails::Security::ControllerMethods
|
9
|
+
end
|
data/rspec/_all_specs.rb
ADDED
data/rspec/_setup.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
$TESTING = true
|
2
|
+
|
3
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
4
|
+
require "ucb_rails_security"
|
5
|
+
|
6
|
+
# Swallow logger calls during testing
|
7
|
+
module Mock
|
8
|
+
class Logger
|
9
|
+
def debug(msg); end
|
10
|
+
def info(msg); end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
UCB::Rails::Security.logger = Mock::Logger.new
|
14
|
+
|
15
|
+
def reset_cas_authentication_class()
|
16
|
+
ca = UCB::Rails::Security::CASAuthentication
|
17
|
+
ca.reset_instance_variables()
|
18
|
+
ca
|
19
|
+
end
|
20
|
+
|
21
|
+
# Mixin like a Rails application will
|
22
|
+
module ActionController
|
23
|
+
class Base
|
24
|
+
include UCB::Rails::Security::ControllerMethods
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Return new ActionController::Base
|
29
|
+
def new_controller
|
30
|
+
c = ActionController::Base.new
|
31
|
+
c.session = {}
|
32
|
+
c
|
33
|
+
end
|
34
|
+
|
35
|
+
class User
|
36
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/_setup.rb"
|
2
|
+
|
3
|
+
context "For an LDAP attribute" do
|
4
|
+
setup do
|
5
|
+
@controller = new_controller()
|
6
|
+
end
|
7
|
+
|
8
|
+
specify "true is true" do
|
9
|
+
@controller.ldap_boolean(true).should be_true
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "a string is true" do
|
13
|
+
@controller.ldap_boolean("x").should be_true
|
14
|
+
end
|
15
|
+
|
16
|
+
specify "a number, including 0, is true" do
|
17
|
+
@controller.ldap_boolean(0).should be_true
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "a populated Array is true" do
|
21
|
+
@controller.ldap_boolean(["x"]).should be_true
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "false is false" do
|
25
|
+
@controller.ldap_boolean(false).should be_false
|
26
|
+
end
|
27
|
+
specify "nil is false" do
|
28
|
+
@controller.ldap_boolean(nil).should be_false
|
29
|
+
end
|
30
|
+
specify "' ' is false" do
|
31
|
+
@controller.ldap_boolean(' ').should be_false
|
32
|
+
end
|
33
|
+
specify "[] is false" do
|
34
|
+
@controller.ldap_boolean([]).should be_false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "When a user is not logged in to the application" do
|
39
|
+
setup do
|
40
|
+
@controller = new_controller()
|
41
|
+
@controller.should_receive(:filter_logged_in)
|
42
|
+
end
|
43
|
+
|
44
|
+
specify "call to ldap_filter should call filter_logged_in" do
|
45
|
+
@controller.filter_ldap_anthing
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "When a user is logged in to the application" do
|
50
|
+
before(:all) do
|
51
|
+
RAILS_ENV = "re"
|
52
|
+
end
|
53
|
+
|
54
|
+
setup do
|
55
|
+
@ldap_uid = '42'
|
56
|
+
@ldap_user = mock("ldap_user")
|
57
|
+
UCB::LDAP::Person.stub!(:find_by_uid).and_return(@ldap_user)
|
58
|
+
User.stub!(:find_by_ldap_uid)
|
59
|
+
@controller = new_controller()
|
60
|
+
@controller.application_login(@uid)
|
61
|
+
@controller.stub!(:redirect_to)
|
62
|
+
@controller.stub!(:not_authorized_url).and_return("nal")
|
63
|
+
end
|
64
|
+
|
65
|
+
specify "filter_ldap_method returns 'true' when ldap.method does" do
|
66
|
+
@ldap_user.stub!(:attr_true).and_return(true)
|
67
|
+
@controller.filter_ldap_attr_true.should be_true
|
68
|
+
end
|
69
|
+
|
70
|
+
specify "filter_ldap_method returns 'false' when ldap.method does" do
|
71
|
+
@ldap_user.stub!(:attr_false).and_return(false)
|
72
|
+
@controller.filter_ldap_attr_false.should be_false
|
73
|
+
end
|
74
|
+
|
75
|
+
specify "filter_ldap_method__eq__value is true if ldap.method eq 'value'" do
|
76
|
+
@ldap_user.stub!(:attr).and_return("a")
|
77
|
+
@controller.filter_ldap_attr__eq__a.should be_true
|
78
|
+
@controller.filter_ldap_attr__eq__b.should be_false
|
79
|
+
end
|
80
|
+
|
81
|
+
specify "filter_ldap_method__ne__value is true if ldap.method ne 'value'" do
|
82
|
+
@ldap_user.stub!(:attr).and_return("a")
|
83
|
+
@controller.filter_ldap_attr__ne__b.should be_true
|
84
|
+
@controller.filter_ldap_attr__ne__a.should be_false
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/_setup.rb"
|
2
|
+
|
3
|
+
context "The Role filter" do
|
4
|
+
setup do
|
5
|
+
@controller = new_controller()
|
6
|
+
UCB::Rails::Security.using_user_table = true
|
7
|
+
end
|
8
|
+
|
9
|
+
specify "should call filter_logged_in when user not logged in" do
|
10
|
+
@controller.should_receive(:filter_logged_in).and_return(false)
|
11
|
+
@controller.filter_role_foo.should be_false
|
12
|
+
end
|
13
|
+
|
14
|
+
specify "should call filter_in_user_table() when user logged in" do
|
15
|
+
@controller.stub!(:filter_logged_in).and_return(true)
|
16
|
+
@controller.should_receive(:filter_in_user_table).and_return(false)
|
17
|
+
@controller.stub!(:redirect_to)
|
18
|
+
@controller.stub!(:not_authorized_url).and_return("nal")
|
19
|
+
@controller.filter_role_foo.should be_false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "Role filters" do
|
24
|
+
before(:each) do
|
25
|
+
@controller = new_controller()
|
26
|
+
@controller.stub!(:role_names).and_return(%w{role1 role2 role3})
|
27
|
+
@controller.stub!(:filter_logged_in).and_return(true)
|
28
|
+
@controller.stub!(:filter_in_user_table).and_return(true)
|
29
|
+
@controller.stub!(:redirect_to)
|
30
|
+
@controller.stub!(:not_authorized_url).and_return("nal")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "filter_role_rolename should return true if one of user's roles is 'rolename'" do
|
34
|
+
@controller.filter_role_role1.should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
it "filter_role_rolename should return false unless one of user's roles is 'rolename'" do
|
38
|
+
@controller.filter_role_bogus.should_not be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "filter_role_has_one_of_r1_or_r2_or_r3 returns true if user has one of the roles" do
|
42
|
+
@controller.filter_role_has_one_of_role3_or_role4.should be_true
|
43
|
+
end
|
44
|
+
|
45
|
+
it "filter_role_has_one_of_r1_or_r2_or_r3 returns false unless user has one of the roles" do
|
46
|
+
@controller.filter_role_has_one_of_role4_or_role5.should be_false
|
47
|
+
end
|
48
|
+
|
49
|
+
it "filter_role_has_all_of_r1_and_r2_and_r3 returns true if user has all of the roles" do
|
50
|
+
@controller.filter_role_has_all_of_role1_and_role2.should be_true
|
51
|
+
end
|
52
|
+
|
53
|
+
it "filter_role_has_one_of_r1_and_r2_and_r3 returns false unless user has one of the roles" do
|
54
|
+
@controller.filter_role_has_all_of_role3_and_role4.should be_false
|
55
|
+
end
|
56
|
+
end
|