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,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
|