mirror of
https://github.com/TracksApp/tracks.git
synced 2026-01-04 08:18:50 +01:00
Upgraded to open_id_authentication plugin at 00d8bc7f97 and unpacked ruby-openid gem version 2.1.2.
This commit is contained in:
parent
6149900e0c
commit
e92dae2ffc
227 changed files with 30857 additions and 669 deletions
490
vendor/gems/ruby-openid-2.1.2/lib/openid/consumer/discovery.rb
vendored
Normal file
490
vendor/gems/ruby-openid-2.1.2/lib/openid/consumer/discovery.rb
vendored
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
# Functions to discover OpenID endpoints from identifiers.
|
||||
|
||||
require 'uri'
|
||||
require 'openid/util'
|
||||
require 'openid/fetchers'
|
||||
require 'openid/urinorm'
|
||||
require 'openid/message'
|
||||
require 'openid/yadis/discovery'
|
||||
require 'openid/yadis/xrds'
|
||||
require 'openid/yadis/xri'
|
||||
require 'openid/yadis/services'
|
||||
require 'openid/yadis/filters'
|
||||
require 'openid/consumer/html_parse'
|
||||
require 'openid/yadis/xrires'
|
||||
|
||||
module OpenID
|
||||
|
||||
OPENID_1_0_NS = 'http://openid.net/xmlns/1.0'
|
||||
OPENID_IDP_2_0_TYPE = 'http://specs.openid.net/auth/2.0/server'
|
||||
OPENID_2_0_TYPE = 'http://specs.openid.net/auth/2.0/signon'
|
||||
OPENID_1_1_TYPE = 'http://openid.net/signon/1.1'
|
||||
OPENID_1_0_TYPE = 'http://openid.net/signon/1.0'
|
||||
|
||||
OPENID_1_0_MESSAGE_NS = OPENID1_NS
|
||||
OPENID_2_0_MESSAGE_NS = OPENID2_NS
|
||||
|
||||
# Object representing an OpenID service endpoint.
|
||||
class OpenIDServiceEndpoint
|
||||
|
||||
# OpenID service type URIs, listed in order of preference. The
|
||||
# ordering of this list affects yadis and XRI service discovery.
|
||||
OPENID_TYPE_URIS = [
|
||||
OPENID_IDP_2_0_TYPE,
|
||||
|
||||
OPENID_2_0_TYPE,
|
||||
OPENID_1_1_TYPE,
|
||||
OPENID_1_0_TYPE,
|
||||
]
|
||||
|
||||
# the verified identifier.
|
||||
attr_accessor :claimed_id
|
||||
|
||||
# For XRI, the persistent identifier.
|
||||
attr_accessor :canonical_id
|
||||
|
||||
attr_accessor :server_url, :type_uris, :local_id, :used_yadis
|
||||
|
||||
def initialize
|
||||
@claimed_id = nil
|
||||
@server_url = nil
|
||||
@type_uris = []
|
||||
@local_id = nil
|
||||
@canonical_id = nil
|
||||
@used_yadis = false # whether this came from an XRDS
|
||||
@display_identifier = nil
|
||||
end
|
||||
|
||||
def display_identifier
|
||||
return @display_identifier if @display_identifier
|
||||
|
||||
return @claimed_id if @claimed_id.nil?
|
||||
|
||||
begin
|
||||
parsed_identifier = URI.parse(@claimed_id)
|
||||
rescue URI::InvalidURIError
|
||||
raise ProtocolError, "Claimed identifier #{claimed_id} is not a valid URI"
|
||||
end
|
||||
|
||||
return @claimed_id if not parsed_identifier.fragment
|
||||
|
||||
disp = parsed_identifier
|
||||
disp.fragment = nil
|
||||
|
||||
return disp.to_s
|
||||
end
|
||||
|
||||
def display_identifier=(display_identifier)
|
||||
@display_identifier = display_identifier
|
||||
end
|
||||
|
||||
def uses_extension(extension_uri)
|
||||
return @type_uris.member?(extension_uri)
|
||||
end
|
||||
|
||||
def preferred_namespace
|
||||
if (@type_uris.member?(OPENID_IDP_2_0_TYPE) or
|
||||
@type_uris.member?(OPENID_2_0_TYPE))
|
||||
return OPENID_2_0_MESSAGE_NS
|
||||
else
|
||||
return OPENID_1_0_MESSAGE_NS
|
||||
end
|
||||
end
|
||||
|
||||
def supports_type(type_uri)
|
||||
# Does this endpoint support this type?
|
||||
#
|
||||
# I consider C{/server} endpoints to implicitly support C{/signon}.
|
||||
(
|
||||
@type_uris.member?(type_uri) or
|
||||
(type_uri == OPENID_2_0_TYPE and is_op_identifier())
|
||||
)
|
||||
end
|
||||
|
||||
def compatibility_mode
|
||||
return preferred_namespace() != OPENID_2_0_MESSAGE_NS
|
||||
end
|
||||
|
||||
def is_op_identifier
|
||||
return @type_uris.member?(OPENID_IDP_2_0_TYPE)
|
||||
end
|
||||
|
||||
def parse_service(yadis_url, uri, type_uris, service_element)
|
||||
# Set the state of this object based on the contents of the
|
||||
# service element.
|
||||
@type_uris = type_uris
|
||||
@server_url = uri
|
||||
@used_yadis = true
|
||||
|
||||
if !is_op_identifier()
|
||||
# XXX: This has crappy implications for Service elements that
|
||||
# contain both 'server' and 'signon' Types. But that's a
|
||||
# pathological configuration anyway, so I don't think I care.
|
||||
@local_id = OpenID.find_op_local_identifier(service_element,
|
||||
@type_uris)
|
||||
@claimed_id = yadis_url
|
||||
end
|
||||
end
|
||||
|
||||
def get_local_id
|
||||
# Return the identifier that should be sent as the
|
||||
# openid.identity parameter to the server.
|
||||
if @local_id.nil? and @canonical_id.nil?
|
||||
return @claimed_id
|
||||
else
|
||||
return (@local_id or @canonical_id)
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_basic_service_endpoint(endpoint)
|
||||
# Create a new instance of this class from the endpoint object
|
||||
# passed in.
|
||||
#
|
||||
# @return: nil or OpenIDServiceEndpoint for this endpoint object"""
|
||||
|
||||
type_uris = endpoint.match_types(OPENID_TYPE_URIS)
|
||||
|
||||
# If any Type URIs match and there is an endpoint URI specified,
|
||||
# then this is an OpenID endpoint
|
||||
if (!type_uris.nil? and !type_uris.empty?) and !endpoint.uri.nil?
|
||||
openid_endpoint = self.new
|
||||
openid_endpoint.parse_service(
|
||||
endpoint.yadis_url,
|
||||
endpoint.uri,
|
||||
endpoint.type_uris,
|
||||
endpoint.service_element)
|
||||
else
|
||||
openid_endpoint = nil
|
||||
end
|
||||
|
||||
return openid_endpoint
|
||||
end
|
||||
|
||||
def self.from_html(uri, html)
|
||||
# Parse the given document as HTML looking for an OpenID <link
|
||||
# rel=...>
|
||||
#
|
||||
# @rtype: [OpenIDServiceEndpoint]
|
||||
|
||||
discovery_types = [
|
||||
[OPENID_2_0_TYPE, 'openid2.provider', 'openid2.local_id'],
|
||||
[OPENID_1_1_TYPE, 'openid.server', 'openid.delegate'],
|
||||
]
|
||||
|
||||
link_attrs = OpenID.parse_link_attrs(html)
|
||||
services = []
|
||||
discovery_types.each { |type_uri, op_endpoint_rel, local_id_rel|
|
||||
|
||||
op_endpoint_url = OpenID.find_first_href(link_attrs, op_endpoint_rel)
|
||||
|
||||
if !op_endpoint_url
|
||||
next
|
||||
end
|
||||
|
||||
service = self.new
|
||||
service.claimed_id = uri
|
||||
service.local_id = OpenID.find_first_href(link_attrs, local_id_rel)
|
||||
service.server_url = op_endpoint_url
|
||||
service.type_uris = [type_uri]
|
||||
|
||||
services << service
|
||||
}
|
||||
|
||||
return services
|
||||
end
|
||||
|
||||
def self.from_xrds(uri, xrds)
|
||||
# Parse the given document as XRDS looking for OpenID services.
|
||||
#
|
||||
# @rtype: [OpenIDServiceEndpoint]
|
||||
#
|
||||
# @raises L{XRDSError}: When the XRDS does not parse.
|
||||
return Yadis::apply_filter(uri, xrds, self)
|
||||
end
|
||||
|
||||
def self.from_discovery_result(discoveryResult)
|
||||
# Create endpoints from a DiscoveryResult.
|
||||
#
|
||||
# @type discoveryResult: L{DiscoveryResult}
|
||||
#
|
||||
# @rtype: list of L{OpenIDServiceEndpoint}
|
||||
#
|
||||
# @raises L{XRDSError}: When the XRDS does not parse.
|
||||
if discoveryResult.is_xrds()
|
||||
meth = self.method('from_xrds')
|
||||
else
|
||||
meth = self.method('from_html')
|
||||
end
|
||||
|
||||
return meth.call(discoveryResult.normalized_uri,
|
||||
discoveryResult.response_text)
|
||||
end
|
||||
|
||||
def self.from_op_endpoint_url(op_endpoint_url)
|
||||
# Construct an OP-Identifier OpenIDServiceEndpoint object for
|
||||
# a given OP Endpoint URL
|
||||
#
|
||||
# @param op_endpoint_url: The URL of the endpoint
|
||||
# @rtype: OpenIDServiceEndpoint
|
||||
service = self.new
|
||||
service.server_url = op_endpoint_url
|
||||
service.type_uris = [OPENID_IDP_2_0_TYPE]
|
||||
return service
|
||||
end
|
||||
|
||||
def to_s
|
||||
return sprintf("<%s server_url=%s claimed_id=%s " +
|
||||
"local_id=%s canonical_id=%s used_yadis=%s>",
|
||||
self.class, @server_url, @claimed_id,
|
||||
@local_id, @canonical_id, @used_yadis)
|
||||
end
|
||||
end
|
||||
|
||||
def self.find_op_local_identifier(service_element, type_uris)
|
||||
# Find the OP-Local Identifier for this xrd:Service element.
|
||||
#
|
||||
# This considers openid:Delegate to be a synonym for xrd:LocalID
|
||||
# if both OpenID 1.X and OpenID 2.0 types are present. If only
|
||||
# OpenID 1.X is present, it returns the value of
|
||||
# openid:Delegate. If only OpenID 2.0 is present, it returns the
|
||||
# value of xrd:LocalID. If there is more than one LocalID tag and
|
||||
# the values are different, it raises a DiscoveryFailure. This is
|
||||
# also triggered when the xrd:LocalID and openid:Delegate tags are
|
||||
# different.
|
||||
|
||||
# XXX: Test this function on its own!
|
||||
|
||||
# Build the list of tags that could contain the OP-Local
|
||||
# Identifier
|
||||
local_id_tags = []
|
||||
if type_uris.member?(OPENID_1_1_TYPE) or
|
||||
type_uris.member?(OPENID_1_0_TYPE)
|
||||
# local_id_tags << Yadis::nsTag(OPENID_1_0_NS, 'openid', 'Delegate')
|
||||
service_element.add_namespace('openid', OPENID_1_0_NS)
|
||||
local_id_tags << "openid:Delegate"
|
||||
end
|
||||
|
||||
if type_uris.member?(OPENID_2_0_TYPE)
|
||||
# local_id_tags.append(Yadis::nsTag(XRD_NS_2_0, 'xrd', 'LocalID'))
|
||||
service_element.add_namespace('xrd', Yadis::XRD_NS_2_0)
|
||||
local_id_tags << "xrd:LocalID"
|
||||
end
|
||||
|
||||
# Walk through all the matching tags and make sure that they all
|
||||
# have the same value
|
||||
local_id = nil
|
||||
local_id_tags.each { |local_id_tag|
|
||||
service_element.each_element(local_id_tag) { |local_id_element|
|
||||
if local_id.nil?
|
||||
local_id = local_id_element.text
|
||||
elsif local_id != local_id_element.text
|
||||
format = 'More than one %s tag found in one service element'
|
||||
message = sprintf(format, local_id_tag)
|
||||
raise DiscoveryFailure.new(message, nil)
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
return local_id
|
||||
end
|
||||
|
||||
def self.normalize_url(url)
|
||||
# Normalize a URL, converting normalization failures to
|
||||
# DiscoveryFailure
|
||||
begin
|
||||
normalized = URINorm.urinorm(url)
|
||||
rescue URI::Error => why
|
||||
raise DiscoveryFailure.new("Error normalizing #{url}: #{why.message}", nil)
|
||||
else
|
||||
defragged = URI::parse(normalized)
|
||||
defragged.fragment = nil
|
||||
return defragged.normalize.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def self.best_matching_service(service, preferred_types)
|
||||
# Return the index of the first matching type, or something higher
|
||||
# if no type matches.
|
||||
#
|
||||
# This provides an ordering in which service elements that contain
|
||||
# a type that comes earlier in the preferred types list come
|
||||
# before service elements that come later. If a service element
|
||||
# has more than one type, the most preferred one wins.
|
||||
preferred_types.each_with_index { |value, index|
|
||||
if service.type_uris.member?(value)
|
||||
return index
|
||||
end
|
||||
}
|
||||
|
||||
return preferred_types.length
|
||||
end
|
||||
|
||||
def self.arrange_by_type(service_list, preferred_types)
|
||||
# Rearrange service_list in a new list so services are ordered by
|
||||
# types listed in preferred_types. Return the new list.
|
||||
|
||||
# Build a list with the service elements in tuples whose
|
||||
# comparison will prefer the one with the best matching service
|
||||
prio_services = []
|
||||
|
||||
service_list.each_with_index { |s, index|
|
||||
prio_services << [best_matching_service(s, preferred_types), index, s]
|
||||
}
|
||||
|
||||
prio_services.sort!
|
||||
|
||||
# Now that the services are sorted by priority, remove the sort
|
||||
# keys from the list.
|
||||
(0...prio_services.length).each { |i|
|
||||
prio_services[i] = prio_services[i][2]
|
||||
}
|
||||
|
||||
return prio_services
|
||||
end
|
||||
|
||||
def self.get_op_or_user_services(openid_services)
|
||||
# Extract OP Identifier services. If none found, return the rest,
|
||||
# sorted with most preferred first according to
|
||||
# OpenIDServiceEndpoint.openid_type_uris.
|
||||
#
|
||||
# openid_services is a list of OpenIDServiceEndpoint objects.
|
||||
#
|
||||
# Returns a list of OpenIDServiceEndpoint objects.
|
||||
|
||||
op_services = arrange_by_type(openid_services, [OPENID_IDP_2_0_TYPE])
|
||||
|
||||
openid_services = arrange_by_type(openid_services,
|
||||
OpenIDServiceEndpoint::OPENID_TYPE_URIS)
|
||||
|
||||
if !op_services.empty?
|
||||
return op_services
|
||||
else
|
||||
return openid_services
|
||||
end
|
||||
end
|
||||
|
||||
def self.discover_yadis(uri)
|
||||
# Discover OpenID services for a URI. Tries Yadis and falls back
|
||||
# on old-style <link rel='...'> discovery if Yadis fails.
|
||||
#
|
||||
# @param uri: normalized identity URL
|
||||
# @type uri: str
|
||||
#
|
||||
# @return: (claimed_id, services)
|
||||
# @rtype: (str, list(OpenIDServiceEndpoint))
|
||||
#
|
||||
# @raises DiscoveryFailure: when discovery fails.
|
||||
|
||||
# Might raise a yadis.discover.DiscoveryFailure if no document
|
||||
# came back for that URI at all. I don't think falling back to
|
||||
# OpenID 1.0 discovery on the same URL will help, so don't bother
|
||||
# to catch it.
|
||||
response = Yadis.discover(uri)
|
||||
|
||||
yadis_url = response.normalized_uri
|
||||
body = response.response_text
|
||||
|
||||
begin
|
||||
openid_services = OpenIDServiceEndpoint.from_xrds(yadis_url, body)
|
||||
rescue Yadis::XRDSError
|
||||
# Does not parse as a Yadis XRDS file
|
||||
openid_services = []
|
||||
end
|
||||
|
||||
if openid_services.empty?
|
||||
# Either not an XRDS or there are no OpenID services.
|
||||
|
||||
if response.is_xrds
|
||||
# if we got the Yadis content-type or followed the Yadis
|
||||
# header, re-fetch the document without following the Yadis
|
||||
# header, with no Accept header.
|
||||
return self.discover_no_yadis(uri)
|
||||
end
|
||||
|
||||
# Try to parse the response as HTML.
|
||||
# <link rel="...">
|
||||
openid_services = OpenIDServiceEndpoint.from_html(yadis_url, body)
|
||||
end
|
||||
|
||||
return [yadis_url, self.get_op_or_user_services(openid_services)]
|
||||
end
|
||||
|
||||
def self.discover_xri(iname)
|
||||
endpoints = []
|
||||
|
||||
begin
|
||||
canonical_id, services = Yadis::XRI::ProxyResolver.new().query(
|
||||
iname, OpenIDServiceEndpoint::OPENID_TYPE_URIS)
|
||||
|
||||
if canonical_id.nil?
|
||||
raise Yadis::XRDSError.new(sprintf('No CanonicalID found for XRI %s', iname))
|
||||
end
|
||||
|
||||
flt = Yadis.make_filter(OpenIDServiceEndpoint)
|
||||
|
||||
services.each { |service_element|
|
||||
endpoints += flt.get_service_endpoints(iname, service_element)
|
||||
}
|
||||
rescue Yadis::XRDSError => why
|
||||
Util.log('xrds error on ' + iname + ': ' + why.to_s)
|
||||
end
|
||||
|
||||
endpoints.each { |endpoint|
|
||||
# Is there a way to pass this through the filter to the endpoint
|
||||
# constructor instead of tacking it on after?
|
||||
endpoint.canonical_id = canonical_id
|
||||
endpoint.claimed_id = canonical_id
|
||||
endpoint.display_identifier = iname
|
||||
}
|
||||
|
||||
# FIXME: returned xri should probably be in some normal form
|
||||
return [iname, self.get_op_or_user_services(endpoints)]
|
||||
end
|
||||
|
||||
def self.discover_no_yadis(uri)
|
||||
http_resp = OpenID.fetch(uri)
|
||||
if http_resp.code != "200" and http_resp.code != "206"
|
||||
raise DiscoveryFailure.new(
|
||||
"HTTP Response status from identity URL host is not \"200\". "\
|
||||
"Got status #{http_resp.code.inspect}", http_resp)
|
||||
end
|
||||
|
||||
claimed_id = http_resp.final_url
|
||||
openid_services = OpenIDServiceEndpoint.from_html(
|
||||
claimed_id, http_resp.body)
|
||||
return [claimed_id, openid_services]
|
||||
end
|
||||
|
||||
def self.discover_uri(uri)
|
||||
# Hack to work around URI parsing for URls with *no* scheme.
|
||||
if uri.index("://").nil?
|
||||
uri = 'http://' + uri
|
||||
end
|
||||
|
||||
begin
|
||||
parsed = URI::parse(uri)
|
||||
rescue URI::InvalidURIError => why
|
||||
raise DiscoveryFailure.new("URI is not valid: #{why.message}", nil)
|
||||
end
|
||||
|
||||
if !parsed.scheme.nil? and !parsed.scheme.empty?
|
||||
if !['http', 'https'].member?(parsed.scheme)
|
||||
raise DiscoveryFailure.new(
|
||||
"URI scheme #{parsed.scheme} is not HTTP or HTTPS", nil)
|
||||
end
|
||||
end
|
||||
|
||||
uri = self.normalize_url(uri)
|
||||
claimed_id, openid_services = self.discover_yadis(uri)
|
||||
claimed_id = self.normalize_url(claimed_id)
|
||||
return [claimed_id, openid_services]
|
||||
end
|
||||
|
||||
def self.discover(identifier)
|
||||
if Yadis::XRI::identifier_scheme(identifier) == :xri
|
||||
normalized_identifier, services = discover_xri(identifier)
|
||||
else
|
||||
return discover_uri(identifier)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue