blob: 4f9a61c52169a1b68281b77e5676d80da0daffb8 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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
|