class Rack::Cas::Client
Attributes
mem[R]
Public Instance Methods
call(env)
click to toggle source
# File lib/rack/cas_client.rb, line 63 def call(env) if assets_request?(env); return app.call(env); end if logout_options = logout_request?(env); return logout(*logout_options) end if request = sso_request?(env); return single_sign_out(request) end if valid_session_options = authenticated?(env); return valid_session(*valid_session_options) end if xml_request?(env); return unauthorized_request end redirect_to_cas_for_authentication(env) end
Protected Instance Methods
assets_request?(env)
click to toggle source
# File lib/rack/cas_client.rb, line 103 def assets_request?(env) Rack::Request.new(env).path =~ /.*\.(js|css|png|jpg|jpeg|gif|ico)$/i end
authenticated?(env)
click to toggle source
# File lib/rack/cas_client.rb, line 164 def authenticated?(env) request = Rack::Request.new(env) @mem = request.session['cas'] || {} current_service_ticket = nil user = nil user_extra = nil new_session = true case check_service_ticket(env) when :identical log.warn("Re-using previously validated ticket since the ticket id and service are the same.") new_session = false current_service_ticket = last_service_ticket when :different log.debug "Existing local CAS session detected for #{client_username_session_key.inspect}. "+"Previous ticket #{last_service_ticket.ticket.inspect} will be re-used." new_session = false current_service_ticket = last_service_ticket else log.debug("New session!") current_service_ticket = service_ticket(env) end if current_service_ticket unless current_service_ticket.has_been_validated? log.debug("VALIDATING SERVICE TICKET") begin client.validate_service_ticket(current_service_ticket) rescue Exception => ex log.error("call to validate service ticket failed: #{ex.inspect}") return false end end vr = current_service_ticket.response if current_service_ticket.is_valid? work_for_vr_pgt_iou(vr,env) if vr.pgt_iou return [env, request, new_session, current_service_ticket] else log.warn("Ticket #{current_service_ticket.ticket.inspect} failed validation -- #{vr.failure_code}: #{vr.failure_message}") return false end else # no service ticket was present in the request if gateway log.info "Returning from CAS gateway without authentication." # unset, to allow for the next request to be authenticated if necessary sent_to_gateway = false if config[:use_gatewaying] log.info "This CAS client is configured to use gatewaying, so we will permit the user to continue without authentication." client_username_session_key = nil return true else log.warn "The CAS client is NOT configured to allow gatewaying, yet this request was gatewayed. Something is not right!" end end return false end rescue OpenSSL::SSL::SSLError log.error("SSL Error: hostname was not match with the server certificate. You can try to disable the ssl verification with a :force_ssl_verification => false in your configurations file.") return false end
casfilteruser=(value)
click to toggle source
# File lib/rack/cas_client.rb, line 327 def casfilteruser=(value) @mem['filteruser'] = value end
check_service_ticket(env)
click to toggle source
# File lib/rack/cas_client.rb, line 287 def check_service_ticket(env) st, last_st = [service_ticket(env), last_service_ticket] return :identical if st && last_st && last_st.ticket == st.ticket && last_st.service == st.service return :different if last_st && !config[:authenticate_on_every_request] && client_username_session_key end
client()
click to toggle source
# File lib/rack/cas_client.rb, line 74 def client @client ||= CASClient::Client.new(config) end
client_extra_attributes_session_key()
click to toggle source
# File lib/rack/cas_client.rb, line 321 def client_extra_attributes_session_key @mem['user_extra'] end
client_extra_attributes_session_key=(value)
click to toggle source
# File lib/rack/cas_client.rb, line 324 def client_extra_attributes_session_key=(value) @mem['user_extra'] = value end
client_username_session_key()
click to toggle source
# File lib/rack/cas_client.rb, line 314 def client_username_session_key @mem['username_session_key'] end
client_username_session_key=(value)
click to toggle source
# File lib/rack/cas_client.rb, line 317 def client_username_session_key=(value) @mem['username_session_key'] = value end
config()
click to toggle source
# File lib/rack/cas_client.rb, line 82 def config @config ||= { :cas_base_url => nil, :cas_destination_logout_param_name => nil, :logger => log, :username_session_key => nil, :extra_attributes_session_key => nil, :ticket_store => nil, :login_url => nil, :validate_url => nil, :proxy_url => nil, :logout_url => nil, :service_url => nil, :proxy_callback_url => nil, :proxy_retrieval_url => nil, :tmp_dir => nil }.merge(options) raise "You must provide the location " if @config[:enable_single_sign_out] && @config[:session_dir].nil? @config end
gateway()
click to toggle source
# File lib/rack/cas_client.rb, line 333 def gateway @mem['sent_to_gateway'] end
gateway=(value)
click to toggle source
# File lib/rack/cas_client.rb, line 330 def gateway=(value) @mem['sent_to_gateway'] = value end
last_service_ticket()
click to toggle source
# File lib/rack/cas_client.rb, line 307 def last_service_ticket @mem['last_valid_ticket'] end
last_service_ticket=(value)
click to toggle source
# File lib/rack/cas_client.rb, line 310 def last_service_ticket=(value) @mem['last_valid_ticket'] = value end
log()
click to toggle source
# File lib/rack/cas_client.rb, line 78 def log @logger ||= Rails.logger rescue ::Logger.new(STDOUT) end
login_url(env)
click to toggle source
Returns the login URL for the current controller. Useful when you want to provide a “Login” link in a GatewayFilter’ed action.
# File lib/rack/cas_client.rb, line 409 def login_url(env) url = client.add_service_to_login_url(service_url(env)) log.debug("Generated login url: #{url}") return url end
logout(st, request)
click to toggle source
# File lib/rack/cas_client.rb, line 115 def logout(st, request) log.debug("Logging out!!") log.debug("looking up st for deletion #{st.inspect}") delete_service_session_lookup(st) if st request.session.delete('cas') response = Rack::Response.new response.redirect(client.logout_url(request.referer)) response.finish end
logout_request?(env)
click to toggle source
# File lib/rack/cas_client.rb, line 107 def logout_request?(env) request = Rack::Request.new(env) if request.path == '/logout' && request.delete? st = request.session['cas']['last_valid_ticket'] [st, request] end end
previous_redirect_to_cas()
click to toggle source
# File lib/rack/cas_client.rb, line 336 def previous_redirect_to_cas @mem['previous_redirect'] end
previous_redirect_to_cas=(value)
click to toggle source
# File lib/rack/cas_client.rb, line 339 def previous_redirect_to_cas=(value) @mem['cas']['previous_redirect'] = value end
redirect_to_cas_for_authentication(env)
click to toggle source
# File lib/rack/cas_client.rb, line 375 def redirect_to_cas_for_authentication(env) redirect_url = login_url(env) if config[:use_gatewaying] gateway = true redirect_url << "&gateway=true" else gateway = false end if previous_redirect_to_cas && previous_redirect_to_cas > (Time.now - 1.second) log.warn("Previous redirect to the CAS server was less than a second ago. The client at #{controller.request.remote_ip.inspect} may be stuck in a redirection loop!") if validation_retry > 3 log.error("Redirection loop intercepted. Client at #{controller.request.remote_ip.inspect} will be redirected back to login page and forced to renew authentication.") redirect_url += "&renew=1&redirection_loop_intercepted=1" end validation_retry = validation_retry + 1 else validation_retry = 0 end previous_redirect_to_cas = Time.now request = Rack::Request.new(env) response = Rack::Response.new(["redirect to #{redirect_url}"],302, {'Location' => redirect_url, 'Content-Type' => 'text/plain'}) return response.finish end
service_ticket(env)
click to toggle source
# File lib/rack/cas_client.rb, line 294 def service_ticket(env) request = Rack::Request.new(env) ticket = request.params['ticket'] return unless ticket if ticket =~ /^PT-/ CASClient::ProxyTicket.new(ticket, service_url(env), request.params.delete('renew')) else CASClient::ServiceTicket.new(ticket, service_url(env), request.params.delete('renew')) end end
service_url(env)
click to toggle source
# File lib/rack/cas_client.rb, line 357 def service_url(env) return @service_url if @service_url if config[:service_url] log.debug("Using explicitly set service url: #{config[:service_url]}") return @service_url = config[:service_url] end request = Rack::Request.new(env) params = request.params.dup params.delete(:ticket) url = URI.const_get(request.scheme.upcase).build(:host => request.host, :port => request.port, :path => request.path, :query => request.query_string) @service_url = url.to_s log.debug("Guessed service url: #{@service_url}") @service_url end
single_sign_out(request)
click to toggle source
# File lib/rack/cas_client.rb, line 132 def single_sign_out(request) log.debug("SINGLE SIGN OUT") logoutRequest = URI.unescape(request.params['logoutRequest']) md = logoutRequest.match( %r{^<samlp:LogoutRequest.*?<samlp:SessionIndex>(.*)</samlp:SessionIndex>}m ) if md && md[1] ticket = md[1] done = delete_service_session_lookup(ticket) if done [200,{'Content-type' => 'text/plain'},['session deleted']] else [404,{'Content-type' => 'text/plain'},['session not found']] end else [400,{'Content-type' => 'text/plain'},['missing service ticket in request']] end end
sso_request?(env)
click to toggle source
# File lib/rack/cas_client.rb, line 127 def sso_request?(env) request = Rack::Request.new(env) request if request.post? && request.params['logoutRequest'] end
valid_session(env, request, new_session, current_service_ticket)
click to toggle source
# File lib/rack/cas_client.rb, line 239 def valid_session(env, request, new_session, current_service_ticket) cas_resp = current_service_ticket.response log.info("Ticket #{current_service_ticket.ticket.inspect} for service #{current_service_ticket.service.inspect} belonging to user #{cas_resp.user.inspect} is VALID.") env['rack.cas.client.user'] = cas_resp.user env['rack.cas.client.user_extra'] = cas_resp.extra_attributes.dup # TODO: remove ticket params from env status, headers, body = app.call(env) response = Rack::Response.new(body, status, headers) # only modify the session when it's a new_session if new_session session = request.session session['cas'] = {'last_valid_ticket' => current_service_ticket, 'filteruser' => cas_resp.user, 'username_session_key' => cas_resp.user} if config[:enable_single_sign_out] f = store_service_session_lookup(current_service_ticket, session) log.debug("Wrote service session lookup file to #{f.inspect} with session id #{session.inspect}.") end response.delete_cookie(request.session_options[:key], {}) response.set_cookie(request.session_options[:key], session) end response.finish end
validation_retry()
click to toggle source
# File lib/rack/cas_client.rb, line 342 def validation_retry @mem['validation_retry'] || 0 end
validation_retry=(value)
click to toggle source
# File lib/rack/cas_client.rb, line 345 def validation_retry=(value) @mem['validation_retry'] = value end
vr()
click to toggle source
# File lib/rack/cas_client.rb, line 349 def vr @vr end
vr=(value)
click to toggle source
# File lib/rack/cas_client.rb, line 353 def vr=(value) @vr = value end
work_for_vr_pgt_iou(vr,env)
click to toggle source
# File lib/rack/cas_client.rb, line 266 def work_for_vr_pgt_iou(vr,env) log.debug("CALLING work_for_vr_pgt_iou with vr #{vr.inspect}") request = Rack::Request.new(env) unless request.session[:cas_pgt] && request.session[:cas_pgt].ticket && request.session[:cas_pgt].iou == vr.pgt_iou log.info("Receipt has a proxy-granting ticket IOU. Attempting to retrieve the proxy-granting ticket...") pgt = client.retrieve_proxy_granting_ticket(vr.pgt_iou) if pgt log.debug("Got PGT #{pgt.ticket.inspect} for PGT IOU #{pgt.iou.inspect}. This will be stored in the session.") request.session[:cas_pgt] = pgt # For backwards compatibility with RubyCAS-Client 1.x configurations... request.session[:casfilterpgt] = pgt else log.error("Failed to retrieve a PGT for PGT IOU #{vr.pgt_iou}!") end else log.info("PGT is present in session and PGT IOU #{vr.pgt_iou} matches the saved PGT IOU. Not retrieving new PGT.") end end
xml_request?(env)
click to toggle source
# File lib/rack/cas_client.rb, line 159 def xml_request?(env) Rack::Request.new(env).params[:format] == "xml" end