#
# 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