rubycas-client 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,46 @@
1
+ = RubyCAS-Client Changelog
2
+
3
+ == Version 0.11.0
4
+
5
+ * Added this changelog to advise users of major changes to the library.
6
+
7
+ * Large chunks of the library have been re-written. Beware of the possibility
8
+ of new bugs (although the re-write was meant to fix a whole slew of existing
9
+ bugs, so you're almost certainly better off upgrading).
10
+
11
+ * service and targetService parameters in requests are now properly URI-encoded,
12
+ so the filter should behave properly when your service has query parameters.
13
+ Thanks sakazuki for pointing out the problem.
14
+
15
+ * You can now force the CAS client to re-authenticate itself with the CAS server
16
+ (i.e. override the authentication stored in the session) by providing a new
17
+ service ticket in the URI. In other words, the client will authenticate with
18
+ CAS if: a) you have a 'ticket' parameter in the URI, and there is currently no
19
+ authentication info in the session, or b) you have a 'ticket' parameter in the
20
+ URI and this ticket is different than the ticket that was used to authenticat
21
+ the existing session. This is especially useful when you are using CAS proxying,
22
+ since it allows you to force re-authentication in proxied applications (for
23
+ example, when the user has logged out and a new user has logged in in the parent
24
+ proxy-granting application).
25
+
26
+ * If your service URI has a 'ticket' parameter, it will now be automatically
27
+ removed when passing the service as a parameter in any CAS request. This is
28
+ done because at least some CAS servers will happily accept a service URI with
29
+ a 'ticket' parameter, which will result in a URI with multiple 'ticket'
30
+ parameters once you are redirected back to CAS (and that in turn can result
31
+ in an endless redirection loop).
32
+
33
+ * Logging has been greatly improved, which should make debugging your CAS
34
+ installation much easier. Look for the logs under log/cas_client_RAILS_ENV.log
35
+
36
+ * When you install RubyCAS-Client as a Rails plugin, it will now by default
37
+ use a custom logger. You can change this by explicitly setting your own
38
+ logger in your environment.rb, or by modifying the plugin's init.rb.
39
+
40
+ * CasProxyCallbackController no longer checks to make sure that the incoming
41
+ request is secure. The check is impossible since the secure header is not
42
+ passed on by at least some reverse proxies (like Pound), and if you are using
43
+ the callback controller then you are almost certainly also using a reverse
44
+ proxy.
45
+
46
+ * Cleaned up and updated documentation, fixed some example code.
data/README CHANGED
@@ -1,6 +1,6 @@
1
1
  = RubyCAS-Client
2
2
 
3
- Author:: Ola Bini <ola.bini AT ki DOT se>, Matt Zukowski <matt AT roughest DOT net>, Matt Walker <mwalker AT tamu DOT edu>
3
+ Author:: Matt Zukowski <matt AT roughest DOT net>, Ola Bini <ola.bini AT ki DOT se>, Matt Walker <mwalker AT tamu DOT edu>
4
4
  Copyright:: (c) 2006 Karolinska Institutet, portions (c) 2006 Urbacon Ltd.
5
5
  License:: GNU Lesser General Public License v2.1 (LGPL 2.1)
6
6
  Website:: http://rubyforge.org/projects/rubycas-client and http://code.google.com/p/rubycas-client
@@ -22,15 +22,16 @@ This CAS client library is designed to work easily with Rails, but can of course
22
22
  == Installing
23
23
 
24
24
  You can always download the latest version of RubyCAS-Client from the project's rubyforge page at http://rubyforge.org/projects/rubycas-client.
25
- However probably the easiest way to install CAS support into your Rails app is via the plugins facility:
25
+ However, probably the easiest way to install CAS support into your Rails app is via the plugins facility:
26
26
 
27
- ./script/plugin install http://rubycas-client.rubyforge.org/plugin/rubycas-client
27
+ ./script/plugin install http://rubycas-client.googlecode.com/svn/trunk/rubycas-client
28
28
 
29
29
  Alternatively, the library is also available as a gem, which can be installed by:
30
30
 
31
31
  gem install rubycas-client
32
32
 
33
- The latest development version is availabe via subversion:
33
+ If your Rails application is under subversion control, you can also install the plugin as an external, which will ensure that
34
+ you are always up to date:
34
35
 
35
36
  ./script/plugin install -x http://rubycas-client.googlecode.com/svn/trunk/rubycas-client
36
37
 
@@ -45,6 +46,12 @@ Somewhere in your <tt>config/environment.rb</tt> file add this (assuming that yo
45
46
  you'll need to <tt>require 'cas_auth'</tt> and <tt>require 'cas_proxy_callback_controller'</tt>):
46
47
 
47
48
  CAS::Filter.cas_base_url = "https://login.example.com/cas"
49
+
50
+ You will also probably (but not necessarily) need to specify the server name where your CAS-protected app is running:
51
+
52
+ CAS::Filter.server_name = "yourapplication.example.com:3000"
53
+
54
+ The above setting might not be necessary if your application is running on the standard port 80.
48
55
 
49
56
  Then, in your <tt>app/controllers/application.rb</tt> (or in whatever controller you want to add the CAS filter for):
50
57
 
@@ -127,14 +134,18 @@ to authenticate another application:
127
134
 
128
135
  service_uri = "http://some.other.application"
129
136
  proxy_granting_ticket = session[:casfilterpgt]
130
- ticket = CAS::Filter.request_proxy_ticket(service_uri, proxy_granting_ticket)
137
+ ticket = CAS::Filter.request_proxy_ticket(service_uri, proxy_granting_ticket).proxy_ticket
131
138
 
132
- <tt>ticket</tt> should now contain a valid service ticket. You can use it to authenticate your other by sending it and the service URI
139
+ <tt>ticket</tt> should now contain a valid service ticket. You can use it to authenticate by sending it and the service URI
133
140
  as query parameters to your target application:
134
141
 
135
- http://some.other.application?service=#{ticket.target_service}&ticket=#{ticket.proxy_ticket}
142
+ http://some.other.application?service=#{CGI.encode(ticket.target_service)}&ticket=#{ticket.proxy_ticket}
136
143
 
137
- This is of course assuming that some.other.application is also protected by the CAS filter.
144
+ This is of course assuming that some.other.application is also protected by the CAS filter.
145
+ Note that you should always URI-encode your service parameter inside URIs!
146
+
147
+ Note that CAS::Filter#request_proxy_ticket actually returns a CAS::ProxyTicketRequest object, which is why we need to call
148
+ #proxy_ticket on it to retrieve the actual service ticket.
138
149
 
139
150
  For extra security -- and you will likely want to do this on production machines in the wild -- in the proxied app's configuration
140
151
  (some.other.appliction in this example) you can specify the list of authorized proxies. For example, on your proxied app the CAS
data/init.rb CHANGED
@@ -1,12 +1,20 @@
1
1
  require 'cas_auth'
2
+ require 'cas_logger'
2
3
  require 'cas_proxy_callback_controller'
3
4
 
4
5
  #CAS::Filter.logger = RAILS_DEFAULT_LOGGER if !RAILS_DEFAULT_LOGGER.nil?
5
6
  #CAS::Filter.logger = config.logger if !config.logger.nil?
6
7
 
7
- CAS::Filter.logger = Logger.new "#{RAILS_ROOT}/log/cas_filter.log"
8
- CAS::Filter.logger.level = Logger::DEBUG
8
+ CAS::Filter.logger = CAS::Logger.new("#{RAILS_ROOT}/log/cas_client_#{RAILS_ENV}.log", 1024000)
9
+ CAS::Filter.logger.formatter = CAS::Logger::Formatter.new
10
+
11
+ #if RAILS_ENV == "production"
12
+ # CAS::Filter.logger.level = Logger::WARN
13
+ #else
14
+ CAS::Filter.logger.level = Logger::DEBUG
15
+ #end
16
+
9
17
 
10
18
  #class ActionController::Base
11
19
  # append_before_filter CAS::Filter
12
- #end
20
+ #end
data/lib/cas.rb CHANGED
@@ -57,6 +57,7 @@ module CAS
57
57
  class AbstractCASResponse
58
58
 
59
59
  def self.retrieve(uri_str)
60
+ # puts uri_str
60
61
  prs = URI.parse(uri_str)
61
62
  # puts prs.inspect
62
63
  https = Net::HTTP.new(prs.host,prs.port)
@@ -105,7 +106,7 @@ module CAS
105
106
  raise ValidationException, "must set validation URL and ticket" if validate_url.nil? || service_ticket.nil?
106
107
  clear!
107
108
  @attempted_authentication = true
108
- url_building = "#{validate_url}#{(url_building =~ /\?/)?'&':'?'}service=#{service}&ticket=#{service_ticket}"
109
+ url_building = "#{validate_url}#{(url_building =~ /\?/)?'&':'?'}service=#{CGI.escape(service)}&ticket=#{service_ticket}"
109
110
  url_building += "&pgtUrl=#{proxy_callback_url}" if proxy_callback_url
110
111
  url_building += "&renew=true" if renew
111
112
  @@entire_response = ServiceTicketValidator.retrieve url_building
@@ -169,7 +170,7 @@ module CAS
169
170
  attr_reader :proxy_ticket
170
171
 
171
172
  def request
172
- url_building = "#{proxy_url}#{(url_building =~ /\?/)?'&':'?'}targetService=#{target_service}&pgt=#{pgt}"
173
+ url_building = "#{proxy_url}#{(url_building =~ /\?/)?'&':'?'}pgt=#{pgt}&targetService=#{CGI.escape(target_service)}"
173
174
  # puts "REQUESTING:"+url_building
174
175
  @@entire_response = ServiceTicketValidator.retrieve url_building
175
176
  # puts @@entire_response.to_s
data/lib/cas_auth.rb CHANGED
@@ -1,6 +1,11 @@
1
- require 'uri'
1
+ require 'cgi'
2
2
  require 'logger'
3
3
 
4
+ # these requires are needed when outside of a Rails app context (e.g. in unit tests)
5
+ require 'rubygems'
6
+ require 'active_support'
7
+ require 'action_controller'
8
+
4
9
  require File.dirname(File.expand_path(__FILE__))+'/cas'
5
10
 
6
11
  module CAS
@@ -85,6 +90,7 @@ module CAS
85
90
 
86
91
 
87
92
  class << self
93
+
88
94
  # Retrieves the current Logger instance
89
95
  def logger
90
96
  CAS::LOGGER
@@ -92,32 +98,34 @@ module CAS
92
98
  def logger=(val)
93
99
  CAS::LOGGER.set_logger(val)
94
100
  end
95
-
101
+
96
102
  alias :log :logger
97
103
  alias :log= :logger=
98
-
104
+
99
105
  def create_logout_url
100
106
  if !@@logout_url && @@login_url =~ %r{^(.+?)/[^/]*$}
101
107
  @@logout_url = "#{$1}/logout"
102
108
  end
103
- logger.info "Created logout-url: #{@@logout_url}"
109
+ logger.info "Created logout url: #{@@logout_url}"
104
110
  end
105
111
 
106
112
  def logout_url(controller)
107
113
  create_logout_url unless @@logout_url
108
114
  url = redirect_url(controller,@@logout_url)
109
- logger.info "Using logout-url #{url}"
115
+ logger.info "Logout url is: #{url}"
110
116
  url
111
117
  end
112
118
 
113
- def logout_url=(val)
114
- @@logout_url = val
119
+ def logout_url=(url)
120
+ @@logout_url = url
121
+ logger.info "Set logout url to: #{url}"
115
122
  end
116
123
 
117
124
  def cas_base_url=(url)
118
125
  CAS::Filter.login_url = "#{url}/login"
119
126
  CAS::Filter.validate_url = "#{url}/proxyValidate"
120
127
  CAS::Filter.proxy_url = "#{url}/proxy"
128
+ logger.info "Set CAS base url to: #{url}"
121
129
  end
122
130
 
123
131
  def fake
@@ -127,14 +135,17 @@ module CAS
127
135
  def fake=(val)
128
136
  if val.nil?
129
137
  alias :filter :filter_r
138
+ logger.info "Will use real filter"
130
139
  else
131
140
  alias :filter :filter_f
141
+ logger.warn "Will use fake filter"
142
+ end
143
+ @@fake = val
132
144
  end
133
- @@fake = val
134
- end
135
-
145
+
136
146
  def filter_f(controller)
137
- logger.debug("entering fake cas filter")
147
+ logger.break
148
+ logger.warn("Using fake CAS filter")
138
149
  username = @@fake
139
150
  if :failure == @@fake
140
151
  return false
@@ -143,147 +154,244 @@ module CAS
143
154
  elsif Proc === @@fake
144
155
  username = @@fake.call(controller)
145
156
  end
146
- logger.debug("our username is: #{username}")
157
+ logger.info("The username set by the fake filter is: #{username}")
147
158
  controller.session[@@session_username] = username
148
159
  return true
149
160
  end
150
161
 
151
162
  def filter_r(controller)
152
- logger.debug("filter of controller: #{controller}")
153
- receipt = controller.session[:casfilterreceipt]
154
- logger.info("receipt: #{receipt}")
155
- valid = false
156
- if receipt
157
- valid = validate_receipt(receipt)
158
- logger.info("valid receipt?: #{valid}")
159
- else
160
- reqticket = controller.params["ticket"]
161
- logger.info("ticket: #{reqticket}")
162
- if reqticket
163
- # We temporarily allow ActionController requests to be handled concurrently.
164
- # Otherwise proxy granting ticket callbacks from CAS wouldn't work, since
165
- # the Rails server would be deadlocked while it waits for the CAS server to validate
166
- # the ticket, and the CAS server waits for the Rails server to receive the PGT callback.
167
- # Note that since the allow_concurrency option is undocumented and considered
168
- # experimental, what we're doing here may cause unforseen problems. Beware!
169
- ActionController::Base.allow_concurrency = true
170
- receipt = authenticated_user(reqticket,controller)
171
- ActionController::Base.allow_concurrency = false
163
+ logger.break
164
+ logger.info("Using real CAS filter in controller: #{controller}")
165
+ session_receipt = controller.session[:casfilterreceipt]
166
+ session_ticket = controller.session[:caslastticket]
167
+ ticket = controller.params[:ticket]
168
+
169
+ is_valid = false
170
+
171
+ if ticket and (!session_ticket or session_ticket != ticket)
172
+ log.info "A ticket parameter was given in the URI: #{ticket} and "+
173
+ (!session_ticket ? "there is no previous ticket for this session" :
174
+ "the ticket is different than the previous ticket, which was #{session_ticket}")
175
+
176
+ receipt = get_receipt_for_ticket(ticket, controller)
177
+
178
+ if receipt && validate_receipt(receipt)
179
+ logger.info("Receipt for ticket request #{ticket} is valid, belongs to user #{receipt.user_name}, and will be stored in the session.")
180
+ controller.session[:casfilterreceipt] = receipt
181
+ controller.session[:caslastticket] = ticket
182
+ controller.session[@@session_username] = receipt.user_name
172
183
 
173
- logger.info("new receipt: #{receipt}")
174
- logger.info("validate_receipt: " + validate_receipt(receipt).to_s)
175
- if receipt && validate_receipt(receipt)
176
- controller.session[:casfilterreceipt] = receipt
177
- controller.session[@@session_username] = receipt.user_name
178
-
179
- if receipt.pgt_iou
180
- ActionController::Base.allow_concurrency = true
181
- retrieve_url = "#{@@proxy_retrieval_url}?pgtIou=#{receipt.pgt_iou}"
182
- logger.info("retrieving pgt from: #{retrieve_url}")
183
- controller.session[:casfilterpgt] = CAS::ServiceTicketValidator.retrieve(retrieve_url)
184
- ActionController::Base.allow_concurrency = false
184
+ if receipt.pgt_iou
185
+ logger.info("Receipt has a proxy-granting ticket IOU. Attempting to retrieve the proxy-granting ticket...")
186
+ pgt = retrieve_pgt(receipt)
187
+ if pgt
188
+ log.debug("Got PGT #{pgt} for PGT IOU #{receipt.pgt_iou}. This will be stored in the session.")
189
+ controller.session[:casfilterpgt] = pgt
190
+ else
191
+ log.warning("Failed to retrieve a PGT for PGT IOU #{receipt.pgt_iou}!")
185
192
  end
186
-
187
- valid = true
188
193
  end
194
+
195
+ is_valid = true
189
196
  else
190
- did_gateway = controller.session[:casfiltergateway]
191
- raise CASException, "Can't redirect without login url" if !@@login_url
192
- if did_gateway
193
- if controller.session[@@session_username]
194
- valid = true
195
- else
196
- controller.session[:casfiltergateway] = true
197
- end
197
+ if receipt
198
+ log.warn "get_receipt_for_ticket() for ticket #{ticket} did not return a receipt!"
198
199
  else
200
+ log.warn "Receipt was invalid for ticket #{ticket}!"
201
+ end
202
+ end
203
+
204
+ elsif session_receipt
205
+
206
+ log.info "Validating receipt from the session because " +
207
+ (ticket ? "the given ticket #{ticket} is the same as the old ticket" : "there was no ticket given in the URI") + "."
208
+ log.debug "The session receipt is: #{session_receipt}"
209
+
210
+ is_valid = validate_receipt(session_receipt)
211
+
212
+ if is_valid
213
+ log.info "The session receipt is VALID"
214
+ else
215
+ log.warn "The session receipt is NOT VALID!"
216
+ end
217
+
218
+ else
219
+
220
+ log.info "No ticket was given and we do not have a receipt in the session."
221
+
222
+ did_gateway = controller.session[:casfiltergateway]
223
+ raise CASException, "Can't redirect without login url" unless @@login_url
224
+
225
+ if did_gateway
226
+ if controller.session[@@session_username]
227
+ log.info "We gatewayed and have a username stored in the session. The gateway was therefore successful."
228
+ is_valid = true
229
+ else
230
+ log.debug "We gatewayed but do not have a username stored in the session, so we will keep session[:casfiltergateway] true"
199
231
  controller.session[:casfiltergateway] = true
200
232
  end
233
+ else
234
+ log.info "We did not gateway, so we will notify the filter that the next request is being gatewayed by setting sesson[:casfiltergateway} to true"
235
+ controller.session[:casfiltergateway] = true
201
236
  end
237
+
238
+ end
239
+
240
+ if is_valid
241
+ logger.info "This request is successfully CAS authenticated for user #{controller.session[@@session_username]}!"
242
+ return true
243
+ else
244
+ logger.info "This request is NOT CAS authenticated, so we will redirect to the login page at: #{redirect_url(controller)}"
245
+ controller.send :redirect_to, redirect_url(controller) and return false
202
246
  end
203
- logger.info("will send redirect #{redirect_url(controller)}") if !valid
204
- controller.send :redirect_to,redirect_url(controller) if !valid
205
- return valid
206
247
  end
207
248
  alias :filter :filter_r
208
-
209
-
249
+
250
+
210
251
  def request_proxy_ticket(target_service, pgt)
211
252
  r = ProxyTicketRequest.new
212
253
  r.proxy_url = @@proxy_url
213
- r.target_service = escape_service_uri(target_service)
254
+ r.target_service = target_service
214
255
  r.pgt = pgt
215
-
216
- raise "Cannot request a proxy ticket for service #{r.target_service} because no proxy granting ticket (PGT) has been set." unless r.pgt
256
+
257
+ raise CAS::ProxyGrantingNotAvailable, "Cannot request a proxy ticket for service #{r.target_service} because no proxy granting ticket (PGT) has been set." unless r.pgt
217
258
 
218
- logger.info("requesting proxy ticket for service #{r.target_service} with pgt #{pgt}")
259
+ logger.info("Requesting proxy ticket for service: #{r.target_service} with PGT #{pgt}")
219
260
  r.request
220
261
 
221
262
  if r.proxy_ticket
222
- logger.info("got proxy ticket #{r.proxy_ticket} for service #{r.target_service}")
263
+ logger.info("Got proxy ticket #{r.proxy_ticket} for service #{r.target_service}")
223
264
  else
224
- logger.warn("did not receive a proxy ticket for service #{r.target_service}!")
265
+ logger.warn("Did not receive a proxy ticket for service #{r.target_service}!")
225
266
  end
226
267
 
227
268
  return r
228
269
  end
229
270
  end
230
271
 
272
+
273
+
231
274
  private
232
- def self.validate_receipt(receipt)
233
- if receipt
234
- logger.debug "authorized proxies: #{@@authorized_proxies.inspect}"
235
- logger.debug "proxying service: #{receipt.proxying_service.inspect}"
275
+
276
+ def self.retrieve_pgt(receipt)
277
+ retrieve_url = "#{@@proxy_retrieval_url}?pgtIou=#{receipt.pgt_iou}"
278
+
279
+ logger.debug("Will attempt to retrieve the PGT from: #{retrieve_url}")
280
+
281
+ pgt = CAS::ServiceTicketValidator.retrieve(retrieve_url)
282
+
283
+ logger.info("Retrieved the PGT: #{pgt}")
284
+
285
+ return pgt
286
+ end
287
+
288
+ def self.validate_receipt(receipt)
289
+ logger.info "Checking that the receipt is valid and coherent..."
290
+
291
+ if not receipt
292
+ logger.info "No receipt given, so the receipt is invalid"
293
+ return false
294
+ elsif @@renew && !receipt.primary_authentication?
295
+ logger.info "The filter is configured to force primary authentication (i.e. the renew options is set to true), but the receipt was not generated by primary authentication so we consider it invalid"
296
+ return false
236
297
  end
237
298
 
238
- valid = receipt && !(@@renew && !receipt.primary_authentication?)
299
+ if receipt.proxied?
300
+ logger.info "The receipt is proxied by proxying service: #{receipt.proxying_service}"
301
+
302
+ if @@authorized_proxies and !@@authorized_proxies.empty?
303
+ logger.debug "Authorized proxies are: #{@@authorized_proxies.inspect}"
304
+
305
+ if !@@authorized_proxies.include? receipt.proxying_service
306
+ logger.warn "Receipt was proxied by #{receipt_proxying_service} but this proxying service is not in the list of authorized proxies. The receipt is therefore invalid."
307
+ return false
308
+ else
309
+ logger.info "Receipt is proxied by a valid proxying service."
310
+ end
311
+ else
312
+ logger.info "No authorized proxies set, so any proxy will be considered valid"
313
+ end
314
+ else
315
+ logger.info "Receipt is not proxied"
316
+ end
239
317
 
240
- if @@authorized_proxies and !@@authorized_proxies.empty?
241
- valid = valid && !(receipt.proxied? && !@@authorized_proxies.include?(receipt.proxying_service))
318
+ return true
319
+ end
320
+
321
+ def self.get_receipt_for_ticket(ticket, controller)
322
+ logger.info "Getting receipt for ticket '#{ticket}'"
323
+ pv = ProxyTicketValidator.new
324
+ pv.validate_url = @@validate_url
325
+ pv.service_ticket = ticket
326
+ pv.service = service_url(controller)
327
+ pv.renew = @@renew
328
+ pv.proxy_callback_url = @@proxy_callback_url
329
+ receipt = nil
330
+ logger.debug "ProxyTicketValidator is: #{pv.inspect}"
331
+ begin
332
+ receipt = Receipt.new(pv)
333
+ rescue AuthenticationException => e
334
+ logger.warn("Getting a receipt for the ProxyTicketValidator threw an exception: #{e}")
242
335
  end
336
+ logger.debug "Receipt is: #{receipt.inspect}"
337
+ receipt
338
+ end
339
+
340
+ def self.service_url(controller)
341
+ unclean = @@service_url || guess_service(controller)
342
+ clean = remove_ticket_from_service_uri(unclean)
343
+ logger.debug("Service URI with ticket removed is: #{clean}")
344
+ clean
345
+ end
346
+
347
+ # FIXME: this method is really poorly named :(
348
+ def self.redirect_url(controller,url=@@login_url)
349
+ "#{url}?service=#{CGI.escape(service_url(controller))}" + ((@@renew)? "&renew=true":"") + ((@@gateway)? "&gateway=true":"") + ((@@query_string.blank?)? "" : "&"+(@@query_string.collect { |k,v| "#{k}=#{v}"}.join("&")))
350
+ end
351
+
352
+ def self.guess_service(controller)
353
+ logger.info "Guessing service based on params: #{controller.params.inspect}"
243
354
 
244
- return valid
245
- end
246
-
247
- def self.authenticated_user(tick, controller)
248
- pv = ProxyTicketValidator.new
249
- pv.validate_url = @@validate_url
250
- pv.service_ticket = tick
251
- pv.service = service_url(controller)
252
- pv.renew = @@renew
253
- pv.proxy_callback_url = @@proxy_callback_url
254
- receipt = nil
255
- logger.debug("pv: #{pv.inspect}")
256
- begin
257
- receipt = Receipt.new(pv)
258
- rescue AuthenticationException=>auth
259
- logger.warn("filter: had an authentication-exception #{auth}")
355
+ # we're assuming that controller.params[:service] is url-encoded!
356
+ if controller.params and controller.params.include? :service
357
+ service = controller.params[:service]
358
+ logger.info "We have a :service param, so we will URI-decode it and use this as the service: #{controller.params[:service]}"
359
+ return service
360
+ end
361
+
362
+ req = controller.request
363
+
364
+ if controller.params
365
+ parms = controller.params.dup
366
+ else
367
+ parms = {}
368
+ end
369
+
370
+ parms.delete("ticket")
371
+
372
+ query = (parms.collect {|key, val| "#{key}=#{val}"}).join("&")
373
+ query = "?" + query unless query.empty?
374
+
375
+ service = "#{req.protocol}#{@@server_name}#{req.request_uri.split(/\?/)[0]}#{query}"
376
+
377
+ logger.info "Guessed service is: #{service}"
378
+
379
+ return service
260
380
  end
261
- receipt
262
- end
263
- def self.service_url(controller)
264
- before = @@service_url || guess_service(controller)
265
- logger.debug("before: #{before}")
266
- after = escape_service_uri(before)
267
- logger.debug("after: #{after}")
268
- after
269
- end
270
- def self.redirect_url(controller,url=@@login_url)
271
- "#{url}?service=#{service_url(controller)}" + ((@@renew)? "&renew=true":"") + ((@@gateway)? "&gateway=true":"") + ((@@query_string.nil?)? "" : "&"+(@@query_string.collect { |k,v| "#{k}=#{v}"}.join("&")))
272
- end
273
- def self.guess_service(controller)
274
- # we're assuming that controller.params[:service] is url-encoded!
275
- return controller.params[:service] if controller.params.include? :service
276
381
 
277
- req = controller.request
278
- parms = controller.params.dup
279
- parms.delete("ticket")
280
- query = (parms.collect {|key, val| "#{key}=#{val}"}).join("&")
281
- query = "?" + query unless query.empty?
282
- "#{req.protocol}#{@@server_name}#{req.request_uri.split(/\?/)[0]}#{query}"
283
- end
284
- def self.escape_service_uri(uri)
285
- URI.encode(uri, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]", false, 'U').freeze)
286
- end
382
+ def self.escape_service_uri(uri)
383
+ URI.encode(uri, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]", false, 'U').freeze)
384
+ end
385
+
386
+ # The service URI should never have a ticket parameter, but we use this to remove
387
+ # any parameters named "ticket" just in case, as having a "ticket" parameter in the
388
+ # service URI will generally cause an infinite redirection loop.
389
+ def self.remove_ticket_from_service_uri(uri)
390
+ uri.gsub(/ticket=[^&$]*&?/, '')
391
+ end
392
+ end
393
+
394
+ class ProxyGrantingNotAvailable < Exception
287
395
  end
288
396
  end
289
397
 
data/lib/cas_logger.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'logger'
2
+
3
+ # this overrides clean_logger.rb in Rails that pretty much completely breaks logging #!@%*(#@*$&%!!...
4
+ module CAS
5
+ class Logger < ::Logger
6
+ def initialize(logdev, shift_age = 0, shift_size = 1048576)
7
+ @default_formatter = CAS::Logger::Formatter.new
8
+ super
9
+ end
10
+
11
+ def format_message(severity, datetime, progrname, msg)
12
+ (@formatter || @default_formatter).call(severity, datetime, progname, msg)
13
+ end
14
+
15
+ def break
16
+ self << "\n"
17
+ end
18
+
19
+ class Formatter < ::Logger::Formatter
20
+ Format = "[%s#%d] %5s -- %s: %s\n"
21
+
22
+ def call(severity, time, progname, msg)
23
+ Format % [format_datetime(time), $$, severity, progname, msg2str(msg)]
24
+ end
25
+ end
26
+ end
27
+ end
@@ -8,8 +8,10 @@ class CasProxyCallbackController < ActionController::Base
8
8
  # Note that this action should ALWAYS be called via https, otherwise you have a gaping security hole.
9
9
  # In fact, the JA-SIG implementation of the CAS server will refuse to send PGTs to non-https URLs.
10
10
  def receive_pgt
11
- render_error "PGTs can be received only via HTTPS or local connections." and return unless
12
- request.ssl? or request.env['REMOTE_HOST'] == "127.0.0.1"
11
+ #FIXME: these checks don't work because REMOTE_HOST doesn't work consistently under all web servers (for example it doesn't work at all under mongrel)
12
+ # ... need to find a reliable way to check if the request came through from a reverse HTTPS proxy -- until then I'm disabling this check
13
+ #render_error "PGTs can be received only via HTTPS or local connections." and return unless
14
+ # request.ssl? or request.env['REMOTE_HOST'] == "127.0.0.1"
13
15
 
14
16
  pgtIou = params['pgtIou']
15
17
  pgtId = params['pgtId']
@@ -34,8 +36,8 @@ class CasProxyCallbackController < ActionController::Base
34
36
  # in fact, the action will not work if the request is not made via SSL or is not local (we allow for local
35
37
  # non-SSL requests since this allows for the use of reverse HTTPS proxies like Pound).
36
38
  def retrieve_pgt
37
- render_error "You can only retrieve PGTs via HTTPS or local connections." and return unless
38
- request.ssl? or request.env['REMOTE_HOST'] == "127.0.0.1"
39
+ #render_error "You can only retrieve PGTs via HTTPS or local connections." and return unless
40
+ # request.ssl? or request.env['REMOTE_HOST'] == "127.0.0.1"
39
41
 
40
42
  pgtIou = params['pgtIou']
41
43
 
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.11
2
+ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: rubycas-client
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.10.1
7
- date: 2006-10-11 00:00:00 -04:00
6
+ version: 0.11.0
7
+ date: 2007-01-18 00:00:00 -05:00
8
8
  summary: Client library for the CAS single-sign-on protocol.
9
9
  require_paths:
10
10
  - lib
@@ -25,6 +25,7 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
25
25
  platform: ruby
26
26
  signing_key:
27
27
  cert_chain:
28
+ post_install_message:
28
29
  authors:
29
30
  - Matt Zukowski
30
31
  - Ola Bini
@@ -32,12 +33,14 @@ authors:
32
33
  files:
33
34
  - install.rb
34
35
  - init.rb
35
- - lib/cas_proxy_callback_controller.rb
36
36
  - lib/cas.rb
37
+ - lib/cas_proxy_callback_controller.rb
37
38
  - lib/cas_auth.rb
38
- - LICENSE
39
+ - lib/cas_logger.rb
40
+ - CHANGES
39
41
  - Rakefile
40
42
  - README
43
+ - LICENSE
41
44
  test_files: []
42
45
 
43
46
  rdoc_options: