rubycas-server 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.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 # UNCOMMENT IF REQUIRED: File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue 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",
@@ -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
- # For example, with MySQL, your config wold be something like:
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
- server: localhost
62
+ host: localhost
64
63
 
65
- # If you prefer to use SQLite3 (which does not require a separate database server),
66
- # your configuration would look something like the following (don't forget to install
67
- # the sqlite3-ruby gem beforehand!):
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
- # user: root
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, rather than typing in their sAMAccountName. In other words
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
- Net::LDAP::Filter.eq(username_attribute, @username)
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
@@ -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
- $AUTH = $CONF[:authenticator][:class].constantize.new
49
- rescue NameError
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
- # the authenticator class hasn't yet been loaded, so lets try to load it from the casserver/authenticators directory
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
- $AUTH = $CONF[:authenticator][:class].constantize.new
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 && !@renew && tgt && !tgt_error
32
- st = generate_service_ticket(@service, tgt.username)
33
- service_with_ticket = service_uri_with_ticket(@service, st)
34
- $LOG.info("User '#{tgt.username}' authenticated based on ticket granting cookie. Redirecting to service '#{@service}'.")
35
- return redirect(service_with_ticket, :status => 303) # response code 303 means "See Other" (see Appendix B in CAS Protocol spec)
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
- render :login
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
- $AUTH.configure(CASServer::Conf.authenticator)
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
- credentials_are_valid = $AUTH.validate(:username => @username, :password => @password, :service => @service)
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 '#{$AUTH.username}' successfully validated")
129
+ $LOG.info("Credentials for username '#{@username}' successfully validated")
86
130
 
87
131
  # 3.6 (ticket-granting cookie)
88
- tgt = generate_ticket_granting_ticket($AUTH.username)
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 '#{$AUTH.username}'. #{expiry_info}")
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 '#{$AUTH.username}' at '#{tgt.client_hostname}'. No service param was given, so we will not redirect.")
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, $AUTH.username)
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 '#{$AUTH.username}' at '#{@st.client_hostname}' to service '#{@service}'")
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 '#{$AUTH.username}'")
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
- # switching users a lot smoother.
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
- render :login
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
@@ -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