diff options
Diffstat (limited to 'vendor/gems/omniauth-cas3/lib/omniauth/strategies/cas3/service_ticket_validator.rb')
-rw-r--r-- | vendor/gems/omniauth-cas3/lib/omniauth/strategies/cas3/service_ticket_validator.rb | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/vendor/gems/omniauth-cas3/lib/omniauth/strategies/cas3/service_ticket_validator.rb b/vendor/gems/omniauth-cas3/lib/omniauth/strategies/cas3/service_ticket_validator.rb new file mode 100644 index 00000000000..4f9a61c5216 --- /dev/null +++ b/vendor/gems/omniauth-cas3/lib/omniauth/strategies/cas3/service_ticket_validator.rb @@ -0,0 +1,103 @@ +require 'net/http' +require 'net/https' +require 'nokogiri' + +module OmniAuth + module Strategies + class CAS3 + class ServiceTicketValidator + VALIDATION_REQUEST_HEADERS = { 'Accept' => '*/*' } + + # Build a validator from a +configuration+, a + # +return_to+ URL, and a +ticket+. + # + # @param [Hash] options the OmniAuth Strategy options + # @param [String] return_to_url the URL of this CAS client service + # @param [String] ticket the service ticket to validate + def initialize(strategy, options, return_to_url, ticket) + @options = options + @uri = URI.parse(strategy.service_validate_url(return_to_url, ticket)) + end + + # Executes a network request to process the CAS Service Response + def call + @response_body = get_service_response_body + @success_body = find_authentication_success(@response_body) + self + end + + # Request validation of the ticket from the CAS server's + # serviceValidate (CAS 2.0) function. + # + # Swallows all XML parsing errors (and returns +nil+ in those cases). + # + # @return [Hash, nil] a user information hash if the response is valid; +nil+ otherwise. + # + # @raise any connection errors encountered. + def user_info + parse_user_info(@success_body) + end + + private + + # turns an `<cas:authenticationSuccess>` node into a Hash; + # returns nil if given nil + def parse_user_info(node) + return nil if node.nil? + {}.tap do |hash| + node.children.each do |e| + node_name = e.name.sub(/^cas:/, '') + unless e.kind_of?(Nokogiri::XML::Text) || node_name == 'proxies' + # There are no child elements + if e.element_children.count == 0 + hash[node_name] = e.content + elsif e.element_children.count + # JASIG style extra attributes + if node_name == 'attributes' + hash.merge!(parse_user_info(e)) + else + hash[node_name] = [] if hash[node_name].nil? + hash[node_name].push(parse_user_info(e)) + end + end + end + end + end + end + + # finds an `<cas:authenticationSuccess>` node in + # a `<cas:serviceResponse>` body if present; returns nil + # if the passed body is nil or if there is no such node. + def find_authentication_success(body) + return nil if body.nil? || body == '' + begin + doc = Nokogiri::XML(body) + begin + doc.xpath('/cas:serviceResponse/cas:authenticationSuccess') + rescue Nokogiri::XML::XPath::SyntaxError + doc.xpath('/serviceResponse/authenticationSuccess') + end + rescue Nokogiri::XML::XPath::SyntaxError + nil + end + end + + # retrieves the `<cas:serviceResponse>` XML from the CAS server + def get_service_response_body + result = '' + http = Net::HTTP.new(@uri.host, @uri.port) + http.use_ssl = @uri.port == 443 || @uri.instance_of?(URI::HTTPS) + if http.use_ssl? + http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @options.disable_ssl_verification? + http.ca_path = @options.ca_path + end + http.start do |c| + response = c.get "#{@uri.path}?#{@uri.query}", VALIDATION_REQUEST_HEADERS.dup + result = response.body + end + result + end + end + end + end +end |