nov-ruby-openid 2.1.9

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 (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