entp-ruby-openid 2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. data/CHANGELOG +215 -0
  2. data/INSTALL +47 -0
  3. data/LICENSE +210 -0
  4. data/NOTICE +2 -0
  5. data/README +85 -0
  6. data/UPGRADE +127 -0
  7. data/admin/runtests.rb +45 -0
  8. data/examples/README +32 -0
  9. data/examples/active_record_openid_store/README +58 -0
  10. data/examples/active_record_openid_store/XXX_add_open_id_store_to_db.rb +24 -0
  11. data/examples/active_record_openid_store/XXX_upgrade_open_id_store.rb +26 -0
  12. data/examples/active_record_openid_store/init.rb +8 -0
  13. data/examples/active_record_openid_store/lib/association.rb +10 -0
  14. data/examples/active_record_openid_store/lib/nonce.rb +3 -0
  15. data/examples/active_record_openid_store/lib/open_id_setting.rb +4 -0
  16. data/examples/active_record_openid_store/lib/openid_ar_store.rb +57 -0
  17. data/examples/active_record_openid_store/test/store_test.rb +212 -0
  18. data/examples/discover +49 -0
  19. data/examples/rails_openid/README +153 -0
  20. data/examples/rails_openid/Rakefile +10 -0
  21. data/examples/rails_openid/app/controllers/application.rb +4 -0
  22. data/examples/rails_openid/app/controllers/consumer_controller.rb +125 -0
  23. data/examples/rails_openid/app/controllers/login_controller.rb +45 -0
  24. data/examples/rails_openid/app/controllers/server_controller.rb +265 -0
  25. data/examples/rails_openid/app/helpers/application_helper.rb +3 -0
  26. data/examples/rails_openid/app/helpers/login_helper.rb +2 -0
  27. data/examples/rails_openid/app/helpers/server_helper.rb +9 -0
  28. data/examples/rails_openid/app/views/consumer/index.rhtml +81 -0
  29. data/examples/rails_openid/app/views/layouts/server.rhtml +68 -0
  30. data/examples/rails_openid/app/views/login/index.rhtml +56 -0
  31. data/examples/rails_openid/app/views/server/decide.rhtml +26 -0
  32. data/examples/rails_openid/config/boot.rb +19 -0
  33. data/examples/rails_openid/config/database.yml +74 -0
  34. data/examples/rails_openid/config/environment.rb +54 -0
  35. data/examples/rails_openid/config/environments/development.rb +19 -0
  36. data/examples/rails_openid/config/environments/production.rb +19 -0
  37. data/examples/rails_openid/config/environments/test.rb +19 -0
  38. data/examples/rails_openid/config/routes.rb +24 -0
  39. data/examples/rails_openid/doc/README_FOR_APP +2 -0
  40. data/examples/rails_openid/public/404.html +8 -0
  41. data/examples/rails_openid/public/500.html +8 -0
  42. data/examples/rails_openid/public/dispatch.cgi +12 -0
  43. data/examples/rails_openid/public/dispatch.fcgi +26 -0
  44. data/examples/rails_openid/public/dispatch.rb +12 -0
  45. data/examples/rails_openid/public/favicon.ico +0 -0
  46. data/examples/rails_openid/public/images/openid_login_bg.gif +0 -0
  47. data/examples/rails_openid/public/javascripts/controls.js +750 -0
  48. data/examples/rails_openid/public/javascripts/dragdrop.js +584 -0
  49. data/examples/rails_openid/public/javascripts/effects.js +854 -0
  50. data/examples/rails_openid/public/javascripts/prototype.js +1785 -0
  51. data/examples/rails_openid/public/robots.txt +1 -0
  52. data/examples/rails_openid/script/about +3 -0
  53. data/examples/rails_openid/script/breakpointer +3 -0
  54. data/examples/rails_openid/script/console +3 -0
  55. data/examples/rails_openid/script/destroy +3 -0
  56. data/examples/rails_openid/script/generate +3 -0
  57. data/examples/rails_openid/script/performance/benchmarker +3 -0
  58. data/examples/rails_openid/script/performance/profiler +3 -0
  59. data/examples/rails_openid/script/plugin +3 -0
  60. data/examples/rails_openid/script/process/reaper +3 -0
  61. data/examples/rails_openid/script/process/spawner +3 -0
  62. data/examples/rails_openid/script/process/spinner +3 -0
  63. data/examples/rails_openid/script/runner +3 -0
  64. data/examples/rails_openid/script/server +3 -0
  65. data/examples/rails_openid/test/functional/login_controller_test.rb +18 -0
  66. data/examples/rails_openid/test/functional/server_controller_test.rb +18 -0
  67. data/examples/rails_openid/test/test_helper.rb +28 -0
  68. data/lib/hmac/hmac.rb +112 -0
  69. data/lib/hmac/sha1.rb +11 -0
  70. data/lib/hmac/sha2.rb +25 -0
  71. data/lib/openid.rb +22 -0
  72. data/lib/openid/association.rb +249 -0
  73. data/lib/openid/consumer.rb +395 -0
  74. data/lib/openid/consumer/associationmanager.rb +344 -0
  75. data/lib/openid/consumer/checkid_request.rb +186 -0
  76. data/lib/openid/consumer/discovery.rb +497 -0
  77. data/lib/openid/consumer/discovery_manager.rb +123 -0
  78. data/lib/openid/consumer/html_parse.rb +134 -0
  79. data/lib/openid/consumer/idres.rb +523 -0
  80. data/lib/openid/consumer/responses.rb +150 -0
  81. data/lib/openid/cryptutil.rb +115 -0
  82. data/lib/openid/dh.rb +89 -0
  83. data/lib/openid/extension.rb +39 -0
  84. data/lib/openid/extensions/ax.rb +539 -0
  85. data/lib/openid/extensions/oauth.rb +91 -0
  86. data/lib/openid/extensions/pape.rb +179 -0
  87. data/lib/openid/extensions/sreg.rb +277 -0
  88. data/lib/openid/extras.rb +11 -0
  89. data/lib/openid/fetchers.rb +258 -0
  90. data/lib/openid/kvform.rb +136 -0
  91. data/lib/openid/kvpost.rb +58 -0
  92. data/lib/openid/message.rb +553 -0
  93. data/lib/openid/protocolerror.rb +12 -0
  94. data/lib/openid/server.rb +1544 -0
  95. data/lib/openid/store.rb +10 -0
  96. data/lib/openid/store/filesystem.rb +272 -0
  97. data/lib/openid/store/interface.rb +75 -0
  98. data/lib/openid/store/memcache.rb +109 -0
  99. data/lib/openid/store/memory.rb +84 -0
  100. data/lib/openid/store/nonce.rb +68 -0
  101. data/lib/openid/trustroot.rb +349 -0
  102. data/lib/openid/urinorm.rb +75 -0
  103. data/lib/openid/util.rb +119 -0
  104. data/lib/openid/version.rb +3 -0
  105. data/lib/openid/yadis.rb +15 -0
  106. data/lib/openid/yadis/accept.rb +148 -0
  107. data/lib/openid/yadis/constants.rb +21 -0
  108. data/lib/openid/yadis/discovery.rb +153 -0
  109. data/lib/openid/yadis/filters.rb +205 -0
  110. data/lib/openid/yadis/htmltokenizer.rb +305 -0
  111. data/lib/openid/yadis/parsehtml.rb +45 -0
  112. data/lib/openid/yadis/services.rb +42 -0
  113. data/lib/openid/yadis/xrds.rb +155 -0
  114. data/lib/openid/yadis/xri.rb +90 -0
  115. data/lib/openid/yadis/xrires.rb +91 -0
  116. data/test/data/test_discover/openid_utf8.html +11 -0
  117. data/test/support/test_data_mixin.rb +127 -0
  118. data/test/support/test_util.rb +53 -0
  119. data/test/support/yadis_data.rb +131 -0
  120. data/test/support/yadis_data/accept.txt +124 -0
  121. data/test/support/yadis_data/dh.txt +29 -0
  122. data/test/support/yadis_data/example-xrds.xml +14 -0
  123. data/test/support/yadis_data/linkparse.txt +587 -0
  124. data/test/support/yadis_data/n2b64 +650 -0
  125. data/test/support/yadis_data/test1-discover.txt +137 -0
  126. data/test/support/yadis_data/test1-parsehtml.txt +152 -0
  127. data/test/support/yadis_data/test_discover/malformed_meta_tag.html +19 -0
  128. data/test/support/yadis_data/test_discover/openid.html +11 -0
  129. data/test/support/yadis_data/test_discover/openid2.html +11 -0
  130. data/test/support/yadis_data/test_discover/openid2_xrds.xml +12 -0
  131. data/test/support/yadis_data/test_discover/openid2_xrds_no_local_id.xml +11 -0
  132. data/test/support/yadis_data/test_discover/openid_1_and_2.html +11 -0
  133. data/test/support/yadis_data/test_discover/openid_1_and_2_xrds.xml +16 -0
  134. data/test/support/yadis_data/test_discover/openid_1_and_2_xrds_bad_delegate.xml +17 -0
  135. data/test/support/yadis_data/test_discover/openid_and_yadis.html +12 -0
  136. data/test/support/yadis_data/test_discover/openid_no_delegate.html +10 -0
  137. data/test/support/yadis_data/test_discover/openid_utf8.html +11 -0
  138. data/test/support/yadis_data/test_discover/yadis_0entries.xml +12 -0
  139. data/test/support/yadis_data/test_discover/yadis_2_bad_local_id.xml +15 -0
  140. data/test/support/yadis_data/test_discover/yadis_2entries_delegate.xml +22 -0
  141. data/test/support/yadis_data/test_discover/yadis_2entries_idp.xml +21 -0
  142. data/test/support/yadis_data/test_discover/yadis_another_delegate.xml +14 -0
  143. data/test/support/yadis_data/test_discover/yadis_idp.xml +12 -0
  144. data/test/support/yadis_data/test_discover/yadis_idp_delegate.xml +13 -0
  145. data/test/support/yadis_data/test_discover/yadis_no_delegate.xml +11 -0
  146. data/test/support/yadis_data/test_xrds/=j3h.2007.11.14.xrds +25 -0
  147. data/test/support/yadis_data/test_xrds/README +12 -0
  148. data/test/support/yadis_data/test_xrds/delegated-20060809-r1.xrds +34 -0
  149. data/test/support/yadis_data/test_xrds/delegated-20060809-r2.xrds +34 -0
  150. data/test/support/yadis_data/test_xrds/delegated-20060809.xrds +34 -0
  151. data/test/support/yadis_data/test_xrds/no-xrd.xml +7 -0
  152. data/test/support/yadis_data/test_xrds/not-xrds.xml +2 -0
  153. data/test/support/yadis_data/test_xrds/prefixsometimes.xrds +34 -0
  154. data/test/support/yadis_data/test_xrds/ref.xrds +109 -0
  155. data/test/support/yadis_data/test_xrds/sometimesprefix.xrds +34 -0
  156. data/test/support/yadis_data/test_xrds/spoof1.xrds +25 -0
  157. data/test/support/yadis_data/test_xrds/spoof2.xrds +25 -0
  158. data/test/support/yadis_data/test_xrds/spoof3.xrds +37 -0
  159. data/test/support/yadis_data/test_xrds/status222.xrds +9 -0
  160. data/test/support/yadis_data/test_xrds/subsegments.xrds +58 -0
  161. data/test/support/yadis_data/test_xrds/valid-populated-xrds.xml +39 -0
  162. data/test/support/yadis_data/trustroot.txt +153 -0
  163. data/test/support/yadis_data/urinorm.txt +79 -0
  164. data/test/test_accept.rb +170 -0
  165. data/test/test_association.rb +268 -0
  166. data/test/test_associationmanager.rb +918 -0
  167. data/test/test_ax.rb +690 -0
  168. data/test/test_checkid_request.rb +293 -0
  169. data/test/test_consumer.rb +260 -0
  170. data/test/test_cryptutil.rb +119 -0
  171. data/test/test_dh.rb +85 -0
  172. data/test/test_discover.rb +848 -0
  173. data/test/test_discovery_manager.rb +259 -0
  174. data/test/test_extension.rb +46 -0
  175. data/test/test_extras.rb +35 -0
  176. data/test/test_fetchers.rb +554 -0
  177. data/test/test_filters.rb +269 -0
  178. data/test/test_helper.rb +4 -0
  179. data/test/test_idres.rb +961 -0
  180. data/test/test_kvform.rb +164 -0
  181. data/test/test_kvpost.rb +64 -0
  182. data/test/test_linkparse.rb +100 -0
  183. data/test/test_message.rb +1115 -0
  184. data/test/test_nonce.rb +89 -0
  185. data/test/test_oauth.rb +176 -0
  186. data/test/test_openid_yadis.rb +177 -0
  187. data/test/test_pape.rb +248 -0
  188. data/test/test_parsehtml.rb +79 -0
  189. data/test/test_responses.rb +63 -0
  190. data/test/test_server.rb +2455 -0
  191. data/test/test_sreg.rb +479 -0
  192. data/test/test_stores.rb +292 -0
  193. data/test/test_trustroot.rb +111 -0
  194. data/test/test_urinorm.rb +34 -0
  195. data/test/test_util.rb +145 -0
  196. data/test/test_xrds.rb +167 -0
  197. data/test/test_xri.rb +48 -0
  198. data/test/test_xrires.rb +67 -0
  199. data/test/test_yadis_discovery.rb +218 -0
  200. metadata +268 -0
@@ -0,0 +1,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