gunark-rubycas-server 0.6.99.336 → 0.7.999.20090212
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/History.txt +26 -5
- data/Manifest.txt +20 -10
- data/README.txt +3 -2
- data/bin/rubycas-server +5 -4
- data/bin/rubycas-server-ctl +3 -2
- data/config/hoe.rb +9 -8
- data/config.example.yml +43 -12
- data/config.ru +21 -0
- data/lib/casserver/authenticators/google.rb +54 -0
- data/lib/casserver/authenticators/sql_rest_auth.rb +77 -0
- data/lib/casserver/cas.rb +40 -27
- data/lib/casserver/conf.rb +61 -96
- data/lib/casserver/controllers.rb +38 -31
- data/lib/casserver/environment.rb +16 -11
- data/lib/casserver/localization.rb +62 -0
- data/lib/casserver/models.rb +2 -2
- data/lib/casserver/postambles.rb +12 -12
- data/lib/casserver/version.rb +2 -2
- data/lib/casserver/views.rb +12 -12
- data/lib/casserver.rb +41 -97
- data/lib/rubycas-server.rb +1 -1
- data/po/de_DE/rubycas-server.po +91 -0
- data/po/es_ES/rubycas-server.po +90 -0
- data/po/fr_FR/rubycas-server.po +90 -0
- data/po/ja_JP/rubycas-server.po +92 -0
- data/po/pl_PL/rubycas-server.po +93 -0
- data/po/ru_RU/rubycas-server.po +91 -0
- data/po/rubycas-server.pot +82 -0
- data/resources/init.d.sh +1 -1
- data/tasks/localization.rake +11 -0
- metadata +60 -15
- data/misc/basic_cas_single_signon_mechanism_diagram.png +0 -0
- data/misc/basic_cas_single_signon_mechanism_diagram.svg +0 -652
- data/website/index.html +0 -40
- data/website/index.txt +0 -3
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -138
- data/website/template.html.erb +0 -40
data/History.txt
CHANGED
@@ -1,7 +1,26 @@
|
|
1
|
-
=== 0.
|
1
|
+
=== 0.8.0 :: In Progress...
|
2
2
|
|
3
|
-
*
|
4
|
-
*
|
3
|
+
* NEW:
|
4
|
+
* Support for localization via Ruby-GetText. [antono]
|
5
|
+
* New SQL authenticator (sql_rest_auth) compatible with the
|
6
|
+
restful_authentication Rails plugin. [antono]
|
7
|
+
|
8
|
+
* FIXED:
|
9
|
+
* Fixed weird problems with loading controllers when using older versions of
|
10
|
+
activesupport and/or rubygems.
|
11
|
+
* Failure to connect to a service during a single sign out request is now
|
12
|
+
handled gracefully.
|
13
|
+
* Required gem dependencies have been re-enabled in the gemspec.
|
14
|
+
|
15
|
+
=== 0.7.1 :: 2008-11-10
|
16
|
+
|
17
|
+
* Fixed dependency loading problems introduced by upstream changes in RubyGems
|
18
|
+
1.3.1.
|
19
|
+
|
20
|
+
=== 0.7.0 :: 2008-11-04
|
21
|
+
|
22
|
+
* NEW:
|
23
|
+
* Implemented single-sign-out functionality as specified in CAS 3.3. See
|
5
24
|
http://www.ja-sig.org/wiki/display/CASUM/Single+Sign+Out.
|
6
25
|
* It is now possible to configure Authenticators to return extra attributes
|
7
26
|
to CAS clients alongside the username. For an example of how to do this see
|
@@ -14,7 +33,7 @@
|
|
14
33
|
* Added new Google authenticator for authenticating against Google/GMail
|
15
34
|
accounts.
|
16
35
|
|
17
|
-
*
|
36
|
+
* CHANGED:
|
18
37
|
* Service URIs are now automatically normalized. For example, if the service
|
19
38
|
URI given to the server has a 'ticket' parameter, the ticket will now be
|
20
39
|
automatically stripped. This is to avert any possible issues raised by
|
@@ -48,7 +67,7 @@
|
|
48
67
|
errors (where the server rather than the client is at fault) have error 500.
|
49
68
|
Previously most responses had error code 200, regardless of their contents.
|
50
69
|
|
51
|
-
*
|
70
|
+
* FIXED:
|
52
71
|
* Fixed logout action to work properly with ActiveRecord 2.1 (eager loading behaviour
|
53
72
|
was changed upstream forcing a change to the way we look for ProxyGrantingTickets
|
54
73
|
to delete on logout).
|
@@ -56,6 +75,8 @@
|
|
56
75
|
expected -- however currently this only works when the server is running
|
57
76
|
in the foregaround. When daemonized, USR2 will shut down the server without
|
58
77
|
restarting (see issue #58).
|
78
|
+
* Fixed activerecord/activesupport gem load problems, hopefully once and for all
|
79
|
+
(however picnic-0.7.0 is now required).
|
59
80
|
|
60
81
|
=== 0.6.0 :: 2008-03-28
|
61
82
|
|
data/Manifest.txt
CHANGED
@@ -7,10 +7,8 @@ README.txt
|
|
7
7
|
Rakefile
|
8
8
|
bin/rubycas-server
|
9
9
|
bin/rubycas-server-ctl
|
10
|
-
casserver.db
|
11
|
-
casserver.log
|
12
|
-
casserver_db.log
|
13
10
|
config.example.yml
|
11
|
+
config.ru
|
14
12
|
config/hoe.rb
|
15
13
|
config/requirements.rb
|
16
14
|
custom_views.example.rb
|
@@ -18,17 +16,20 @@ lib/casserver.rb
|
|
18
16
|
lib/casserver/authenticators/active_directory_ldap.rb
|
19
17
|
lib/casserver/authenticators/base.rb
|
20
18
|
lib/casserver/authenticators/client_certificate.rb
|
19
|
+
lib/casserver/authenticators/google.rb
|
21
20
|
lib/casserver/authenticators/ldap.rb
|
22
21
|
lib/casserver/authenticators/ntlm.rb
|
23
22
|
lib/casserver/authenticators/open_id.rb
|
24
23
|
lib/casserver/authenticators/sql.rb
|
25
24
|
lib/casserver/authenticators/sql_encrypted.rb
|
26
25
|
lib/casserver/authenticators/sql_md5.rb
|
26
|
+
lib/casserver/authenticators/sql_rest_auth.rb
|
27
27
|
lib/casserver/authenticators/test.rb
|
28
28
|
lib/casserver/cas.rb
|
29
29
|
lib/casserver/conf.rb
|
30
30
|
lib/casserver/controllers.rb
|
31
31
|
lib/casserver/environment.rb
|
32
|
+
lib/casserver/localization.rb
|
32
33
|
lib/casserver/models.rb
|
33
34
|
lib/casserver/postambles.rb
|
34
35
|
lib/casserver/utils.rb
|
@@ -48,8 +49,20 @@ lib/themes/urbacon/login_box_bg.png
|
|
48
49
|
lib/themes/urbacon/logo.png
|
49
50
|
lib/themes/urbacon/theme.css
|
50
51
|
lib/themes/warning.png
|
51
|
-
|
52
|
-
|
52
|
+
locale/de_DE/LC_MESSAGES/rubycas-server.mo
|
53
|
+
locale/es_ES/LC_MESSAGES/rubycas-server.mo
|
54
|
+
locale/fr_FR/LC_MESSAGES/rubycas-server.mo
|
55
|
+
locale/ja_JP/LC_MESSAGES/rubycas-server.mo
|
56
|
+
locale/pl_PL/LC_MESSAGES/rubycas-server.mo
|
57
|
+
locale/ru_RU/LC_MESSAGES/rubycas-server.mo
|
58
|
+
po/de_DE/rubycas-server.po
|
59
|
+
po/es_ES/rubycas-server.po
|
60
|
+
po/fr_FR/rubycas-server.po
|
61
|
+
po/ja_JP/rubycas-server.po
|
62
|
+
po/pl_PL/rubycas-server.po
|
63
|
+
po/ru_RU/rubycas-server.po
|
64
|
+
po/rubycas-server.pot
|
65
|
+
public/restart.txt
|
53
66
|
resources/init.d.sh
|
54
67
|
script/console
|
55
68
|
script/destroy
|
@@ -58,6 +71,7 @@ script/txt2html
|
|
58
71
|
setup.rb
|
59
72
|
tasks/deployment.rake
|
60
73
|
tasks/environment.rake
|
74
|
+
tasks/localization.rake
|
61
75
|
tasks/website.rake
|
62
76
|
vendor/isaac_0.9.1/LICENSE
|
63
77
|
vendor/isaac_0.9.1/README
|
@@ -67,8 +81,4 @@ vendor/isaac_0.9.1/crypt/ISAAC.rb
|
|
67
81
|
vendor/isaac_0.9.1/isaac.gemspec
|
68
82
|
vendor/isaac_0.9.1/setup.rb
|
69
83
|
vendor/isaac_0.9.1/test/TC_ISAAC.rb
|
70
|
-
|
71
|
-
website/index.txt
|
72
|
-
website/javascripts/rounded_corners_lite.inc.js
|
73
|
-
website/stylesheets/screen.css
|
74
|
-
website/template.html.erb
|
84
|
+
|
data/README.txt
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
= RubyCAS-Server
|
2
2
|
|
3
|
-
*Copyright*:: 2008 Urbacon Ltd.
|
4
|
-
|
3
|
+
*Copyright*:: Portions contributed by Matt Zukowski are copyright (c) 2008 Urbacon Ltd.
|
4
|
+
Other portions are copyright of their respective authors.
|
5
|
+
*Authors*:: See http://github.com/gunark/rubycas-server/commits/
|
5
6
|
*Homepage*:: http://rubycas-server.googlecode.com
|
6
7
|
|
7
8
|
For info and installation instructions please see http://code.google.com/p/rubycas-server
|
data/bin/rubycas-server
CHANGED
@@ -8,10 +8,11 @@ else
|
|
8
8
|
require 'rubygems'
|
9
9
|
|
10
10
|
# make things backwards-compatible for rubygems < 0.9.0
|
11
|
-
|
11
|
+
if respond_to?(:require_gem)
|
12
|
+
puts "WARNING: aliasing gem to require_gem in #{__FILE__} -- you should update your RubyGems system!"
|
12
13
|
alias gem require_gem
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
gem 'picnic'
|
16
17
|
end
|
17
18
|
|
@@ -19,8 +20,8 @@ require 'picnic/cli'
|
|
19
20
|
|
20
21
|
cli = Picnic::Cli.new(
|
21
22
|
'rubycas-server',
|
22
|
-
:
|
23
|
-
:
|
23
|
+
:app_module => 'CASServer',
|
24
|
+
:app_file => File.expand_path(File.dirname(File.expand_path($0))+"/../lib/casserver.rb")
|
24
25
|
)
|
25
26
|
|
26
27
|
cli.handle_cli_input
|
data/bin/rubycas-server-ctl
CHANGED
@@ -8,10 +8,11 @@ else
|
|
8
8
|
require 'rubygems'
|
9
9
|
|
10
10
|
# make things backwards-compatible for rubygems < 0.9.0
|
11
|
-
|
11
|
+
if respond_to?(:require_gem)
|
12
|
+
puts "WARNING: aliasing gem to require_gem in #{__FILE__} -- you should update your RubyGems system!"
|
12
13
|
alias gem require_gem
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
gem 'picnic'
|
16
17
|
end
|
17
18
|
|
data/config/hoe.rb
CHANGED
@@ -8,9 +8,10 @@ RUBYFORGE_PROJECT = 'rubycas-server' # The unix name for your project
|
|
8
8
|
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
9
|
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
10
|
EXTRA_DEPENDENCIES = [
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
'activesupport',
|
12
|
+
'activerecord',
|
13
|
+
'gettext',
|
14
|
+
['picnic', '>= 0.7.999']
|
14
15
|
] # An array of rubygem dependencies [name, version]
|
15
16
|
|
16
17
|
@config_file = "~/.rubyforge/user-config.yml"
|
@@ -36,7 +37,7 @@ ENV['NODOT'] = '1'
|
|
36
37
|
|
37
38
|
#REV = nil
|
38
39
|
# UNCOMMENT IF REQUIRED:
|
39
|
-
REV =
|
40
|
+
REV = Time.now.strftime('%y%m%d%H%M')
|
40
41
|
VERS = CASServer::VERSION::STRING + (REV ? ".#{REV}" : "")
|
41
42
|
RDOC_OPTS = ['--quiet', '--title', 'rubycas-server documentation',
|
42
43
|
"--opname", "index.html",
|
@@ -64,13 +65,13 @@ $hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
|
64
65
|
|
65
66
|
# == Optional
|
66
67
|
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
67
|
-
|
68
|
+
p.extra_deps = EXTRA_DEPENDENCIES
|
68
69
|
|
69
|
-
|
70
|
-
|
70
|
+
p.spec_extras = {:executables => ['rubycas-server', 'rubycas-server-ctl']} # A hash of extra values to set in the gemspec.
|
71
|
+
end
|
71
72
|
|
72
73
|
CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
73
74
|
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}"
|
74
75
|
$hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
75
76
|
$hoe.rsync_args = '-av --delete --ignore-errors'
|
76
|
-
$hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
|
77
|
+
$hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
|
data/config.example.yml
CHANGED
@@ -132,7 +132,7 @@ database:
|
|
132
132
|
# database: some_database_with_users_table
|
133
133
|
# username: root
|
134
134
|
# password:
|
135
|
-
#
|
135
|
+
# host: localhost
|
136
136
|
# user_table: users
|
137
137
|
# username_column: username
|
138
138
|
# password_column: password
|
@@ -187,7 +187,7 @@ database:
|
|
187
187
|
# database: some_database_with_users_table
|
188
188
|
# user: root
|
189
189
|
# password:
|
190
|
-
#
|
190
|
+
# host: localhost
|
191
191
|
# user_table: user
|
192
192
|
# username_column: username
|
193
193
|
# password_column: password
|
@@ -212,7 +212,7 @@ database:
|
|
212
212
|
#authenticator:
|
213
213
|
# class: CASServer::Authenticators::ActiveDirectoryLDAP
|
214
214
|
# ldap:
|
215
|
-
#
|
215
|
+
# host: ad.example.net
|
216
216
|
# port: 389
|
217
217
|
# base: dc=example,dc=net
|
218
218
|
# filter: (objectClass=person)
|
@@ -226,7 +226,7 @@ database:
|
|
226
226
|
#authenticator:
|
227
227
|
# class: CASServer::Authenticators::ActiveDirectoryLDAP
|
228
228
|
# ldap:
|
229
|
-
#
|
229
|
+
# host: ad.example.net
|
230
230
|
# port: 636
|
231
231
|
# base: dc=example,dc=net
|
232
232
|
# filter: (objectClass=person) & !(msExchHideFromAddressLists=TRUE)
|
@@ -247,28 +247,34 @@ database:
|
|
247
247
|
#
|
248
248
|
# This is a more general version of the ActiveDirectory authenticator.
|
249
249
|
# The configuration is similar, except you don't need an authenticator
|
250
|
-
# username or password.
|
251
|
-
#
|
250
|
+
# username or password. The following example has been reported to work
|
251
|
+
# for a basic OpenLDAP setup.
|
252
252
|
#
|
253
253
|
#authenticator:
|
254
254
|
# class: CASServer::Authenticators::LDAP
|
255
255
|
# ldap:
|
256
|
-
#
|
256
|
+
# host: ldap.example.net
|
257
257
|
# port: 389
|
258
258
|
# base: dc=example,dc=net
|
259
|
+
# username_attribute: uid
|
259
260
|
# filter: (objectClass=person)
|
260
261
|
#
|
261
262
|
# If you need more secure connections via TSL, specify the 'encryption'
|
262
|
-
# option and change the port
|
263
|
+
# option and change the port. This example also forces the authenticator
|
264
|
+
# to connect using a special "authenticator" user with the given
|
265
|
+
# username and password (see the ActiveDirectoryLDAP authenticator
|
266
|
+
# explanation above):
|
263
267
|
#
|
264
268
|
#authenticator:
|
265
269
|
# class: CASServer::Authenticators::LDAP
|
266
270
|
# ldap:
|
267
|
-
#
|
271
|
+
# host: ldap.example.net
|
268
272
|
# port: 636
|
269
273
|
# base: dc=example,dc=net
|
270
274
|
# filter: (objectClass=person)
|
271
275
|
# encryption: simple_tls
|
276
|
+
# auth_user: cn=admin,dc=example,dc=net
|
277
|
+
# auth_password: secret
|
272
278
|
#
|
273
279
|
# If you need additional data about the user passed to the client (for example,
|
274
280
|
# their 'cn' and 'mail' attributes, you can specify the list of attributes
|
@@ -277,7 +283,7 @@ database:
|
|
277
283
|
#authenticator:
|
278
284
|
# class: CASServer::Authenticators::LDAP
|
279
285
|
# ldap:
|
280
|
-
#
|
286
|
+
# host: ldap.example.net
|
281
287
|
# port: 389
|
282
288
|
# base: dc=example,dc=net
|
283
289
|
# filter: (objectClass=person)
|
@@ -321,7 +327,7 @@ database:
|
|
321
327
|
# -
|
322
328
|
# class: CASServer::Authenticators::ActiveDirectoryLDAP
|
323
329
|
# ldap:
|
324
|
-
#
|
330
|
+
# host: ad.example.net
|
325
331
|
# port: 389
|
326
332
|
# base: dc=example,dc=net
|
327
333
|
# filter: (objectClass=person)
|
@@ -332,7 +338,7 @@ database:
|
|
332
338
|
# database: some_database_with_users_table
|
333
339
|
# user: root
|
334
340
|
# password:
|
335
|
-
#
|
341
|
+
# host: localhost
|
336
342
|
# user_table: user
|
337
343
|
# username_column: username
|
338
344
|
# password_column: password
|
@@ -367,6 +373,31 @@ infoline: Powered by <a href="http://code.google.com/p/rubycas-server/">RubyCAS-
|
|
367
373
|
# Custom views file. Overrides methodes in lib/casserver/views.rb
|
368
374
|
#custom_views_file: /path/to/custom/views.rb
|
369
375
|
|
376
|
+
##### LOCALIZATION (L10N) #######################################################
|
377
|
+
# The server will attempt to detect the user's locale and show text in the
|
378
|
+
# appropriate language based on:
|
379
|
+
#
|
380
|
+
# 1. The 'lang' URL parameter (if any)
|
381
|
+
# 2. The 'lang' cookie (if any)
|
382
|
+
# 3. The HTTP_ACCEPT_LANGUAGE header supplied by the user's browser.
|
383
|
+
# 4. The HTTP_USER_AGENT header supplied by the user's browser.
|
384
|
+
#
|
385
|
+
# If the locale cannot be established based on one of the above checks (in the
|
386
|
+
# shown order), then the below 'default_locale' option will be used.
|
387
|
+
#
|
388
|
+
# The format is the same as standard linux locales (langagecode_COUNTRYCODE):
|
389
|
+
#
|
390
|
+
# ru_RU - Russian, Russia
|
391
|
+
# eo_AQ - Esperanto, Antarctica
|
392
|
+
#
|
393
|
+
# It will also work if you leave out the region (i.e. just "ru" for Russian,
|
394
|
+
# "eo" for Esperanto).
|
395
|
+
#
|
396
|
+
# If you are interested in contributing new translations or have corrections
|
397
|
+
# to the existing translations, see
|
398
|
+
# http://code.google.com/p/rubycas-server/wiki/HowToContribueTranslations
|
399
|
+
#
|
400
|
+
default_locale: en
|
370
401
|
|
371
402
|
##### LOGGING ##################################################################
|
372
403
|
|
data/config.ru
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
$APP_NAME = 'rubycas-server'
|
5
|
+
$APP_ROOT = File.dirname(File.expand_path(__FILE__))
|
6
|
+
$: << $APP_ROOT + "/lib"
|
7
|
+
|
8
|
+
require File.dirname(File.expand_path(__FILE__)) + '/lib/casserver'
|
9
|
+
|
10
|
+
$LOG = Logger.new("casserver.log")
|
11
|
+
$LOG.level = Logger::DEBUG
|
12
|
+
|
13
|
+
CASServer.create
|
14
|
+
|
15
|
+
if $CONF.uri_path
|
16
|
+
map($CONF.uri_path) do
|
17
|
+
run CASServer
|
18
|
+
end
|
19
|
+
else
|
20
|
+
run CASServer
|
21
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'casserver/authenticators/base'
|
2
|
+
require 'uri'
|
3
|
+
require 'net/http'
|
4
|
+
require 'net/https'
|
5
|
+
require 'timeout'
|
6
|
+
|
7
|
+
# Validates Google accounts against Google's authentication service -- in other
|
8
|
+
# words, this authenticator allows users to log in to CAS using their
|
9
|
+
# Gmail/Google accounts.
|
10
|
+
class CASServer::Authenticators::Google < CASServer::Authenticators::Base
|
11
|
+
def validate(credentials)
|
12
|
+
read_standard_credentials(credentials)
|
13
|
+
|
14
|
+
return false if @username.blank? || @password.blank?
|
15
|
+
|
16
|
+
auth_data = {
|
17
|
+
'Email' => @username,
|
18
|
+
'Passwd' => @password,
|
19
|
+
'service' => 'xapi',
|
20
|
+
'source' => 'RubyCAS-Server',
|
21
|
+
'accountType' => 'HOSTED_OR_GOOGLE'
|
22
|
+
}
|
23
|
+
|
24
|
+
url = URI.parse('https://www.google.com/accounts/ClientLogin')
|
25
|
+
http = Net::HTTP.new(url.host, url.port)
|
26
|
+
http.use_ssl = true
|
27
|
+
|
28
|
+
# TODO: make the timeout configurable
|
29
|
+
wait_seconds = 10
|
30
|
+
begin
|
31
|
+
timeout(wait_seconds) do
|
32
|
+
res = http.start do |conn|
|
33
|
+
req = Net::HTTP::Post.new(url.path)
|
34
|
+
req.set_form_data(auth_data,'&')
|
35
|
+
conn.request(req)
|
36
|
+
end
|
37
|
+
|
38
|
+
case res
|
39
|
+
when Net::HTTPSuccess
|
40
|
+
true
|
41
|
+
when Net::HTTPForbidden
|
42
|
+
false
|
43
|
+
else
|
44
|
+
$LOG.error("Unexpected response from Google while validating credentials: #{res.inspect} ==> #{res.body}.")
|
45
|
+
raise CASServer::AuthenticatorError, "Unexpected response received from Google while validating credentials."
|
46
|
+
end
|
47
|
+
end
|
48
|
+
rescue Timeout::Error
|
49
|
+
$LOG.error("Google did not respond to the credential validation request. We waited for #{wait_seconds.inspect} seconds before giving up.")
|
50
|
+
raise CASServer::AuthenticatorError, "Timeout while waiting for Google to validate credentials."
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'casserver/authenticators/base'
|
2
|
+
|
3
|
+
require 'digest/sha1'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'active_record'
|
7
|
+
rescue LoadError
|
8
|
+
require 'rubygems'
|
9
|
+
require 'active_record'
|
10
|
+
end
|
11
|
+
|
12
|
+
# This is a version of the SQL authenticator that works nicely with RestfulAuthentication.
|
13
|
+
# Passwords are encrypted the same way as it done in RestfulAuthentication.
|
14
|
+
# Before use you this, you MUST configure rest_auth_digest_streches and rest_auth_site_key in
|
15
|
+
# config.
|
16
|
+
#
|
17
|
+
# Using this authenticator requires restful authentication plugin on rails (client) side.
|
18
|
+
#
|
19
|
+
# * git://github.com/technoweenie/restful-authentication.git
|
20
|
+
#
|
21
|
+
class CASServer::Authenticators::SQLRestAuth < CASServer::Authenticators::Base
|
22
|
+
|
23
|
+
def validate(credentials)
|
24
|
+
read_standard_credentials(credentials)
|
25
|
+
|
26
|
+
raise CASServer::AuthenticatorError, "Cannot validate credentials because the authenticator hasn't yet been configured" unless @options
|
27
|
+
raise CASServer::AuthenticatorError, "Invalid authenticator configuration!" unless @options[:database]
|
28
|
+
|
29
|
+
CASUser.establish_connection @options[:database]
|
30
|
+
CASUser.set_table_name @options[:user_table] || "users"
|
31
|
+
|
32
|
+
username_column = @options[:username_column] || "email"
|
33
|
+
|
34
|
+
results = CASUser.find(:all, :conditions => ["#{username_column} = ?", @username])
|
35
|
+
|
36
|
+
if results.size > 0
|
37
|
+
$LOG.warn("Multiple matches found for user '#{@username}'") if results.size > 1
|
38
|
+
user = results.first
|
39
|
+
return (user.crypted_password == user.encrypt(@password))
|
40
|
+
else
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module EncryptedPassword
|
46
|
+
|
47
|
+
# XXX: this constants MUST be defined in config.
|
48
|
+
# For more details # look at restful-authentication docs.
|
49
|
+
#
|
50
|
+
REST_AUTH_DIGEST_STRETCHES = $CONF.rest_auth_digest_streches
|
51
|
+
REST_AUTH_SITE_KEY = $CONF.rest_auth_site_key
|
52
|
+
|
53
|
+
def self.included(mod)
|
54
|
+
raise "#{self} should be inclued in an ActiveRecord class!" unless mod.respond_to?(:before_save)
|
55
|
+
end
|
56
|
+
|
57
|
+
def encrypt(password)
|
58
|
+
password_digest(password, self.salt)
|
59
|
+
end
|
60
|
+
|
61
|
+
def secure_digest(*args)
|
62
|
+
Digest::SHA1.hexdigest(args.flatten.join('--'))
|
63
|
+
end
|
64
|
+
|
65
|
+
def password_digest(password, salt)
|
66
|
+
digest = REST_AUTH_SITE_KEY
|
67
|
+
REST_AUTH_DIGEST_STRETCHES.times do
|
68
|
+
digest = secure_digest(digest, salt, password, REST_AUTH_SITE_KEY)
|
69
|
+
end
|
70
|
+
digest
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class CASUser < ActiveRecord::Base
|
75
|
+
include EncryptedPassword
|
76
|
+
end
|
77
|
+
end
|
data/lib/casserver/cas.rb
CHANGED
@@ -11,7 +11,8 @@ module CASServer::CAS
|
|
11
11
|
# 3.5 (login ticket)
|
12
12
|
lt = LoginTicket.new
|
13
13
|
lt.ticket = "LT-" + CASServer::Utils.random_string
|
14
|
-
|
14
|
+
|
15
|
+
lt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
|
15
16
|
lt.save!
|
16
17
|
$LOG.debug("Generated login ticket '#{lt.ticket}' for client" +
|
17
18
|
" at '#{lt.client_hostname}'")
|
@@ -30,7 +31,7 @@ module CASServer::CAS
|
|
30
31
|
tgt.ticket = "TGC-" + CASServer::Utils.random_string
|
31
32
|
tgt.username = username
|
32
33
|
tgt.extra_attributes = extra_attributes
|
33
|
-
tgt.client_hostname = env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_HOST'] || env['REMOTE_ADDR']
|
34
|
+
tgt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
|
34
35
|
tgt.save!
|
35
36
|
$LOG.debug("Generated ticket granting ticket '#{tgt.ticket}' for user" +
|
36
37
|
" '#{tgt.username}' at '#{tgt.client_hostname}'" +
|
@@ -45,7 +46,7 @@ module CASServer::CAS
|
|
45
46
|
st.service = service
|
46
47
|
st.username = username
|
47
48
|
st.ticket_granting_ticket = tgt
|
48
|
-
st.client_hostname = env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_HOST'] || env['REMOTE_ADDR']
|
49
|
+
st.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
|
49
50
|
st.save!
|
50
51
|
$LOG.debug("Generated service ticket '#{st.ticket}' for service '#{st.service}'" +
|
51
52
|
" for user '#{st.username}' at '#{st.client_hostname}'")
|
@@ -60,7 +61,7 @@ module CASServer::CAS
|
|
60
61
|
pt.username = pgt.service_ticket.username
|
61
62
|
pt.proxy_granting_ticket_id = pgt.id
|
62
63
|
pt.ticket_granting_ticket = pgt.service_ticket.ticket_granting_ticket
|
63
|
-
pt.client_hostname = env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_HOST'] || env['REMOTE_ADDR']
|
64
|
+
pt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
|
64
65
|
pt.save!
|
65
66
|
$LOG.debug("Generated proxy ticket '#{pt.ticket}' for target service '#{pt.service}'" +
|
66
67
|
" for user '#{pt.username}' at '#{pt.client_hostname}' using proxy-granting" +
|
@@ -87,7 +88,7 @@ module CASServer::CAS
|
|
87
88
|
pgt.ticket = "PGT-" + CASServer::Utils.random_string(60)
|
88
89
|
pgt.iou = "PGTIOU-" + CASServer::Utils.random_string(57)
|
89
90
|
pgt.service_ticket_id = st.id
|
90
|
-
pgt.client_hostname = env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_HOST'] || env['REMOTE_ADDR']
|
91
|
+
pgt.client_hostname = @env['HTTP_X_FORWARDED_FOR'] || @env['REMOTE_HOST'] || @env['REMOTE_ADDR']
|
91
92
|
|
92
93
|
# FIXME: The CAS protocol spec says to use 'pgt' as the parameter, but in practice
|
93
94
|
# the JA-SIG and Yale server implementations use pgtId. We'll go with the
|
@@ -119,7 +120,7 @@ module CASServer::CAS
|
|
119
120
|
if lt.consumed?
|
120
121
|
error = "The login ticket you provided has already been used up. Please try logging in again."
|
121
122
|
$LOG.warn("Login ticket '#{ticket}' previously used up")
|
122
|
-
elsif Time.now - lt.created_on <
|
123
|
+
elsif Time.now - lt.created_on < $CONF.login_ticket_expiry
|
123
124
|
$LOG.info("Login ticket '#{ticket}' successfully validated")
|
124
125
|
else
|
125
126
|
error = "Your login ticket has expired. Please try logging in again."
|
@@ -142,7 +143,7 @@ module CASServer::CAS
|
|
142
143
|
error = "No ticket granting ticket given."
|
143
144
|
$LOG.debug(error)
|
144
145
|
elsif tgt = TicketGrantingTicket.find_by_ticket(ticket)
|
145
|
-
if
|
146
|
+
if $CONF.expire_sessions && Time.now - tgt.created_on > $CONF.ticket_granting_ticket_expiry
|
146
147
|
error = "Your session has expired. Please log in again."
|
147
148
|
$LOG.info("Ticket granting ticket '#{ticket}' for user '#{tgt.username}' expired.")
|
148
149
|
else
|
@@ -169,7 +170,7 @@ module CASServer::CAS
|
|
169
170
|
elsif st.kind_of?(CASServer::Models::ProxyTicket) && !allow_proxy_tickets
|
170
171
|
error = Error.new(:INVALID_TICKET, "Ticket '#{ticket}' is a proxy ticket, but only service tickets are allowed here.")
|
171
172
|
$LOG.warn("#{error.code} - #{error.message}")
|
172
|
-
elsif Time.now - st.created_on >
|
173
|
+
elsif Time.now - st.created_on > $CONF.service_ticket_expiry
|
173
174
|
error = Error.new(:INVALID_TICKET, "Ticket '#{ticket}' has expired.")
|
174
175
|
$LOG.warn("Ticket '#{ticket}' has expired.")
|
175
176
|
elsif !st.matches_service? service
|
@@ -234,30 +235,38 @@ module CASServer::CAS
|
|
234
235
|
# See http://www.ja-sig.org/wiki/display/CASUM/Single+Sign+Out
|
235
236
|
def send_logout_notification_for_service_ticket(st)
|
236
237
|
uri = URI.parse(st.service)
|
237
|
-
http = Net::HTTP.new(uri.host,uri.port)
|
238
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
238
239
|
#http.use_ssl = true if uri.scheme = 'https'
|
239
240
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
241
|
+
time = Time.now
|
242
|
+
rand = CASServer::Utils.random_string
|
243
|
+
|
244
|
+
path = uri.path
|
245
|
+
path = '/' if path.empty?
|
246
|
+
|
247
|
+
req = Net::HTTP::Post.new(path)
|
248
|
+
req.set_form_data(
|
249
|
+
'logoutRequest' => %{<samlp:LogoutRequest ID="#{rand}" Version="2.0" IssueInstant="#{time.rfc2822}">
|
248
250
|
<saml:NameID></saml:NameID>
|
249
251
|
<samlp:SessionIndex>#{st.ticket}</samlp:SessionIndex>
|
250
252
|
</samlp:LogoutRequest>}
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
253
|
+
)
|
254
|
+
|
255
|
+
begin
|
256
|
+
http.start do |conn|
|
257
|
+
response = conn.request(req)
|
258
|
+
|
259
|
+
if response.kind_of? Net::HTTPSuccess
|
260
|
+
$LOG.info "Logout notification successfully posted to #{st.service.inspect}."
|
261
|
+
return true
|
262
|
+
else
|
263
|
+
$LOG.error "Service #{st.service.inspect} responed to logout notification with code '#{response.code}'!"
|
264
|
+
return false
|
265
|
+
end
|
260
266
|
end
|
267
|
+
rescue => e
|
268
|
+
$LOG.error "Failed to send logout notification to service #{st.service.inspect} due to #{e}"
|
269
|
+
return false
|
261
270
|
end
|
262
271
|
end
|
263
272
|
|
@@ -283,7 +292,7 @@ module CASServer::CAS
|
|
283
292
|
end
|
284
293
|
|
285
294
|
# Strips CAS-related parameters from a service URL and normalizes it,
|
286
|
-
# removing trailing / and ?.
|
295
|
+
# removing trailing / and ?. Also converts any spaces to +.
|
287
296
|
#
|
288
297
|
# For example, "http://google.com?ticket=12345" will be returned as
|
289
298
|
# "http://google.com". Also, "http://google.com/" would be returned as
|
@@ -300,7 +309,11 @@ module CASServer::CAS
|
|
300
309
|
end
|
301
310
|
|
302
311
|
clean_service.gsub!(/[\/\?]$/, '')
|
312
|
+
clean_service.gsub!(' ', '+')
|
303
313
|
|
314
|
+
$LOG.debug("Cleaned dirty service URL #{dirty_service.inspect} to #{clean_service.inspect}") if
|
315
|
+
dirty_service != clean_service
|
316
|
+
|
304
317
|
return clean_service
|
305
318
|
end
|
306
319
|
module_function :clean_service_url
|