entp-ruby-openid 2.2

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