rubycas-server 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +37 -0
- data/Manifest.txt +10 -0
- data/Rakefile +3 -2
- data/bin/rubycas-server-ctl +1 -1
- data/config.example.yml +44 -11
- data/custom_views.example.rb +11 -0
- data/lib/casserver/authenticators/ldap.rb +11 -5
- data/lib/casserver/conf.rb +35 -12
- data/lib/casserver/controllers.rb +111 -23
- data/lib/casserver/models.rb +23 -0
- data/lib/casserver/postambles.rb +21 -24
- data/lib/casserver/utils.rb +16 -0
- data/lib/casserver/version.rb +3 -3
- data/lib/casserver/views.rb +50 -36
- data/lib/casserver.rb +9 -2
- data/lib/themes/cas.css +1 -0
- data/vendor/camping-1.5.180/lib/camping/db.rb +78 -0
- data/vendor/camping-1.5.180/lib/camping/fastcgi.rb +244 -0
- data/vendor/camping-1.5.180/lib/camping/reloader.rb +163 -0
- data/vendor/camping-1.5.180/lib/camping/session.rb +123 -0
- data/vendor/camping-1.5.180/lib/camping/webrick.rb +65 -0
- data/vendor/camping-1.5.180/lib/camping-unabridged.rb +762 -0
- data/vendor/camping-1.5.180/lib/camping.rb +55 -0
- metadata +10 -11
data/CHANGELOG.txt
CHANGED
@@ -1,3 +1,40 @@
|
|
1
|
+
=== 0.5.0 :: 2007-09-20
|
2
|
+
|
3
|
+
* Gateway requests should now be handled correctly. When the request to the
|
4
|
+
login page is made with gateway=true as one of the parameters, the CAS
|
5
|
+
server will immediately redirect back to the target service along with
|
6
|
+
a service ticket if an SSO session exists for the user (or without a
|
7
|
+
service ticket if there is no pre-existing SSO session).
|
8
|
+
Note that if you are using RubyCAS-Client and want gatewaying, you will
|
9
|
+
need to upgrade it to 1.1.0 as gatewaying was broken in prior versions.
|
10
|
+
* If gateway=true is specified as part of the logout URI, the server will
|
11
|
+
log the user out and immediately redirect them back to the specified
|
12
|
+
service. In other words, you can now do "gatewayed logouts" as well
|
13
|
+
as logins.
|
14
|
+
* A login ticket can now be remotely requested from the server by placing
|
15
|
+
a POST request to '/loginTicket'.
|
16
|
+
* The login view can now be made to return only the login form. This is
|
17
|
+
done by adding the 'onlyLoginForm' parameter to the '/login' request.
|
18
|
+
Optionally, a 'submitToURI' parameter can be supplied to force the login
|
19
|
+
form to submit to the given URI (otherwise the server will try to figure
|
20
|
+
out the full URI to its own login controller). This functionality may be
|
21
|
+
useful when you want to embed the login form in some external page, as
|
22
|
+
an IFRAME otherwise.
|
23
|
+
* Custom views can now be used to override the default Markaby templates
|
24
|
+
by specifying a 'custom_views_file' option in the configuration. See
|
25
|
+
custom_views.example.rb. [jzylks]
|
26
|
+
* Table names have been shortened to work with Oracle. A migration has
|
27
|
+
been added that should do the shortening for you the first time you run
|
28
|
+
this new RubyCAS-Server version.
|
29
|
+
* Multiple authenticators can now be specified. During authentication,
|
30
|
+
credentials are presented to the first authenticator, then the second,
|
31
|
+
and so on, until the user is validated by any one authenticator or fails
|
32
|
+
validation for all of them. [jzylks]
|
33
|
+
* When using webrick, you can now run with SSL disabled by omitting the
|
34
|
+
ssl_cert and ssl_key parameters.
|
35
|
+
* Changed incorrect MySQL example database configuration -- option should
|
36
|
+
be 'host:' not 'server:' (issue #22).
|
37
|
+
|
1
38
|
=== 0.4.2 :: 2007-07-26
|
2
39
|
|
3
40
|
* The LDAP/AD authenticator has been largely re-written. The code is a bit
|
data/Manifest.txt
CHANGED
@@ -6,6 +6,7 @@ Rakefile
|
|
6
6
|
bin/rubycas-server
|
7
7
|
bin/rubycas-server-ctl
|
8
8
|
config.example.yml
|
9
|
+
custom_views.example.rb
|
9
10
|
lib/casserver.rb
|
10
11
|
lib/casserver/authenticators/active_directory_ldap.rb
|
11
12
|
lib/casserver/authenticators/base.rb
|
@@ -35,3 +36,12 @@ lib/themes/warning.png
|
|
35
36
|
resources/init.d.sh
|
36
37
|
setup.rb
|
37
38
|
test/test_casserver.rb
|
39
|
+
|
40
|
+
vendor/camping-1.5.180/lib/camping-unabridged.rb
|
41
|
+
vendor/camping-1.5.180/lib/camping.rb
|
42
|
+
vendor/camping-1.5.180/lib/camping/db.rb
|
43
|
+
vendor/camping-1.5.180/lib/camping/fastcgi.rb
|
44
|
+
vendor/camping-1.5.180/lib/camping/reloader.rb
|
45
|
+
vendor/camping-1.5.180/lib/camping/session.rb
|
46
|
+
vendor/camping-1.5.180/lib/camping/webrick.rb
|
47
|
+
|
data/Rakefile
CHANGED
@@ -19,14 +19,15 @@ RUBYFORGE_PROJECT = "rubycas-server" # The unix name for your project
|
|
19
19
|
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
20
20
|
|
21
21
|
DEPS = [
|
22
|
-
['camping', '>= 1.5'],
|
22
|
+
# ['camping', '>= 1.5'], # camping is now bundled with rubycas-server
|
23
23
|
['activesupport', '>= 1.4.0'],
|
24
24
|
['activerecord', '>=1.15.3']
|
25
25
|
]
|
26
26
|
|
27
27
|
|
28
28
|
NAME = "rubycas-server"
|
29
|
-
REV = nil
|
29
|
+
REV = nil
|
30
|
+
#REV = `svn info`[/Revision: (\d+)/, 1] rescue nil
|
30
31
|
VERS = ENV['VERSION'] || (CASServer::VERSION::STRING + (REV ? ".#{REV}" : ""))
|
31
32
|
CLEAN.include ['**/.*.sw?', '*.gem', '.config']
|
32
33
|
RDOC_OPTS = ['--quiet', '--title', "RubyCAS-Server #{VERS} Documentation",
|
data/bin/rubycas-server-ctl
CHANGED
@@ -21,7 +21,7 @@ def start
|
|
21
21
|
when :ok
|
22
22
|
$stderr.puts "rubycas-server is already running"
|
23
23
|
exit 1
|
24
|
-
when :not_running
|
24
|
+
when :not_running, :empty_pid
|
25
25
|
$stderr.puts "The pid file '#{@options[:pid_file]}' exists but rubycas-server is not running." +
|
26
26
|
" The pid file will be automatically deleted for you, but this shouldn't have happened!"
|
27
27
|
File.delete(@options[:pid_file])
|
data/config.example.yml
CHANGED
@@ -49,22 +49,25 @@ ssl_cert: /path/to/your/ssl.pem
|
|
49
49
|
#
|
50
50
|
# By default, we use MySQL, since it is widely used and does not require any additional
|
51
51
|
# ruby libraries besides ActiveRecord.
|
52
|
-
#
|
53
|
-
# Instead of MySQL you can use SQLite3, PostgreSQL, MSSQL, or anything else supported
|
54
|
-
# by ActiveRecord.
|
55
52
|
#
|
56
|
-
#
|
53
|
+
# With MySQL, your config would be something like the following:
|
54
|
+
# (be sure to create the casserver database in MySQL beforehand,
|
55
|
+
# i.e. `mysqladmin -u root create casserver`)
|
57
56
|
|
58
57
|
database:
|
59
58
|
adapter: mysql
|
60
59
|
database: casserver
|
61
60
|
username: root
|
62
61
|
password:
|
63
|
-
|
62
|
+
host: localhost
|
64
63
|
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
64
|
+
#
|
65
|
+
# Instead of MySQL you can use SQLite3, PostgreSQL, MSSQL, or anything else supported
|
66
|
+
# by ActiveRecord.
|
67
|
+
#
|
68
|
+
# With SQLite3 (which does not require a separate database server), your configuration
|
69
|
+
# would look something like the following (don't forget to install the
|
70
|
+
# sqlite3-ruby gem beforehand!):
|
68
71
|
#
|
69
72
|
#database:
|
70
73
|
# adapter: sqlite3
|
@@ -95,7 +98,7 @@ database:
|
|
95
98
|
# database:
|
96
99
|
# adapter: mysql
|
97
100
|
# database: some_database_with_users_table
|
98
|
-
#
|
101
|
+
# username: root
|
99
102
|
# password:
|
100
103
|
# server: localhost
|
101
104
|
# user_table: user
|
@@ -128,7 +131,7 @@ database:
|
|
128
131
|
#
|
129
132
|
# It is possible to authenticate against Active Directory without the
|
130
133
|
# authenticator user, but this requires that users type in their CN as
|
131
|
-
# the username
|
134
|
+
# the username rather than typing in their sAMAccountName. In other words
|
132
135
|
# users will likely have to authenticate by typing their full name,
|
133
136
|
# rather than their username. If you prefer to do this, then just
|
134
137
|
# omit the auth_user and auth_password values in the above example.
|
@@ -170,7 +173,35 @@ database:
|
|
170
173
|
# source: /path/to/source.rb
|
171
174
|
# option_a: foo
|
172
175
|
# another_option: yeeha
|
173
|
-
|
176
|
+
#
|
177
|
+
# ==> Multiple Authenticators
|
178
|
+
# If you need to have more than one source for authentication, such as an LDAP directory
|
179
|
+
# and a database, you can use multiple authenticators by making :authenticator an array
|
180
|
+
# of authenticators.
|
181
|
+
#
|
182
|
+
#authenticator:
|
183
|
+
# -
|
184
|
+
# class: CASServer::Authenticators::ActiveDirectoryLDAP
|
185
|
+
# ldap:
|
186
|
+
# server: ad.example.net
|
187
|
+
# port: 389
|
188
|
+
# base: dc=example,dc=net
|
189
|
+
# filter: (objectClass=person)
|
190
|
+
# -
|
191
|
+
# class: CASServer::Authenticators::SQL
|
192
|
+
# database:
|
193
|
+
# adapter: mysql
|
194
|
+
# database: some_database_with_users_table
|
195
|
+
# user: root
|
196
|
+
# password:
|
197
|
+
# server: localhost
|
198
|
+
# user_table: user
|
199
|
+
# username_column: username
|
200
|
+
# password_column: password
|
201
|
+
#
|
202
|
+
# During authentication, the user credentials will be checked against the first
|
203
|
+
# authenticator and on failure fall through to the second authenticator.
|
204
|
+
#
|
174
205
|
|
175
206
|
##### LOOK & FEEL ######################################################################
|
176
207
|
|
@@ -192,6 +223,8 @@ organization: CAS
|
|
192
223
|
# A short bit of text that shows up on the login page. You can make this blank if you prefer.
|
193
224
|
infoline: Powered by <a href="http://code.google.com/p/rubycas-server/">RubyCAS-Server</a>
|
194
225
|
|
226
|
+
# Custom views file. Overrides methodes in lib/casserver/views.rb
|
227
|
+
#custom_views_file: /path/to/custom/views.rb
|
195
228
|
|
196
229
|
##### LOGGING #########################################################################
|
197
230
|
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Custom views file; add methods to the module definition below
|
2
|
+
|
3
|
+
module CASServer::Views
|
4
|
+
|
5
|
+
# Override views here, for example, a custom login form:
|
6
|
+
def login_form
|
7
|
+
# Add your custom login form here, using Markaby
|
8
|
+
# See the original views.rb file at lib/casserver/views.rb for method names and usage
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
@@ -11,9 +11,9 @@ end
|
|
11
11
|
class CASServer::Authenticators::LDAP < CASServer::Authenticators::Base
|
12
12
|
def validate(credentials)
|
13
13
|
read_standard_credentials(credentials)
|
14
|
-
|
14
|
+
|
15
15
|
return false if @password.blank?
|
16
|
-
|
16
|
+
|
17
17
|
raise CASServer::AuthenticatorError, "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
|
18
18
|
raise CASServer::AuthenticatorError, "Invalid authenticator configuration!" unless @options[:ldap]
|
19
19
|
raise CASServer::AuthenticatorError, "You must specify an ldap server in the configuration!" unless @options[:ldap][:server]
|
@@ -68,8 +68,14 @@ class CASServer::Authenticators::LDAP < CASServer::Authenticators::Base
|
|
68
68
|
|
69
69
|
username_attribute = options[:ldap][:username_attribute] || default_username_attribute
|
70
70
|
|
71
|
-
filter = Net::LDAP::Filter.construct(@options[:ldap][:filter])
|
72
|
-
|
71
|
+
filter = Net::LDAP::Filter.construct(@options[:ldap][:filter]) if
|
72
|
+
@options[:ldap][:filter] && !@options[:ldap][:filter].blank?
|
73
|
+
username_filter = Net::LDAP::Filter.eq(username_attribute, @username)
|
74
|
+
if filter
|
75
|
+
filter &= username_filter
|
76
|
+
else
|
77
|
+
filter = username_filter
|
78
|
+
end
|
73
79
|
|
74
80
|
@ldap.bind_as(:base => @options[:ldap][:base], :password => @password, :filter => filter)
|
75
81
|
end
|
@@ -86,4 +92,4 @@ class CASServer::Authenticators::LDAP < CASServer::Authenticators::Base
|
|
86
92
|
@ldap.authenticate(cn, @password)
|
87
93
|
@ldap.bind
|
88
94
|
end
|
89
|
-
end
|
95
|
+
end
|
data/lib/casserver/conf.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# load configuration
|
2
|
+
|
2
3
|
begin
|
3
4
|
if $CONFIG_FILE
|
4
5
|
conf_file = $CONFIG_FILE
|
@@ -33,8 +34,7 @@ begin
|
|
33
34
|
" suit your needs and then run rubycas-server again.\n"
|
34
35
|
exit 1
|
35
36
|
end
|
36
|
-
|
37
|
-
|
37
|
+
|
38
38
|
loaded_conf = HashWithIndifferentAccess.new(YAML.load_file(conf_file))
|
39
39
|
|
40
40
|
if $CONF
|
@@ -42,21 +42,44 @@ begin
|
|
42
42
|
else
|
43
43
|
$CONF = loaded_conf
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
|
+
if $CONF[:authenticator].instance_of? Array
|
47
|
+
$CONF[:authenticator].each_index { |auth_index| $CONF[:authenticator][auth_index] = HashWithIndifferentAccess.new($CONF[:authenticator][auth_index])}
|
48
|
+
end
|
49
|
+
|
50
|
+
$AUTH = []
|
46
51
|
begin
|
47
52
|
# attempt to instantiate the authenticator
|
48
|
-
|
49
|
-
|
50
|
-
if !$CONF[:authenticator][:source].nil?
|
51
|
-
# config.yml explicitly names source file
|
52
|
-
require $CONF[:authenticator][:source]
|
53
|
+
if $CONF[:authenticator].instance_of? Array
|
54
|
+
$CONF[:authenticator].each { |authenticator| $AUTH << authenticator[:class].constantize.new}
|
53
55
|
else
|
54
|
-
|
55
|
-
auth_rb = $CONF[:authenticator][:class].underscore.gsub('cas_server/', '')
|
56
|
-
require 'casserver/'+auth_rb
|
56
|
+
$AUTH << $CONF[:authenticator][:class].constantize.new
|
57
57
|
end
|
58
|
+
rescue NameError
|
59
|
+
if $CONF[:authenticator].instance_of? Array
|
60
|
+
$CONF[:authenticator].each do |authenticator|
|
61
|
+
if !authenticator[:source].nil?
|
62
|
+
# config.yml explicitly names source file
|
63
|
+
require authenticator[:source]
|
64
|
+
else
|
65
|
+
# the authenticator class hasn't yet been loaded, so lets try to load it from the casserver/authenticators directory
|
66
|
+
auth_rb = authenticator[:class].underscore.gsub('cas_server/', '')
|
67
|
+
require 'casserver/'+auth_rb
|
68
|
+
end
|
69
|
+
$AUTH << authenticator[:class].constantize.new
|
70
|
+
end
|
71
|
+
else
|
72
|
+
if !$CONF[:authenticator][:source].nil?
|
73
|
+
# config.yml explicitly names source file
|
74
|
+
require $CONF[:authenticator][:source]
|
75
|
+
else
|
76
|
+
# the authenticator class hasn't yet been loaded, so lets try to load it from the casserver/authenticators directory
|
77
|
+
auth_rb = $CONF[:authenticator][:class].underscore.gsub('cas_server/', '')
|
78
|
+
require 'casserver/'+auth_rb
|
79
|
+
end
|
58
80
|
|
59
|
-
|
81
|
+
$AUTH << $CONF[:authenticator][:class].constantize.new
|
82
|
+
end
|
60
83
|
end
|
61
84
|
rescue
|
62
85
|
raise "Your RubyCAS-Server configuration may be invalid."+
|
@@ -9,6 +9,8 @@ module CASServer::Controllers
|
|
9
9
|
|
10
10
|
# 2.1.1
|
11
11
|
def get
|
12
|
+
CASServer::Utils::log_controller_action(self.class, @input)
|
13
|
+
|
12
14
|
# make sure there's no caching
|
13
15
|
headers['Pragma'] = 'no-cache'
|
14
16
|
headers['Cache-Control'] = 'no-store'
|
@@ -17,7 +19,7 @@ module CASServer::Controllers
|
|
17
19
|
# optional params
|
18
20
|
@service = @input['service']
|
19
21
|
@renew = @input['renew']
|
20
|
-
@gateway = @input['gateway']
|
22
|
+
@gateway = @input['gateway'] == 'true' || @input['gateway'] == '1'
|
21
23
|
|
22
24
|
if tgc = @cookies[:tgt]
|
23
25
|
tgt, tgt_error = validate_ticket_granting_ticket(tgc)
|
@@ -28,13 +30,21 @@ module CASServer::Controllers
|
|
28
30
|
end
|
29
31
|
|
30
32
|
begin
|
31
|
-
if @service
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
if @service
|
34
|
+
if !@renew && tgt && !tgt_error
|
35
|
+
st = generate_service_ticket(@service, tgt.username)
|
36
|
+
service_with_ticket = service_uri_with_ticket(@service, st)
|
37
|
+
$LOG.info("User '#{tgt.username}' authenticated based on ticket granting cookie. Redirecting to service '#{@service}'.")
|
38
|
+
return redirect(service_with_ticket, :status => 303) # response code 303 means "See Other" (see Appendix B in CAS Protocol spec)
|
39
|
+
elsif @gateway
|
40
|
+
$LOG.info("Redirecting unauthenticated gateway request to service '#{@service}'.")
|
41
|
+
return redirect(@service, :status => 303)
|
42
|
+
end
|
43
|
+
elsif @gateway
|
44
|
+
$LOG.error("This is a gateway request but no service parameter was given!")
|
45
|
+
@message = {:type => 'mistake', :message => "The server cannot fulfill this gateway request because no service parameter was given."}
|
36
46
|
end
|
37
|
-
rescue
|
47
|
+
rescue # FIXME: shouldn't this only rescue URI::InvalidURIError?
|
38
48
|
$LOG.error("The service '#{@service}' is not a valid URI!")
|
39
49
|
@message = {:type => 'mistake', :message => "The target service your browser supplied appears to be invalid. Please contact your system administrator for help."}
|
40
50
|
end
|
@@ -45,11 +55,37 @@ module CASServer::Controllers
|
|
45
55
|
|
46
56
|
@lt = lt.ticket
|
47
57
|
|
48
|
-
|
58
|
+
$LOG.debug(env)
|
59
|
+
|
60
|
+
# If the 'onlyLoginForm' parameter is specified, we will only return the
|
61
|
+
# login form part of the page. This is useful for when you want to
|
62
|
+
# embed the login form in some external page (as an IFRAME, or otherwise).
|
63
|
+
# The optional 'submitToURI' parameter can be given to explicitly set the
|
64
|
+
# action for the form, otherwise the server will try to guess this for you.
|
65
|
+
if @input.has_key? 'onlyLoginForm'
|
66
|
+
if env['HTTP_HOST']
|
67
|
+
guessed_login_uri = "http#{env['HTTPS'] && env['HTTPS'] == 'on' ? 's' : ''}://#{env['REQUEST_URI']}#{self / '/login'}"
|
68
|
+
else
|
69
|
+
guessed_login_uri = nil
|
70
|
+
end
|
71
|
+
|
72
|
+
@form_action = @input['submitToURI'] || guessed_login_uri
|
73
|
+
|
74
|
+
if @form_action
|
75
|
+
render :login_form
|
76
|
+
else
|
77
|
+
@status = 500
|
78
|
+
"Could not guess the CAS login URI. Please supply a submitURI parameter with your request."
|
79
|
+
end
|
80
|
+
else
|
81
|
+
render :login
|
82
|
+
end
|
49
83
|
end
|
50
84
|
|
51
85
|
# 2.2
|
52
86
|
def post
|
87
|
+
CASServer::Utils::log_controller_action(self.class, @input)
|
88
|
+
|
53
89
|
# 2.2.1 (optional)
|
54
90
|
@service = @input['service']
|
55
91
|
@warn = @input['warn']
|
@@ -69,12 +105,20 @@ module CASServer::Controllers
|
|
69
105
|
# generate another login ticket to allow for re-submitting the form after a post
|
70
106
|
@lt = generate_login_ticket.ticket
|
71
107
|
|
72
|
-
$
|
73
|
-
|
108
|
+
if $CONF[:authenticator].instance_of? Array
|
109
|
+
$AUTH.each_index {|auth_index| $AUTH[auth_index].configure(CASServer::Conf.authenticator[auth_index])}
|
110
|
+
else
|
111
|
+
$AUTH[0].configure(CASServer::Conf.authenticator)
|
112
|
+
end
|
113
|
+
|
74
114
|
$LOG.debug("Logging in with username: #{@username}, lt: #{@lt}, service: #{@service}, auth: #{$AUTH}")
|
75
115
|
|
116
|
+
credentials_are_valid = false
|
76
117
|
begin
|
77
|
-
|
118
|
+
$AUTH.each do |auth|
|
119
|
+
credentials_are_valid = auth.validate(:username => @username, :password => @password, :service => @service)
|
120
|
+
break if credentials_are_valid
|
121
|
+
end
|
78
122
|
rescue CASServer::AuthenticatorError => e
|
79
123
|
$LOG.error(e)
|
80
124
|
@message = {:type => 'mistake', :message => e.to_s}
|
@@ -82,10 +126,10 @@ module CASServer::Controllers
|
|
82
126
|
end
|
83
127
|
|
84
128
|
if credentials_are_valid
|
85
|
-
$LOG.info("Credentials for username '#{
|
129
|
+
$LOG.info("Credentials for username '#{@username}' successfully validated")
|
86
130
|
|
87
131
|
# 3.6 (ticket-granting cookie)
|
88
|
-
tgt = generate_ticket_granting_ticket(
|
132
|
+
tgt = generate_ticket_granting_ticket(@username)
|
89
133
|
|
90
134
|
if CASServer::Conf.expire_sessions
|
91
135
|
expires = CASServer::Conf.ticket_granting_ticket_expiry.to_i.from_now
|
@@ -98,17 +142,17 @@ module CASServer::Controllers
|
|
98
142
|
# seem to be an easy way to set cookie expire times in Camping :(
|
99
143
|
@cookies[:tgt] = tgt.to_s
|
100
144
|
|
101
|
-
$LOG.debug("Ticket granting cookie '#{@cookies[:tgt]}' granted to '#{
|
145
|
+
$LOG.debug("Ticket granting cookie '#{@cookies[:tgt]}' granted to '#{@username}'. #{expiry_info}")
|
102
146
|
|
103
147
|
if @service.blank?
|
104
|
-
$LOG.info("Successfully authenticated user '#{
|
148
|
+
$LOG.info("Successfully authenticated user '#{@username}' at '#{tgt.client_hostname}'. No service param was given, so we will not redirect.")
|
105
149
|
@message = {:type => 'confirmation', :message => "You have successfully logged in."}
|
106
150
|
else
|
107
|
-
@st = generate_service_ticket(@service,
|
151
|
+
@st = generate_service_ticket(@service, @username)
|
108
152
|
begin
|
109
153
|
service_with_ticket = service_uri_with_ticket(@service, @st)
|
110
154
|
|
111
|
-
$LOG.info("Redirecting authenticated user '#{
|
155
|
+
$LOG.info("Redirecting authenticated user '#{@username}' at '#{@st.client_hostname}' to service '#{@service}'")
|
112
156
|
return redirect(service_with_ticket, :status => 303) # response code 303 means "See Other" (see Appendix B in CAS Protocol spec)
|
113
157
|
rescue URI::InvalidURIError
|
114
158
|
$LOG.error("The service '#{@service}' is not a valid URI!")
|
@@ -116,7 +160,7 @@ module CASServer::Controllers
|
|
116
160
|
end
|
117
161
|
end
|
118
162
|
else
|
119
|
-
$LOG.warn("Invalid credentials given for user '#{
|
163
|
+
$LOG.warn("Invalid credentials given for user '#{@username}'")
|
120
164
|
@message = {:type => 'mistake', :message => "Incorrect username or password."}
|
121
165
|
end
|
122
166
|
|
@@ -130,13 +174,17 @@ module CASServer::Controllers
|
|
130
174
|
|
131
175
|
# 2.3.1
|
132
176
|
def get
|
177
|
+
CASServer::Utils::log_controller_action(self.class, @input)
|
178
|
+
|
133
179
|
# The behaviour here is somewhat non-standard. Rather than showing just a blank
|
134
180
|
# "logout" page, we take the user back to the login page with a "you have been logged out"
|
135
|
-
# message, allowing for an opportunity to immediately log back in. This makes
|
136
|
-
#
|
181
|
+
# message, allowing for an opportunity to immediately log back in. This makes it
|
182
|
+
# easier for the user to log out and log in as someone else.
|
137
183
|
@service = @input['url'] || @input['service']
|
138
184
|
# TODO: display service name in view as per 2.3.2
|
139
185
|
|
186
|
+
@gateway = @input['gateway'] == 'true' || @input['gateway'] == '1'
|
187
|
+
|
140
188
|
tgt = CASServer::Models::TicketGrantingTicket.find_by_ticket(@cookies[:tgt])
|
141
189
|
|
142
190
|
@cookies.delete :tgt
|
@@ -162,7 +210,11 @@ module CASServer::Controllers
|
|
162
210
|
|
163
211
|
@lt = generate_login_ticket
|
164
212
|
|
165
|
-
|
213
|
+
if @gateway && @service
|
214
|
+
redirect(@service, :status => 303)
|
215
|
+
else
|
216
|
+
render :login
|
217
|
+
end
|
166
218
|
end
|
167
219
|
end
|
168
220
|
|
@@ -172,6 +224,8 @@ module CASServer::Controllers
|
|
172
224
|
|
173
225
|
# 2.4.1
|
174
226
|
def get
|
227
|
+
CASServer::Utils::log_controller_action(self.class, @input)
|
228
|
+
|
175
229
|
# required
|
176
230
|
@service = @input['service']
|
177
231
|
@ticket = @input['ticket']
|
@@ -193,6 +247,8 @@ module CASServer::Controllers
|
|
193
247
|
|
194
248
|
# 2.5.1
|
195
249
|
def get
|
250
|
+
CASServer::Utils::log_controller_action(self.class, @input)
|
251
|
+
|
196
252
|
# required
|
197
253
|
@service = @input['service']
|
198
254
|
@ticket = @input['ticket']
|
@@ -221,6 +277,8 @@ module CASServer::Controllers
|
|
221
277
|
|
222
278
|
# 2.6.1
|
223
279
|
def get
|
280
|
+
CASServer::Utils::log_controller_action(self.class, @input)
|
281
|
+
|
224
282
|
# required
|
225
283
|
@service = @input['service']
|
226
284
|
@ticket = @input['ticket']
|
@@ -259,6 +317,8 @@ module CASServer::Controllers
|
|
259
317
|
|
260
318
|
# 2.7
|
261
319
|
def get
|
320
|
+
CASServer::Utils::log_controller_action(self.class, @input)
|
321
|
+
|
262
322
|
# required
|
263
323
|
@ticket = @input['pgt']
|
264
324
|
@target_service = @input['targetService']
|
@@ -274,13 +334,41 @@ module CASServer::Controllers
|
|
274
334
|
end
|
275
335
|
end
|
276
336
|
|
337
|
+
# Controller for obtaining login tickets.
|
338
|
+
# This is useful when you want to build a custom login form located on a
|
339
|
+
# remote server. Your form will have to include a valid login ticket
|
340
|
+
# value, and this can be fetched from the CAS server using this controller'
|
341
|
+
# POST method.
|
342
|
+
class LoginTicketDispenser < R '/loginTicket'
|
343
|
+
include CASServer::CAS
|
344
|
+
|
345
|
+
def get
|
346
|
+
CASServer::Utils::log_controller_action(self.class, @input)
|
347
|
+
$LOG.error("Tried to use login ticket dispenser with get method!")
|
348
|
+
@status = 500
|
349
|
+
"To generate a login ticket, you must make a POST request."
|
350
|
+
end
|
351
|
+
|
352
|
+
# Renders a page with a login ticket (and only the login ticket)
|
353
|
+
# in the response body.
|
354
|
+
def post
|
355
|
+
CASServer::Utils::log_controller_action(self.class, @input)
|
356
|
+
lt = generate_login_ticket
|
357
|
+
|
358
|
+
$LOG.debug("Generated login ticket: #{lt}, host: #{env['REMOTE_HOST'] || env['REMOTE_ADDR']}")
|
359
|
+
|
360
|
+
@lt = lt.ticket
|
361
|
+
|
362
|
+
@lt
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
277
366
|
class Themes < R '/themes/(.+)'
|
278
367
|
MIME_TYPES = {'.css' => 'text/css', '.js' => 'text/javascript',
|
279
368
|
'.jpg' => 'image/jpeg'}
|
280
369
|
PATH = CASServer::Conf.themes_dir || File.expand_path(File.dirname(__FILE__))+'/../themes'
|
281
370
|
|
282
|
-
def get(path)
|
283
|
-
@headers['Content-Type'] = MIME_TYPES[path[/\.\w+$/, 0]] || "text/plain"
|
371
|
+
def get(path)@headers['Content-Type'] = MIME_TYPES[path[/\.\w+$/, 0]] || "text/plain"
|
284
372
|
unless path.include? ".." # prevent directory traversal attacks
|
285
373
|
@headers['X-Sendfile'] = "#{PATH}/#{path}"
|
286
374
|
else
|
data/lib/casserver/models.rb
CHANGED
@@ -31,10 +31,12 @@ module CASServer::Models
|
|
31
31
|
end
|
32
32
|
|
33
33
|
class LoginTicket < Ticket
|
34
|
+
set_table_name 'casserver_lt'
|
34
35
|
include Consumable
|
35
36
|
end
|
36
37
|
|
37
38
|
class ServiceTicket < Ticket
|
39
|
+
set_table_name 'casserver_st'
|
38
40
|
include Consumable
|
39
41
|
|
40
42
|
def matches_service?(service)
|
@@ -50,9 +52,11 @@ module CASServer::Models
|
|
50
52
|
end
|
51
53
|
|
52
54
|
class TicketGrantingTicket < Ticket
|
55
|
+
set_table_name 'casserver_tgt'
|
53
56
|
end
|
54
57
|
|
55
58
|
class ProxyGrantingTicket < Ticket
|
59
|
+
set_table_name 'casserver_pgt'
|
56
60
|
belongs_to :service_ticket
|
57
61
|
has_many :proxy_tickets, :dependent => :destroy
|
58
62
|
end
|
@@ -113,4 +117,23 @@ module CASServer::Models
|
|
113
117
|
drop_table :casserver_login_tickets
|
114
118
|
end
|
115
119
|
end
|
120
|
+
|
121
|
+
# Oracle table names cannot exceed 30 chars...
|
122
|
+
# See http://code.google.com/p/rubycas-server/issues/detail?id=15
|
123
|
+
class ShortenTableNames < V 0.5
|
124
|
+
def self.up
|
125
|
+
$LOG.info("Shortening table names")
|
126
|
+
rename_table :casserver_login_tickets, :casserver_lt
|
127
|
+
rename_table :casserver_service_tickets, :casserver_st
|
128
|
+
rename_table :casserver_ticket_granting_tickets, :casserver_tgt
|
129
|
+
rename_table :casserver_proxy_granting_tickets, :casserver_pgt
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.down
|
133
|
+
rename_table :casserver_lt, :cassserver_login_tickets
|
134
|
+
rename_table :casserver_st, :casserver_service_tickets
|
135
|
+
rename_table :casserver_tgt, :casserver_ticket_granting_tickets
|
136
|
+
rename_table :casserver_pgt, :casserver_proxy_granting_tickets
|
137
|
+
end
|
138
|
+
end
|
116
139
|
end
|