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,119 @@
|
|
1
|
+
|
2
|
+
module UCB
|
3
|
+
module Rails
|
4
|
+
module Security
|
5
|
+
module RspecHelpers
|
6
|
+
#
|
7
|
+
# Adds mock user login functionality for testing apps using ucb_rails_security
|
8
|
+
#
|
9
|
+
# The main advantage to using these helpers is that, when running your tests,
|
10
|
+
# actual ldap connections are never made, instead a mock ldap object is used.
|
11
|
+
# This dramatically increases the performance of your tests.
|
12
|
+
#
|
13
|
+
# The helpers also avoid adding the logged in user to the users table, again
|
14
|
+
# this increases the speed of the tests.
|
15
|
+
#
|
16
|
+
#
|
17
|
+
# Usage:
|
18
|
+
#
|
19
|
+
# # log user into the application before controller test(s) are run.
|
20
|
+
# before(:each) do
|
21
|
+
# login_user() do
|
22
|
+
# User.create!(
|
23
|
+
# :ldap_uid => "666",
|
24
|
+
# :first_name => "first_name",
|
25
|
+
# :last_name => "last_name"
|
26
|
+
# )
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
#
|
31
|
+
# # log user into the application with specified roles before controller
|
32
|
+
# # test(s) are run.
|
33
|
+
# before(:each) do
|
34
|
+
# login_user_with_roles(["security", "admin"]) do
|
35
|
+
# User.create!(
|
36
|
+
# :ldap_uid => "666",
|
37
|
+
# :first_name => "first_name",
|
38
|
+
# :last_name => "last_name"
|
39
|
+
# )
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# One caveat, when using login_user_with_roles, the roles that are granted
|
44
|
+
# to the user are not saved to the database. For that user, we stub
|
45
|
+
# user.roles to return those roles. This means that you cannot add additional
|
46
|
+
# roles to this user during a test as roles() has been stubbed. The user
|
47
|
+
# you use to login should only be used to allow access to a given
|
48
|
+
# controller/action during your test.
|
49
|
+
|
50
|
+
def mock_ldap_person(ldap_uid = 1)
|
51
|
+
ldap_person = mock("ldap_person")
|
52
|
+
ldap_person.stub!(:uid).and_return(ldap_uid.to_s)
|
53
|
+
ldap_person.stub!(:email).and_return("email_#{ldap_uid}")
|
54
|
+
ldap_person.stub!(:first_name).and_return("first_name_#{ldap_uid}")
|
55
|
+
ldap_person.stub!(:last_name).and_return("last_name_#{ldap_uid}")
|
56
|
+
ldap_person.stub!(:phone).and_return("phone_#{ldap_uid}")
|
57
|
+
ldap_person.stub!(:dept_code).and_return("dept_code_#{ldap_uid}")
|
58
|
+
ldap_person.stub!(:dept_name).and_return("dept_name_#{ldap_uid}")
|
59
|
+
ldap_person
|
60
|
+
end
|
61
|
+
|
62
|
+
def new_user_instance(ldap_uid = 1)
|
63
|
+
User.new(
|
64
|
+
:ldap_uid => ldap_uid,
|
65
|
+
:email => "email_#{ldap_uid}",
|
66
|
+
:first_name => "first_name_#{ldap_uid}",
|
67
|
+
:last_name => "last_name_#{ldap_uid}",
|
68
|
+
:phone => "phone_#{ldap_uid}",
|
69
|
+
:department => "department_#{ldap_uid}"
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Logs in a given user with the specified roles. Block should return the User instance:
|
74
|
+
#
|
75
|
+
# @current_user = login_user_with_roles(["security"]) do
|
76
|
+
# User.create!(:ldap_uid => "666", :first_name => "first_name", :last_name => "last_name")
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
def login_user_with_roles(roles, &block)
|
80
|
+
raise(Exception, "Expecting block to return User object") unless block_given?
|
81
|
+
user = yield()
|
82
|
+
login_user(user)
|
83
|
+
grant_roles_to_user(user, roles)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Logs in a given user to the application:
|
87
|
+
#
|
88
|
+
# user = User.create!(:ldap_uid => "666", :first_name => "first_name", :last_name => "last_name")
|
89
|
+
# login_user(user)
|
90
|
+
#
|
91
|
+
def login_user(user)
|
92
|
+
user = yield() if block_given?
|
93
|
+
raise(Exception, "login_user() expects user object as argument or return value of a block") if user.nil?
|
94
|
+
UCB::Rails::Security::CASAuthentication.force_login_filter_true_for = user.ldap_uid
|
95
|
+
mock_ldap_person = UCB::LDAP::Person.new([])
|
96
|
+
mock_ldap_person.stub!(:first_name).and_return(user.first_name)
|
97
|
+
mock_ldap_person.stub!(:last_name).and_return(user.last_name)
|
98
|
+
mock_ldap_person.stub!(:uid).and_return(user.ldap_uid)
|
99
|
+
|
100
|
+
# Inject our mock objects into the UCB::Rails::Security system
|
101
|
+
controller().send(:ldap_user=, mock_ldap_person)
|
102
|
+
controller().send(:user_table_id=, user.id)
|
103
|
+
controller().send(:user_table_user=, user)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Gives the uesrs instance the specified roles:
|
107
|
+
#
|
108
|
+
# grant_roles_to_user(user, ["Security"])
|
109
|
+
#
|
110
|
+
def grant_roles_to_user(user, r_names)
|
111
|
+
roles = r_names.map { |r| Role.new(:name => r) }
|
112
|
+
user.stub!(:roles).and_return(roles)
|
113
|
+
#user.roles << roles
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
namespace :ucb do
|
2
|
+
desc 'Create user w/security role'
|
3
|
+
task :create_security_user => :environment do
|
4
|
+
if (ldap_uid = ENV['UID'])
|
5
|
+
role = Role.find_or_create_by_name('security')
|
6
|
+
begin
|
7
|
+
user = User.find_or_create_by_ldap_uid!(ldap_uid)
|
8
|
+
user.roles << role unless user.roles.include?(role)
|
9
|
+
user.save!
|
10
|
+
puts "Security role granted to user (ldap_uid: #{ldap_uid})"
|
11
|
+
rescue UCB::LDAP::Person::RecordNotFound
|
12
|
+
puts "Unable to find person (ldap_uid: #{ldap_uid}) in LDAP."
|
13
|
+
end
|
14
|
+
else
|
15
|
+
puts
|
16
|
+
puts 'USAGE: '
|
17
|
+
puts "\trake ucb:create_security_user UID=<uid>"
|
18
|
+
puts "\trake ucb:create_security_user UID=<uid> RAILS_ENV=<env>"
|
19
|
+
puts
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
gem 'actionpack', '>= 2.0.0'
|
4
|
+
require 'action_controller'
|
5
|
+
|
6
|
+
gem 'rubycas-client', '>= 2.0.1'
|
7
|
+
require 'casclient'
|
8
|
+
require 'casclient/frameworks/rails/filter'
|
9
|
+
|
10
|
+
gem 'ucb_ldap', '>= 1.3.0'
|
11
|
+
require 'ucb_ldap'
|
12
|
+
|
13
|
+
require 'ucb_rails_security_casauthentication'
|
14
|
+
require 'ucb_rs_controller_methods'
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
module UCB #:nodoc:
|
19
|
+
module Rails #:nodoc:
|
20
|
+
# = UCB Rails Security
|
21
|
+
module Security
|
22
|
+
|
23
|
+
# Returns +true+ if application is using a user table
|
24
|
+
# which must be named +User+.
|
25
|
+
def self.using_user_table?
|
26
|
+
@using_user_table
|
27
|
+
end
|
28
|
+
|
29
|
+
# Set this to +true+ if your application is using a +User+ table.
|
30
|
+
def self.using_user_table=(bool)
|
31
|
+
@using_user_table = bool
|
32
|
+
end
|
33
|
+
|
34
|
+
# URL user is redirected to when authorization fails.
|
35
|
+
# Defaults to '/not_authorized'
|
36
|
+
def self.not_authorized_url()
|
37
|
+
@not_authorized_url || '/not_authorized'
|
38
|
+
end
|
39
|
+
|
40
|
+
# Setter for not_authorized_url()
|
41
|
+
def self.not_authorized_url=(url)
|
42
|
+
@not_authorized_url = url
|
43
|
+
end
|
44
|
+
|
45
|
+
# Reset instance variables for testing
|
46
|
+
def self.reset_instance_variables() #:nodoc:
|
47
|
+
self.using_user_table = nil
|
48
|
+
self.not_authorized_url = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.logger
|
52
|
+
@logger ||= UCB::Rails::Security::Logger.new("#{RAILS_ROOT}/log/ucb_security_#{RAILS_ENV}.log")
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.logger=(val)
|
56
|
+
@logger = val
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# Implementation of UCB::Rails::Security
|
2
|
+
|
3
|
+
module UCB #:nodoc:
|
4
|
+
module Rails #:nodoc:
|
5
|
+
module Security
|
6
|
+
# = CAS Authentication Class
|
7
|
+
#
|
8
|
+
# This class is where you override the default CAS settings.
|
9
|
+
class CASAuthentication
|
10
|
+
|
11
|
+
ENV_DEVELOPMENT = 'development'
|
12
|
+
ENV_DEV_INTEGRATION = 'dev_integration'
|
13
|
+
ENV_TEST = 'test'
|
14
|
+
ENV_PRODUCTION = 'production'
|
15
|
+
|
16
|
+
CAS_BASE_URL_TEST = "https://auth-test.berkeley.edu/cas"
|
17
|
+
CAS_BASE_URL_PRODUCTION = "https://auth.berkeley.edu/cas"
|
18
|
+
|
19
|
+
def self.logger()
|
20
|
+
UCB::Rails::Security.logger
|
21
|
+
end
|
22
|
+
|
23
|
+
# Filter for CAS authentication. To use filter, in controller:
|
24
|
+
#
|
25
|
+
# before_filter UCB::Rails::Security::CASAuthentication
|
26
|
+
#
|
27
|
+
# or use the controller method instead
|
28
|
+
#
|
29
|
+
# before_filter :filter_logged_in
|
30
|
+
#
|
31
|
+
def self.filter(controller) #:nodoc:
|
32
|
+
logger.debug("In UCB::Rails::Security::CASAuthentication.filter")
|
33
|
+
if environment == ENV_TEST && force_login_filter_true_for
|
34
|
+
controller.session[:cas_user] = force_login_filter_true_for
|
35
|
+
return true
|
36
|
+
end
|
37
|
+
CASClient::Frameworks::Rails::Filter.configure(
|
38
|
+
:cas_base_url => self.cas_base_url(),
|
39
|
+
:logger => self.logger()
|
40
|
+
)
|
41
|
+
|
42
|
+
logger.debug("Before CASClient::Frameworks::Rails::Filter.filter(controller)")
|
43
|
+
if CASClient::Frameworks::Rails::Filter.filter(controller)
|
44
|
+
logger.debug("After CASClient::Frameworks::Rails::Filter.filter(controller)")
|
45
|
+
return true
|
46
|
+
else
|
47
|
+
return false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns CAS base url to be used for CAS authentication. Default
|
52
|
+
# is based on Rails environment (RAILS_ENV).
|
53
|
+
def self.cas_base_url
|
54
|
+
return @cas_base_url if @cas_base_url
|
55
|
+
(environment == ENV_PRODUCTION) ? CAS_BASE_URL_PRODUCTION : CAS_BASE_URL_TEST
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.allow_test_entries?
|
59
|
+
@allow_test_entries ||= (environment != ENV_PRODUCTION)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.allow_test_entries=(bool)
|
63
|
+
@allow_test_entries = bool
|
64
|
+
end
|
65
|
+
|
66
|
+
# Setter for cas_base_url
|
67
|
+
def self.cas_base_url=(url)
|
68
|
+
@cas_base_url = url
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns CAS logout url
|
72
|
+
def self.logout_url
|
73
|
+
"#{self.cas_base_url}/logout"
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.home_url=(url)
|
77
|
+
@home_url = url
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.home_url
|
81
|
+
@home_url || "ucb_security"
|
82
|
+
end
|
83
|
+
|
84
|
+
# This method exists so it can be stubbed to test cas_base_url()
|
85
|
+
def self.environment #:nodoc:
|
86
|
+
RAILS_ENV
|
87
|
+
end
|
88
|
+
|
89
|
+
# LDAP Uid for which login is forced successful if in test
|
90
|
+
# environemnt.
|
91
|
+
def self.force_login_filter_true_for()
|
92
|
+
@force_login_filter_true_for || false
|
93
|
+
end
|
94
|
+
|
95
|
+
# In test environment, every call to #filter() will simulate
|
96
|
+
# successful authentication for _ldap_uid_ if this method
|
97
|
+
# is called.
|
98
|
+
def self.force_login_filter_true_for=(ldap_uid)
|
99
|
+
@force_login_filter_true_for = ldap_uid
|
100
|
+
end
|
101
|
+
|
102
|
+
# Servername is pulled from request object.
|
103
|
+
# def self.server_name(controller) #:nodoc:
|
104
|
+
# $TESTING ? "host_with_port" : controller.request.host_with_port
|
105
|
+
# end
|
106
|
+
|
107
|
+
# Used for testing
|
108
|
+
def self.reset_instance_variables() #:nodoc:
|
109
|
+
self.force_login_filter_true_for = nil
|
110
|
+
self.cas_base_url = nil
|
111
|
+
self.allow_test_entries = nil
|
112
|
+
self.home_url = nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
# this overrides clean_logger.rb in Rails that pretty much completely breaks logging #!@%*(#@*$&%!!...
|
4
|
+
module UCB
|
5
|
+
module Rails
|
6
|
+
module Security
|
7
|
+
|
8
|
+
class Logger < ::Logger
|
9
|
+
def initialize(logdev, shift_age = 0, shift_size = 1048576)
|
10
|
+
@default_formatter = self.class::Formatter.new
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def format_message(severity, datetime, progrname, msg)
|
15
|
+
(@formatter || @default_formatter).call(severity, datetime, progname, msg)
|
16
|
+
end
|
17
|
+
|
18
|
+
def break
|
19
|
+
self << "\n"
|
20
|
+
end
|
21
|
+
|
22
|
+
class Formatter < ::Logger::Formatter
|
23
|
+
Format = "[%s#%d] %5s -- %s: %s\n"
|
24
|
+
|
25
|
+
def call(severity, time, progname, msg)
|
26
|
+
Format % [format_datetime(time), $$, severity, progname, msg2str(msg)]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|