# # Copyright (C) 2007 Mobio Networks, Inc. # # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation, either version 3 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program. If not, see . # # # This module contains custom wrapper logic on the rubycas client. Namely, we # need to enhance parsing of the serviceResponse: # # # someid # someuser # # # # In order to use this validation, we need to modify the rubycas client filter # as well as the casclient itself. # require 'rubycas-client' require 'casclient/frameworks/rails/filter' require 'casclient' require 'rmobio/utils' module Rmobio module Cas class MobioValidationResponse < CASClient::ValidationResponse attr_reader :uuid # Parse out our custom attributes def initialize(raw_text) parse(raw_text) parse_uuid(raw_text) end def parse_uuid(raw_text) raise BadResponseException, "CAS response is empty/blank." if raw_text.blank? @xml = check_and_parse_xml(raw_text) if is_success? @uuid = @xml.elements["cas:uuid"].text.strip if @xml.elements["cas:uuid"] RAILS_DEFAULT_LOGGER.info 'CAS: Successfully authenticated user ' + @uuid.to_s + '...' unless not defined? RAILS_DEFAULT_LOGGER else # this should never happen, since the response should already have # been recognized as invalid raise BadResponseException, "BAD CAS RESPONSE:\n#{raw_text.inspect}\n\nXML DOC:\n#{@xml.inspect}" end end end class Client < CASClient::Client attr_accessor :xml_response # Override service ticket validation so we use our XmlResponse def validate_service_ticket(st) RAILS_DEFAULT_LOGGER.debug 'CAS: Starting to validate service ticket...' unless not defined? RAILS_DEFAULT_LOGGER uri = URI.parse(validate_url) h = uri.query ? query_to_hash(uri.query) : {} h['service'] = st.service h['ticket'] = st.ticket h['renew'] = 1 if st.renew h['pgtUrl'] = proxy_callback_url if proxy_callback_url # Add our domain parameter h['domain'] = Rmobio::Utils.get_domain(st.service) uri.query = hash_to_query(h) # Override the validation response st.response = request_cas_response(uri, Rmobio::Cas::MobioValidationResponse) @xml_response = st.response return st end # We have to override this method because MobioValidationResponse is # uninitialized in the base class def request_cas_response(uri, type) log.debug "Requesting CAS response form URI #{uri.inspect}" uri = URI.parse(uri) unless uri.kind_of? URI https = Net::HTTP.new(uri.host, uri.port) https.use_ssl = (uri.scheme == 'https') raw_res = https.start do |conn| conn.get("#{uri.path}?#{uri.query}") end # TODO: check to make sure that response code is 200 and handle errors # otherwise RAILS_DEFAULT_LOGGER.debug "CAS Responded with " + "#{raw_res.inspect}:\n#{raw_res.body}" unless not defined? RAILS_DEFAULT_LOGGER type.new(raw_res.body) end # Override to add the domain param def add_service_to_login_url(service_url) uri = super(service_url) domain = Rmobio::Utils.get_domain(service_url) if not domain.nil? RAILS_DEFAULT_LOGGER.debug 'CAS: Adding domain parameter ' + domain + '...' unless not defined? RAILS_DEFAULT_LOGGER param_token = uri.index("?").nil? ? '?' : '&' uri << param_token + 'domain=' + domain end uri.to_s end end class MobioCasFilter < CASClient::Frameworks::Rails::Filter # Override configure so we use our cas client def self.configure(config) @@config = config @@config[:logger] = RAILS_DEFAULT_LOGGER unless @@config[:logger] @@client = Rmobio::Cas::Client.new(config) @@log = client.log end # Here's where we override the filter def self.filter(controller) RAILS_DEFAULT_LOGGER.debug 'CAS: Starting filter...' unless not defined? RAILS_DEFAULT_LOGGER @handset_id = controller.params[:handsetid] # handsetid gets appended to request uri, we need to remove it for # service validation to work controller.params.delete('handsetid') # Call filter on the base class CASClient::Frameworks::Rails::Filter.filter(controller) # Now let's put the handsetid back into the request in case we do a redirect controller.params[:handsetid] = @handset_id # Use the overloaded cas client to retrieve uuid. This should only # happen after service ticket validation. if not @@client.xml_response.nil? @uuid = @@client.xml_response.uuid end # Setup the uuid and handset_id session variables if not @uuid.nil? and not @uuid == '' and not @handset_id.nil? and not @handset_id == '' controller.session[:uuid] = @uuid controller.session[:handset_id] = @handset_id RAILS_DEFAULT_LOGGER.debug 'CAS: Stored cas uuid: ' + @uuid + ' and handset_id: ' + @handset_id + ' into the session.' unless not defined? RAILS_DEFAULT_LOGGER return true else # Should only happen on initial redirect RAILS_DEFAULT_LOGGER.debug 'CAS: MobioCasFilter cannot read the uuid/handset_id ' + 'attributes for the user!' unless not defined? RAILS_DEFAULT_LOGGER return false end end end class BadResponseException < Exception end end end include Rmobio::Cas