ruby-openid 1.1.4 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/INSTALL +0 -9
- data/README +21 -22
- data/UPGRADE +117 -0
- data/admin/runtests.rb +36 -0
- data/examples/README +13 -21
- data/examples/active_record_openid_store/README +8 -3
- data/examples/active_record_openid_store/XXX_add_open_id_store_to_db.rb +4 -8
- data/examples/active_record_openid_store/XXX_upgrade_open_id_store.rb +26 -0
- data/examples/active_record_openid_store/lib/association.rb +2 -0
- data/examples/active_record_openid_store/lib/openid_ar_store.rb +22 -47
- data/examples/active_record_openid_store/test/store_test.rb +78 -48
- data/examples/discover +46 -0
- data/examples/{rails_server → rails_openid}/README +0 -0
- data/examples/{rails_server → rails_openid}/Rakefile +0 -0
- data/examples/{rails_server → rails_openid}/app/controllers/application.rb +0 -0
- data/examples/rails_openid/app/controllers/consumer_controller.rb +115 -0
- data/examples/{rails_server → rails_openid}/app/controllers/login_controller.rb +10 -2
- data/examples/rails_openid/app/controllers/server_controller.rb +265 -0
- data/examples/{rails_server → rails_openid}/app/helpers/application_helper.rb +0 -0
- data/examples/{rails_server → rails_openid}/app/helpers/login_helper.rb +0 -0
- data/examples/{rails_server → rails_openid}/app/helpers/server_helper.rb +0 -0
- data/examples/rails_openid/app/views/consumer/index.rhtml +81 -0
- data/examples/rails_openid/app/views/consumer/start.rhtml +8 -0
- data/examples/{rails_server → rails_openid}/app/views/layouts/server.rhtml +0 -0
- data/examples/{rails_server → rails_openid}/app/views/login/index.rhtml +1 -1
- data/examples/rails_openid/app/views/server/decide.rhtml +26 -0
- data/examples/{rails_server → rails_openid}/config/boot.rb +0 -0
- data/examples/{rails_server → rails_openid}/config/database.yml +0 -0
- data/examples/{rails_server → rails_openid}/config/environment.rb +0 -0
- data/examples/{rails_server → rails_openid}/config/environments/development.rb +0 -0
- data/examples/{rails_server → rails_openid}/config/environments/production.rb +0 -0
- data/examples/{rails_server → rails_openid}/config/environments/test.rb +0 -0
- data/examples/{rails_server → rails_openid}/config/routes.rb +2 -1
- data/examples/{rails_server → rails_openid}/doc/README_FOR_APP +0 -0
- data/examples/{rails_server → rails_openid}/public/404.html +0 -0
- data/examples/{rails_server → rails_openid}/public/500.html +0 -0
- data/examples/{rails_server → rails_openid}/public/dispatch.cgi +0 -0
- data/examples/{rails_server → rails_openid}/public/dispatch.fcgi +0 -0
- data/examples/{rails_server → rails_openid}/public/dispatch.rb +0 -0
- data/examples/{rails_server → rails_openid}/public/favicon.ico +0 -0
- data/examples/rails_openid/public/images/openid_login_bg.gif +0 -0
- data/examples/{rails_server → rails_openid}/public/javascripts/controls.js +0 -0
- data/examples/{rails_server → rails_openid}/public/javascripts/dragdrop.js +0 -0
- data/examples/{rails_server → rails_openid}/public/javascripts/effects.js +0 -0
- data/examples/{rails_server → rails_openid}/public/javascripts/prototype.js +0 -0
- data/examples/{rails_server → rails_openid}/public/robots.txt +0 -0
- data/examples/{rails_server → rails_openid}/script/about +0 -0
- data/examples/{rails_server → rails_openid}/script/breakpointer +0 -0
- data/examples/{rails_server → rails_openid}/script/console +0 -0
- data/examples/{rails_server → rails_openid}/script/destroy +0 -0
- data/examples/{rails_server → rails_openid}/script/generate +0 -0
- data/examples/{rails_server → rails_openid}/script/performance/benchmarker +0 -0
- data/examples/{rails_server → rails_openid}/script/performance/profiler +0 -0
- data/examples/{rails_server → rails_openid}/script/plugin +0 -0
- data/examples/{rails_server → rails_openid}/script/process/reaper +0 -0
- data/examples/{rails_server → rails_openid}/script/process/spawner +0 -0
- data/examples/{rails_server → rails_openid}/script/process/spinner +0 -0
- data/examples/{rails_server → rails_openid}/script/runner +0 -0
- data/examples/{rails_server → rails_openid}/script/server +0 -0
- data/examples/{rails_server → rails_openid}/test/functional/login_controller_test.rb +0 -0
- data/examples/{rails_server → rails_openid}/test/functional/server_controller_test.rb +0 -0
- data/examples/{rails_server → rails_openid}/test/test_helper.rb +0 -0
- data/lib/{hmac.rb → hmac/hmac.rb} +0 -0
- data/lib/{hmac-sha1.rb → hmac/sha1.rb} +1 -1
- data/lib/{hmac-sha2.rb → hmac/sha2.rb} +1 -1
- data/lib/openid/association.rb +213 -73
- data/lib/openid/consumer/associationmanager.rb +338 -0
- data/lib/openid/consumer/checkid_request.rb +175 -0
- data/lib/openid/consumer/discovery.rb +480 -0
- data/lib/openid/consumer/discovery_manager.rb +123 -0
- data/lib/openid/consumer/html_parse.rb +136 -0
- data/lib/openid/consumer/idres.rb +525 -0
- data/lib/openid/consumer/responses.rb +133 -0
- data/lib/openid/consumer.rb +280 -807
- data/lib/openid/cryptutil.rb +85 -0
- data/lib/openid/dh.rb +60 -23
- data/lib/openid/extension.rb +31 -0
- data/lib/openid/extensions/ax.rb +506 -0
- data/lib/openid/extensions/pape.rb +182 -0
- data/lib/openid/extensions/sreg.rb +275 -0
- data/lib/openid/extras.rb +11 -0
- data/lib/openid/fetchers.rb +132 -93
- data/lib/openid/kvform.rb +133 -0
- data/lib/openid/kvpost.rb +56 -0
- data/lib/openid/message.rb +534 -0
- data/lib/openid/protocolerror.rb +6 -0
- data/lib/openid/server.rb +1215 -666
- data/lib/openid/store/filesystem.rb +271 -0
- data/lib/openid/store/interface.rb +75 -0
- data/lib/openid/store/memory.rb +84 -0
- data/lib/openid/store/nonce.rb +68 -0
- data/lib/openid/trustroot.rb +314 -87
- data/lib/openid/urinorm.rb +37 -34
- data/lib/openid/util.rb +42 -220
- data/lib/openid/yadis/accept.rb +148 -0
- data/lib/openid/yadis/constants.rb +21 -0
- data/lib/openid/yadis/discovery.rb +153 -0
- data/lib/openid/yadis/filters.rb +205 -0
- data/lib/openid/{htmltokenizer.rb → yadis/htmltokenizer.rb} +1 -54
- data/lib/openid/yadis/parsehtml.rb +36 -0
- data/lib/openid/yadis/services.rb +42 -0
- data/lib/openid/yadis/xrds.rb +171 -0
- data/lib/openid/yadis/xri.rb +90 -0
- data/lib/openid/yadis/xrires.rb +106 -0
- data/lib/openid.rb +1 -4
- data/test/data/accept.txt +124 -0
- data/test/data/dh.txt +29 -0
- data/test/data/example-xrds.xml +14 -0
- data/test/data/linkparse.txt +587 -0
- data/test/data/n2b64 +650 -0
- data/test/data/test1-discover.txt +137 -0
- data/test/data/test1-parsehtml.txt +128 -0
- data/test/data/test_discover/openid.html +11 -0
- data/test/data/test_discover/openid2.html +11 -0
- data/test/data/test_discover/openid2_xrds.xml +12 -0
- data/test/data/test_discover/openid2_xrds_no_local_id.xml +11 -0
- data/test/data/test_discover/openid_1_and_2.html +11 -0
- data/test/data/test_discover/openid_1_and_2_xrds.xml +16 -0
- data/test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml +17 -0
- data/test/data/test_discover/openid_and_yadis.html +12 -0
- data/test/data/test_discover/openid_no_delegate.html +10 -0
- data/test/data/test_discover/yadis_0entries.xml +12 -0
- data/test/data/test_discover/yadis_2_bad_local_id.xml +15 -0
- data/test/data/test_discover/yadis_2entries_delegate.xml +22 -0
- data/test/data/test_discover/yadis_2entries_idp.xml +21 -0
- data/test/data/test_discover/yadis_another_delegate.xml +14 -0
- data/test/data/test_discover/yadis_idp.xml +12 -0
- data/test/data/test_discover/yadis_idp_delegate.xml +13 -0
- data/test/data/test_discover/yadis_no_delegate.xml +11 -0
- data/test/data/test_xrds/=j3h.2007.11.14.xrds +25 -0
- data/test/data/test_xrds/README +12 -0
- data/test/data/test_xrds/delegated-20060809-r1.xrds +34 -0
- data/test/data/test_xrds/delegated-20060809-r2.xrds +34 -0
- data/test/data/test_xrds/delegated-20060809.xrds +34 -0
- data/test/data/test_xrds/no-xrd.xml +7 -0
- data/test/data/test_xrds/not-xrds.xml +2 -0
- data/test/data/test_xrds/prefixsometimes.xrds +34 -0
- data/test/data/test_xrds/ref.xrds +109 -0
- data/test/data/test_xrds/sometimesprefix.xrds +34 -0
- data/test/data/test_xrds/spoof1.xrds +25 -0
- data/test/data/test_xrds/spoof2.xrds +25 -0
- data/test/data/test_xrds/spoof3.xrds +37 -0
- data/test/data/test_xrds/status222.xrds +9 -0
- data/test/data/test_xrds/valid-populated-xrds.xml +39 -0
- data/test/data/trustroot.txt +147 -0
- data/test/discoverdata.rb +131 -0
- data/test/test_accept.rb +170 -0
- data/test/test_association.rb +266 -0
- data/test/test_associationmanager.rb +899 -0
- data/test/test_ax.rb +587 -0
- data/test/test_checkid_request.rb +297 -0
- data/test/test_consumer.rb +257 -0
- data/test/test_cryptutil.rb +117 -0
- data/test/test_dh.rb +86 -0
- data/test/test_discover.rb +772 -0
- data/test/test_discovery_manager.rb +262 -0
- data/test/test_extras.rb +35 -0
- data/test/test_fetchers.rb +472 -0
- data/test/test_filters.rb +270 -0
- data/test/test_idres.rb +816 -0
- data/test/test_kvform.rb +165 -0
- data/test/test_kvpost.rb +65 -0
- data/test/test_linkparse.rb +101 -0
- data/test/test_message.rb +1058 -0
- data/test/test_nonce.rb +89 -0
- data/test/test_openid_yadis.rb +178 -0
- data/test/test_pape.rb +233 -0
- data/test/test_parsehtml.rb +80 -0
- data/test/test_responses.rb +63 -0
- data/test/test_server.rb +2270 -0
- data/test/test_sreg.rb +479 -0
- data/test/test_stores.rb +269 -0
- data/test/test_trustroot.rb +112 -0
- data/test/{urinorm.rb → test_urinorm.rb} +6 -3
- data/test/test_util.rb +144 -0
- data/test/test_xrds.rb +160 -0
- data/test/test_xri.rb +48 -0
- data/test/test_xrires.rb +63 -0
- data/test/test_yadis_discovery.rb +207 -0
- data/test/testutil.rb +116 -0
- data/test/util.rb +47 -50
- metadata +233 -143
- data/examples/consumer.rb +0 -290
- data/examples/rails_openid_login_generator/openid_login_generator-0.1.gem +0 -0
- data/examples/rails_server/app/controllers/server_controller.rb +0 -190
- data/examples/rails_server/app/views/server/decide.rhtml +0 -11
- data/examples/rails_server/public/images/rails.png +0 -0
- data/lib/hmac-md5.rb +0 -11
- data/lib/hmac-rmd160.rb +0 -11
- data/lib/openid/discovery.rb +0 -122
- data/lib/openid/filestore.rb +0 -315
- data/lib/openid/parse.rb +0 -23
- data/lib/openid/service.rb +0 -147
- data/lib/openid/stores.rb +0 -178
- data/test/assoc.rb +0 -38
- data/test/consumer.rb +0 -376
- data/test/data/brian.xrds +0 -16
- data/test/data/brianellin.mylid.xrds +0 -42
- data/test/dh.rb +0 -20
- data/test/extensions.rb +0 -30
- data/test/linkparse.rb +0 -305
- data/test/runtests.rb +0 -22
- data/test/server2.rb +0 -1053
- data/test/service.rb +0 -47
- data/test/storetestcase.rb +0 -172
- data/test/teststore.rb +0 -47
- data/test/trustroot.rb +0 -117
data/lib/openid/trustroot.rb
CHANGED
|
@@ -1,114 +1,341 @@
|
|
|
1
1
|
require 'uri'
|
|
2
|
-
|
|
3
|
-
TOP_LEVEL_DOMAINS = 'com|edu|gov|int|mil|net|org|biz|info|name|museum|coop|aero|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|fi|fj|fk|fm|fo|fr|ga|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|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|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw'.split('|')
|
|
2
|
+
require 'openid/urinorm'
|
|
4
3
|
|
|
5
4
|
module OpenID
|
|
6
5
|
|
|
7
|
-
class
|
|
6
|
+
class RealmVerificationRedirected < Exception
|
|
7
|
+
# Attempting to verify this realm resulted in a redirect.
|
|
8
|
+
def initialize(relying_party_url, rp_url_after_redirects)
|
|
9
|
+
@relying_party_url = relying_party_url
|
|
10
|
+
@rp_url_after_redirects = rp_url_after_redirects
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_s
|
|
14
|
+
return "Attempting to verify #{@relying_party_url} resulted in " +
|
|
15
|
+
"redirect to #{@rp_url_after_redirects}"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
8
18
|
|
|
9
|
-
|
|
19
|
+
module TrustRoot
|
|
20
|
+
TOP_LEVEL_DOMAINS = %w'
|
|
21
|
+
com edu gov int mil net org biz info name museum coop aero ac ad
|
|
22
|
+
ae af ag ai al am an ao aq ar as at au aw az ba bb bd be bf bg
|
|
23
|
+
bh bi bj bm bn bo br bs bt bv bw by bz ca cc cd cf cg ch ci ck
|
|
24
|
+
cl cm cn co cr cu cv cx cy cz de dj dk dm do dz ec ee eg eh er
|
|
25
|
+
es et eu fi fj fk fm fo fr ga gd ge gf gg gh gi gl gm gn gp gq
|
|
26
|
+
gr gs gt gu gw gy hk hm hn hr ht hu id ie il im in io iq ir is
|
|
27
|
+
it je jm jo jp ke kg kh ki km kn kp kr kw ky kz la lb lc li lk
|
|
28
|
+
lr ls lt lu lv ly ma mc md mg mh mk ml mm mn mo mp mq mr ms mt
|
|
29
|
+
mu mv mw mx my mz na nc ne nf ng ni nl no np nr nu nz om pa pe
|
|
30
|
+
pf pg ph pk pl pm pn pr ps pt pw py qa re ro ru rw sa sb sc sd
|
|
31
|
+
se sg sh si sj sk sl sm sn so sr st sv sy sz tc td tf tg th tj
|
|
32
|
+
tk tm tn to tp tr tt tv tw tz ua ug uk um us uy uz va vc ve vg
|
|
33
|
+
vi vn vu wf ws ye yt yu za zm zw'
|
|
10
34
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
35
|
+
ALLOWED_PROTOCOLS = ['http', 'https']
|
|
36
|
+
|
|
37
|
+
# The URI for relying party discovery, used in realm verification.
|
|
38
|
+
#
|
|
39
|
+
# XXX: This should probably live somewhere else (like in
|
|
40
|
+
# OpenID or OpenID::Yadis somewhere)
|
|
41
|
+
RP_RETURN_TO_URL_TYPE = 'http://specs.openid.net/auth/2.0/return_to'
|
|
42
|
+
|
|
43
|
+
# If the endpoint is a relying party OpenID return_to endpoint,
|
|
44
|
+
# return the endpoint URL. Otherwise, return None.
|
|
45
|
+
#
|
|
46
|
+
# This function is intended to be used as a filter for the Yadis
|
|
47
|
+
# filtering interface.
|
|
48
|
+
#
|
|
49
|
+
# endpoint: An XRDS BasicServiceEndpoint, as returned by
|
|
50
|
+
# performing Yadis dicovery.
|
|
51
|
+
#
|
|
52
|
+
# returns the endpoint URL or None if the endpoint is not a
|
|
53
|
+
# relying party endpoint.
|
|
54
|
+
def TrustRoot._extract_return_url(endpoint)
|
|
55
|
+
if endpoint.matchTypes([RP_RETURN_TO_URL_TYPE])
|
|
56
|
+
return endpoint.uri
|
|
57
|
+
else
|
|
15
58
|
return nil
|
|
16
59
|
end
|
|
17
|
-
|
|
18
|
-
return [parsed.scheme, parsed.host, parsed.port, parsed.path]
|
|
19
60
|
end
|
|
20
61
|
|
|
21
|
-
|
|
22
|
-
|
|
62
|
+
# Is the return_to URL under one of the supplied allowed
|
|
63
|
+
# return_to URLs?
|
|
64
|
+
def TrustRoot.return_to_matches(allowed_return_to_urls, return_to)
|
|
65
|
+
allowed_return_to_urls.each { |allowed_return_to|
|
|
66
|
+
# A return_to pattern works the same as a realm, except that
|
|
67
|
+
# it's not allowed to use a wildcard. We'll model this by
|
|
68
|
+
# parsing it as a realm, and not trying to match it if it has
|
|
69
|
+
# a wildcard.
|
|
23
70
|
|
|
24
|
-
|
|
25
|
-
|
|
71
|
+
return_realm = TrustRoot.parse(allowed_return_to)
|
|
72
|
+
if (# Parses as a trust root
|
|
73
|
+
!return_realm.nil? and
|
|
26
74
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
trust_root.sub!('*.', '') if wildcard
|
|
30
|
-
|
|
31
|
-
# handle http://*/ case
|
|
32
|
-
if not wildcard and @@empty_re.match(trust_root)
|
|
33
|
-
proto = trust_root.split(':')[0]
|
|
34
|
-
port = proto == 'http' ? 80 : 443
|
|
35
|
-
return new(unparsed, proto, true, '', port, '/')
|
|
36
|
-
end
|
|
75
|
+
# Does not have a wildcard
|
|
76
|
+
!return_realm.wildcard and
|
|
37
77
|
|
|
38
|
-
|
|
39
|
-
|
|
78
|
+
# Matches the return_to that we passed in with it
|
|
79
|
+
return_realm.validate_url(return_to)
|
|
80
|
+
)
|
|
81
|
+
return true
|
|
82
|
+
end
|
|
83
|
+
}
|
|
40
84
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return nil unless ['http', 'https'].member?(proto)
|
|
44
|
-
return new(unparsed, proto, wildcard, host, port, path)
|
|
85
|
+
# No URL in the list matched
|
|
86
|
+
return false
|
|
45
87
|
end
|
|
46
88
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def initialize(unparsed, proto, wildcard, host, port, path)
|
|
55
|
-
@unparsed = unparsed
|
|
56
|
-
@proto = proto
|
|
57
|
-
@wildcard = wildcard
|
|
58
|
-
@host = host
|
|
59
|
-
@port = port
|
|
60
|
-
@path = path
|
|
61
|
-
end
|
|
89
|
+
# Given a relying party discovery URL return a list of return_to
|
|
90
|
+
# URLs.
|
|
91
|
+
def TrustRoot.get_allowed_return_urls(relying_party_url)
|
|
92
|
+
rp_url_after_redirects, return_to_urls = services.get_service_endpoints(
|
|
93
|
+
relying_party_url, _extract_return_url)
|
|
62
94
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
# a note: ruby string split does not put an empty string
|
|
68
|
-
# at the end of the list if the split element is last. for example,
|
|
69
|
-
# 'foo.com.'.split('.') => ['foo','com']. Mentioned because the python
|
|
70
|
-
# code differs here.
|
|
71
|
-
|
|
72
|
-
return false if host_parts.length == 0
|
|
73
|
-
|
|
74
|
-
# no adjacent dots
|
|
75
|
-
return false if host_parts.member?('')
|
|
76
|
-
|
|
77
|
-
# last part must be a tld
|
|
78
|
-
tld = host_parts[-1]
|
|
79
|
-
return false unless TOP_LEVEL_DOMAINS.member?(tld)
|
|
80
|
-
|
|
81
|
-
return false if host_parts.length == 1
|
|
82
|
-
|
|
83
|
-
if @wildcard
|
|
84
|
-
if tld.length == 2 and host_parts[-2].length <= 3
|
|
85
|
-
# It's a 2-letter tld with a short second to last segment
|
|
86
|
-
# so there needs to be more than two segments specified
|
|
87
|
-
# (e.g. *.co.uk is insane)
|
|
88
|
-
return host_parts.length > 2
|
|
89
|
-
end
|
|
95
|
+
if rp_url_after_redirects != relying_party_url
|
|
96
|
+
# Verification caused a redirect
|
|
97
|
+
raise RealmVerificationRedirected.new(
|
|
98
|
+
relying_party_url, rp_url_after_redirects)
|
|
90
99
|
end
|
|
91
100
|
|
|
92
|
-
return
|
|
101
|
+
return return_to_urls
|
|
93
102
|
end
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
103
|
+
|
|
104
|
+
# Verify that a return_to URL is valid for the given realm.
|
|
105
|
+
#
|
|
106
|
+
# This function builds a discovery URL, performs Yadis discovery
|
|
107
|
+
# on it, makes sure that the URL does not redirect, parses out
|
|
108
|
+
# the return_to URLs, and finally checks to see if the current
|
|
109
|
+
# return_to URL matches the return_to.
|
|
110
|
+
#
|
|
111
|
+
# raises DiscoveryFailure when Yadis discovery fails returns
|
|
112
|
+
# true if the return_to URL is valid for the realm
|
|
113
|
+
def TrustRoot.verify_return_to(realm_str, return_to, _vrfy=nil)
|
|
114
|
+
# _vrfy parameter is there to make testing easier
|
|
115
|
+
if _vrfy.nil?
|
|
116
|
+
_vrfy = self.method('get_allowed_return_urls')
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
if !(_vrfy.is_a?(Proc) or _vrfy.is_a?(Method))
|
|
120
|
+
raise ArgumentError, "_vrfy must be a Proc or Method"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
realm = TrustRoot.parse(realm_str)
|
|
124
|
+
if realm.nil?
|
|
125
|
+
# The realm does not parse as a URL pattern
|
|
126
|
+
return false
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
begin
|
|
130
|
+
allowable_urls = _vrfy.call(realm.build_discovery_url())
|
|
131
|
+
rescue RealmVerificationRedirected => err
|
|
132
|
+
Util.log(err.to_s)
|
|
133
|
+
return false
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
if return_to_matches(allowable_urls, return_to)
|
|
137
|
+
return true
|
|
107
138
|
else
|
|
108
|
-
|
|
139
|
+
Util.log("Failed to validate return_to #{return_to} for " +
|
|
140
|
+
"realm #{realm_str}, was not in #{allowable_urls}")
|
|
141
|
+
return false
|
|
109
142
|
end
|
|
110
143
|
end
|
|
111
144
|
|
|
145
|
+
class TrustRoot
|
|
146
|
+
|
|
147
|
+
attr_reader :unparsed, :proto, :wildcard, :host, :port, :path
|
|
148
|
+
|
|
149
|
+
@@empty_re = Regexp.new('^http[s]*:\/\/\*\/$')
|
|
150
|
+
|
|
151
|
+
def TrustRoot._build_path(path, query=nil, frag=nil)
|
|
152
|
+
s = path.dup
|
|
153
|
+
|
|
154
|
+
frag = nil if frag == ''
|
|
155
|
+
query = nil if query == ''
|
|
156
|
+
|
|
157
|
+
if query
|
|
158
|
+
s << "?" << query
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
if frag
|
|
162
|
+
s << "#" << frag
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
return s
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def TrustRoot._parse_url(url)
|
|
169
|
+
begin
|
|
170
|
+
url = URINorm.urinorm(url)
|
|
171
|
+
rescue URI::InvalidURIError => err
|
|
172
|
+
nil
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
begin
|
|
176
|
+
parsed = URI::parse(url)
|
|
177
|
+
rescue URI::InvalidURIError
|
|
178
|
+
return nil
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
path = TrustRoot._build_path(parsed.path,
|
|
182
|
+
parsed.query,
|
|
183
|
+
parsed.fragment)
|
|
184
|
+
|
|
185
|
+
return [parsed.scheme || '', parsed.host || '',
|
|
186
|
+
parsed.port || '', path || '']
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def TrustRoot.parse(trust_root)
|
|
190
|
+
return nil unless trust_root.instance_of?(String)
|
|
191
|
+
|
|
192
|
+
trust_root = trust_root.dup
|
|
193
|
+
unparsed = trust_root.dup
|
|
194
|
+
|
|
195
|
+
# look for wildcard
|
|
196
|
+
wildcard = (not trust_root.index('://*.').nil?)
|
|
197
|
+
trust_root.sub!('*.', '') if wildcard
|
|
198
|
+
|
|
199
|
+
# handle http://*/ case
|
|
200
|
+
if not wildcard and @@empty_re.match(trust_root)
|
|
201
|
+
proto = trust_root.split(':')[0]
|
|
202
|
+
port = proto == 'http' ? 80 : 443
|
|
203
|
+
return new(unparsed, proto, true, '', port, '/')
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
parts = TrustRoot._parse_url(trust_root)
|
|
207
|
+
return nil if parts.nil?
|
|
208
|
+
|
|
209
|
+
proto, host, port, path = parts
|
|
210
|
+
|
|
211
|
+
# check for URI fragment
|
|
212
|
+
if path and !path.index('#').nil?
|
|
213
|
+
return nil
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
return nil unless ['http', 'https'].member?(proto)
|
|
217
|
+
return new(unparsed, proto, wildcard, host, port, path)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def TrustRoot.check_sanity(trust_root)
|
|
221
|
+
return TrustRoot.parse(trust_root).sane?
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# quick func for validating a url against a trust root. See the
|
|
225
|
+
# TrustRoot class if you need more control.
|
|
226
|
+
def self.check_url(trust_root, url)
|
|
227
|
+
tr = self.parse(trust_root)
|
|
228
|
+
return (!tr.nil? and tr.validate_url(url))
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Return a discovery URL for this realm.
|
|
232
|
+
#
|
|
233
|
+
# This function does not check to make sure that the realm is
|
|
234
|
+
# valid. Its behaviour on invalid inputs is undefined.
|
|
235
|
+
#
|
|
236
|
+
# return_to:: The relying party return URL of the OpenID
|
|
237
|
+
# authentication request
|
|
238
|
+
#
|
|
239
|
+
# Returns the URL upon which relying party discovery should be
|
|
240
|
+
# run in order to verify the return_to URL
|
|
241
|
+
def build_discovery_url
|
|
242
|
+
if self.wildcard
|
|
243
|
+
# Use "www." in place of the star
|
|
244
|
+
www_domain = 'www.' + @host
|
|
245
|
+
port = (!@port.nil? and ![80, 443].member?(@port)) ? (":" + @port.to_s) : ''
|
|
246
|
+
return "#{@proto}://#{www_domain}#{port}#{@path}"
|
|
247
|
+
else
|
|
248
|
+
return @unparsed
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def initialize(unparsed, proto, wildcard, host, port, path)
|
|
253
|
+
@unparsed = unparsed
|
|
254
|
+
@proto = proto
|
|
255
|
+
@wildcard = wildcard
|
|
256
|
+
@host = host
|
|
257
|
+
@port = port
|
|
258
|
+
@path = path
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def sane?
|
|
262
|
+
return true if @host == 'localhost'
|
|
263
|
+
|
|
264
|
+
host_parts = @host.split('.')
|
|
265
|
+
|
|
266
|
+
# a note: ruby string split does not put an empty string at
|
|
267
|
+
# the end of the list if the split element is last. for
|
|
268
|
+
# example, 'foo.com.'.split('.') => ['foo','com']. Mentioned
|
|
269
|
+
# because the python code differs here.
|
|
270
|
+
|
|
271
|
+
return false if host_parts.length == 0
|
|
272
|
+
|
|
273
|
+
# no adjacent dots
|
|
274
|
+
return false if host_parts.member?('')
|
|
275
|
+
|
|
276
|
+
# last part must be a tld
|
|
277
|
+
tld = host_parts[-1]
|
|
278
|
+
return false unless TOP_LEVEL_DOMAINS.member?(tld)
|
|
279
|
+
|
|
280
|
+
return false if host_parts.length == 1
|
|
281
|
+
|
|
282
|
+
if @wildcard
|
|
283
|
+
if tld.length == 2 and host_parts[-2].length <= 3
|
|
284
|
+
# It's a 2-letter tld with a short second to last segment
|
|
285
|
+
# so there needs to be more than two segments specified
|
|
286
|
+
# (e.g. *.co.uk is insane)
|
|
287
|
+
return host_parts.length > 2
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
return true
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def validate_url(url)
|
|
295
|
+
parts = TrustRoot._parse_url(url)
|
|
296
|
+
return false if parts.nil?
|
|
297
|
+
|
|
298
|
+
proto, host, port, path = parts
|
|
299
|
+
|
|
300
|
+
return false unless proto == @proto
|
|
301
|
+
return false unless port == @port
|
|
302
|
+
return false unless host.index('*').nil?
|
|
303
|
+
|
|
304
|
+
if !@wildcard
|
|
305
|
+
if host != @host
|
|
306
|
+
return false
|
|
307
|
+
end
|
|
308
|
+
elsif ((@host != '') and
|
|
309
|
+
(!host.ends_with?('.' + @host)) and
|
|
310
|
+
(host != @host))
|
|
311
|
+
return false
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
if path != @path
|
|
315
|
+
path_len = @path.length
|
|
316
|
+
trust_prefix = @path[0...path_len]
|
|
317
|
+
url_prefix = path[0...path_len]
|
|
318
|
+
|
|
319
|
+
# must be equal up to the length of the path, at least
|
|
320
|
+
if trust_prefix != url_prefix
|
|
321
|
+
return false
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# These characters must be on the boundary between the end
|
|
325
|
+
# of the trust root's path and the start of the URL's path.
|
|
326
|
+
if !@path.index('?').nil?
|
|
327
|
+
allowed = '&'
|
|
328
|
+
else
|
|
329
|
+
allowed = '?/'
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
return (!allowed.index(@path[-1]).nil? or
|
|
333
|
+
!allowed.index(path[path_len]).nil?)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
return true
|
|
337
|
+
end
|
|
338
|
+
end
|
|
112
339
|
end
|
|
113
340
|
end
|
|
114
341
|
|
data/lib/openid/urinorm.rb
CHANGED
|
@@ -1,16 +1,44 @@
|
|
|
1
1
|
require 'uri'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
('A'[0]..'Z'[0]).each {|i| UNRESERVED[i] = true}
|
|
5
|
-
('a'[0]..'z'[0]).each {|i| UNRESERVED[i] = true}
|
|
6
|
-
('0'[0]..'9'[0]).each {|i| UNRESERVED[i] = true}
|
|
7
|
-
%W(- . _ ~).each {|i| UNRESERVED[i[0]] = true}
|
|
3
|
+
require "openid/extras"
|
|
8
4
|
|
|
9
5
|
module OpenID
|
|
10
6
|
|
|
11
|
-
module
|
|
12
|
-
|
|
13
|
-
def
|
|
7
|
+
module URINorm
|
|
8
|
+
public
|
|
9
|
+
def URINorm.urinorm(uri)
|
|
10
|
+
uri = URI.parse(uri)
|
|
11
|
+
|
|
12
|
+
raise URI::InvalidURIError.new('no scheme') unless uri.scheme
|
|
13
|
+
uri.scheme = uri.scheme.downcase
|
|
14
|
+
unless ['http','https'].member?(uri.scheme)
|
|
15
|
+
raise URI::InvalidURIError.new('Not an HTTP or HTTPS URI')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
raise URI::InvalidURIError.new('no host') unless uri.host
|
|
19
|
+
uri.host = uri.host.downcase
|
|
20
|
+
|
|
21
|
+
uri.path = remove_dot_segments(uri.path)
|
|
22
|
+
uri.path = '/' if uri.path.length == 0
|
|
23
|
+
|
|
24
|
+
uri = uri.normalize.to_s
|
|
25
|
+
uri = uri.gsub(PERCENT_ESCAPE_RE) {
|
|
26
|
+
sub = $&[1..2].to_i(16).chr
|
|
27
|
+
reserved(sub) ? $&.upcase : sub
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return uri
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
RESERVED_RE = /[A-Za-z0-9._~-]/
|
|
35
|
+
PERCENT_ESCAPE_RE = /%[0-9a-zA-Z]{2}/
|
|
36
|
+
|
|
37
|
+
def URINorm.reserved(chr)
|
|
38
|
+
not RESERVED_RE =~ chr
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def URINorm.remove_dot_segments(path)
|
|
14
42
|
result_segments = []
|
|
15
43
|
|
|
16
44
|
while path.length > 0
|
|
@@ -39,34 +67,9 @@ module OpenID
|
|
|
39
67
|
path = path[i..-1]
|
|
40
68
|
end
|
|
41
69
|
end
|
|
42
|
-
|
|
43
|
-
return result_segments.join('')
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def Util.urinorm(uri)
|
|
47
|
-
uri = URI.parse(uri)
|
|
48
|
-
|
|
49
|
-
raise URI::InvalidURIError.new('no scheme') unless uri.scheme
|
|
50
|
-
uri.scheme = uri.scheme.downcase
|
|
51
|
-
unless ['http','https'].member?(uri.scheme)
|
|
52
|
-
raise URI::InvalidURIError.new('Not an HTTP or HTTPS URI')
|
|
53
|
-
end
|
|
54
70
|
|
|
55
|
-
|
|
56
|
-
uri.host = uri.host.downcase
|
|
57
|
-
|
|
58
|
-
uri.path = _remove_dot_segments(uri.path)
|
|
59
|
-
uri.path = '/' if uri.path.length == 0
|
|
60
|
-
|
|
61
|
-
uri = uri.normalize.to_s
|
|
62
|
-
uri = uri.gsub(/%[0-9a-zA-Z]{2}/) {
|
|
63
|
-
i = $&[1..2].upcase.to_i(16)
|
|
64
|
-
UNRESERVED[i] ? i.chr : $&.upcase
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return uri
|
|
71
|
+
return result_segments.join('')
|
|
68
72
|
end
|
|
69
|
-
|
|
70
73
|
end
|
|
71
74
|
|
|
72
75
|
end
|