Permalink
Browse files

working on Rails filter...

git-svn-id: https://rubycas-client.googlecode.com/svn/branches/2.x@109 e5935e18-7a1f-0410-a9c8-d10ac5b774bc
  • Loading branch information...
1 parent 5e7af37 commit 43147ff1152197797a0541e67d345a7ed7038b8c matt.zukowski committed Jan 10, 2008
Showing with 108 additions and 32 deletions.
  1. +3 −2 init.rb
  2. +27 −1 lib/casclient.rb
  3. +66 −23 lib/casclient/adapters/rails/filter.rb
  4. +12 −6 lib/casclient/client.rb
View
@@ -1,5 +1,6 @@
# This file makes it possible to install RubyCAS-Client as a Rails plugin.
-$: << File.expand_path(File.basedir(__FILE__))+'/lib'
+$: << File.expand_path(File.dirname(__FILE__))+'/lib'
-require 'casclient'
+require 'casclient'
+require 'casclient/adapters/rails/filter'
View
@@ -16,9 +16,35 @@ module CASClient
class CASException < Exception
end
+ # Customized logger for the client.
+ # This is useful if you're trying to do logging in Rails, since Rails'
+ # clean_logger.rb pretty much completely breaks the base Logger class.
+ class Logger < ::Logger
+ def initialize(logdev, shift_age = 0, shift_size = 1048576)
+ @default_formatter = Formatter.new
+ super
+ end
+
+ def format_message(severity, datetime, progrname, msg)
+ (@formatter || @default_formatter).call(severity, datetime, progname, msg)
+ end
+
+ def break
+ self << $/
+ end
+
+ class Formatter < ::Logger::Formatter
+ Format = "[%s#%d] %5s -- %s: %s\n"
+
+ def call(severity, time, progname, msg)
+ Format % [format_datetime(time), $$, severity, progname, msg2str(msg)]
+ end
+ end
+ end
+
# Wraps a real Logger. If no real Logger is set, then this wrapper
# will quietly swallow any logging calls.
- class Logger
+ class LoggerWrapper
def initialize(real_logger=nil)
set_logger(real_logger)
end
@@ -3,35 +3,78 @@ module Adapters
module Rails
class Filter
@@config = nil
- cattr_reader :config
+ @@log = nil
+ cattr_reader :config, :log
- def self.filter(controller)
- raise "Cannot use the CASClient filter because it has not yet been configured." if config.nil?
-
- client = CASClient::Client.new(config)
- log = client.log
+ class << self
+ def filter(controller)
+ raise "Cannot use the CASClient filter because it has not yet been configured." if config.nil?
+
+ client = CASClient::Client.new(config)
+ @@log = client.log
+
+ ticket = read_ticket(controller)
+
+ if ticket
+ client.validate_service_ticket(ticket)
+ vr = ticket.response
+ if ticket.is_valid?
+ log.info("Ticket #{ticket.ticket.inspect} for service #{ticket.service.inspect} belonging to user #{vr.user.inspect} was successfully validated.")
+ controller.session[client.session_username_key] = vr.user
+ controller.session[client.session_username_key] = vr.extra_attributes
+
+ # RubyCAS-Client 1.x used :casfilteruser as it's session username key,
+ # so we need to set this here to ensure compatibility with configurations
+ # built around the old client.
+ controller.session[:casfilteruser] = vr.user
+ else
+ log.warn("Ticket #{ticket.ticket.inspect} failed validation -- #{vr.failure_code}: #{vr.failure_message}")
+ redirect_to_cas_for_authentication(controller, client)
+ return false
+ end
+ else
+ redirect_to_cas_for_authentication(controller, client)
+ return false
+ end
+ end
- ticket = controller.params[:ticket]
+ def configure(config)
+ @@config = config
+ @@config[:logger] = RAILS_DEFAULT_LOGGER unless @@config[:logger]
+ end
- if ticket
- vr = client.validate_service_ticket(ticket)
- if vr.is_successful?
- log.info("Ticket #{ticket.inspect} for service #{vr.service} belonging to user #{vr.inspect} was successfully validated.")
- controllers.session[client.session_username_key] = vr.user
- controllers.session[client.session_username_key] = vr.extra_attributes
-
- # RubyCAS-Client 1.x used :casfilteruser as it's session username key,
- # so we need to set this here to ensure compatibility with configurations
- # built around the old client.
- controllers.session[:casfilteruser] = vr.user
+ private
+ def read_ticket(controller)
+ ticket = controller.params[:ticket]
+
+ return nil unless ticket
+
+ if ticket =~ /^PT-/
+ ProxyTicket.new(ticket, read_service_url(controller), pgt_url, controller.params[:renew])
else
- log.warn("Ticket #{ticket.inspect} failed validation: #{vr.failure_code}: #{vr.failure_message}")
+ ServiceTicket.new(ticket, read_service_url(controller), controller.params[:renew])
end
end
- end
-
- def self.configure(config)
- @@config = config
+
+ def read_service_url(controller)
+ if config[:service]
+ log.debug("Using explicitly set service url: #{config[:service]}")
+ return config[:service]
+ end
+
+ params = controller.params.dup
+ params.delete(:ticket)
+ service_url = controller.url_for(params)
+ log.debug("Guessed service url: #{service_url.inspect}")
+ return service_url
+ end
+
+ def redirect_to_cas_for_authentication(controller, client)
+ service_url = read_service_url(controller)
+ redirect_url = client.add_service_to_login_url(service_url)
+ log.debug("Redirecting to #{redirect_url.inspect}")
+ controller.send(:redirect_to, redirect_url)
+ end
end
end
end
@@ -12,7 +12,7 @@ def initialize(conf = nil)
def configure(conf)
raise ArgumentError, "Missing :cas_base_url parameter!" unless conf[:cas_base_url]
- @cas_url = conf[:cas_base_url].gsub(/\/$/, '')
+ @cas_base_url = conf[:cas_base_url].gsub(/\/$/, '')
@login_url = conf[:login_url]
@validate_url = conf[:validate_url]
@@ -22,7 +22,7 @@ def configure(conf)
@session_username_key = conf[:session_username_key] || :cas_user
@session_extra_attributes_key = conf[:session_extra_attributes_key] || :cas_extra_attributes
- @log = CASClient::Logger.new
+ @log = CASClient::LoggerWrapper.new
@log.set_real_logger(conf[:logger]) if conf[:logger]
end
@@ -43,7 +43,7 @@ def proxy_url
end
def validate_service_ticket(st)
- uri = URI.parse(@validate_url)
+ uri = URI.parse(validate_url)
h = uri.query ? query_to_hash(uri.query) : {}
h['service'] = st.service
h['ticket'] = st.ticket
@@ -66,7 +66,7 @@ def login_to_service(credentials, service)
:service => service
)
- res = submit_data_to_cas(@login_url, data)
+ res = submit_data_to_cas(login_url, data)
CASClient::LoginResponse.new(res)
end
@@ -76,7 +76,7 @@ def login_to_service(credentials, service)
# This only works with RubyCAS-Server, since obtaining login
# tickets in this manner is not part of the official CAS spec.
def request_login_ticket
- uri = URI.parse(@login_url+'Ticket')
+ uri = URI.parse(login_url+'Ticket')
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = (uri.scheme == 'https')
res = https.post(uri.path, ';')
@@ -93,7 +93,7 @@ def request_login_ticket
# The pgt required to request a proxy ticket is obtained as part of
# a ValidationResponse.
def request_proxy_ticket(pgt, target_service)
- uri = URI.parse(@login_url+'Ticket')
+ uri = URI.parse(login_url+'Ticket')
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = (uri.scheme == 'https')
res = https.post(uri.path, ';')
@@ -103,6 +103,12 @@ def request_proxy_ticket(pgt, target_service)
res.body.strip
end
+ def add_service_to_login_url(service_url)
+ uri = URI.parse(login_url)
+ uri.query = (uri.query ? uri.query + "&" : "") + "service=#{CGI.escape(service_url)}"
+ uri.to_s
+ end
+
private
# Fetches a CAS ValidationResponse from the given URI.
def request_cas_response(uri)

0 comments on commit 43147ff

Please sign in to comment.