ucb_rails_security 2.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|