mirror of
https://github.com/redmine/redmine.git
synced 2025-11-14 01:06:00 +01:00
Unpacked OpenID gem. #699
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2437 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
349
vendor/gems/ruby-openid-2.1.4/lib/openid/trustroot.rb
vendored
Normal file
349
vendor/gems/ruby-openid-2.1.4/lib/openid/trustroot.rb
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
require 'uri'
|
||||
require 'openid/urinorm'
|
||||
|
||||
module OpenID
|
||||
|
||||
class RealmVerificationRedirected < Exception
|
||||
# Attempting to verify this realm resulted in a redirect.
|
||||
def initialize(relying_party_url, rp_url_after_redirects)
|
||||
@relying_party_url = relying_party_url
|
||||
@rp_url_after_redirects = rp_url_after_redirects
|
||||
end
|
||||
|
||||
def to_s
|
||||
return "Attempting to verify #{@relying_party_url} resulted in " +
|
||||
"redirect to #{@rp_url_after_redirects}"
|
||||
end
|
||||
end
|
||||
|
||||
module TrustRoot
|
||||
TOP_LEVEL_DOMAINS = %w'
|
||||
ac ad ae aero af ag ai al am an ao aq ar arpa as asia at
|
||||
au aw ax az ba bb bd be bf bg bh bi biz bj bm bn bo br bs bt
|
||||
bv bw by bz ca cat cc cd cf cg ch ci ck cl cm cn co com coop
|
||||
cr cu cv cx cy cz de dj dk dm do dz ec edu ee eg er es et eu
|
||||
fi fj fk fm fo fr ga gb gd ge gf gg gh gi gl gm gn gov gp gq
|
||||
gr gs gt gu gw gy hk hm hn hr ht hu id ie il im in info int
|
||||
io iq ir is it je jm jo jobs jp ke kg kh ki km kn kp kr kw
|
||||
ky kz la lb lc li lk lr ls lt lu lv ly ma mc md me mg mh mil
|
||||
mk ml mm mn mo mobi mp mq mr ms mt mu museum mv mw mx my mz
|
||||
na name nc ne net nf ng ni nl no np nr nu nz om org pa pe pf
|
||||
pg ph pk pl pm pn pr pro ps pt pw py qa re ro rs ru rw sa sb
|
||||
sc sd se sg sh si sj sk sl sm sn so sr st su sv sy sz tc td
|
||||
tel tf tg th tj tk tl tm tn to tp tr travel tt tv tw tz ua
|
||||
ug uk us uy uz va vc ve vg vi vn vu wf ws xn--0zwm56d
|
||||
xn--11b5bs3a9aj6g xn--80akhbyknj4f xn--9t4b11yi5a
|
||||
xn--deba0ad xn--g6w251d xn--hgbk6aj7f53bba
|
||||
xn--hlcj6aya9esc7a xn--jxalpdlp xn--kgbechtv xn--zckzah ye
|
||||
yt yu za zm zw'
|
||||
|
||||
ALLOWED_PROTOCOLS = ['http', 'https']
|
||||
|
||||
# The URI for relying party discovery, used in realm verification.
|
||||
#
|
||||
# XXX: This should probably live somewhere else (like in
|
||||
# OpenID or OpenID::Yadis somewhere)
|
||||
RP_RETURN_TO_URL_TYPE = 'http://specs.openid.net/auth/2.0/return_to'
|
||||
|
||||
# If the endpoint is a relying party OpenID return_to endpoint,
|
||||
# return the endpoint URL. Otherwise, return None.
|
||||
#
|
||||
# This function is intended to be used as a filter for the Yadis
|
||||
# filtering interface.
|
||||
#
|
||||
# endpoint: An XRDS BasicServiceEndpoint, as returned by
|
||||
# performing Yadis dicovery.
|
||||
#
|
||||
# returns the endpoint URL or None if the endpoint is not a
|
||||
# relying party endpoint.
|
||||
def TrustRoot._extract_return_url(endpoint)
|
||||
if endpoint.matchTypes([RP_RETURN_TO_URL_TYPE])
|
||||
return endpoint.uri
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
# Is the return_to URL under one of the supplied allowed
|
||||
# return_to URLs?
|
||||
def TrustRoot.return_to_matches(allowed_return_to_urls, return_to)
|
||||
allowed_return_to_urls.each { |allowed_return_to|
|
||||
# A return_to pattern works the same as a realm, except that
|
||||
# it's not allowed to use a wildcard. We'll model this by
|
||||
# parsing it as a realm, and not trying to match it if it has
|
||||
# a wildcard.
|
||||
|
||||
return_realm = TrustRoot.parse(allowed_return_to)
|
||||
if (# Parses as a trust root
|
||||
!return_realm.nil? and
|
||||
|
||||
# Does not have a wildcard
|
||||
!return_realm.wildcard and
|
||||
|
||||
# Matches the return_to that we passed in with it
|
||||
return_realm.validate_url(return_to)
|
||||
)
|
||||
return true
|
||||
end
|
||||
}
|
||||
|
||||
# No URL in the list matched
|
||||
return false
|
||||
end
|
||||
|
||||
# Given a relying party discovery URL return a list of return_to
|
||||
# URLs.
|
||||
def TrustRoot.get_allowed_return_urls(relying_party_url)
|
||||
rp_url_after_redirects, return_to_urls = services.get_service_endpoints(
|
||||
relying_party_url, _extract_return_url)
|
||||
|
||||
if rp_url_after_redirects != relying_party_url
|
||||
# Verification caused a redirect
|
||||
raise RealmVerificationRedirected.new(
|
||||
relying_party_url, rp_url_after_redirects)
|
||||
end
|
||||
|
||||
return return_to_urls
|
||||
end
|
||||
|
||||
# Verify that a return_to URL is valid for the given realm.
|
||||
#
|
||||
# This function builds a discovery URL, performs Yadis discovery
|
||||
# on it, makes sure that the URL does not redirect, parses out
|
||||
# the return_to URLs, and finally checks to see if the current
|
||||
# return_to URL matches the return_to.
|
||||
#
|
||||
# raises DiscoveryFailure when Yadis discovery fails returns
|
||||
# true if the return_to URL is valid for the realm
|
||||
def TrustRoot.verify_return_to(realm_str, return_to, _vrfy=nil)
|
||||
# _vrfy parameter is there to make testing easier
|
||||
if _vrfy.nil?
|
||||
_vrfy = self.method('get_allowed_return_urls')
|
||||
end
|
||||
|
||||
if !(_vrfy.is_a?(Proc) or _vrfy.is_a?(Method))
|
||||
raise ArgumentError, "_vrfy must be a Proc or Method"
|
||||
end
|
||||
|
||||
realm = TrustRoot.parse(realm_str)
|
||||
if realm.nil?
|
||||
# The realm does not parse as a URL pattern
|
||||
return false
|
||||
end
|
||||
|
||||
begin
|
||||
allowable_urls = _vrfy.call(realm.build_discovery_url())
|
||||
rescue RealmVerificationRedirected => err
|
||||
Util.log(err.to_s)
|
||||
return false
|
||||
end
|
||||
|
||||
if return_to_matches(allowable_urls, return_to)
|
||||
return true
|
||||
else
|
||||
Util.log("Failed to validate return_to #{return_to} for " +
|
||||
"realm #{realm_str}, was not in #{allowable_urls}")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
class TrustRoot
|
||||
|
||||
attr_reader :unparsed, :proto, :wildcard, :host, :port, :path
|
||||
|
||||
@@empty_re = Regexp.new('^http[s]*:\/\/\*\/$')
|
||||
|
||||
def TrustRoot._build_path(path, query=nil, frag=nil)
|
||||
s = path.dup
|
||||
|
||||
frag = nil if frag == ''
|
||||
query = nil if query == ''
|
||||
|
||||
if query
|
||||
s << "?" << query
|
||||
end
|
||||
|
||||
if frag
|
||||
s << "#" << frag
|
||||
end
|
||||
|
||||
return s
|
||||
end
|
||||
|
||||
def TrustRoot._parse_url(url)
|
||||
begin
|
||||
url = URINorm.urinorm(url)
|
||||
rescue URI::InvalidURIError => err
|
||||
nil
|
||||
end
|
||||
|
||||
begin
|
||||
parsed = URI::parse(url)
|
||||
rescue URI::InvalidURIError
|
||||
return nil
|
||||
end
|
||||
|
||||
path = TrustRoot._build_path(parsed.path,
|
||||
parsed.query,
|
||||
parsed.fragment)
|
||||
|
||||
return [parsed.scheme || '', parsed.host || '',
|
||||
parsed.port || '', path || '']
|
||||
end
|
||||
|
||||
def TrustRoot.parse(trust_root)
|
||||
trust_root = trust_root.dup
|
||||
unparsed = trust_root.dup
|
||||
|
||||
# look for wildcard
|
||||
wildcard = (not trust_root.index('://*.').nil?)
|
||||
trust_root.sub!('*.', '') if wildcard
|
||||
|
||||
# handle http://*/ case
|
||||
if not wildcard and @@empty_re.match(trust_root)
|
||||
proto = trust_root.split(':')[0]
|
||||
port = proto == 'http' ? 80 : 443
|
||||
return new(unparsed, proto, true, '', port, '/')
|
||||
end
|
||||
|
||||
parts = TrustRoot._parse_url(trust_root)
|
||||
return nil if parts.nil?
|
||||
|
||||
proto, host, port, path = parts
|
||||
|
||||
# check for URI fragment
|
||||
if path and !path.index('#').nil?
|
||||
return nil
|
||||
end
|
||||
|
||||
return nil unless ['http', 'https'].member?(proto)
|
||||
return new(unparsed, proto, wildcard, host, port, path)
|
||||
end
|
||||
|
||||
def TrustRoot.check_sanity(trust_root_string)
|
||||
trust_root = TrustRoot.parse(trust_root_string)
|
||||
if trust_root.nil?
|
||||
return false
|
||||
else
|
||||
return trust_root.sane?
|
||||
end
|
||||
end
|
||||
|
||||
# quick func for validating a url against a trust root. See the
|
||||
# TrustRoot class if you need more control.
|
||||
def self.check_url(trust_root, url)
|
||||
tr = self.parse(trust_root)
|
||||
return (!tr.nil? and tr.validate_url(url))
|
||||
end
|
||||
|
||||
# Return a discovery URL for this realm.
|
||||
#
|
||||
# This function does not check to make sure that the realm is
|
||||
# valid. Its behaviour on invalid inputs is undefined.
|
||||
#
|
||||
# return_to:: The relying party return URL of the OpenID
|
||||
# authentication request
|
||||
#
|
||||
# Returns the URL upon which relying party discovery should be
|
||||
# run in order to verify the return_to URL
|
||||
def build_discovery_url
|
||||
if self.wildcard
|
||||
# Use "www." in place of the star
|
||||
www_domain = 'www.' + @host
|
||||
port = (!@port.nil? and ![80, 443].member?(@port)) ? (":" + @port.to_s) : ''
|
||||
return "#{@proto}://#{www_domain}#{port}#{@path}"
|
||||
else
|
||||
return @unparsed
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(unparsed, proto, wildcard, host, port, path)
|
||||
@unparsed = unparsed
|
||||
@proto = proto
|
||||
@wildcard = wildcard
|
||||
@host = host
|
||||
@port = port
|
||||
@path = path
|
||||
end
|
||||
|
||||
def sane?
|
||||
return true if @host == 'localhost'
|
||||
|
||||
host_parts = @host.split('.')
|
||||
|
||||
# a note: ruby string split does not put an empty string at
|
||||
# the end of the list if the split element is last. for
|
||||
# example, 'foo.com.'.split('.') => ['foo','com']. Mentioned
|
||||
# because the python code differs here.
|
||||
|
||||
return false if host_parts.length == 0
|
||||
|
||||
# no adjacent dots
|
||||
return false if host_parts.member?('')
|
||||
|
||||
# last part must be a tld
|
||||
tld = host_parts[-1]
|
||||
return false unless TOP_LEVEL_DOMAINS.member?(tld)
|
||||
|
||||
return false if host_parts.length == 1
|
||||
|
||||
if @wildcard
|
||||
if tld.length == 2 and host_parts[-2].length <= 3
|
||||
# It's a 2-letter tld with a short second to last segment
|
||||
# so there needs to be more than two segments specified
|
||||
# (e.g. *.co.uk is insane)
|
||||
return host_parts.length > 2
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
def validate_url(url)
|
||||
parts = TrustRoot._parse_url(url)
|
||||
return false if parts.nil?
|
||||
|
||||
proto, host, port, path = parts
|
||||
|
||||
return false unless proto == @proto
|
||||
return false unless port == @port
|
||||
return false unless host.index('*').nil?
|
||||
|
||||
if !@wildcard
|
||||
if host != @host
|
||||
return false
|
||||
end
|
||||
elsif ((@host != '') and
|
||||
(!host.ends_with?('.' + @host)) and
|
||||
(host != @host))
|
||||
return false
|
||||
end
|
||||
|
||||
if path != @path
|
||||
path_len = @path.length
|
||||
trust_prefix = @path[0...path_len]
|
||||
url_prefix = path[0...path_len]
|
||||
|
||||
# must be equal up to the length of the path, at least
|
||||
if trust_prefix != url_prefix
|
||||
return false
|
||||
end
|
||||
|
||||
# These characters must be on the boundary between the end
|
||||
# of the trust root's path and the start of the URL's path.
|
||||
if !@path.index('?').nil?
|
||||
allowed = '&'
|
||||
else
|
||||
allowed = '?/'
|
||||
end
|
||||
|
||||
return (!allowed.index(@path[-1]).nil? or
|
||||
!allowed.index(path[path_len]).nil?)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user