kch-rubycas-server 0.8.0.20090715

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 (78) hide show
  1. data/CHANGELOG.txt +1 -0
  2. data/History.txt +270 -0
  3. data/LICENSE.txt +504 -0
  4. data/Manifest.txt +85 -0
  5. data/PostInstall.txt +3 -0
  6. data/README.rdoc +26 -0
  7. data/Rakefile +4 -0
  8. data/bin/rubycas-server +13 -0
  9. data/bin/rubycas-server-ctl +9 -0
  10. data/config.example.yml +544 -0
  11. data/config.ru +38 -0
  12. data/config/hoe.rb +78 -0
  13. data/config/requirements.rb +15 -0
  14. data/custom_views.example.rb +11 -0
  15. data/lib/casserver.rb +58 -0
  16. data/lib/casserver/authenticators/active_directory_ldap.rb +11 -0
  17. data/lib/casserver/authenticators/base.rb +48 -0
  18. data/lib/casserver/authenticators/client_certificate.rb +46 -0
  19. data/lib/casserver/authenticators/google.rb +54 -0
  20. data/lib/casserver/authenticators/ldap.rb +147 -0
  21. data/lib/casserver/authenticators/ntlm.rb +88 -0
  22. data/lib/casserver/authenticators/open_id.rb +22 -0
  23. data/lib/casserver/authenticators/sql.rb +102 -0
  24. data/lib/casserver/authenticators/sql_encrypted.rb +77 -0
  25. data/lib/casserver/authenticators/sql_md5.rb +19 -0
  26. data/lib/casserver/authenticators/sql_rest_auth.rb +77 -0
  27. data/lib/casserver/authenticators/test.rb +19 -0
  28. data/lib/casserver/cas.rb +322 -0
  29. data/lib/casserver/conf.rb +75 -0
  30. data/lib/casserver/controllers.rb +456 -0
  31. data/lib/casserver/load_picnic.rb +19 -0
  32. data/lib/casserver/localization.rb +82 -0
  33. data/lib/casserver/models.rb +265 -0
  34. data/lib/casserver/postambles.rb +174 -0
  35. data/lib/casserver/utils.rb +30 -0
  36. data/lib/casserver/version.rb +9 -0
  37. data/lib/casserver/views.rb +245 -0
  38. data/lib/rubycas-server.rb +1 -0
  39. data/lib/rubycas-server/version.rb +1 -0
  40. data/po/de_DE/rubycas-server.po +119 -0
  41. data/po/es_ES/rubycas-server.po +115 -0
  42. data/po/fr_FR/rubycas-server.po +116 -0
  43. data/po/ja_JP/rubycas-server.po +118 -0
  44. data/po/pl_PL/rubycas-server.po +115 -0
  45. data/po/pt_BR/rubycas-server.po +115 -0
  46. data/po/ru_RU/rubycas-server.po +110 -0
  47. data/po/rubycas-server.pot +104 -0
  48. data/public/themes/cas.css +121 -0
  49. data/public/themes/notice.png +0 -0
  50. data/public/themes/ok.png +0 -0
  51. data/public/themes/simple/bg.png +0 -0
  52. data/public/themes/simple/login_box_bg.png +0 -0
  53. data/public/themes/simple/logo.png +0 -0
  54. data/public/themes/simple/theme.css +28 -0
  55. data/public/themes/urbacon/bg.png +0 -0
  56. data/public/themes/urbacon/login_box_bg.png +0 -0
  57. data/public/themes/urbacon/logo.png +0 -0
  58. data/public/themes/urbacon/theme.css +33 -0
  59. data/public/themes/warning.png +0 -0
  60. data/resources/init.d.sh +58 -0
  61. data/script/console +10 -0
  62. data/script/destroy +14 -0
  63. data/script/generate +14 -0
  64. data/script/txt2html +82 -0
  65. data/setup.rb +1585 -0
  66. data/tasks/deployment.rake +34 -0
  67. data/tasks/environment.rake +7 -0
  68. data/tasks/localization.rake +11 -0
  69. data/tasks/website.rake +17 -0
  70. data/vendor/isaac_0.9.1/LICENSE +26 -0
  71. data/vendor/isaac_0.9.1/README +78 -0
  72. data/vendor/isaac_0.9.1/TODO +3 -0
  73. data/vendor/isaac_0.9.1/VERSIONS +3 -0
  74. data/vendor/isaac_0.9.1/crypt/ISAAC.rb +171 -0
  75. data/vendor/isaac_0.9.1/isaac.gemspec +39 -0
  76. data/vendor/isaac_0.9.1/setup.rb +596 -0
  77. data/vendor/isaac_0.9.1/test/TC_ISAAC.rb +76 -0
  78. metadata +193 -0
@@ -0,0 +1,75 @@
1
+
2
+ conf_defaults = {
3
+ :maximum_unused_login_ticket_lifetime => 5.minutes,
4
+ :maximum_unused_service_ticket_lifetime => 5.minutes, # CAS Protocol Spec, sec. 3.2.1 (recommended expiry time)
5
+ :maximum_session_lifetime => 1.month, # all tickets are deleted after this period of time
6
+ :log => {:file => 'casserver.log', :level => 'DEBUG'},
7
+ :uri_path => "/"
8
+ }
9
+
10
+ if $CONF
11
+ $CONF.merge_defaults(conf_defaults)
12
+ else
13
+ unless $APP_NAME && $APP_ROOT
14
+ raise "Can't load the RubyCAS-Server configuration because $APP_NAME and/or $APP_ROOT are not defined."
15
+ end
16
+
17
+ require 'picnic/conf'
18
+ $CONF = Picnic::Conf.new(conf_defaults)
19
+ $CONF.load_from_file($APP_NAME, $APP_ROOT)
20
+ end
21
+
22
+ $AUTH = []
23
+
24
+ unless $CONF[:authenticator]
25
+ err = "
26
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
27
+
28
+ You have not yet defined an authenticator for your CAS server!
29
+ Please consult the documentation and make the necessary changes to
30
+ your config file.
31
+
32
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
33
+ "
34
+ raise Picnic::Config::Error, err
35
+ end
36
+
37
+ begin
38
+ # attempt to instantiate the authenticator
39
+ if $CONF[:authenticator].instance_of? Array
40
+ $CONF[:authenticator].each { |authenticator| $AUTH << authenticator[:class].constantize.new}
41
+ else
42
+ $AUTH << $CONF[:authenticator][:class].constantize.new
43
+ end
44
+ rescue NameError
45
+ if $CONF[:authenticator].instance_of? Array
46
+ $CONF[:authenticator].each do |authenticator|
47
+ if !authenticator[:source].nil?
48
+ # config.yml explicitly names source file
49
+ require authenticator[:source]
50
+ else
51
+ # the authenticator class hasn't yet been loaded, so lets try to load it from the casserver/authenticators directory
52
+ auth_rb = authenticator[:class].underscore.gsub('cas_server/', '')
53
+ require 'casserver/'+auth_rb
54
+ end
55
+ $AUTH << authenticator[:class].constantize.new
56
+ end
57
+ else
58
+ if $CONF[:authenticator][:source]
59
+ # config.yml explicitly names source file
60
+ require $CONF[:authenticator][:source]
61
+ else
62
+ # the authenticator class hasn't yet been loaded, so lets try to load it from the casserver/authenticators directory
63
+ auth_rb = $CONF[:authenticator][:class].underscore.gsub('cas_server/', '')
64
+ require 'casserver/'+auth_rb
65
+ end
66
+
67
+ $AUTH << $CONF[:authenticator][:class].constantize.new
68
+ end
69
+ end
70
+
71
+ $CONF[:static] = {
72
+ :urls => "/themes",
73
+ :root => "#{$APP_ROOT}/public"
74
+ }
75
+
@@ -0,0 +1,456 @@
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
+ require 'casserver/cas'
5
+
6
+ module CASServer::Controllers
7
+
8
+ # 2.1
9
+ class Login < R '/', '/login'
10
+ include CASServer::CAS
11
+
12
+ # 2.1.1
13
+ def get
14
+ CASServer::Utils::log_controller_action(self.class, input)
15
+
16
+ # make sure there's no caching
17
+ headers['Pragma'] = 'no-cache'
18
+ headers['Cache-Control'] = 'no-store'
19
+ headers['Expires'] = (Time.now - 1.year).rfc2822
20
+
21
+ # optional params
22
+ @service = clean_service_url(input['service'])
23
+ @renew = input['renew']
24
+ @gateway = input['gateway'] == 'true' || input['gateway'] == '1'
25
+
26
+ if tgc = cookies['tgt']
27
+ tgt, tgt_error = validate_ticket_granting_ticket(tgc)
28
+ end
29
+
30
+ if tgt and !tgt_error
31
+ @message = {:type => 'notice',
32
+ :message => _("You are currently logged in as '%s'. If this is not you, please log in below.") % tgt.username }
33
+ end
34
+
35
+ if input['redirection_loop_intercepted']
36
+ @message = {:type => 'mistake',
37
+ :message => _("The client and server are unable to negotiate authentication. Please try logging in again later.")}
38
+ end
39
+
40
+ begin
41
+ if @service
42
+ if !@renew && tgt && !tgt_error
43
+ st = generate_service_ticket(@service, tgt.username, tgt)
44
+ service_with_ticket = service_uri_with_ticket(@service, st)
45
+ $LOG.info("User '#{tgt.username}' authenticated based on ticket granting cookie. Redirecting to service '#{@service}'.")
46
+ return redirect(service_with_ticket, :status => 303) # response code 303 means "See Other" (see Appendix B in CAS Protocol spec)
47
+ elsif @gateway
48
+ $LOG.info("Redirecting unauthenticated gateway request to service '#{@service}'.")
49
+ return redirect(@service, :status => 303)
50
+ end
51
+ elsif @gateway
52
+ $LOG.error("This is a gateway request but no service parameter was given!")
53
+ @message = {:type => 'mistake',
54
+ :message => _("The server cannot fulfill this gateway request because no service parameter was given.")}
55
+ end
56
+ rescue URI::InvalidURIError
57
+ $LOG.error("The service '#{@service}' is not a valid URI!")
58
+ @message = {:type => 'mistake',
59
+ :message => _("The target service your browser supplied appears to be invalid. Please contact your system administrator for help.")}
60
+ end
61
+
62
+ lt = generate_login_ticket
63
+
64
+ $LOG.debug("Rendering login form with lt: #{lt}, service: #{@service}, renew: #{@renew}, gateway: #{@gateway}")
65
+
66
+ @lt = lt.ticket
67
+
68
+ #$LOG.debug(env)
69
+
70
+ # If the 'onlyLoginForm' parameter is specified, we will only return the
71
+ # login form part of the page. This is useful for when you want to
72
+ # embed the login form in some external page (as an IFRAME, or otherwise).
73
+ # The optional 'submitToURI' parameter can be given to explicitly set the
74
+ # action for the form, otherwise the server will try to guess this for you.
75
+ if input.has_key? 'onlyLoginForm'
76
+ if @env['HTTP_HOST']
77
+ guessed_login_uri = "http#{@env['HTTPS'] && @env['HTTPS'] == 'on' ? 's' : ''}://#{@env['REQUEST_URI']}#{self / '/login'}"
78
+ else
79
+ guessed_login_uri = nil
80
+ end
81
+
82
+ @form_action = input['submitToURI'] || guessed_login_uri
83
+
84
+ if @form_action
85
+ render :login_form
86
+ else
87
+ @status = 500
88
+ _("Could not guess the CAS login URI. Please supply a submitToURI parameter with your request.")
89
+ end
90
+ else
91
+ render :login
92
+ end
93
+ end
94
+
95
+ # 2.2
96
+ def post
97
+ CASServer::Utils::log_controller_action(self.class, input)
98
+
99
+ # 2.2.1 (optional)
100
+ @service = clean_service_url(input['service'])
101
+
102
+ # 2.2.2 (required)
103
+ @username = input['username']
104
+ @password = input['password']
105
+ @lt = input['lt']
106
+
107
+ # Remove leading and trailing widespace from username.
108
+ @username.strip! if @username
109
+
110
+ if @username && $CONF[:downcase_username]
111
+ $LOG.debug("Converting username #{@username.inspect} to lowercase because 'downcase_username' option is enabled.")
112
+ @username.downcase!
113
+ end
114
+
115
+ if error = validate_login_ticket(@lt)
116
+ @message = {:type => 'mistake', :message => error}
117
+ # generate another login ticket to allow for re-submitting the form
118
+ @lt = generate_login_ticket.ticket
119
+ @status = 401
120
+ return render(:login)
121
+ end
122
+
123
+ # generate another login ticket to allow for re-submitting the form after a post
124
+ @lt = generate_login_ticket.ticket
125
+
126
+ if $CONF[:authenticator].instance_of? Array
127
+ $AUTH.each_index {|auth_index| $AUTH[auth_index].configure($CONF.authenticator[auth_index])}
128
+ else
129
+ $AUTH[0].configure($CONF.authenticator)
130
+ end
131
+
132
+ $LOG.debug("Logging in with username: #{@username}, lt: #{@lt}, service: #{@service}, auth: #{$AUTH}")
133
+
134
+ credentials_are_valid = false
135
+ extra_attributes = {}
136
+ successful_authenticator = nil
137
+ begin
138
+ $AUTH.each do |auth|
139
+ credentials_are_valid = auth.validate(
140
+ :username => @username,
141
+ :password => @password,
142
+ :service => @service,
143
+ :request => @env
144
+ )
145
+ if credentials_are_valid
146
+ extra_attributes.merge!(auth.extra_attributes) unless auth.extra_attributes.blank?
147
+ successful_authenticator = auth
148
+ break
149
+ end
150
+ end
151
+ rescue CASServer::AuthenticatorError => e
152
+ $LOG.error(e)
153
+ @message = {:type => 'mistake', :message => e.to_s}
154
+ return render(:login)
155
+ end
156
+
157
+ if credentials_are_valid
158
+ $LOG.info("Credentials for username '#{@username}' successfully validated using #{successful_authenticator.class.name}.")
159
+ $LOG.debug("Authenticator provided additional user attributes: #{extra_attributes.inspect}") unless extra_attributes.blank?
160
+
161
+ # 3.6 (ticket-granting cookie)
162
+ tgt = generate_ticket_granting_ticket(@username, extra_attributes)
163
+
164
+ if $CONF.maximum_session_lifetime
165
+ expires = $CONF.maximum_session_lifetime.to_i.from_now
166
+ expiry_info = " It will expire on #{expires}."
167
+ else
168
+ expiry_info = " It will not expire."
169
+ end
170
+
171
+ if $CONF.maximum_session_lifetime
172
+ cookies['tgt'] = {
173
+ :value => tgt.to_s,
174
+ :expires => Time.now + $CONF.maximum_session_lifetime
175
+ }
176
+ else
177
+ cookies['tgt'] = tgt.to_s
178
+ end
179
+
180
+ $LOG.debug("Ticket granting cookie '#{cookies['tgt'].inspect}' granted to #{@username.inspect}. #{expiry_info}")
181
+
182
+ if @service.blank?
183
+ $LOG.info("Successfully authenticated user '#{@username}' at '#{tgt.client_hostname}'. No service param was given, so we will not redirect.")
184
+ @message = {:type => 'confirmation', :message => _("You have successfully logged in.")}
185
+ else
186
+ @st = generate_service_ticket(@service, @username, tgt)
187
+ begin
188
+ service_with_ticket = service_uri_with_ticket(@service, @st)
189
+
190
+ $LOG.info("Redirecting authenticated user '#{@username}' at '#{@st.client_hostname}' to service '#{@service}'")
191
+ return redirect(service_with_ticket, :status => 303) # response code 303 means "See Other" (see Appendix B in CAS Protocol spec)
192
+ rescue URI::InvalidURIError
193
+ $LOG.error("The service '#{@service}' is not a valid URI!")
194
+ @message = {:type => 'mistake',
195
+ :message => _("The target service your browser supplied appears to be invalid. Please contact your system administrator for help.")}
196
+ end
197
+ end
198
+ else
199
+ $LOG.warn("Invalid credentials given for user '#{@username}'")
200
+ @message = {:type => 'mistake', :message => _("Incorrect username or password.")}
201
+ @status = 401
202
+ end
203
+
204
+ render :login
205
+ end
206
+ end
207
+
208
+ # 2.3
209
+ class Logout < R '/logout'
210
+ include CASServer::CAS
211
+
212
+ # 2.3.1
213
+ def get
214
+ CASServer::Utils::log_controller_action(self.class, input)
215
+
216
+ # The behaviour here is somewhat non-standard. Rather than showing just a blank
217
+ # "logout" page, we take the user back to the login page with a "you have been logged out"
218
+ # message, allowing for an opportunity to immediately log back in. This makes it
219
+ # easier for the user to log out and log in as someone else.
220
+ @service = clean_service_url(input['service'] || input['destination'])
221
+ @continue_url = input['url']
222
+
223
+ @gateway = input['gateway'] == 'true' || input['gateway'] == '1'
224
+
225
+ tgt = CASServer::Models::TicketGrantingTicket.find_by_ticket(cookies['tgt'])
226
+
227
+ cookies.delete 'tgt'
228
+
229
+ if tgt
230
+ CASServer::Models::TicketGrantingTicket.transaction do
231
+ $LOG.debug("Deleting Service/Proxy Tickets for '#{tgt}' for user '#{tgt.username}'")
232
+ tgt.granted_service_tickets.each do |st|
233
+ send_logout_notification_for_service_ticket(st) if $CONF.enable_single_sign_out
234
+ # TODO: Maybe we should do some special handling if send_logout_notification_for_service_ticket fails?
235
+ # (the above method returns false if the POST results in a non-200 HTTP response).
236
+ $LOG.debug "Deleting #{st.class.name.demodulize} #{st.ticket.inspect} for service #{st.service}."
237
+ st.destroy
238
+ end
239
+
240
+ pgts = CASServer::Models::ProxyGrantingTicket.find(:all,
241
+ :conditions => [CASServer::Models::Base.connection.quote_table_name(CASServer::Models::ServiceTicket.table_name)+".username = ?", tgt.username],
242
+ :include => :service_ticket)
243
+ pgts.each do |pgt|
244
+ $LOG.debug("Deleting Proxy-Granting Ticket '#{pgt}' for user '#{pgt.service_ticket.username}'")
245
+ pgt.destroy
246
+ end
247
+
248
+ $LOG.debug("Deleting #{tgt.class.name.demodulize} '#{tgt}' for user '#{tgt.username}'")
249
+ tgt.destroy
250
+ end
251
+
252
+ $LOG.info("User '#{tgt.username}' logged out.")
253
+ else
254
+ $LOG.warn("User tried to log out without a valid ticket-granting ticket.")
255
+ end
256
+
257
+ @message = {:type => 'confirmation', :message => _("You have successfully logged out.")}
258
+
259
+ @message[:message] +=_(" 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 = CASServer::Controllers.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.granted_by_tgt.extra_attributes || {}
323
+ end
324
+
325
+ @status = CASServer::Controllers.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.granted_by_pgt.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.granted_by_tgt.extra_attributes || {}
365
+ end
366
+
367
+ @status = CASServer::Controllers.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 = CASServer::Controllers.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 = $CONF.themes_dir || File.expand_path(File.dirname(__FILE__))+'/../themes'
430
+ #
431
+ # def get(path)
432
+ # headers['Content-Type'] = MIME_TYPES[path[/\.\w+$/, 0]] || "text/plain"
433
+ # unless path.include? ".." # prevent directory traversal attacks
434
+ # headers['X-Sendfile'] = "#{PATH}/#{path}"
435
+ # data = File.read(headers['X-Sendfile'])
436
+ # headers['Content-Length'] = data.size.to_s # Rack Camping adapter chokes without this
437
+ # return data
438
+ # else
439
+ # status = "403"
440
+ # "403 - Invalid path"
441
+ # end
442
+ # end
443
+ # end
444
+
445
+ def response_status_from_error(error)
446
+ case error.code.to_s
447
+ when /^INVALID_/, 'BAD_PGT'
448
+ 422
449
+ when 'INTERNAL_ERROR'
450
+ 500
451
+ else
452
+ 500
453
+ end
454
+ end
455
+ module_function :response_status_from_error
456
+ end