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