nov-ruby-openid 2.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. data/CHANGELOG +215 -0
  2. data/CHANGES-2.1.0 +36 -0
  3. data/INSTALL +47 -0
  4. data/LICENSE +210 -0
  5. data/NOTICE +2 -0
  6. data/README +81 -0
  7. data/Rakefile +98 -0
  8. data/UPGRADE +127 -0
  9. data/VERSION +1 -0
  10. data/contrib/google/ruby-openid-apps-discovery-1.0.gem +0 -0
  11. data/contrib/google/ruby-openid-apps-discovery-1.01.gem +0 -0
  12. data/examples/README +32 -0
  13. data/examples/active_record_openid_store/README +58 -0
  14. data/examples/active_record_openid_store/XXX_add_open_id_store_to_db.rb +24 -0
  15. data/examples/active_record_openid_store/XXX_upgrade_open_id_store.rb +26 -0
  16. data/examples/active_record_openid_store/init.rb +8 -0
  17. data/examples/active_record_openid_store/lib/association.rb +10 -0
  18. data/examples/active_record_openid_store/lib/nonce.rb +3 -0
  19. data/examples/active_record_openid_store/lib/open_id_setting.rb +4 -0
  20. data/examples/active_record_openid_store/lib/openid_ar_store.rb +57 -0
  21. data/examples/active_record_openid_store/test/store_test.rb +212 -0
  22. data/examples/discover +49 -0
  23. data/examples/rails_openid/README +153 -0
  24. data/examples/rails_openid/Rakefile +10 -0
  25. data/examples/rails_openid/app/controllers/application.rb +4 -0
  26. data/examples/rails_openid/app/controllers/consumer_controller.rb +122 -0
  27. data/examples/rails_openid/app/controllers/login_controller.rb +45 -0
  28. data/examples/rails_openid/app/controllers/server_controller.rb +265 -0
  29. data/examples/rails_openid/app/helpers/application_helper.rb +3 -0
  30. data/examples/rails_openid/app/helpers/login_helper.rb +2 -0
  31. data/examples/rails_openid/app/helpers/server_helper.rb +9 -0
  32. data/examples/rails_openid/app/views/consumer/index.rhtml +81 -0
  33. data/examples/rails_openid/app/views/layouts/server.rhtml +68 -0
  34. data/examples/rails_openid/app/views/login/index.rhtml +56 -0
  35. data/examples/rails_openid/app/views/server/decide.rhtml +26 -0
  36. data/examples/rails_openid/config/boot.rb +19 -0
  37. data/examples/rails_openid/config/database.yml +74 -0
  38. data/examples/rails_openid/config/environment.rb +54 -0
  39. data/examples/rails_openid/config/environments/development.rb +19 -0
  40. data/examples/rails_openid/config/environments/production.rb +19 -0
  41. data/examples/rails_openid/config/environments/test.rb +19 -0
  42. data/examples/rails_openid/config/routes.rb +24 -0
  43. data/examples/rails_openid/doc/README_FOR_APP +2 -0
  44. data/examples/rails_openid/public/.htaccess +40 -0
  45. data/examples/rails_openid/public/404.html +8 -0
  46. data/examples/rails_openid/public/500.html +8 -0
  47. data/examples/rails_openid/public/dispatch.cgi +12 -0
  48. data/examples/rails_openid/public/dispatch.fcgi +26 -0
  49. data/examples/rails_openid/public/dispatch.rb +12 -0
  50. data/examples/rails_openid/public/favicon.ico +0 -0
  51. data/examples/rails_openid/public/images/openid_login_bg.gif +0 -0
  52. data/examples/rails_openid/public/javascripts/controls.js +750 -0
  53. data/examples/rails_openid/public/javascripts/dragdrop.js +584 -0
  54. data/examples/rails_openid/public/javascripts/effects.js +854 -0
  55. data/examples/rails_openid/public/javascripts/prototype.js +1785 -0
  56. data/examples/rails_openid/public/robots.txt +1 -0
  57. data/examples/rails_openid/script/about +3 -0
  58. data/examples/rails_openid/script/breakpointer +3 -0
  59. data/examples/rails_openid/script/console +3 -0
  60. data/examples/rails_openid/script/destroy +3 -0
  61. data/examples/rails_openid/script/generate +3 -0
  62. data/examples/rails_openid/script/performance/benchmarker +3 -0
  63. data/examples/rails_openid/script/performance/profiler +3 -0
  64. data/examples/rails_openid/script/plugin +3 -0
  65. data/examples/rails_openid/script/process/reaper +3 -0
  66. data/examples/rails_openid/script/process/spawner +3 -0
  67. data/examples/rails_openid/script/process/spinner +3 -0
  68. data/examples/rails_openid/script/runner +3 -0
  69. data/examples/rails_openid/script/server +3 -0
  70. data/examples/rails_openid/test/functional/login_controller_test.rb +18 -0
  71. data/examples/rails_openid/test/functional/server_controller_test.rb +18 -0
  72. data/examples/rails_openid/test/test_helper.rb +28 -0
  73. data/lib/hmac/hmac.rb +112 -0
  74. data/lib/hmac/sha1.rb +11 -0
  75. data/lib/hmac/sha2.rb +25 -0
  76. data/lib/openid.rb +20 -0
  77. data/lib/openid/association.rb +249 -0
  78. data/lib/openid/consumer.rb +395 -0
  79. data/lib/openid/consumer/associationmanager.rb +344 -0
  80. data/lib/openid/consumer/checkid_request.rb +186 -0
  81. data/lib/openid/consumer/discovery.rb +497 -0
  82. data/lib/openid/consumer/discovery_manager.rb +123 -0
  83. data/lib/openid/consumer/html_parse.rb +134 -0
  84. data/lib/openid/consumer/idres.rb +523 -0
  85. data/lib/openid/consumer/responses.rb +148 -0
  86. data/lib/openid/cryptutil.rb +115 -0
  87. data/lib/openid/dh.rb +89 -0
  88. data/lib/openid/extension.rb +39 -0
  89. data/lib/openid/extensions/ax.rb +539 -0
  90. data/lib/openid/extensions/oauth.rb +91 -0
  91. data/lib/openid/extensions/pape.rb +179 -0
  92. data/lib/openid/extensions/sreg.rb +277 -0
  93. data/lib/openid/extensions/ui.rb +53 -0
  94. data/lib/openid/extras.rb +11 -0
  95. data/lib/openid/fetchers.rb +258 -0
  96. data/lib/openid/kvform.rb +136 -0
  97. data/lib/openid/kvpost.rb +58 -0
  98. data/lib/openid/message.rb +553 -0
  99. data/lib/openid/protocolerror.rb +8 -0
  100. data/lib/openid/server.rb +1544 -0
  101. data/lib/openid/store/filesystem.rb +271 -0
  102. data/lib/openid/store/interface.rb +75 -0
  103. data/lib/openid/store/memcache.rb +107 -0
  104. data/lib/openid/store/memory.rb +84 -0
  105. data/lib/openid/store/nonce.rb +68 -0
  106. data/lib/openid/trustroot.rb +349 -0
  107. data/lib/openid/urinorm.rb +75 -0
  108. data/lib/openid/util.rb +110 -0
  109. data/lib/openid/yadis/accept.rb +148 -0
  110. data/lib/openid/yadis/constants.rb +21 -0
  111. data/lib/openid/yadis/discovery.rb +153 -0
  112. data/lib/openid/yadis/filters.rb +205 -0
  113. data/lib/openid/yadis/htmltokenizer.rb +305 -0
  114. data/lib/openid/yadis/parsehtml.rb +45 -0
  115. data/lib/openid/yadis/services.rb +42 -0
  116. data/lib/openid/yadis/xrds.rb +155 -0
  117. data/lib/openid/yadis/xri.rb +90 -0
  118. data/lib/openid/yadis/xrires.rb +99 -0
  119. data/setup.rb +1551 -0
  120. data/test/data/accept.txt +124 -0
  121. data/test/data/dh.txt +29 -0
  122. data/test/data/example-xrds.xml +14 -0
  123. data/test/data/linkparse.txt +587 -0
  124. data/test/data/n2b64 +650 -0
  125. data/test/data/test1-discover.txt +137 -0
  126. data/test/data/test1-parsehtml.txt +152 -0
  127. data/test/data/test_discover/malformed_meta_tag.html +19 -0
  128. data/test/data/test_discover/openid.html +11 -0
  129. data/test/data/test_discover/openid2.html +11 -0
  130. data/test/data/test_discover/openid2_xrds.xml +12 -0
  131. data/test/data/test_discover/openid2_xrds_no_local_id.xml +11 -0
  132. data/test/data/test_discover/openid_1_and_2.html +11 -0
  133. data/test/data/test_discover/openid_1_and_2_xrds.xml +16 -0
  134. data/test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml +17 -0
  135. data/test/data/test_discover/openid_and_yadis.html +12 -0
  136. data/test/data/test_discover/openid_no_delegate.html +10 -0
  137. data/test/data/test_discover/openid_utf8.html +11 -0
  138. data/test/data/test_discover/yadis_0entries.xml +12 -0
  139. data/test/data/test_discover/yadis_2_bad_local_id.xml +15 -0
  140. data/test/data/test_discover/yadis_2entries_delegate.xml +22 -0
  141. data/test/data/test_discover/yadis_2entries_idp.xml +21 -0
  142. data/test/data/test_discover/yadis_another_delegate.xml +14 -0
  143. data/test/data/test_discover/yadis_idp.xml +12 -0
  144. data/test/data/test_discover/yadis_idp_delegate.xml +13 -0
  145. data/test/data/test_discover/yadis_no_delegate.xml +11 -0
  146. data/test/data/test_xrds/=j3h.2007.11.14.xrds +25 -0
  147. data/test/data/test_xrds/README +12 -0
  148. data/test/data/test_xrds/delegated-20060809-r1.xrds +34 -0
  149. data/test/data/test_xrds/delegated-20060809-r2.xrds +34 -0
  150. data/test/data/test_xrds/delegated-20060809.xrds +34 -0
  151. data/test/data/test_xrds/no-xrd.xml +7 -0
  152. data/test/data/test_xrds/not-xrds.xml +2 -0
  153. data/test/data/test_xrds/prefixsometimes.xrds +34 -0
  154. data/test/data/test_xrds/ref.xrds +109 -0
  155. data/test/data/test_xrds/sometimesprefix.xrds +34 -0
  156. data/test/data/test_xrds/spoof1.xrds +25 -0
  157. data/test/data/test_xrds/spoof2.xrds +25 -0
  158. data/test/data/test_xrds/spoof3.xrds +37 -0
  159. data/test/data/test_xrds/status222.xrds +9 -0
  160. data/test/data/test_xrds/subsegments.xrds +58 -0
  161. data/test/data/test_xrds/valid-populated-xrds.xml +39 -0
  162. data/test/data/trustroot.txt +153 -0
  163. data/test/data/urinorm.txt +79 -0
  164. data/test/discoverdata.rb +131 -0
  165. data/test/test_accept.rb +170 -0
  166. data/test/test_association.rb +266 -0
  167. data/test/test_associationmanager.rb +917 -0
  168. data/test/test_ax.rb +690 -0
  169. data/test/test_checkid_request.rb +294 -0
  170. data/test/test_consumer.rb +257 -0
  171. data/test/test_cryptutil.rb +119 -0
  172. data/test/test_dh.rb +86 -0
  173. data/test/test_discover.rb +852 -0
  174. data/test/test_discovery_manager.rb +262 -0
  175. data/test/test_extension.rb +46 -0
  176. data/test/test_extras.rb +35 -0
  177. data/test/test_fetchers.rb +565 -0
  178. data/test/test_filters.rb +270 -0
  179. data/test/test_idres.rb +963 -0
  180. data/test/test_kvform.rb +165 -0
  181. data/test/test_kvpost.rb +65 -0
  182. data/test/test_linkparse.rb +101 -0
  183. data/test/test_message.rb +1116 -0
  184. data/test/test_nonce.rb +89 -0
  185. data/test/test_oauth.rb +175 -0
  186. data/test/test_openid_yadis.rb +178 -0
  187. data/test/test_pape.rb +247 -0
  188. data/test/test_parsehtml.rb +80 -0
  189. data/test/test_responses.rb +63 -0
  190. data/test/test_server.rb +2457 -0
  191. data/test/test_sreg.rb +479 -0
  192. data/test/test_stores.rb +298 -0
  193. data/test/test_trustroot.rb +113 -0
  194. data/test/test_ui.rb +93 -0
  195. data/test/test_urinorm.rb +35 -0
  196. data/test/test_util.rb +145 -0
  197. data/test/test_xrds.rb +169 -0
  198. data/test/test_xri.rb +48 -0
  199. data/test/test_xrires.rb +63 -0
  200. data/test/test_yadis_discovery.rb +220 -0
  201. data/test/testutil.rb +127 -0
  202. data/test/util.rb +53 -0
  203. metadata +336 -0
@@ -0,0 +1,270 @@
1
+
2
+ require 'test/unit'
3
+ require 'openid/yadis/filters'
4
+
5
+ module OpenID
6
+ class BasicServiceEndpointTest < Test::Unit::TestCase
7
+ def test_match_types
8
+ # Make sure the match_types operation returns the expected
9
+ # results with various inputs.
10
+ types = ["urn:bogus", "urn:testing"]
11
+ yadis_url = "http://yadis/"
12
+
13
+ no_types_endpoint = Yadis::BasicServiceEndpoint.new(yadis_url, [], nil, nil)
14
+
15
+ some_types_endpoint = Yadis::BasicServiceEndpoint.new(yadis_url, types,
16
+ nil, nil)
17
+
18
+ assert(no_types_endpoint.match_types([]) == [])
19
+ assert(no_types_endpoint.match_types(["urn:absent"]) == [])
20
+
21
+ assert(some_types_endpoint.match_types([]) == [])
22
+ assert(some_types_endpoint.match_types(["urn:absent"]) == [])
23
+ assert(some_types_endpoint.match_types(types) == types)
24
+ assert(some_types_endpoint.match_types([types[1], types[0]]) == types)
25
+ assert(some_types_endpoint.match_types([types[0]]) == [types[0]])
26
+ assert(some_types_endpoint.match_types(types + ["urn:absent"]) == types)
27
+ end
28
+
29
+ def test_from_basic_service_endpoint
30
+ # Check BasicServiceEndpoint.from_basic_service_endpoint
31
+ endpoint = "unused"
32
+ e = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil)
33
+
34
+ assert(Yadis::BasicServiceEndpoint.from_basic_service_endpoint(endpoint) ==
35
+ endpoint)
36
+ assert(e.from_basic_service_endpoint(endpoint) ==
37
+ endpoint)
38
+ end
39
+ end
40
+
41
+ class TransformFilterMakerTest < Test::Unit::TestCase
42
+ def make_service_element(types, uris)
43
+ service = REXML::Element.new('Service')
44
+ types.each { |type_text|
45
+ service.add_element('Type').text = type_text
46
+ }
47
+ uris.each { |uri_text|
48
+ service.add_element('URI').text = uri_text
49
+ }
50
+ return service
51
+ end
52
+ def test_get_service_endpoints
53
+ yadis_url = "http://yad.is/"
54
+ uri = "http://uri/"
55
+ type_uris = ["urn:type1", "urn:type2"]
56
+ element = make_service_element(type_uris, [uri])
57
+
58
+ data = [
59
+ [type_uris, uri, element],
60
+ ]
61
+
62
+ filters = [Proc.new { |endpoint|
63
+ if endpoint.service_element == element
64
+ endpoint
65
+ else
66
+ nil
67
+ end
68
+ }
69
+ ]
70
+
71
+ tf = Yadis::TransformFilterMaker.new(filters)
72
+ result = tf.get_service_endpoints(yadis_url, element)
73
+
74
+ assert_equal(result[0].yadis_url, yadis_url, result)
75
+ assert_equal(result[0].uri, uri, result)
76
+ end
77
+
78
+ def test_empty_transform_filter
79
+ # A transform filter with no filter procs should return nil.
80
+ endpoint = "unused"
81
+ t = Yadis::TransformFilterMaker.new([])
82
+ assert(t.apply_filters(endpoint).nil?)
83
+ end
84
+
85
+ def test_nil_filter
86
+ # A transform filter with a single nil filter should return nil.
87
+ nil_filter = Proc.new { |endpoint| nil }
88
+ t = Yadis::TransformFilterMaker.new([nil_filter])
89
+ endpoint = "unused"
90
+ assert(t.apply_filters(endpoint).nil?)
91
+ end
92
+
93
+ def test_identity_filter
94
+ # A transform filter with an identity filter should return the
95
+ # input.
96
+ identity_filter = Proc.new { |endpoint| endpoint }
97
+ t = Yadis::TransformFilterMaker.new([identity_filter])
98
+ endpoint = "unused"
99
+ assert(t.apply_filters(endpoint) == endpoint)
100
+ end
101
+
102
+ def test_return_different_endpoint
103
+ # Make sure the result of the filter is returned, rather than
104
+ # the input.
105
+ returned_endpoint = "returned endpoint"
106
+ filter = Proc.new { |endpoint| returned_endpoint }
107
+ t = Yadis::TransformFilterMaker.new([filter])
108
+ endpoint = "unused"
109
+ assert(t.apply_filters(endpoint) == returned_endpoint)
110
+ end
111
+
112
+ def test_multiple_filters
113
+ # Check filter fallback behavior on different inputs.
114
+ odd, odd_result = 45, "odd"
115
+ even, even_result = 46, "even"
116
+
117
+ filter_odd = Proc.new { |endpoint|
118
+ if endpoint % 2 == 1
119
+ odd_result
120
+ else
121
+ nil
122
+ end
123
+ }
124
+
125
+ filter_even = Proc.new { |endpoint|
126
+ if endpoint % 2 == 0
127
+ even_result
128
+ else
129
+ nil
130
+ end
131
+ }
132
+
133
+ t = Yadis::TransformFilterMaker.new([filter_odd, filter_even])
134
+ assert(t.apply_filters(odd) == odd_result)
135
+ assert(t.apply_filters(even) == even_result)
136
+ end
137
+ end
138
+
139
+ class BogusServiceEndpointExtractor
140
+ def initialize(data)
141
+ @data = data
142
+ end
143
+
144
+ def get_service_endpoints(yadis_url, service_element)
145
+ return @data
146
+ end
147
+ end
148
+
149
+ class CompoundFilterTest < Test::Unit::TestCase
150
+ def test_get_service_endpoints
151
+ first = ["bogus", "test"]
152
+ second = ["third"]
153
+ all = first + second
154
+
155
+ subfilters = [
156
+ BogusServiceEndpointExtractor.new(first),
157
+ BogusServiceEndpointExtractor.new(second),
158
+ ]
159
+
160
+ cf = Yadis::CompoundFilter.new(subfilters)
161
+ assert(cf.get_service_endpoints("unused", "unused") == all)
162
+ end
163
+ end
164
+
165
+ class MakeFilterTest < Test::Unit::TestCase
166
+ def test_parts_nil
167
+ result = Yadis.make_filter(nil)
168
+ assert(result.is_a?(Yadis::TransformFilterMaker),
169
+ result)
170
+ end
171
+
172
+ def test_parts_array
173
+ e1 = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil)
174
+ e2 = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil)
175
+
176
+ result = Yadis.make_filter([e1, e2])
177
+ assert(result.is_a?(Yadis::TransformFilterMaker),
178
+ result)
179
+ assert(result.filter_procs[0] == e1.method('from_basic_service_endpoint'))
180
+ assert(result.filter_procs[1] == e2.method('from_basic_service_endpoint'))
181
+ end
182
+
183
+ def test_parts_single
184
+ e = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil)
185
+ result = Yadis.make_filter(e)
186
+ assert(result.is_a?(Yadis::TransformFilterMaker),
187
+ result)
188
+ end
189
+ end
190
+
191
+ class MakeCompoundFilterTest < Test::Unit::TestCase
192
+ def test_no_filters
193
+ result = Yadis.mk_compound_filter([])
194
+ assert(result.subfilters == [])
195
+ end
196
+
197
+ def test_single_transform_filter
198
+ f = Yadis::TransformFilterMaker.new([])
199
+ assert(Yadis.mk_compound_filter([f]) == f)
200
+ end
201
+
202
+ def test_single_endpoint
203
+ e = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil)
204
+ result = Yadis.mk_compound_filter([e])
205
+ assert(result.is_a?(Yadis::TransformFilterMaker))
206
+
207
+ # Expect the transform filter to call
208
+ # from_basic_service_endpoint on the endpoint
209
+ filter = result.filter_procs[0]
210
+ assert(filter == e.method('from_basic_service_endpoint'),
211
+ filter)
212
+ end
213
+
214
+ def test_single_proc
215
+ # Create a proc that just returns nil for any endpoint
216
+ p = Proc.new { |endpoint| nil }
217
+ result = Yadis.mk_compound_filter([p])
218
+ assert(result.is_a?(Yadis::TransformFilterMaker))
219
+
220
+ # Expect the transform filter to call
221
+ # from_basic_service_endpoint on the endpoint
222
+ filter = result.filter_procs[0]
223
+ assert(filter == p)
224
+ end
225
+
226
+ def test_multiple_filters_same_type
227
+ f1 = Yadis::TransformFilterMaker.new([])
228
+ f2 = Yadis::TransformFilterMaker.new([])
229
+
230
+ # Expect mk_compound_filter to actually make a CompoundFilter
231
+ # from f1 and f2.
232
+ result = Yadis.mk_compound_filter([f1, f2])
233
+
234
+ assert(result.is_a?(Yadis::CompoundFilter))
235
+ assert(result.subfilters == [f1, f2])
236
+ end
237
+
238
+ def test_multiple_filters_different_type
239
+ f1 = Yadis::TransformFilterMaker.new([])
240
+ f2 = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil)
241
+ f3 = Proc.new { |endpoint| nil }
242
+
243
+ e = Yadis::BasicServiceEndpoint.new(nil, [], nil, nil)
244
+ f4 = [e]
245
+
246
+ # Expect mk_compound_filter to actually make a CompoundFilter
247
+ # from f1 and f2.
248
+ result = Yadis.mk_compound_filter([f1, f2, f3, f4])
249
+
250
+ assert(result.is_a?(Yadis::CompoundFilter))
251
+
252
+ assert(result.subfilters[0] == f1)
253
+ assert(result.subfilters[1].filter_procs[0] ==
254
+ e.method('from_basic_service_endpoint'))
255
+ assert(result.subfilters[2].filter_procs[0] ==
256
+ f2.method('from_basic_service_endpoint'))
257
+ assert(result.subfilters[2].filter_procs[1] == f3)
258
+ end
259
+
260
+ def test_filter_type_error
261
+ # Pass various non-filter objects and make sure the filter
262
+ # machinery explodes.
263
+ [nil, ["bogus"], [1], [nil, "bogus"]].each { |thing|
264
+ assert_raise(TypeError) {
265
+ Yadis.mk_compound_filter(thing)
266
+ }
267
+ }
268
+ end
269
+ end
270
+ end
@@ -0,0 +1,963 @@
1
+ require "testutil"
2
+ require "util"
3
+ require "test/unit"
4
+ require "openid/consumer/idres"
5
+ require "openid/protocolerror"
6
+ require "openid/store/memory"
7
+ require "openid/store/nonce"
8
+
9
+ module OpenID
10
+ class Consumer
11
+ class IdResHandler
12
+
13
+ # Subclass of IdResHandler that doesn't do verification upon
14
+ # construction. All of the tests call this, except for the ones
15
+ # explicitly for id_res.
16
+ class IdResHandler < OpenID::Consumer::IdResHandler
17
+ def id_res
18
+ end
19
+ end
20
+
21
+ class CheckForFieldsTest < Test::Unit::TestCase
22
+ include ProtocolErrorMixin
23
+
24
+ BASE_FIELDS = ['return_to', 'assoc_handle', 'sig', 'signed']
25
+ OPENID2_FIELDS = BASE_FIELDS + ['op_endpoint']
26
+ OPENID1_FIELDS = BASE_FIELDS + ['identity']
27
+
28
+ OPENID1_SIGNED = ['return_to', 'identity']
29
+ OPENID2_SIGNED =
30
+ OPENID1_SIGNED + ['response_nonce', 'claimed_id', 'assoc_handle',
31
+ 'op_endpoint']
32
+
33
+ def mkMsg(ns, fields, signed_fields)
34
+ msg = Message.new(ns)
35
+ fields.each do |field|
36
+ msg.set_arg(OPENID_NS, field, "don't care")
37
+ end
38
+ if fields.member?('signed')
39
+ msg.set_arg(OPENID_NS, 'signed', signed_fields.join(','))
40
+ end
41
+ msg
42
+ end
43
+
44
+ 1.times do # so as not to bleed into the outer namespace
45
+ n = 0
46
+ [[],
47
+ ['foo'],
48
+ ['bar', 'baz'],
49
+ ].each do |signed_fields|
50
+ test = lambda do
51
+ msg = mkMsg(OPENID2_NS, OPENID2_FIELDS, signed_fields)
52
+ idres = IdResHandler.new(msg, nil)
53
+ assert_equal(signed_fields, idres.send(:signed_list))
54
+ # Do it again to make sure logic for caching is correct
55
+ assert_equal(signed_fields, idres.send(:signed_list))
56
+ end
57
+ define_method("test_signed_list_#{n += 1}", test)
58
+ end
59
+ end
60
+
61
+ # test all missing fields for OpenID 1 and 2
62
+ 1.times do
63
+ [["openid1", OPENID1_NS, OPENID1_FIELDS],
64
+ ["openid1", OPENID11_NS, OPENID1_FIELDS],
65
+ ["openid2", OPENID2_NS, OPENID2_FIELDS],
66
+ ].each do |ver, ns, all_fields|
67
+ all_fields.each do |field|
68
+ test = lambda do
69
+ fields = all_fields.dup
70
+ fields.delete(field)
71
+ msg = mkMsg(ns, fields, [])
72
+ idres = IdResHandler.new(msg, nil)
73
+ assert_protocol_error("Missing required field #{field}") {
74
+ idres.send(:check_for_fields)
75
+ }
76
+ end
77
+ define_method("test_#{ver}_check_missing_#{field}", test)
78
+ end
79
+ end
80
+ end
81
+
82
+ # Test all missing signed for OpenID 1 and 2
83
+ 1.times do
84
+ [["openid1", OPENID1_NS, OPENID1_FIELDS, OPENID1_SIGNED],
85
+ ["openid1", OPENID11_NS, OPENID1_FIELDS, OPENID1_SIGNED],
86
+ ["openid2", OPENID2_NS, OPENID2_FIELDS, OPENID2_SIGNED],
87
+ ].each do |ver, ns, all_fields, signed_fields|
88
+ signed_fields.each do |signed_field|
89
+ test = lambda do
90
+ fields = signed_fields.dup
91
+ fields.delete(signed_field)
92
+ msg = mkMsg(ns, all_fields, fields)
93
+ # Make sure the signed field is actually in the request
94
+ msg.set_arg(OPENID_NS, signed_field, "don't care")
95
+ idres = IdResHandler.new(msg, nil)
96
+ assert_protocol_error("#{signed_field.inspect} not signed") {
97
+ idres.send(:check_for_fields)
98
+ }
99
+ end
100
+ define_method("test_#{ver}_check_missing_signed_#{signed_field}", test)
101
+ end
102
+ end
103
+ end
104
+
105
+ def test_112
106
+ args = {'openid.assoc_handle' => 'fa1f5ff0-cde4-11dc-a183-3714bfd55ca8',
107
+ 'openid.claimed_id' => 'http://binkley.lan/user/test01',
108
+ 'openid.identity' => 'http://test01.binkley.lan/',
109
+ 'openid.mode' => 'id_res',
110
+ 'openid.ns' => 'http://specs.openid.net/auth/2.0',
111
+ 'openid.ns.pape' => 'http://specs.openid.net/extensions/pape/1.0',
112
+ 'openid.op_endpoint' => 'http://binkley.lan/server',
113
+ 'openid.pape.auth_policies' => 'none',
114
+ 'openid.pape.auth_time' => '2008-01-28T20:42:36Z',
115
+ 'openid.pape.nist_auth_level' => '0',
116
+ 'openid.response_nonce' => '2008-01-28T21:07:04Z99Q=',
117
+ 'openid.return_to' => 'http://binkley.lan:8001/process?janrain_nonce=2008-01-28T21%3A07%3A02Z0tMIKx',
118
+ 'openid.sig' => 'YJlWH4U6SroB1HoPkmEKx9AyGGg=',
119
+ 'openid.signed' => 'assoc_handle,identity,response_nonce,return_to,claimed_id,op_endpoint,pape.auth_time,ns.pape,pape.nist_auth_level,pape.auth_policies'
120
+ }
121
+ assert_equal(args['openid.ns'], OPENID2_NS)
122
+ incoming = Message.from_post_args(args)
123
+ assert(incoming.is_openid2)
124
+ idres = IdResHandler.new(incoming, nil)
125
+ car = idres.send(:create_check_auth_request)
126
+ expected_args = args.dup
127
+ expected_args['openid.mode'] = 'check_authentication'
128
+ expected = Message.from_post_args(expected_args)
129
+ assert(expected.is_openid2)
130
+ assert_equal(expected, car)
131
+ assert_equal(expected_args, car.to_post_args)
132
+ end
133
+
134
+ def test_no_signed_list
135
+ msg = Message.new(OPENID2_NS)
136
+ idres = IdResHandler.new(msg, nil)
137
+ assert_protocol_error("Response missing signed") {
138
+ idres.send(:signed_list)
139
+ }
140
+ end
141
+
142
+ def test_success_openid1
143
+ msg = mkMsg(OPENID1_NS, OPENID1_FIELDS, OPENID1_SIGNED)
144
+ idres = IdResHandler.new(msg, nil)
145
+ assert_nothing_raised {
146
+ idres.send(:check_for_fields)
147
+ }
148
+ end
149
+
150
+ def test_success_openid1_1
151
+ msg = mkMsg(OPENID11_NS, OPENID1_FIELDS, OPENID1_SIGNED)
152
+ idres = IdResHandler.new(msg, nil)
153
+ assert_nothing_raised {
154
+ idres.send(:check_for_fields)
155
+ }
156
+ end
157
+ end
158
+
159
+ class ReturnToArgsTest < Test::Unit::TestCase
160
+ include OpenID::ProtocolErrorMixin
161
+
162
+ def check_return_to_args(query)
163
+ idres = IdResHandler.new(Message.from_post_args(query), nil)
164
+ class << idres
165
+ def verify_return_to_base(unused)
166
+ end
167
+ end
168
+ idres.send(:verify_return_to)
169
+ end
170
+
171
+ def assert_bad_args(msg, query)
172
+ assert_protocol_error(msg) {
173
+ check_return_to_args(query)
174
+ }
175
+ end
176
+
177
+ def test_return_to_args_okay
178
+ assert_nothing_raised {
179
+ check_return_to_args({
180
+ 'openid.mode' => 'id_res',
181
+ 'openid.return_to' => 'http://example.com/?foo=bar',
182
+ 'foo' => 'bar',
183
+ })
184
+ }
185
+ end
186
+
187
+ def test_unexpected_arg_okay
188
+ assert_bad_args("Unexpected parameter", {
189
+ 'openid.mode' => 'id_res',
190
+ 'openid.return_to' => 'http://example.com/',
191
+ 'foo' => 'bar',
192
+ })
193
+ end
194
+
195
+ def test_return_to_mismatch
196
+ assert_bad_args('Message missing ret', {
197
+ 'openid.mode' => 'id_res',
198
+ 'openid.return_to' => 'http://example.com/?foo=bar',
199
+ })
200
+
201
+ assert_bad_args("Parameter 'foo' val", {
202
+ 'openid.mode' => 'id_res',
203
+ 'openid.return_to' => 'http://example.com/?foo=bar',
204
+ 'foo' => 'foos',
205
+ })
206
+ end
207
+ end
208
+
209
+ class ReturnToVerifyTest < Test::Unit::TestCase
210
+ def test_bad_return_to
211
+ return_to = "http://some.url/path?foo=bar"
212
+
213
+ m = Message.new(OPENID1_NS)
214
+ m.set_arg(OPENID_NS, 'mode', 'cancel')
215
+ m.set_arg(BARE_NS, 'foo', 'bar')
216
+
217
+ # Scheme, authority, and path differences are checked by
218
+ # IdResHandler.verify_return_to_base. Query args checked by
219
+ # IdResHandler.verify_return_to_args.
220
+ [
221
+ # Scheme only
222
+ "https://some.url/path?foo=bar",
223
+ # Authority only
224
+ "http://some.url.invalid/path?foo=bar",
225
+ # Path only
226
+ "http://some.url/path_extra?foo=bar",
227
+ # Query args differ
228
+ "http://some.url/path?foo=bar2",
229
+ "http://some.url/path?foo2=bar",
230
+ ].each do |bad|
231
+ m.set_arg(OPENID_NS, 'return_to', bad)
232
+ idres = IdResHandler.new(m, return_to)
233
+ assert_raises(ProtocolError) {
234
+ idres.send(:verify_return_to)
235
+ }
236
+ end
237
+ end
238
+
239
+ def test_good_return_to
240
+ base = 'http://example.janrain.com/path'
241
+ [ [base, {}],
242
+ [base + "?another=arg", {'another' => 'arg'}],
243
+ [base + "?another=arg#frag", {'another' => 'arg'}],
244
+ ['HTTP'+base[4..-1], {}],
245
+ [base.sub('com', 'COM'), {}],
246
+ ['http://example.janrain.com:80/path', {}],
247
+ ['http://example.janrain.com/p%61th', {}],
248
+ ['http://example.janrain.com/./path',{}],
249
+ ].each do |return_to, args|
250
+ args['openid.return_to'] = return_to
251
+ msg = Message.from_post_args(args)
252
+ idres = IdResHandler.new(msg, base)
253
+ assert_nothing_raised {
254
+ idres.send(:verify_return_to)
255
+ }
256
+ end
257
+ end
258
+ end
259
+
260
+ class DummyEndpoint
261
+ attr_accessor :server_url
262
+ def initialize(server_url)
263
+ @server_url = server_url
264
+ end
265
+ end
266
+
267
+ class CheckSigTest < Test::Unit::TestCase
268
+ include ProtocolErrorMixin
269
+ include TestUtil
270
+
271
+ def setup
272
+ @assoc = GoodAssoc.new('{not_dumb}')
273
+ @store = Store::Memory.new
274
+ @server_url = 'http://server.url/'
275
+ @endpoint = DummyEndpoint.new(@server_url)
276
+ @store.store_association(@server_url, @assoc)
277
+
278
+ @message = Message.from_post_args({
279
+ 'openid.mode' => 'id_res',
280
+ 'openid.identity' => '=example',
281
+ 'openid.sig' => GOODSIG,
282
+ 'openid.assoc_handle' => @assoc.handle,
283
+ 'openid.signed' => 'mode,identity,assoc_handle,signed',
284
+ 'frobboz' => 'banzit',
285
+ })
286
+ end
287
+
288
+ def call_idres_method(method_name)
289
+ idres = IdResHandler.new(@message, nil, @store, @endpoint)
290
+ idres.extend(InstanceDefExtension)
291
+ yield idres
292
+ idres.send(method_name)
293
+ end
294
+
295
+ def call_check_sig(&proc)
296
+ call_idres_method(:check_signature, &proc)
297
+ end
298
+
299
+ def no_check_auth(idres)
300
+ idres.instance_def(:check_auth) { fail "Called check_auth" }
301
+ end
302
+
303
+ def test_sign_good
304
+ assert_nothing_raised {
305
+ call_check_sig(&method(:no_check_auth))
306
+ }
307
+ end
308
+
309
+ def test_bad_sig
310
+ @message.set_arg(OPENID_NS, 'sig', 'bad sig!')
311
+ assert_protocol_error('Bad signature') {
312
+ call_check_sig(&method(:no_check_auth))
313
+ }
314
+ end
315
+
316
+ def test_check_auth_ok
317
+ @message.set_arg(OPENID_NS, 'assoc_handle', 'dumb-handle')
318
+ check_auth_called = false
319
+ call_check_sig do |idres|
320
+ idres.instance_def(:check_auth) do
321
+ check_auth_called = true
322
+ end
323
+ end
324
+ assert(check_auth_called)
325
+ end
326
+
327
+ def test_check_auth_ok_no_store
328
+ @store = nil
329
+ check_auth_called = false
330
+ call_check_sig do |idres|
331
+ idres.instance_def(:check_auth) do
332
+ check_auth_called = true
333
+ end
334
+ end
335
+ assert(check_auth_called)
336
+ end
337
+
338
+ def test_expired_assoc
339
+ @assoc.expires_in = -1
340
+ @store.store_association(@server_url, @assoc)
341
+ assert_protocol_error('Association with') {
342
+ call_check_sig(&method(:no_check_auth))
343
+ }
344
+ end
345
+
346
+ def call_check_auth(&proc)
347
+ assert_log_matches("Using 'check_authentication'") {
348
+ call_idres_method(:check_auth, &proc)
349
+ }
350
+ end
351
+
352
+ def test_check_auth_create_fail
353
+ assert_protocol_error("Could not generate") {
354
+ call_check_auth do |idres|
355
+ idres.instance_def(:create_check_auth_request) do
356
+ raise Message::KeyNotFound, "Testing"
357
+ end
358
+ end
359
+ }
360
+ end
361
+
362
+ def test_check_auth_okay
363
+ OpenID.extend(OverrideMethodMixin)
364
+ me = self
365
+ send_resp = Proc.new do |req, server_url|
366
+ me.assert_equal(:req, req)
367
+ :expected_response
368
+ end
369
+
370
+ OpenID.with_method_overridden(:make_kv_post, send_resp) do
371
+ final_resp = call_check_auth do |idres|
372
+ idres.instance_def(:create_check_auth_request) {
373
+ :req
374
+ }
375
+ idres.instance_def(:process_check_auth_response) do |resp|
376
+ me.assert_equal(:expected_response, resp)
377
+ end
378
+ end
379
+ end
380
+ end
381
+
382
+ def test_check_auth_process_fail
383
+ OpenID.extend(OverrideMethodMixin)
384
+ me = self
385
+ send_resp = Proc.new do |req, server_url|
386
+ me.assert_equal(:req, req)
387
+ :expected_response
388
+ end
389
+
390
+ OpenID.with_method_overridden(:make_kv_post, send_resp) do
391
+ assert_protocol_error("Testing") do
392
+ final_resp = call_check_auth do |idres|
393
+ idres.instance_def(:create_check_auth_request) { :req }
394
+ idres.instance_def(:process_check_auth_response) do |resp|
395
+ me.assert_equal(:expected_response, resp)
396
+ raise ProtocolError, "Testing"
397
+ end
398
+ end
399
+ end
400
+ end
401
+ end
402
+
403
+ 1.times do
404
+ # Fields from the signed list
405
+ ['mode', 'identity', 'assoc_handle'
406
+ ].each do |field|
407
+ test = lambda do
408
+ @message.del_arg(OPENID_NS, field)
409
+ assert_raises(Message::KeyNotFound) {
410
+ call_idres_method(:create_check_auth_request) {}
411
+ }
412
+ end
413
+ define_method("test_create_check_auth_missing_#{field}", test)
414
+ end
415
+ end
416
+
417
+ def test_create_check_auth_request_success
418
+ ca_msg = call_idres_method(:create_check_auth_request) {}
419
+ expected = @message.copy
420
+ expected.set_arg(OPENID_NS, 'mode', 'check_authentication')
421
+ assert_equal(expected, ca_msg)
422
+ end
423
+
424
+ end
425
+
426
+ class CheckAuthResponseTest < Test::Unit::TestCase
427
+ include TestUtil
428
+ include ProtocolErrorMixin
429
+
430
+ def setup
431
+ @message = Message.from_openid_args({
432
+ 'is_valid' => 'true',
433
+ })
434
+ @assoc = GoodAssoc.new
435
+ @store = Store::Memory.new
436
+ @server_url = 'http://invalid/'
437
+ @endpoint = DummyEndpoint.new(@server_url)
438
+ @idres = IdResHandler.new(nil, nil, @store, @endpoint)
439
+ end
440
+
441
+ def call_process
442
+ @idres.send(:process_check_auth_response, @message)
443
+ end
444
+
445
+ def test_valid
446
+ assert_log_matches() { call_process }
447
+ end
448
+
449
+ def test_invalid
450
+ for is_valid in ['false', 'monkeys']
451
+ @message.set_arg(OPENID_NS, 'is_valid', 'false')
452
+ assert_protocol_error("Server #{@server_url} responds") {
453
+ assert_log_matches() { call_process }
454
+ }
455
+ end
456
+ end
457
+
458
+ def test_valid_invalidate
459
+ @message.set_arg(OPENID_NS, 'invalidate_handle', 'cheese')
460
+ assert_log_matches("Received 'invalidate_handle'") { call_process }
461
+ end
462
+
463
+ def test_invalid_invalidate
464
+ @message.set_arg(OPENID_NS, 'invalidate_handle', 'cheese')
465
+ for is_valid in ['false', 'monkeys']
466
+ @message.set_arg(OPENID_NS, 'is_valid', 'false')
467
+ assert_protocol_error("Server #{@server_url} responds") {
468
+ assert_log_matches("Received 'invalidate_handle'") {
469
+ call_process
470
+ }
471
+ }
472
+ end
473
+ end
474
+
475
+ def test_invalidate_no_store
476
+ @idres.instance_variable_set(:@store, nil)
477
+ @message.set_arg(OPENID_NS, 'invalidate_handle', 'cheese')
478
+ assert_log_matches("Received 'invalidate_handle'",
479
+ 'Unexpectedly got "invalidate_handle"') {
480
+ call_process
481
+ }
482
+ end
483
+ end
484
+
485
+ class NonceTest < Test::Unit::TestCase
486
+ include TestUtil
487
+ include ProtocolErrorMixin
488
+
489
+ def setup
490
+ @store = Object.new
491
+ class << @store
492
+ attr_accessor :nonces, :succeed
493
+ def use_nonce(server_url, time, extra)
494
+ @nonces << [server_url, time, extra]
495
+ @succeed
496
+ end
497
+ end
498
+ @store.nonces = []
499
+ @nonce = Nonce.mk_nonce
500
+ end
501
+
502
+ def call_check_nonce(post_args, succeed=false)
503
+ response = Message.from_post_args(post_args)
504
+ if !@store.nil?
505
+ @store.succeed = succeed
506
+ end
507
+ idres = IdResHandler.new(response, nil, @store, nil)
508
+ idres.send(:check_nonce)
509
+ end
510
+
511
+ def test_openid1_success
512
+ [{},
513
+ {'openid.ns' => OPENID1_NS},
514
+ {'openid.ns' => OPENID11_NS}
515
+ ].each do |args|
516
+ assert_nothing_raised {
517
+ call_check_nonce({'rp_nonce' => @nonce}.merge(args), true)
518
+ }
519
+ end
520
+ end
521
+
522
+ def test_openid1_missing
523
+ [{},
524
+ {'openid.ns' => OPENID1_NS},
525
+ {'openid.ns' => OPENID11_NS}
526
+ ].each do |args|
527
+ assert_protocol_error('Nonce missing') { call_check_nonce(args) }
528
+ end
529
+ end
530
+
531
+ def test_openid2_ignore_rp_nonce
532
+ assert_protocol_error('Nonce missing') {
533
+ call_check_nonce({'rp_nonce' => @nonce,
534
+ 'openid.ns' => OPENID2_NS})
535
+ }
536
+ end
537
+
538
+ def test_openid2_success
539
+ assert_nothing_raised {
540
+ call_check_nonce({'openid.response_nonce' => @nonce,
541
+ 'openid.ns' => OPENID2_NS}, true)
542
+ }
543
+ end
544
+
545
+ def test_openid1_ignore_response_nonce
546
+ [{},
547
+ {'openid.ns' => OPENID1_NS},
548
+ {'openid.ns' => OPENID11_NS}
549
+ ].each do |args|
550
+ assert_protocol_error('Nonce missing') {
551
+ call_check_nonce({'openid.response_nonce' => @nonce}.merge(args))
552
+ }
553
+ end
554
+ end
555
+
556
+ def test_no_store
557
+ @store = nil
558
+ assert_nothing_raised {
559
+ call_check_nonce({'rp_nonce' => @nonce})
560
+ }
561
+ end
562
+
563
+ def test_already_used
564
+ assert_protocol_error('Nonce already used') {
565
+ call_check_nonce({'rp_nonce' => @nonce}, false)
566
+ }
567
+ end
568
+
569
+ def test_malformed_nonce
570
+ assert_protocol_error('Malformed nonce') {
571
+ call_check_nonce({'rp_nonce' => 'whee!'})
572
+ }
573
+ end
574
+ end
575
+
576
+ class DiscoveryVerificationTest < Test::Unit::TestCase
577
+ include ProtocolErrorMixin
578
+ include TestUtil
579
+
580
+ def setup
581
+ @endpoint = OpenIDServiceEndpoint.new
582
+ end
583
+
584
+ def call_verify(msg_args)
585
+ call_verify_modify(msg_args){}
586
+ end
587
+
588
+ def call_verify_modify(msg_args)
589
+ msg = Message.from_openid_args(msg_args)
590
+ idres = IdResHandler.new(msg, nil, nil, @endpoint)
591
+ idres.extend(InstanceDefExtension)
592
+ yield idres
593
+ idres.send(:verify_discovery_results)
594
+ idres.instance_variable_get(:@endpoint)
595
+ end
596
+
597
+ def assert_verify_protocol_error(error_prefix, openid_args)
598
+ assert_protocol_error(error_prefix) {call_verify(openid_args)}
599
+ end
600
+
601
+ def test_openid1_no_local_id
602
+ @endpoint.claimed_id = 'http://invalid/'
603
+ assert_verify_protocol_error("Missing required field: "\
604
+ "<#{OPENID1_NS}>identity", {})
605
+ end
606
+
607
+ def test_openid1_no_endpoint
608
+ @endpoint = nil
609
+ assert_raises(ProtocolError) {
610
+ call_verify({'identity' => 'snakes on a plane'})
611
+ }
612
+ end
613
+
614
+ def test_openid1_fallback_1_0
615
+ [OPENID1_NS, OPENID11_NS].each do |openid1_ns|
616
+ claimed_id = 'http://claimed.id/'
617
+ @endpoint = nil
618
+ resp_mesg = Message.from_openid_args({
619
+ 'ns' => openid1_ns,
620
+ 'identity' => claimed_id,
621
+ })
622
+
623
+ # Pass the OpenID 1 claimed_id this way since we're
624
+ # passing None for the endpoint.
625
+ resp_mesg.set_arg(BARE_NS, 'openid1_claimed_id', claimed_id)
626
+
627
+ # We expect the OpenID 1 discovery verification to try
628
+ # matching the discovered endpoint against the 1.1 type
629
+ # and fall back to 1.0.
630
+ expected_endpoint = OpenIDServiceEndpoint.new
631
+ expected_endpoint.type_uris = [OPENID_1_0_TYPE]
632
+ expected_endpoint.local_id = nil
633
+ expected_endpoint.claimed_id = claimed_id
634
+
635
+ hacked_discover = Proc.new {
636
+ |_claimed_id| ['unused', [expected_endpoint]]
637
+ }
638
+ idres = IdResHandler.new(resp_mesg, nil, nil, @endpoint)
639
+ assert_log_matches('Performing discovery') {
640
+ OpenID.with_method_overridden(:discover, hacked_discover) {
641
+ idres.send(:verify_discovery_results)
642
+ }
643
+ }
644
+ actual_endpoint = idres.instance_variable_get(:@endpoint)
645
+ assert_equal(actual_endpoint, expected_endpoint)
646
+ end
647
+ end
648
+
649
+ def test_openid2_no_op_endpoint
650
+ assert_protocol_error("Missing required field: "\
651
+ "<#{OPENID2_NS}>op_endpoint") {
652
+ call_verify({'ns'=>OPENID2_NS})
653
+ }
654
+ end
655
+
656
+ def test_openid2_local_id_no_claimed
657
+ assert_verify_protocol_error('openid.identity is present without',
658
+ {'ns' => OPENID2_NS,
659
+ 'op_endpoint' => 'Phone Home',
660
+ 'identity' => 'Jorge Lius Borges'})
661
+ end
662
+
663
+ def test_openid2_no_local_id_claimed
664
+ assert_log_matches() {
665
+ assert_protocol_error('openid.claimed_id is present without') {
666
+ call_verify({'ns' => OPENID2_NS,
667
+ 'op_endpoint' => 'Phone Home',
668
+ 'claimed_id' => 'Manuel Noriega'})
669
+ }
670
+ }
671
+ end
672
+
673
+ def test_openid2_no_identifiers
674
+ op_endpoint = 'Phone Home'
675
+ result_endpoint = assert_log_matches() {
676
+ call_verify({'ns' => OPENID2_NS,
677
+ 'op_endpoint' => op_endpoint})
678
+ }
679
+ assert(result_endpoint.is_op_identifier)
680
+ assert_equal(op_endpoint, result_endpoint.server_url)
681
+ assert(result_endpoint.claimed_id.nil?)
682
+ end
683
+
684
+ def test_openid2_no_endpoint_does_disco
685
+ endpoint = OpenIDServiceEndpoint.new
686
+ endpoint.claimed_id = 'monkeysoft'
687
+ @endpoint = nil
688
+ result = assert_log_matches('No pre-discovered') {
689
+ call_verify_modify({'ns' => OPENID2_NS,
690
+ 'identity' => 'sour grapes',
691
+ 'claimed_id' => 'monkeysoft',
692
+ 'op_endpoint' => 'Phone Home'}) do |idres|
693
+ idres.instance_def(:discover_and_verify) do |claimed_id, endpoints|
694
+ @endpoint = endpoint
695
+ end
696
+ end
697
+ }
698
+ assert_equal(endpoint, result)
699
+ end
700
+
701
+
702
+ def test_openid2_mismatched_does_disco
703
+ @endpoint.claimed_id = 'nothing special, but different'
704
+ @endpoint.local_id = 'green cheese'
705
+
706
+ endpoint = OpenIDServiceEndpoint.new
707
+ endpoint.claimed_id = 'monkeysoft'
708
+
709
+ result = assert_log_matches('Error attempting to use stored',
710
+ 'Attempting discovery') {
711
+ call_verify_modify({'ns' => OPENID2_NS,
712
+ 'identity' => 'sour grapes',
713
+ 'claimed_id' => 'monkeysoft',
714
+ 'op_endpoint' => 'Green Cheese'}) do |idres|
715
+ idres.instance_def(:discover_and_verify) do |claimed_id, endpoints|
716
+ @endpoint = endpoint
717
+ end
718
+ end
719
+ }
720
+ assert(endpoint.equal?(result))
721
+ end
722
+
723
+ def test_verify_discovery_single_claimed_id_mismatch
724
+ idres = IdResHandler.new(nil, nil)
725
+ @endpoint.local_id = 'my identity'
726
+ @endpoint.claimed_id = 'http://i-am-sam/'
727
+ @endpoint.server_url = 'Phone Home'
728
+ @endpoint.type_uris = [OPENID_2_0_TYPE]
729
+
730
+ to_match = @endpoint.dup
731
+ to_match.claimed_id = 'http://something.else/'
732
+
733
+ e = assert_raises(ProtocolError) {
734
+ idres.send(:verify_discovery_single, @endpoint, to_match)
735
+ }
736
+ assert(e.to_s =~ /different subjects/)
737
+ end
738
+
739
+ def test_openid1_1_verify_discovery_single_no_server_url
740
+ idres = IdResHandler.new(nil, nil)
741
+ @endpoint.local_id = 'my identity'
742
+ @endpoint.claimed_id = 'http://i-am-sam/'
743
+ @endpoint.server_url = 'Phone Home'
744
+ @endpoint.type_uris = [OPENID_1_1_TYPE]
745
+
746
+ to_match = @endpoint.dup
747
+ to_match.claimed_id = 'http://i-am-sam/'
748
+ to_match.type_uris = [OPENID_1_1_TYPE]
749
+ to_match.server_url = nil
750
+
751
+ idres.send(:verify_discovery_single, @endpoint, to_match)
752
+ end
753
+
754
+ def test_openid2_use_pre_discovered
755
+ @endpoint.local_id = 'my identity'
756
+ @endpoint.claimed_id = 'http://i-am-sam/'
757
+ @endpoint.server_url = 'Phone Home'
758
+ @endpoint.type_uris = [OPENID_2_0_TYPE]
759
+
760
+ result = assert_log_matches() {
761
+ call_verify({'ns' => OPENID2_NS,
762
+ 'identity' => @endpoint.local_id,
763
+ 'claimed_id' => @endpoint.claimed_id,
764
+ 'op_endpoint' => @endpoint.server_url
765
+ })
766
+ }
767
+ assert(result.equal?(@endpoint))
768
+ end
769
+
770
+ def test_openid2_use_pre_discovered_wrong_type
771
+ text = "verify failed"
772
+ me = self
773
+
774
+ @endpoint.local_id = 'my identity'
775
+ @endpoint.claimed_id = 'i am sam'
776
+ @endpoint.server_url = 'Phone Home'
777
+ @endpoint.type_uris = [OPENID_1_1_TYPE]
778
+ endpoint = @endpoint
779
+
780
+ msg = Message.from_openid_args({'ns' => OPENID2_NS,
781
+ 'identity' => @endpoint.local_id,
782
+ 'claimed_id' =>
783
+ @endpoint.claimed_id,
784
+ 'op_endpoint' =>
785
+ @endpoint.server_url})
786
+
787
+ idres = IdResHandler.new(msg, nil, nil, @endpoint)
788
+ idres.extend(InstanceDefExtension)
789
+ idres.instance_def(:discover_and_verify) { |claimed_id, to_match|
790
+ me.assert_equal(endpoint.claimed_id, to_match[0].claimed_id)
791
+ me.assert_equal(claimed_id, endpoint.claimed_id)
792
+ raise ProtocolError, text
793
+ }
794
+ assert_log_matches('Error attempting to use stored',
795
+ 'Attempting discovery') {
796
+ assert_protocol_error(text) {
797
+ idres.send(:verify_discovery_results)
798
+ }
799
+ }
800
+ end
801
+
802
+
803
+ def test_openid1_use_pre_discovered
804
+ @endpoint.local_id = 'my identity'
805
+ @endpoint.claimed_id = 'http://i-am-sam/'
806
+ @endpoint.server_url = 'Phone Home'
807
+ @endpoint.type_uris = [OPENID_1_1_TYPE]
808
+
809
+ result = assert_log_matches() {
810
+ call_verify({'ns' => OPENID1_NS,
811
+ 'identity' => @endpoint.local_id})
812
+ }
813
+ assert(result.equal?(@endpoint))
814
+ end
815
+
816
+
817
+ def test_openid1_use_pre_discovered_wrong_type
818
+ verified_error = Class.new(Exception)
819
+
820
+ @endpoint.local_id = 'my identity'
821
+ @endpoint.claimed_id = 'i am sam'
822
+ @endpoint.server_url = 'Phone Home'
823
+ @endpoint.type_uris = [OPENID_2_0_TYPE]
824
+
825
+ assert_log_matches('Error attempting to use stored',
826
+ 'Attempting discovery') {
827
+ assert_raises(verified_error) {
828
+ call_verify_modify({'ns' => OPENID1_NS,
829
+ 'identity' => @endpoint.local_id}) { |idres|
830
+ idres.instance_def(:discover_and_verify) do |claimed_id, endpoints|
831
+ raise verified_error
832
+ end
833
+ }
834
+ }
835
+ }
836
+ end
837
+
838
+ def test_openid2_fragment
839
+ claimed_id = "http://unittest.invalid/"
840
+ claimed_id_frag = claimed_id + "#fragment"
841
+
842
+ @endpoint.local_id = 'my identity'
843
+ @endpoint.claimed_id = claimed_id
844
+ @endpoint.server_url = 'Phone Home'
845
+ @endpoint.type_uris = [OPENID_2_0_TYPE]
846
+
847
+ result = assert_log_matches() {
848
+ call_verify({'ns' => OPENID2_NS,
849
+ 'identity' => @endpoint.local_id,
850
+ 'claimed_id' => claimed_id_frag,
851
+ 'op_endpoint' => @endpoint.server_url})
852
+ }
853
+
854
+ [:local_id, :server_url, :type_uris].each do |sym|
855
+ assert_equal(@endpoint.send(sym), result.send(sym))
856
+ end
857
+ assert_equal(claimed_id_frag, result.claimed_id)
858
+ end
859
+
860
+ def test_endpoint_without_local_id
861
+ # An endpoint like this with no local_id is generated as a result of
862
+ # e.g. Yadis discovery with no LocalID tag.
863
+ @endpoint.server_url = "http://localhost:8000/openidserver"
864
+ @endpoint.claimed_id = "http://localhost:8000/id/id-jo"
865
+
866
+ to_match = OpenIDServiceEndpoint.new
867
+ to_match.server_url = "http://localhost:8000/openidserver"
868
+ to_match.claimed_id = "http://localhost:8000/id/id-jo"
869
+ to_match.local_id = "http://localhost:8000/id/id-jo"
870
+
871
+ idres = IdResHandler.new(nil, nil)
872
+ assert_log_matches() {
873
+ result = idres.send(:verify_discovery_single, @endpoint, to_match)
874
+ }
875
+ end
876
+ end
877
+
878
+ class IdResTopLevelTest < Test::Unit::TestCase
879
+ def test_id_res
880
+ endpoint = OpenIDServiceEndpoint.new
881
+ endpoint.server_url = 'http://invalid/server'
882
+ endpoint.claimed_id = 'http://my.url/'
883
+ endpoint.local_id = 'http://invalid/username'
884
+ endpoint.type_uris = [OPENID_2_0_TYPE]
885
+
886
+ assoc = GoodAssoc.new
887
+ store = Store::Memory.new
888
+ store.store_association(endpoint.server_url, assoc)
889
+
890
+ signed_fields =
891
+ [
892
+ 'response_nonce',
893
+ 'op_endpoint',
894
+ 'assoc_handle',
895
+ 'identity',
896
+ 'claimed_id',
897
+ 'ns',
898
+ 'return_to',
899
+ ]
900
+
901
+ return_to = 'http://return.to/'
902
+ args = {
903
+ 'ns' => OPENID2_NS,
904
+ 'return_to' => return_to,
905
+ 'claimed_id' => endpoint.claimed_id,
906
+ 'identity' => endpoint.local_id,
907
+ 'assoc_handle' => assoc.handle,
908
+ 'op_endpoint' => endpoint.server_url,
909
+ 'response_nonce' => Nonce.mk_nonce,
910
+ 'signed' => signed_fields.join(','),
911
+ 'sig' => GOODSIG,
912
+ }
913
+ msg = Message.from_openid_args(args)
914
+ idres = OpenID::Consumer::IdResHandler.new(msg, return_to,
915
+ store, endpoint)
916
+ assert_equal(idres.signed_fields,
917
+ signed_fields.map {|f|'openid.' + f})
918
+ end
919
+ end
920
+
921
+
922
+ class DiscoverAndVerifyTest < Test::Unit::TestCase
923
+ include ProtocolErrorMixin
924
+ include TestUtil
925
+
926
+ def test_no_services
927
+ me = self
928
+ disco = Proc.new do |e|
929
+ me.assert_equal(e, :sentinel)
930
+ [:undefined, []]
931
+ end
932
+ endpoint = OpenIDServiceEndpoint.new
933
+ endpoint.claimed_id = :sentinel
934
+ idres = IdResHandler.new(nil, nil)
935
+ assert_log_matches('Performing discovery on') do
936
+ assert_protocol_error('No OpenID information found') do
937
+ OpenID.with_method_overridden(:discover, disco) do
938
+ idres.send(:discover_and_verify, :sentinel, [endpoint])
939
+ end
940
+ end
941
+ end
942
+ end
943
+ end
944
+
945
+ class VerifyDiscoveredServicesTest < Test::Unit::TestCase
946
+ include ProtocolErrorMixin
947
+ include TestUtil
948
+
949
+ def test_no_services
950
+ endpoint = OpenIDServiceEndpoint.new
951
+ endpoint.claimed_id = :sentinel
952
+ idres = IdResHandler.new(nil, nil)
953
+ assert_log_matches('Discovery verification failure') do
954
+ assert_protocol_error('No matching endpoint') do
955
+ idres.send(:verify_discovered_services,
956
+ 'http://bogus.id/', [], [endpoint])
957
+ end
958
+ end
959
+ end
960
+ end
961
+ end
962
+ end
963
+ end