entp-ruby-openid 2.2

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.
Files changed (200) hide show
  1. data/CHANGELOG +215 -0
  2. data/INSTALL +47 -0
  3. data/LICENSE +210 -0
  4. data/NOTICE +2 -0
  5. data/README +85 -0
  6. data/UPGRADE +127 -0
  7. data/admin/runtests.rb +45 -0
  8. data/examples/README +32 -0
  9. data/examples/active_record_openid_store/README +58 -0
  10. data/examples/active_record_openid_store/XXX_add_open_id_store_to_db.rb +24 -0
  11. data/examples/active_record_openid_store/XXX_upgrade_open_id_store.rb +26 -0
  12. data/examples/active_record_openid_store/init.rb +8 -0
  13. data/examples/active_record_openid_store/lib/association.rb +10 -0
  14. data/examples/active_record_openid_store/lib/nonce.rb +3 -0
  15. data/examples/active_record_openid_store/lib/open_id_setting.rb +4 -0
  16. data/examples/active_record_openid_store/lib/openid_ar_store.rb +57 -0
  17. data/examples/active_record_openid_store/test/store_test.rb +212 -0
  18. data/examples/discover +49 -0
  19. data/examples/rails_openid/README +153 -0
  20. data/examples/rails_openid/Rakefile +10 -0
  21. data/examples/rails_openid/app/controllers/application.rb +4 -0
  22. data/examples/rails_openid/app/controllers/consumer_controller.rb +125 -0
  23. data/examples/rails_openid/app/controllers/login_controller.rb +45 -0
  24. data/examples/rails_openid/app/controllers/server_controller.rb +265 -0
  25. data/examples/rails_openid/app/helpers/application_helper.rb +3 -0
  26. data/examples/rails_openid/app/helpers/login_helper.rb +2 -0
  27. data/examples/rails_openid/app/helpers/server_helper.rb +9 -0
  28. data/examples/rails_openid/app/views/consumer/index.rhtml +81 -0
  29. data/examples/rails_openid/app/views/layouts/server.rhtml +68 -0
  30. data/examples/rails_openid/app/views/login/index.rhtml +56 -0
  31. data/examples/rails_openid/app/views/server/decide.rhtml +26 -0
  32. data/examples/rails_openid/config/boot.rb +19 -0
  33. data/examples/rails_openid/config/database.yml +74 -0
  34. data/examples/rails_openid/config/environment.rb +54 -0
  35. data/examples/rails_openid/config/environments/development.rb +19 -0
  36. data/examples/rails_openid/config/environments/production.rb +19 -0
  37. data/examples/rails_openid/config/environments/test.rb +19 -0
  38. data/examples/rails_openid/config/routes.rb +24 -0
  39. data/examples/rails_openid/doc/README_FOR_APP +2 -0
  40. data/examples/rails_openid/public/404.html +8 -0
  41. data/examples/rails_openid/public/500.html +8 -0
  42. data/examples/rails_openid/public/dispatch.cgi +12 -0
  43. data/examples/rails_openid/public/dispatch.fcgi +26 -0
  44. data/examples/rails_openid/public/dispatch.rb +12 -0
  45. data/examples/rails_openid/public/favicon.ico +0 -0
  46. data/examples/rails_openid/public/images/openid_login_bg.gif +0 -0
  47. data/examples/rails_openid/public/javascripts/controls.js +750 -0
  48. data/examples/rails_openid/public/javascripts/dragdrop.js +584 -0
  49. data/examples/rails_openid/public/javascripts/effects.js +854 -0
  50. data/examples/rails_openid/public/javascripts/prototype.js +1785 -0
  51. data/examples/rails_openid/public/robots.txt +1 -0
  52. data/examples/rails_openid/script/about +3 -0
  53. data/examples/rails_openid/script/breakpointer +3 -0
  54. data/examples/rails_openid/script/console +3 -0
  55. data/examples/rails_openid/script/destroy +3 -0
  56. data/examples/rails_openid/script/generate +3 -0
  57. data/examples/rails_openid/script/performance/benchmarker +3 -0
  58. data/examples/rails_openid/script/performance/profiler +3 -0
  59. data/examples/rails_openid/script/plugin +3 -0
  60. data/examples/rails_openid/script/process/reaper +3 -0
  61. data/examples/rails_openid/script/process/spawner +3 -0
  62. data/examples/rails_openid/script/process/spinner +3 -0
  63. data/examples/rails_openid/script/runner +3 -0
  64. data/examples/rails_openid/script/server +3 -0
  65. data/examples/rails_openid/test/functional/login_controller_test.rb +18 -0
  66. data/examples/rails_openid/test/functional/server_controller_test.rb +18 -0
  67. data/examples/rails_openid/test/test_helper.rb +28 -0
  68. data/lib/hmac/hmac.rb +112 -0
  69. data/lib/hmac/sha1.rb +11 -0
  70. data/lib/hmac/sha2.rb +25 -0
  71. data/lib/openid.rb +22 -0
  72. data/lib/openid/association.rb +249 -0
  73. data/lib/openid/consumer.rb +395 -0
  74. data/lib/openid/consumer/associationmanager.rb +344 -0
  75. data/lib/openid/consumer/checkid_request.rb +186 -0
  76. data/lib/openid/consumer/discovery.rb +497 -0
  77. data/lib/openid/consumer/discovery_manager.rb +123 -0
  78. data/lib/openid/consumer/html_parse.rb +134 -0
  79. data/lib/openid/consumer/idres.rb +523 -0
  80. data/lib/openid/consumer/responses.rb +150 -0
  81. data/lib/openid/cryptutil.rb +115 -0
  82. data/lib/openid/dh.rb +89 -0
  83. data/lib/openid/extension.rb +39 -0
  84. data/lib/openid/extensions/ax.rb +539 -0
  85. data/lib/openid/extensions/oauth.rb +91 -0
  86. data/lib/openid/extensions/pape.rb +179 -0
  87. data/lib/openid/extensions/sreg.rb +277 -0
  88. data/lib/openid/extras.rb +11 -0
  89. data/lib/openid/fetchers.rb +258 -0
  90. data/lib/openid/kvform.rb +136 -0
  91. data/lib/openid/kvpost.rb +58 -0
  92. data/lib/openid/message.rb +553 -0
  93. data/lib/openid/protocolerror.rb +12 -0
  94. data/lib/openid/server.rb +1544 -0
  95. data/lib/openid/store.rb +10 -0
  96. data/lib/openid/store/filesystem.rb +272 -0
  97. data/lib/openid/store/interface.rb +75 -0
  98. data/lib/openid/store/memcache.rb +109 -0
  99. data/lib/openid/store/memory.rb +84 -0
  100. data/lib/openid/store/nonce.rb +68 -0
  101. data/lib/openid/trustroot.rb +349 -0
  102. data/lib/openid/urinorm.rb +75 -0
  103. data/lib/openid/util.rb +119 -0
  104. data/lib/openid/version.rb +3 -0
  105. data/lib/openid/yadis.rb +15 -0
  106. data/lib/openid/yadis/accept.rb +148 -0
  107. data/lib/openid/yadis/constants.rb +21 -0
  108. data/lib/openid/yadis/discovery.rb +153 -0
  109. data/lib/openid/yadis/filters.rb +205 -0
  110. data/lib/openid/yadis/htmltokenizer.rb +305 -0
  111. data/lib/openid/yadis/parsehtml.rb +45 -0
  112. data/lib/openid/yadis/services.rb +42 -0
  113. data/lib/openid/yadis/xrds.rb +155 -0
  114. data/lib/openid/yadis/xri.rb +90 -0
  115. data/lib/openid/yadis/xrires.rb +91 -0
  116. data/test/data/test_discover/openid_utf8.html +11 -0
  117. data/test/support/test_data_mixin.rb +127 -0
  118. data/test/support/test_util.rb +53 -0
  119. data/test/support/yadis_data.rb +131 -0
  120. data/test/support/yadis_data/accept.txt +124 -0
  121. data/test/support/yadis_data/dh.txt +29 -0
  122. data/test/support/yadis_data/example-xrds.xml +14 -0
  123. data/test/support/yadis_data/linkparse.txt +587 -0
  124. data/test/support/yadis_data/n2b64 +650 -0
  125. data/test/support/yadis_data/test1-discover.txt +137 -0
  126. data/test/support/yadis_data/test1-parsehtml.txt +152 -0
  127. data/test/support/yadis_data/test_discover/malformed_meta_tag.html +19 -0
  128. data/test/support/yadis_data/test_discover/openid.html +11 -0
  129. data/test/support/yadis_data/test_discover/openid2.html +11 -0
  130. data/test/support/yadis_data/test_discover/openid2_xrds.xml +12 -0
  131. data/test/support/yadis_data/test_discover/openid2_xrds_no_local_id.xml +11 -0
  132. data/test/support/yadis_data/test_discover/openid_1_and_2.html +11 -0
  133. data/test/support/yadis_data/test_discover/openid_1_and_2_xrds.xml +16 -0
  134. data/test/support/yadis_data/test_discover/openid_1_and_2_xrds_bad_delegate.xml +17 -0
  135. data/test/support/yadis_data/test_discover/openid_and_yadis.html +12 -0
  136. data/test/support/yadis_data/test_discover/openid_no_delegate.html +10 -0
  137. data/test/support/yadis_data/test_discover/openid_utf8.html +11 -0
  138. data/test/support/yadis_data/test_discover/yadis_0entries.xml +12 -0
  139. data/test/support/yadis_data/test_discover/yadis_2_bad_local_id.xml +15 -0
  140. data/test/support/yadis_data/test_discover/yadis_2entries_delegate.xml +22 -0
  141. data/test/support/yadis_data/test_discover/yadis_2entries_idp.xml +21 -0
  142. data/test/support/yadis_data/test_discover/yadis_another_delegate.xml +14 -0
  143. data/test/support/yadis_data/test_discover/yadis_idp.xml +12 -0
  144. data/test/support/yadis_data/test_discover/yadis_idp_delegate.xml +13 -0
  145. data/test/support/yadis_data/test_discover/yadis_no_delegate.xml +11 -0
  146. data/test/support/yadis_data/test_xrds/=j3h.2007.11.14.xrds +25 -0
  147. data/test/support/yadis_data/test_xrds/README +12 -0
  148. data/test/support/yadis_data/test_xrds/delegated-20060809-r1.xrds +34 -0
  149. data/test/support/yadis_data/test_xrds/delegated-20060809-r2.xrds +34 -0
  150. data/test/support/yadis_data/test_xrds/delegated-20060809.xrds +34 -0
  151. data/test/support/yadis_data/test_xrds/no-xrd.xml +7 -0
  152. data/test/support/yadis_data/test_xrds/not-xrds.xml +2 -0
  153. data/test/support/yadis_data/test_xrds/prefixsometimes.xrds +34 -0
  154. data/test/support/yadis_data/test_xrds/ref.xrds +109 -0
  155. data/test/support/yadis_data/test_xrds/sometimesprefix.xrds +34 -0
  156. data/test/support/yadis_data/test_xrds/spoof1.xrds +25 -0
  157. data/test/support/yadis_data/test_xrds/spoof2.xrds +25 -0
  158. data/test/support/yadis_data/test_xrds/spoof3.xrds +37 -0
  159. data/test/support/yadis_data/test_xrds/status222.xrds +9 -0
  160. data/test/support/yadis_data/test_xrds/subsegments.xrds +58 -0
  161. data/test/support/yadis_data/test_xrds/valid-populated-xrds.xml +39 -0
  162. data/test/support/yadis_data/trustroot.txt +153 -0
  163. data/test/support/yadis_data/urinorm.txt +79 -0
  164. data/test/test_accept.rb +170 -0
  165. data/test/test_association.rb +268 -0
  166. data/test/test_associationmanager.rb +918 -0
  167. data/test/test_ax.rb +690 -0
  168. data/test/test_checkid_request.rb +293 -0
  169. data/test/test_consumer.rb +260 -0
  170. data/test/test_cryptutil.rb +119 -0
  171. data/test/test_dh.rb +85 -0
  172. data/test/test_discover.rb +848 -0
  173. data/test/test_discovery_manager.rb +259 -0
  174. data/test/test_extension.rb +46 -0
  175. data/test/test_extras.rb +35 -0
  176. data/test/test_fetchers.rb +554 -0
  177. data/test/test_filters.rb +269 -0
  178. data/test/test_helper.rb +4 -0
  179. data/test/test_idres.rb +961 -0
  180. data/test/test_kvform.rb +164 -0
  181. data/test/test_kvpost.rb +64 -0
  182. data/test/test_linkparse.rb +100 -0
  183. data/test/test_message.rb +1115 -0
  184. data/test/test_nonce.rb +89 -0
  185. data/test/test_oauth.rb +176 -0
  186. data/test/test_openid_yadis.rb +177 -0
  187. data/test/test_pape.rb +248 -0
  188. data/test/test_parsehtml.rb +79 -0
  189. data/test/test_responses.rb +63 -0
  190. data/test/test_server.rb +2455 -0
  191. data/test/test_sreg.rb +479 -0
  192. data/test/test_stores.rb +292 -0
  193. data/test/test_trustroot.rb +111 -0
  194. data/test/test_urinorm.rb +34 -0
  195. data/test/test_util.rb +145 -0
  196. data/test/test_xrds.rb +167 -0
  197. data/test/test_xri.rb +48 -0
  198. data/test/test_xrires.rb +67 -0
  199. data/test/test_yadis_discovery.rb +218 -0
  200. metadata +268 -0
@@ -0,0 +1,45 @@
1
+ require "openid/yadis/htmltokenizer"
2
+ require 'cgi'
3
+
4
+ module OpenID
5
+ module Yadis
6
+ def Yadis.html_yadis_location(html)
7
+ parser = HTMLTokenizer.new(html)
8
+
9
+ # to keep track of whether or not we are in the head element
10
+ in_head = false
11
+
12
+ begin
13
+ while el = parser.getTag('head', '/head', 'meta', 'body', '/body',
14
+ 'html', 'script')
15
+
16
+ # we are leaving head or have reached body, so we bail
17
+ return nil if ['/head', 'body', '/body'].member?(el.tag_name)
18
+
19
+ if el.tag_name == 'head'
20
+ unless el.to_s[-2] == ?/ # tag ends with a /: a short tag
21
+ in_head = true
22
+ end
23
+ end
24
+ next unless in_head
25
+
26
+ if el.tag_name == 'script'
27
+ unless el.to_s[-2] == ?/ # tag ends with a /: a short tag
28
+ parser.getTag('/script')
29
+ end
30
+ end
31
+
32
+ return nil if el.tag_name == 'html'
33
+
34
+ if el.tag_name == 'meta' and (equiv = el.attr_hash['http-equiv'])
35
+ if ['x-xrds-location','x-yadis-location'].member?(equiv.downcase) &&
36
+ el.attr_hash.member?('content')
37
+ return CGI::unescapeHTML(el.attr_hash['content'])
38
+ end
39
+ end
40
+ end
41
+ rescue HTMLTokenizerError # just stop parsing if there's an error
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,42 @@
1
+
2
+ require 'openid/yadis/filters'
3
+ require 'openid/yadis/discovery'
4
+ require 'openid/yadis/xrds'
5
+
6
+ module OpenID
7
+ module Yadis
8
+ def Yadis.get_service_endpoints(input_url, flt=nil)
9
+ # Perform the Yadis protocol on the input URL and return an
10
+ # iterable of resulting endpoint objects.
11
+ #
12
+ # @param flt: A filter object or something that is convertable
13
+ # to a filter object (using mkFilter) that will be used to
14
+ # generate endpoint objects. This defaults to generating
15
+ # BasicEndpoint objects.
16
+ result = Yadis.discover(input_url)
17
+ begin
18
+ endpoints = Yadis.apply_filter(result.normalized_uri,
19
+ result.response_text, flt)
20
+ rescue XRDSError => err
21
+ raise DiscoveryFailure.new(err.to_s, nil)
22
+ end
23
+
24
+ return [result.normalized_uri, endpoints]
25
+ end
26
+
27
+ def Yadis.apply_filter(normalized_uri, xrd_data, flt=nil)
28
+ # Generate an iterable of endpoint objects given this input data,
29
+ # presumably from the result of performing the Yadis protocol.
30
+
31
+ flt = Yadis.make_filter(flt)
32
+ et = Yadis.parseXRDS(xrd_data)
33
+
34
+ endpoints = []
35
+ each_service(et) { |service_element|
36
+ endpoints += flt.get_service_endpoints(normalized_uri, service_element)
37
+ }
38
+
39
+ return endpoints
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,155 @@
1
+ require 'rexml/document'
2
+ require 'rexml/element'
3
+ require 'rexml/xpath'
4
+
5
+ require 'openid/yadis/xri'
6
+
7
+ module OpenID
8
+ module Yadis
9
+
10
+ XRD_NS_2_0 = 'xri://$xrd*($v*2.0)'
11
+ XRDS_NS = 'xri://$xrds'
12
+
13
+ XRDS_NAMESPACES = {
14
+ 'xrds' => XRDS_NS,
15
+ 'xrd' => XRD_NS_2_0,
16
+ }
17
+
18
+ class XRDSError < StandardError; end
19
+
20
+ # Raised when there's an assertion in the XRDS that it does not
21
+ # have the authority to make.
22
+ class XRDSFraud < XRDSError
23
+ end
24
+
25
+ def Yadis::get_canonical_id(iname, xrd_tree)
26
+ # Return the CanonicalID from this XRDS document.
27
+ #
28
+ # @param iname: the XRI being resolved.
29
+ # @type iname: unicode
30
+ #
31
+ # @param xrd_tree: The XRDS output from the resolver.
32
+ #
33
+ # @returns: The XRI CanonicalID or None.
34
+ # @returntype: unicode or None
35
+
36
+ xrd_list = []
37
+ REXML::XPath::match(xrd_tree.root, '/xrds:XRDS/xrd:XRD', XRDS_NAMESPACES).each { |el|
38
+ xrd_list << el
39
+ }
40
+
41
+ xrd_list.reverse!
42
+
43
+ cid_elements = []
44
+
45
+ if !xrd_list.empty?
46
+ xrd_list[0].elements.each { |e|
47
+ if !e.respond_to?('name')
48
+ next
49
+ end
50
+ if e.name == 'CanonicalID'
51
+ cid_elements << e
52
+ end
53
+ }
54
+ end
55
+
56
+ cid_element = cid_elements[0]
57
+
58
+ if !cid_element
59
+ return nil
60
+ end
61
+
62
+ canonicalID = XRI.make_xri(cid_element.text)
63
+
64
+ childID = canonicalID.downcase
65
+
66
+ xrd_list[1..-1].each { |xrd|
67
+ parent_sought = childID[0...childID.rindex('!')]
68
+
69
+ parent = XRI.make_xri(xrd.elements["CanonicalID"].text)
70
+
71
+ if parent_sought != parent.downcase
72
+ raise XRDSFraud.new(sprintf("%s can not come from %s", parent_sought,
73
+ parent))
74
+ end
75
+
76
+ childID = parent_sought
77
+ }
78
+
79
+ root = XRI.root_authority(iname)
80
+ if not XRI.provider_is_authoritative(root, childID)
81
+ raise XRDSFraud.new(sprintf("%s can not come from root %s", childID, root))
82
+ end
83
+
84
+ return canonicalID
85
+ end
86
+
87
+ class XRDSError < StandardError
88
+ end
89
+
90
+ def Yadis::parseXRDS(text)
91
+ if text.nil?
92
+ raise XRDSError.new("Not an XRDS document.")
93
+ end
94
+
95
+ begin
96
+ d = REXML::Document.new(text)
97
+ rescue RuntimeError => why
98
+ raise XRDSError.new("Not an XRDS document. Failed to parse XML.")
99
+ end
100
+
101
+ if is_xrds?(d)
102
+ return d
103
+ else
104
+ raise XRDSError.new("Not an XRDS document.")
105
+ end
106
+ end
107
+
108
+ def Yadis::is_xrds?(xrds_tree)
109
+ xrds_root = xrds_tree.root
110
+ return (!xrds_root.nil? and
111
+ xrds_root.name == 'XRDS' and
112
+ xrds_root.namespace == XRDS_NS)
113
+ end
114
+
115
+ def Yadis::get_yadis_xrd(xrds_tree)
116
+ REXML::XPath.each(xrds_tree.root,
117
+ '/xrds:XRDS/xrd:XRD[last()]',
118
+ XRDS_NAMESPACES) { |el|
119
+ return el
120
+ }
121
+ raise XRDSError.new("No XRD element found.")
122
+ end
123
+
124
+ # aka iterServices in Python
125
+ def Yadis::each_service(xrds_tree, &block)
126
+ xrd = get_yadis_xrd(xrds_tree)
127
+ xrd.each_element('Service', &block)
128
+ end
129
+
130
+ def Yadis::services(xrds_tree)
131
+ s = []
132
+ each_service(xrds_tree) { |service|
133
+ s << service
134
+ }
135
+ return s
136
+ end
137
+
138
+ def Yadis::expand_service(service_element)
139
+ es = service_element.elements
140
+ uris = es.each('URI') { |u| }
141
+ uris = prio_sort(uris)
142
+ types = es.each('Type/text()')
143
+ # REXML::Text objects are not strings.
144
+ types = types.collect { |t| t.to_s }
145
+ uris.collect { |uri| [types, uri.text, service_element] }
146
+ end
147
+
148
+ # Sort a list of elements that have priority attributes.
149
+ def Yadis::prio_sort(elements)
150
+ elements.sort { |a,b|
151
+ a.attribute('priority').to_s.to_i <=> b.attribute('priority').to_s.to_i
152
+ }
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,90 @@
1
+ require 'openid/yadis/xrds'
2
+ require 'openid/fetchers'
3
+
4
+ module OpenID
5
+ module Yadis
6
+ module XRI
7
+
8
+ # The '(' is for cross-reference authorities, and hopefully has a
9
+ # matching ')' somewhere.
10
+ XRI_AUTHORITIES = ["!", "=", "@", "+", "$", "("]
11
+
12
+ def self.identifier_scheme(identifier)
13
+ if (!identifier.nil? and
14
+ identifier.length > 0 and
15
+ (identifier.match('^xri://') or
16
+ XRI_AUTHORITIES.member?(identifier[0].chr)))
17
+ return :xri
18
+ else
19
+ return :uri
20
+ end
21
+ end
22
+
23
+ # Transform an XRI reference to an IRI reference. Note this is
24
+ # not not idempotent, so do not apply this to an identifier more
25
+ # than once. XRI Syntax section 2.3.1
26
+ def self.to_iri_normal(xri)
27
+ iri = xri.dup
28
+ iri.insert(0, 'xri://') if not iri.match('^xri://')
29
+ return escape_for_iri(iri)
30
+ end
31
+
32
+ # Note this is not not idempotent, so do not apply this more than
33
+ # once. XRI Syntax section 2.3.2
34
+ def self.escape_for_iri(xri)
35
+ esc = xri.dup
36
+ # encode all %
37
+ esc.gsub!(/%/, '%25')
38
+ esc.gsub!(/\((.*?)\)/) { |xref_match|
39
+ xref_match.gsub(/[\/\?\#]/) { |char_match|
40
+ CGI::escape(char_match)
41
+ }
42
+ }
43
+ return esc
44
+ end
45
+
46
+ # Transform an XRI reference to a URI reference. Note this is not
47
+ # not idempotent, so do not apply this to an identifier more than
48
+ # once. XRI Syntax section 2.3.1
49
+ def self.to_uri_normal(xri)
50
+ return iri_to_uri(to_iri_normal(xri))
51
+ end
52
+
53
+ # RFC 3987 section 3.1
54
+ def self.iri_to_uri(iri)
55
+ uri = iri.dup
56
+ # for char in ucschar or iprivate
57
+ # convert each char to %HH%HH%HH (as many %HH as octets)
58
+ return uri
59
+ end
60
+
61
+ def self.provider_is_authoritative(provider_id, canonical_id)
62
+ lastbang = canonical_id.rindex('!')
63
+ return false unless lastbang
64
+ parent = canonical_id[0...lastbang]
65
+ return parent == provider_id
66
+ end
67
+
68
+ def self.root_authority(xri)
69
+ xri = xri[6..-1] if xri.index('xri://') == 0
70
+ authority = xri.split('/', 2)[0]
71
+ if authority[0].chr == '('
72
+ root = authority[0...authority.index(')')+1]
73
+ elsif XRI_AUTHORITIES.member?(authority[0].chr)
74
+ root = authority[0].chr
75
+ else
76
+ root = authority.split(/[!*]/)[0]
77
+ end
78
+
79
+ self.make_xri(root)
80
+ end
81
+
82
+ def self.make_xri(xri)
83
+ if xri.index('xri://') != 0
84
+ xri = 'xri://' + xri
85
+ end
86
+ return xri
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,91 @@
1
+ require "cgi"
2
+ require "openid/yadis/xri"
3
+ require "openid/yadis/xrds"
4
+ require "openid/fetchers"
5
+
6
+ module OpenID
7
+
8
+ module Yadis
9
+
10
+ module XRI
11
+
12
+ class XRIHTTPError < StandardError; end
13
+
14
+ class ProxyResolver
15
+
16
+ DEFAULT_PROXY = 'http://proxy.xri.net/' unless defined?(DEFAULT_PROXY)
17
+
18
+ def initialize(proxy_url=nil)
19
+ if proxy_url
20
+ @proxy_url = proxy_url
21
+ else
22
+ @proxy_url = DEFAULT_PROXY
23
+ end
24
+
25
+ @proxy_url += '/' unless @proxy_url.match('/$')
26
+ end
27
+
28
+ def query_url(xri, service_type=nil)
29
+ # URI normal form has a leading xri://, but we need to strip
30
+ # that off again for the QXRI. This is under discussion for
31
+ # XRI Resolution WD 11.
32
+ qxri = XRI.to_uri_normal(xri)[6..-1]
33
+ hxri = @proxy_url + CGI::escape( qxri )
34
+ args = {'_xrd_r' => 'application/xrds+xml'}
35
+ args['_xrd_t'] = service_type if service_type
36
+
37
+ return XRI.append_args(hxri, args)
38
+ end
39
+
40
+ def query(xri)
41
+ # these can be query args or http headers, needn't be both.
42
+ # headers = {'Accept' => 'application/xrds+xml;sep=true'}
43
+
44
+ url = self.query_url(xri)
45
+ begin
46
+ response = OpenID.fetch(url)
47
+ rescue
48
+ raise XRIHTTPError, "Could not fetch #{xri}, #{$!}"
49
+ end
50
+ raise XRIHTTPError, "Fetching #{xri} returned nothing" if response.nil?
51
+
52
+ xrds = Yadis::parseXRDS(response.body)
53
+ raise XRIHTTPError, "Fetching #{xri} did not return an XRDS" if xrds.nil?
54
+ canonicalID = Yadis::get_canonical_id(xri, xrds)
55
+
56
+ return canonicalID, Yadis::services(xrds)
57
+ # TODO:
58
+ # * If we do get hits for multiple service_types, we're almost
59
+ # certainly going to have duplicated service entries and
60
+ # broken priority ordering.
61
+ end
62
+ end
63
+
64
+ def self.urlencode(args)
65
+ a = []
66
+ args.each do |key, val|
67
+ a << (CGI::escape(key) + "=" + CGI::escape(val))
68
+ end
69
+ a.join("&")
70
+ end
71
+
72
+ def self.append_args(url, args)
73
+ return url if args.length == 0
74
+
75
+ # strip all trailing question marks
76
+ rstripped = url.dup.sub(/\?+\z/, '').sub(/(%3F)+\z/, '')
77
+
78
+ if rstripped.include?('?') or rstripped.include?('%3F')
79
+ sep = ( rstripped[-1] == '&' ? '' : '&' )
80
+ else
81
+ sep = '?'
82
+ end
83
+
84
+ return rstripped + sep + XRI.urlencode(args)
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html>
3
+ <head>
4
+ <title>Identity Page for Smoker</title>
5
+ <link rel="openid.server" href="http://www.myopenid.com/server" />
6
+ <link rel="openid.delegate" href="http://smoker.myopenid.com/" />
7
+ </head>
8
+ <body>
9
+ <p>こんにちは</p>
10
+ </body>
11
+ </html>
@@ -0,0 +1,127 @@
1
+ require "pathname"
2
+
3
+ module OpenID
4
+ module TestDataMixin
5
+ TESTS_DIR = Pathname.new(__FILE__).dirname
6
+ TEST_DATA_DIR = Pathname.new('yadis_data')
7
+
8
+ def read_data_file(filename, lines=true, data_dir=TEST_DATA_DIR)
9
+ fname = TESTS_DIR.join(data_dir, filename)
10
+
11
+ if lines
12
+ fname.readlines
13
+ else
14
+ fname.read
15
+ end
16
+ end
17
+ end
18
+
19
+ module FetcherMixin
20
+ def with_fetcher(fetcher)
21
+ original_fetcher = OpenID.fetcher
22
+ begin
23
+ OpenID.fetcher = fetcher
24
+ return yield
25
+ ensure
26
+ OpenID.fetcher = original_fetcher
27
+ end
28
+ end
29
+ end
30
+
31
+ module Const
32
+ def const(symbol, value)
33
+ (class << self;self;end).instance_eval do
34
+ define_method(symbol) { value }
35
+ end
36
+ end
37
+ end
38
+
39
+ class MockResponse
40
+ attr_reader :code, :body
41
+
42
+ def initialize(code, body)
43
+ @code = code.to_s
44
+ @body = body
45
+ end
46
+ end
47
+
48
+ module ProtocolErrorMixin
49
+ def assert_protocol_error(str_prefix)
50
+ begin
51
+ result = yield
52
+ rescue ProtocolError => why
53
+ message = "Expected prefix #{str_prefix.inspect}, got "\
54
+ "#{why.message.inspect}"
55
+ assert(why.message.starts_with?(str_prefix), message)
56
+ else
57
+ fail("Expected ProtocolError. Got #{result.inspect}")
58
+ end
59
+ end
60
+ end
61
+
62
+ module OverrideMethodMixin
63
+ def with_method_overridden(method_name, proc)
64
+ original = method(method_name)
65
+ begin
66
+ # TODO: find a combination of undef calls which prevent the warning
67
+ verbose, $VERBOSE = $VERBOSE, false
68
+ define_method(method_name, proc)
69
+ module_function(method_name)
70
+ $VERBOSE = verbose
71
+ yield
72
+ ensure
73
+ if original.respond_to? :owner
74
+ original.owner.send(:undef_method, method_name)
75
+ original.owner.send :define_method, method_name, original
76
+ else
77
+ define_method(method_name, original)
78
+ module_function(method_name)
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ # To use:
85
+ # > x = Object.new
86
+ # > x.extend(InstanceDefExtension)
87
+ # > x.instance_def(:monkeys) do
88
+ # > "bananas"
89
+ # > end
90
+ # > x.monkeys
91
+ #
92
+ module InstanceDefExtension
93
+ def instance_def(method_name, &proc)
94
+ (class << self;self;end).instance_eval do
95
+ # TODO: find a combination of undef calls which prevent the warning
96
+ verbose, $VERBOSE = $VERBOSE, false
97
+ define_method(method_name, proc)
98
+ $VERBOSE = verbose
99
+ end
100
+ end
101
+ end
102
+
103
+ GOODSIG = '[A Good Signature]'
104
+
105
+ class GoodAssoc
106
+ attr_accessor :handle, :expires_in
107
+
108
+ def initialize(handle='-blah-')
109
+ @handle = handle
110
+ @expires_in = 3600
111
+ end
112
+
113
+ def check_message_signature(msg)
114
+ msg.get_arg(OPENID_NS, 'sig') == GOODSIG
115
+ end
116
+ end
117
+
118
+ class HTTPResponse
119
+ def self._from_raw_data(status, body="", headers={}, final_url=nil)
120
+ resp = Net::HTTPResponse.new('1.1', status.to_s, 'NONE')
121
+ me = self._from_net_response(resp, final_url)
122
+ me.initialize_http_header headers
123
+ me.body = body
124
+ return me
125
+ end
126
+ end
127
+ end