wmernagh-rubycas-server 0.6.99.336

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.
Files changed (72) hide show
  1. data/CHANGELOG.txt +1 -0
  2. data/History.txt +245 -0
  3. data/LICENSE.txt +504 -0
  4. data/Manifest.txt +74 -0
  5. data/PostInstall.txt +3 -0
  6. data/README.txt +25 -0
  7. data/Rakefile +4 -0
  8. data/bin/rubycas-server +26 -0
  9. data/bin/rubycas-server-ctl +22 -0
  10. data/config/hoe.rb +76 -0
  11. data/config/requirements.rb +15 -0
  12. data/config.example.yml +442 -0
  13. data/custom_views.example.rb +11 -0
  14. data/lib/casserver/authenticators/active_directory_ldap.rb +11 -0
  15. data/lib/casserver/authenticators/base.rb +48 -0
  16. data/lib/casserver/authenticators/client_certificate.rb +46 -0
  17. data/lib/casserver/authenticators/ldap.rb +138 -0
  18. data/lib/casserver/authenticators/ntlm.rb +88 -0
  19. data/lib/casserver/authenticators/open_id.rb +22 -0
  20. data/lib/casserver/authenticators/sql.rb +102 -0
  21. data/lib/casserver/authenticators/sql_encrypted.rb +75 -0
  22. data/lib/casserver/authenticators/sql_md5.rb +19 -0
  23. data/lib/casserver/authenticators/test.rb +19 -0
  24. data/lib/casserver/cas.rb +308 -0
  25. data/lib/casserver/conf.rb +112 -0
  26. data/lib/casserver/controllers.rb +452 -0
  27. data/lib/casserver/environment.rb +26 -0
  28. data/lib/casserver/models.rb +218 -0
  29. data/lib/casserver/postambles.rb +174 -0
  30. data/lib/casserver/utils.rb +30 -0
  31. data/lib/casserver/version.rb +9 -0
  32. data/lib/casserver/views.rb +243 -0
  33. data/lib/casserver.rb +111 -0
  34. data/lib/rubycas-server/version.rb +1 -0
  35. data/lib/rubycas-server.rb +1 -0
  36. data/lib/themes/cas.css +121 -0
  37. data/lib/themes/notice.png +0 -0
  38. data/lib/themes/ok.png +0 -0
  39. data/lib/themes/simple/bg.png +0 -0
  40. data/lib/themes/simple/login_box_bg.png +0 -0
  41. data/lib/themes/simple/logo.png +0 -0
  42. data/lib/themes/simple/theme.css +28 -0
  43. data/lib/themes/urbacon/bg.png +0 -0
  44. data/lib/themes/urbacon/login_box_bg.png +0 -0
  45. data/lib/themes/urbacon/logo.png +0 -0
  46. data/lib/themes/urbacon/theme.css +33 -0
  47. data/lib/themes/warning.png +0 -0
  48. data/misc/basic_cas_single_signon_mechanism_diagram.png +0 -0
  49. data/misc/basic_cas_single_signon_mechanism_diagram.svg +652 -0
  50. data/resources/init.d.sh +58 -0
  51. data/script/console +10 -0
  52. data/script/destroy +14 -0
  53. data/script/generate +14 -0
  54. data/script/txt2html +82 -0
  55. data/setup.rb +1585 -0
  56. data/tasks/deployment.rake +34 -0
  57. data/tasks/environment.rake +7 -0
  58. data/tasks/website.rake +17 -0
  59. data/vendor/isaac_0.9.1/LICENSE +26 -0
  60. data/vendor/isaac_0.9.1/README +78 -0
  61. data/vendor/isaac_0.9.1/TODO +3 -0
  62. data/vendor/isaac_0.9.1/VERSIONS +3 -0
  63. data/vendor/isaac_0.9.1/crypt/ISAAC.rb +171 -0
  64. data/vendor/isaac_0.9.1/isaac.gemspec +39 -0
  65. data/vendor/isaac_0.9.1/setup.rb +596 -0
  66. data/vendor/isaac_0.9.1/test/TC_ISAAC.rb +76 -0
  67. data/website/index.html +40 -0
  68. data/website/index.txt +3 -0
  69. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  70. data/website/stylesheets/screen.css +138 -0
  71. data/website/template.html.erb +40 -0
  72. metadata +146 -0
@@ -0,0 +1,452 @@
1
+ # The #.#.# comments (e.g. "2.1.3") refer to section numbers in the CAS protocol spec
2
+ # under http://www.ja-sig.org/products/cas/overview/protocol/index.html
3
+
4
+ module CASServer::Controllers
5
+
6
+ # 2.1
7
+ class Login < R '/', '/login'
8
+ include CASServer::CAS
9
+
10
+ # 2.1.1
11
+ def get
12
+ CASServer::Utils::log_controller_action(self.class, @input)
13
+
14
+ # make sure there's no caching
15
+ headers['Pragma'] = 'no-cache'
16
+ headers['Cache-Control'] = 'no-store'
17
+ headers['Expires'] = (Time.now - 1.year).rfc2822
18
+
19
+ # optional params
20
+ @service = clean_service_url(@input['service'])
21
+ @renew = @input['renew']
22
+ @gateway = @input['gateway'] == 'true' || @input['gateway'] == '1'
23
+
24
+ if tgc = @cookies[:tgt]
25
+ tgt, tgt_error = validate_ticket_granting_ticket(tgc)
26
+ end
27
+
28
+ if tgt and !tgt_error
29
+ @message = {:type => 'notice',
30
+ :message => %{You are currently logged in as "#{tgt.username}". If this is not you, please log in below.}}
31
+ end
32
+
33
+ if @input['redirection_loop_intercepted']
34
+ @message = {:type => 'mistake',
35
+ :message => %{The client and server are unable to negotiate authentication. Please try logging in again later.}}
36
+ end
37
+
38
+ begin
39
+ if @service
40
+ if !@renew && tgt && !tgt_error
41
+ st = generate_service_ticket(@service, tgt.username, tgt)
42
+ service_with_ticket = service_uri_with_ticket(@service, st)
43
+ $LOG.info("User '#{tgt.username}' authenticated based on ticket granting cookie. Redirecting to service '#{@service}'.")
44
+ return redirect(service_with_ticket, :status => 303) # response code 303 means "See Other" (see Appendix B in CAS Protocol spec)
45
+ elsif @gateway
46
+ $LOG.info("Redirecting unauthenticated gateway request to service '#{@service}'.")
47
+ return redirect(@service, :status => 303)
48
+ end
49
+ elsif @gateway
50
+ $LOG.error("This is a gateway request but no service parameter was given!")
51
+ @message = {:type => 'mistake',
52
+ :message => "The server cannot fulfill this gateway request because no service parameter was given."}
53
+ end
54
+ rescue URI::InvalidURIError
55
+ $LOG.error("The service '#{@service}' is not a valid URI!")
56
+ @message = {:type => 'mistake',
57
+ :message => "The target service your browser supplied appears to be invalid. Please contact your system administrator for help."}
58
+ end
59
+
60
+ lt = generate_login_ticket
61
+
62
+ $LOG.debug("Rendering login form with lt: #{lt}, service: #{@service}, renew: #{@renew}, gateway: #{@gateway}")
63
+
64
+ @lt = lt.ticket
65
+
66
+ #$LOG.debug(env)
67
+
68
+ # If the 'onlyLoginForm' parameter is specified, we will only return the
69
+ # login form part of the page. This is useful for when you want to
70
+ # embed the login form in some external page (as an IFRAME, or otherwise).
71
+ # The optional 'submitToURI' parameter can be given to explicitly set the
72
+ # action for the form, otherwise the server will try to guess this for you.
73
+ if @input.has_key? 'onlyLoginForm'
74
+ if env['HTTP_HOST']
75
+ guessed_login_uri = "http#{env['HTTPS'] && env['HTTPS'] == 'on' ? 's' : ''}://#{env['REQUEST_URI']}#{self / '/login'}"
76
+ else
77
+ guessed_login_uri = nil
78
+ end
79
+
80
+ @form_action = @input['submitToURI'] || guessed_login_uri
81
+
82
+ if @form_action
83
+ render :login_form
84
+ else
85
+ @status = 500
86
+ "Could not guess the CAS login URI. Please supply a submitToURI parameter with your request."
87
+ end
88
+ else
89
+ render :login
90
+ end
91
+ end
92
+
93
+ # 2.2
94
+ def post
95
+ CASServer::Utils::log_controller_action(self.class, @input)
96
+
97
+ # 2.2.1 (optional)
98
+ @service = clean_service_url(@input['service'])
99
+
100
+ # 2.2.2 (required)
101
+ @username = @input['username']
102
+ @password = @input['password']
103
+ @lt = @input['lt']
104
+
105
+ # Remove leading and trailing widespace from username.
106
+ @username.strip! if @username
107
+
108
+ if @username && $CONF[:downcase_username]
109
+ $LOG.debug("Converting username #{@username.inspect} to lowercase because 'downcase_username' option is enabled.")
110
+ @username.downcase!
111
+ end
112
+
113
+ if error = validate_login_ticket(@lt)
114
+ @message = {:type => 'mistake', :message => error}
115
+ # generate another login ticket to allow for re-submitting the form
116
+ @lt = generate_login_ticket.ticket
117
+ @status = 401
118
+ return render(:login)
119
+ end
120
+
121
+ # generate another login ticket to allow for re-submitting the form after a post
122
+ @lt = generate_login_ticket.ticket
123
+
124
+ if $CONF[:authenticator].instance_of? Array
125
+ $AUTH.each_index {|auth_index| $AUTH[auth_index].configure(CASServer::Conf.authenticator[auth_index])}
126
+ else
127
+ $AUTH[0].configure(CASServer::Conf.authenticator)
128
+ end
129
+
130
+ $LOG.debug("Logging in with username: #{@username}, lt: #{@lt}, service: #{@service}, auth: #{$AUTH}")
131
+
132
+ credentials_are_valid = false
133
+ extra_attributes = {}
134
+ successful_authenticator = nil
135
+ begin
136
+ $AUTH.each do |auth|
137
+ credentials_are_valid = auth.validate(
138
+ :username => @username,
139
+ :password => @password,
140
+ :service => @service,
141
+ :request => env
142
+ )
143
+ if credentials_are_valid
144
+ extra_attributes.merge!(auth.extra_attributes) unless auth.extra_attributes.blank?
145
+ successful_authenticator = auth
146
+ break
147
+ end
148
+ end
149
+ rescue CASServer::AuthenticatorError => e
150
+ $LOG.error(e)
151
+ @message = {:type => 'mistake', :message => e.to_s}
152
+ return render(:login)
153
+ end
154
+
155
+ if credentials_are_valid
156
+ $LOG.info("Credentials for username '#{@username}' successfully validated using #{successful_authenticator.class.name}.")
157
+ $LOG.debug("Authenticator provided additional user attributes: #{extra_attributes.inspect}") unless extra_attributes.blank?
158
+
159
+ # 3.6 (ticket-granting cookie)
160
+ tgt = generate_ticket_granting_ticket(@username, extra_attributes)
161
+
162
+ if CASServer::Conf.expire_sessions
163
+ expires = CASServer::Conf.ticket_granting_ticket_expiry.to_i.from_now
164
+ expiry_info = " It will expire on #{expires}."
165
+ else
166
+ expiry_info = " It will not expire."
167
+ end
168
+
169
+ if CASServer::Conf.expire_sessions
170
+ @cookies[:tgt] = {
171
+ :value => tgt.to_s,
172
+ :expires => Time.now + CASServer::Conf.ticket_granting_ticket_expiry
173
+ }
174
+ else
175
+ @cookies[:tgt] = tgt.to_s
176
+ end
177
+
178
+ $LOG.debug("Ticket granting cookie '#{@cookies[:tgt].inspect}' granted to '#{@username.inspect}'. #{expiry_info}")
179
+
180
+ if @service.blank?
181
+ $LOG.info("Successfully authenticated user '#{@username}' at '#{tgt.client_hostname}'. No service param was given, so we will not redirect.")
182
+ @message = {:type => 'confirmation', :message => "You have successfully logged in."}
183
+ else
184
+ @st = generate_service_ticket(@service, @username, tgt)
185
+ begin
186
+ service_with_ticket = service_uri_with_ticket(@service, @st)
187
+
188
+ $LOG.info("Redirecting authenticated user '#{@username}' at '#{@st.client_hostname}' to service '#{@service}'")
189
+ return redirect(service_with_ticket, :status => 303) # response code 303 means "See Other" (see Appendix B in CAS Protocol spec)
190
+ rescue URI::InvalidURIError
191
+ $LOG.error("The service '#{@service}' is not a valid URI!")
192
+ @message = {:type => 'mistake', :message => "The target service your browser supplied appears to be invalid. Please contact your system administrator for help."}
193
+ end
194
+ end
195
+ else
196
+ $LOG.warn("Invalid credentials given for user '#{@username}'")
197
+ @message = {:type => 'mistake', :message => "Incorrect username or password."}
198
+ @status = 401
199
+ end
200
+
201
+ render :login
202
+ end
203
+ end
204
+
205
+ # 2.3
206
+ class Logout < R '/logout'
207
+ include CASServer::CAS
208
+
209
+ # 2.3.1
210
+ def get
211
+ CASServer::Utils::log_controller_action(self.class, @input)
212
+
213
+ # The behaviour here is somewhat non-standard. Rather than showing just a blank
214
+ # "logout" page, we take the user back to the login page with a "you have been logged out"
215
+ # message, allowing for an opportunity to immediately log back in. This makes it
216
+ # easier for the user to log out and log in as someone else.
217
+ @service = clean_service_url(@input['service'] || @input['destination'])
218
+ @continue_url = @input['url']
219
+
220
+ @gateway = @input['gateway'] == 'true' || @input['gateway'] == '1'
221
+
222
+ tgt = CASServer::Models::TicketGrantingTicket.find_by_ticket(@cookies[:tgt])
223
+
224
+ @cookies.delete :tgt
225
+
226
+ if tgt
227
+ CASServer::Models::TicketGrantingTicket.transaction do
228
+ pgts = CASServer::Models::ProxyGrantingTicket.find(:all,
229
+ :conditions => [CASServer::Models::Base.connection.quote_table_name(CASServer::Models::ServiceTicket.table_name)+".username = ?", tgt.username],
230
+ :include => :service_ticket)
231
+ pgts.each do |pgt|
232
+ $LOG.debug("Deleting Proxy-Granting Ticket '#{pgt}' for user '#{pgt.service_ticket.username}'")
233
+ pgt.destroy
234
+ end
235
+
236
+ if CASServer::Conf.enable_single_sign_out
237
+ $LOG.debug("Deleting Service/Proxy Tickets for '#{tgt}' for user '#{tgt.username}'")
238
+ tgt.service_tickets.each do |st|
239
+ send_logout_notification_for_service_ticket(st)
240
+ # TODO: Maybe we should do some special handling if send_logout_notification_for_service_ticket fails?
241
+ # Note that the method returns false if the POST results in a non-200 HTTP response.
242
+ $LOG.debug "Deleting #{st.class} #{st.ticket.inspect}."
243
+ st.destroy
244
+ end
245
+ end
246
+
247
+ $LOG.debug("Deleting Ticket-Granting Ticket '#{tgt}' for user '#{tgt.username}'")
248
+ tgt.destroy
249
+ end
250
+
251
+ $LOG.info("User '#{tgt.username}' logged out.")
252
+ else
253
+ $LOG.warn("User tried to log out without a valid ticket-granting ticket.")
254
+ end
255
+
256
+ @message = {:type => 'confirmation', :message => "You have successfully logged out."}
257
+
258
+ @message[:message] <<
259
+ " Please click on the following link to continue:" if @continue_url
260
+
261
+ @lt = generate_login_ticket
262
+
263
+ if @gateway && @service
264
+ redirect(@service, :status => 303)
265
+ elsif @continue_url
266
+ render :logout
267
+ else
268
+ render :login
269
+ end
270
+ end
271
+ end
272
+
273
+ # 2.4
274
+ class Validate < R '/validate'
275
+ include CASServer::CAS
276
+
277
+ # 2.4.1
278
+ def get
279
+ CASServer::Utils::log_controller_action(self.class, @input)
280
+
281
+ # required
282
+ @service = clean_service_url(@input['service'])
283
+ @ticket = @input['ticket']
284
+ # optional
285
+ @renew = @input['renew']
286
+
287
+ st, @error = validate_service_ticket(@service, @ticket)
288
+ @success = st && !@error
289
+
290
+ @username = st.username if @success
291
+
292
+ @status = response_status_from_error(@error) if @error
293
+
294
+ render :validate
295
+ end
296
+ end
297
+
298
+ # 2.5
299
+ class ServiceValidate < R '/serviceValidate'
300
+ include CASServer::CAS
301
+
302
+ # 2.5.1
303
+ def get
304
+ CASServer::Utils::log_controller_action(self.class, @input)
305
+
306
+ # required
307
+ @service = clean_service_url(@input['service'])
308
+ @ticket = @input['ticket']
309
+ # optional
310
+ @pgt_url = @input['pgtUrl']
311
+ @renew = @input['renew']
312
+
313
+ st, @error = validate_service_ticket(@service, @ticket)
314
+ @success = st && !@error
315
+
316
+ if @success
317
+ @username = st.username
318
+ if @pgt_url
319
+ pgt = generate_proxy_granting_ticket(@pgt_url, st)
320
+ @pgtiou = pgt.iou if pgt
321
+ end
322
+ @extra_attributes = st.ticket_granting_ticket.extra_attributes || {}
323
+ end
324
+
325
+ @status = response_status_from_error(@error) if @error
326
+
327
+ render :service_validate
328
+ end
329
+ end
330
+
331
+ # 2.6
332
+ class ProxyValidate < R '/proxyValidate'
333
+ include CASServer::CAS
334
+
335
+ # 2.6.1
336
+ def get
337
+ CASServer::Utils::log_controller_action(self.class, @input)
338
+
339
+ # required
340
+ @service = clean_service_url(@input['service'])
341
+ @ticket = @input['ticket']
342
+ # optional
343
+ @pgt_url = @input['pgtUrl']
344
+ @renew = @input['renew']
345
+
346
+ @proxies = []
347
+
348
+ t, @error = validate_proxy_ticket(@service, @ticket)
349
+ @success = t && !@error
350
+
351
+ @extra_attributes = {}
352
+ if @success
353
+ @username = t.username
354
+
355
+ if t.kind_of? CASServer::Models::ProxyTicket
356
+ @proxies << t.proxy_granting_ticket.service_ticket.service
357
+ end
358
+
359
+ if @pgt_url
360
+ pgt = generate_proxy_granting_ticket(@pgt_url, t)
361
+ @pgtiou = pgt.iou if pgt
362
+ end
363
+
364
+ @extra_attributes = t.ticket_granting_ticket.extra_attributes || {}
365
+ end
366
+ $LOG.error @error
367
+ @status = response_status_from_error(@error) if @error
368
+
369
+ render :proxy_validate
370
+ end
371
+ end
372
+
373
+ class Proxy < R '/proxy'
374
+ include CASServer::CAS
375
+
376
+ # 2.7
377
+ def get
378
+ CASServer::Utils::log_controller_action(self.class, @input)
379
+
380
+ # required
381
+ @ticket = @input['pgt']
382
+ @target_service = @input['targetService']
383
+
384
+ pgt, @error = validate_proxy_granting_ticket(@ticket)
385
+ @success = pgt && !@error
386
+
387
+ if @success
388
+ @pt = generate_proxy_ticket(@target_service, pgt)
389
+ end
390
+
391
+ @status = response_status_from_error(@error) if @error
392
+
393
+ render :proxy
394
+ end
395
+ end
396
+
397
+ # Controller for obtaining login tickets.
398
+ # This is useful when you want to build a custom login form located on a
399
+ # remote server. Your form will have to include a valid login ticket
400
+ # value, and this can be fetched from the CAS server using this controller'
401
+ # POST method.
402
+ class LoginTicketDispenser < R '/loginTicket'
403
+ include CASServer::CAS
404
+
405
+ def get
406
+ CASServer::Utils::log_controller_action(self.class, @input)
407
+ $LOG.error("Tried to use login ticket dispenser with get method!")
408
+ @status = 422
409
+ "To generate a login ticket, you must make a POST request."
410
+ end
411
+
412
+ # Renders a page with a login ticket (and only the login ticket)
413
+ # in the response body.
414
+ def post
415
+ CASServer::Utils::log_controller_action(self.class, @input)
416
+ lt = generate_login_ticket
417
+
418
+ $LOG.debug("Dispensing login ticket #{lt} to host #{(env['HTTP_X_FORWARDED_FOR'] || env['REMOTE_HOST'] || env['REMOTE_ADDR']).inspect}")
419
+
420
+ @lt = lt.ticket
421
+
422
+ @lt
423
+ end
424
+ end
425
+
426
+ class Themes < R '/themes/(.+)'
427
+ MIME_TYPES = {'.css' => 'text/css', '.js' => 'text/javascript',
428
+ '.jpg' => 'image/jpeg'}
429
+ PATH = CASServer::Conf.themes_dir || File.expand_path(File.dirname(__FILE__))+'/../themes'
430
+
431
+ def get(path)@headers['Content-Type'] = MIME_TYPES[path[/\.\w+$/, 0]] || "text/plain"
432
+ unless path.include? ".." # prevent directory traversal attacks
433
+ @headers['X-Sendfile'] = "#{PATH}/#{path}"
434
+ else
435
+ @status = "403"
436
+ "403 - Invalid path"
437
+ end
438
+ end
439
+ end
440
+
441
+ def response_status_from_error(error)
442
+ case error.code.to_s
443
+ when /^INVALID_/, 'BAD_PGT'
444
+ 422
445
+ when 'INTERNAL_ERROR'
446
+ 500
447
+ else
448
+ 500
449
+ end
450
+ end
451
+ module_function :response_status_from_error
452
+ end
@@ -0,0 +1,26 @@
1
+ $: << File.dirname(File.expand_path(__FILE__))
2
+
3
+ # Try to load local version of Picnic if possible (for development purposes)
4
+ $: << File.dirname(File.expand_path(__FILE__))+"/../../../picnic/lib"
5
+ $: << File.dirname(File.expand_path(__FILE__))+"/../../vendor/picnic/lib"
6
+
7
+ begin
8
+ require 'picnic'
9
+ rescue LoadError => e
10
+ # make sure that the LoadError was about picnic and not something else
11
+ raise e unless e.to_s =~ /picnic/
12
+
13
+ require 'rubygems'
14
+
15
+ # make things backwards-compatible for rubygems < 0.9.0
16
+ unless Object.method_defined? :gem
17
+ alias gem require_gem
18
+ end
19
+
20
+ gem 'picnic'
21
+
22
+ require 'picnic'
23
+ end
24
+
25
+ # used for serializing user extra_attributes (see #service_validate in views.rb)
26
+ require 'yaml'
@@ -0,0 +1,218 @@
1
+ require 'camping/db'
2
+
3
+ module CASServer::Models
4
+
5
+ module Consumable
6
+ def consume!
7
+ self.consumed = Time.now
8
+ self.save!
9
+ end
10
+ end
11
+
12
+ class Ticket < Base
13
+ def to_s
14
+ ticket
15
+ end
16
+
17
+ def self.cleanup_expired(expiry_time)
18
+ transaction do
19
+ conditions = ["created_on < ?", Time.now - expiry_time]
20
+ expired_tickets_count = count(:conditions => conditions)
21
+
22
+ $LOG.debug("Destroying #{expired_tickets_count} expired #{self.name.split('::').last}"+
23
+ "#{'s' if expired_tickets_count > 1}.") if expired_tickets_count > 0
24
+
25
+ destroy_all(conditions)
26
+ end
27
+ end
28
+ end
29
+
30
+ class LoginTicket < Ticket
31
+ set_table_name 'casserver_lt'
32
+ include Consumable
33
+ end
34
+
35
+ class ServiceTicket < Ticket
36
+ set_table_name 'casserver_st'
37
+ include Consumable
38
+
39
+ belongs_to :ticket_granting_ticket, :foreign_key => :tgt_id
40
+
41
+ def matches_service?(service)
42
+ CASServer::CAS.clean_service_url(self.service) ==
43
+ CASServer::CAS.clean_service_url(service)
44
+ end
45
+ end
46
+
47
+ class ProxyTicket < ServiceTicket
48
+ belongs_to :proxy_granting_ticket
49
+ end
50
+
51
+ class TicketGrantingTicket < Ticket
52
+ set_table_name 'casserver_tgt'
53
+
54
+ serialize :extra_attributes
55
+
56
+ has_many :service_tickets, :foreign_key => :tgt_id
57
+ end
58
+
59
+ class ProxyGrantingTicket < Ticket
60
+ set_table_name 'casserver_pgt'
61
+ belongs_to :service_ticket
62
+ has_many :proxy_tickets, :dependent => :destroy
63
+ end
64
+
65
+ class Error
66
+ attr_reader :code, :message
67
+
68
+ def initialize(code, message)
69
+ @code = code
70
+ @message = message
71
+ end
72
+
73
+ def to_s
74
+ message
75
+ end
76
+ end
77
+
78
+ class CreateCASServer < V 0.1
79
+ def self.up
80
+ if ActiveRecord::Base.connection.table_alias_length > 30
81
+ $LOG.info("Creating database with long table names...")
82
+
83
+ create_table :casserver_login_tickets, :force => true do |t|
84
+ t.column :ticket, :string, :null => false
85
+ t.column :created_on, :timestamp, :null => false
86
+ t.column :consumed, :datetime, :null => true
87
+ t.column :client_hostname, :string, :null => false
88
+ end
89
+
90
+ create_table :casserver_service_tickets, :force => true do |t|
91
+ t.column :ticket, :string, :null => false
92
+ t.column :service, :string, :null => false
93
+ t.column :created_on, :timestamp, :null => false
94
+ t.column :consumed, :datetime, :null => true
95
+ t.column :client_hostname, :string, :null => false
96
+ t.column :username, :string, :null => false
97
+ t.column :type, :string, :null => false
98
+ t.column :proxy_granting_ticket_id, :integer, :null => true
99
+ end
100
+
101
+ create_table :casserver_ticket_granting_tickets, :force => true do |t|
102
+ t.column :ticket, :string, :null => false
103
+ t.column :created_on, :timestamp, :null => false
104
+ t.column :client_hostname, :string, :null => false
105
+ t.column :username, :string, :null => false
106
+ end
107
+
108
+ create_table :casserver_proxy_granting_tickets, :force => true do |t|
109
+ t.column :ticket, :string, :null => false
110
+ t.column :created_on, :timestamp, :null => false
111
+ t.column :client_hostname, :string, :null => false
112
+ t.column :iou, :string, :null => false
113
+ t.column :service_ticket_id, :integer, :null => false
114
+ end
115
+ end
116
+ end
117
+
118
+ def self.down
119
+ if ActiveRecord::Base.connection.table_alias_length > 30
120
+ drop_table :casserver_proxy_granting_tickets
121
+ drop_table :casserver_ticket_granting_tickets
122
+ drop_table :casserver_service_tickets
123
+ drop_table :casserver_login_tickets
124
+ end
125
+ end
126
+ end
127
+
128
+ # Oracle table names cannot exceed 30 chars...
129
+ # See http://code.google.com/p/rubycas-server/issues/detail?id=15
130
+ class ShortenTableNames < V 0.5
131
+ def self.up
132
+ if ActiveRecord::Base.connection.table_alias_length > 30
133
+ $LOG.info("Shortening table names")
134
+ rename_table :casserver_login_tickets, :casserver_lt
135
+ rename_table :casserver_service_tickets, :casserver_st
136
+ rename_table :casserver_ticket_granting_tickets, :casserver_tgt
137
+ rename_table :casserver_proxy_granting_tickets, :casserver_pgt
138
+ else
139
+ create_table :casserver_lt, :force => true do |t|
140
+ t.column :ticket, :string, :null => false
141
+ t.column :created_on, :timestamp, :null => false
142
+ t.column :consumed, :datetime, :null => true
143
+ t.column :client_hostname, :string, :null => false
144
+ end
145
+
146
+ create_table :casserver_st, :force => true do |t|
147
+ t.column :ticket, :string, :null => false
148
+ t.column :service, :string, :null => false
149
+ t.column :created_on, :timestamp, :null => false
150
+ t.column :consumed, :datetime, :null => true
151
+ t.column :client_hostname, :string, :null => false
152
+ t.column :username, :string, :null => false
153
+ t.column :type, :string, :null => false
154
+ t.column :proxy_granting_ticket_id, :integer, :null => true
155
+ end
156
+
157
+ create_table :casserver_tgt, :force => true do |t|
158
+ t.column :ticket, :string, :null => false
159
+ t.column :created_on, :timestamp, :null => false
160
+ t.column :client_hostname, :string, :null => false
161
+ t.column :username, :string, :null => false
162
+ end
163
+
164
+ create_table :casserver_pgt, :force => true do |t|
165
+ t.column :ticket, :string, :null => false
166
+ t.column :created_on, :timestamp, :null => false
167
+ t.column :client_hostname, :string, :null => false
168
+ t.column :iou, :string, :null => false
169
+ t.column :service_ticket_id, :integer, :null => false
170
+ end
171
+ end
172
+ end
173
+
174
+ def self.down
175
+ if ActiveRecord::Base.connection.table_alias_length > 30
176
+ rename_table :casserver_lt, :cassserver_login_tickets
177
+ rename_table :casserver_st, :casserver_service_tickets
178
+ rename_table :casserver_tgt, :casserver_ticket_granting_tickets
179
+ rename_table :casserver_pgt, :casserver_proxy_granting_tickets
180
+ else
181
+ drop_table :casserver_pgt
182
+ drop_table :casserver_tgt
183
+ drop_table :casserver_st
184
+ drop_table :casserver_lt
185
+ end
186
+ end
187
+ end
188
+
189
+ class AddTgtToSt < V 0.7
190
+ def self.up
191
+ add_column :casserver_st, :tgt_id, :integer, :null => true
192
+ end
193
+
194
+ def self.down
195
+ remove_column :casserver_st, :tgt_id, :integer
196
+ end
197
+ end
198
+
199
+ class ChangeServiceToText < V 0.71
200
+ def self.up
201
+ change_column :casserver_st, :service, :text
202
+ end
203
+
204
+ def self.down
205
+ change_column :casserver_st, :service, :string
206
+ end
207
+ end
208
+
209
+ class AddExtraAttributes < V 0.72
210
+ def self.up
211
+ add_column :casserver_tgt, :extra_attributes, :text
212
+ end
213
+
214
+ def self.down
215
+ remove_column :casserver_tgt, :extra_attributes
216
+ end
217
+ end
218
+ end