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 CHANGED
@@ -1,7 +1,26 @@
1
- === 0.7.0 :: In Progress
1
+ === 0.8.0 :: In Progress...
2
2
 
3
- * New features:
4
- * Implemented single-sign-out functionality as specified in CAS 3.1. See
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
- * Changes to existing functionality:
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
- * Bug fixes
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
- misc/basic_cas_single_signon_mechanism_diagram.png
52
- misc/basic_cas_single_signon_mechanism_diagram.svg
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
- website/index.html
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
- *Authors*:: Matt Zukowski <matt at roughest dot net>, Jason Zylks
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
- unless Object.method_defined? :gem
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
- :app_path => File.expand_path(File.dirname(File.expand_path(__FILE__))),
23
- :app_module => 'CASServer'
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
@@ -8,10 +8,11 @@ else
8
8
  require 'rubygems'
9
9
 
10
10
  # make things backwards-compatible for rubygems < 0.9.0
11
- unless Object.method_defined? :gem
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
- ['activesupport', '>= 2.0.2'],
12
- ['activerecord', '>= 2.0.2'],
13
- ['picnic', '>= 0.6.5']
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 = YAML.load(`svn info`)['Revision']
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
- #p.extra_deps = EXTRA_DEPENDENCIES
68
+ p.extra_deps = EXTRA_DEPENDENCIES
68
69
 
69
- p.spec_extras = {:executables => ['rubycas-server', 'rubycas-server-ctl']} # A hash of extra values to set in the gemspec.
70
- end
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
- # server: localhost
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
- # server: localhost
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
- # server: ad.example.net
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
- # server: ad.example.net
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. Note that this authenticator hasn't been widely
251
- # tested, so it is not guaranteed to work.
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
- # server: ldap.example.net
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
- # server: ldap.example.net
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
- # server: ldap.example.net
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
- # server: ad.example.net
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
- # server: localhost
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
- lt.client_hostname = env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_HOST'] || env['REMOTE_ADDR']
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 < CASServer::Conf.login_ticket_expiry
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 CASServer::Conf.expire_sessions && Time.now - tgt.created_on > CASServer::Conf.ticket_granting_ticket_expiry
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 > CASServer::Conf.service_ticket_expiry
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
- http.start do |conn|
241
- path = uri.path
242
- path = '/' if path.empty?
243
-
244
- time = Time.now
245
- rand = CASServer::Utils.random_string
246
-
247
- data = %{<samlp:LogoutRequest ID="#{rand}" Version="2.0" IssueInstant="#{time.rfc2822}">
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
- response = conn.request_post(path, data)
253
-
254
- if response.code.to_i == 200
255
- $LOG.info "Logout notification successfully posted to #{st.service.inspect}."
256
- return true
257
- else
258
- $LOG.error "Service #{st.service.inspect} responed to logout notification with code '#{response.code}'."
259
- return false
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