ruby-openid 1.1.4 → 2.0.1

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 (207) hide show
  1. data/INSTALL +0 -9
  2. data/README +21 -22
  3. data/UPGRADE +117 -0
  4. data/admin/runtests.rb +36 -0
  5. data/examples/README +13 -21
  6. data/examples/active_record_openid_store/README +8 -3
  7. data/examples/active_record_openid_store/XXX_add_open_id_store_to_db.rb +4 -8
  8. data/examples/active_record_openid_store/XXX_upgrade_open_id_store.rb +26 -0
  9. data/examples/active_record_openid_store/lib/association.rb +2 -0
  10. data/examples/active_record_openid_store/lib/openid_ar_store.rb +22 -47
  11. data/examples/active_record_openid_store/test/store_test.rb +78 -48
  12. data/examples/discover +46 -0
  13. data/examples/{rails_server → rails_openid}/README +0 -0
  14. data/examples/{rails_server → rails_openid}/Rakefile +0 -0
  15. data/examples/{rails_server → rails_openid}/app/controllers/application.rb +0 -0
  16. data/examples/rails_openid/app/controllers/consumer_controller.rb +115 -0
  17. data/examples/{rails_server → rails_openid}/app/controllers/login_controller.rb +10 -2
  18. data/examples/rails_openid/app/controllers/server_controller.rb +265 -0
  19. data/examples/{rails_server → rails_openid}/app/helpers/application_helper.rb +0 -0
  20. data/examples/{rails_server → rails_openid}/app/helpers/login_helper.rb +0 -0
  21. data/examples/{rails_server → rails_openid}/app/helpers/server_helper.rb +0 -0
  22. data/examples/rails_openid/app/views/consumer/index.rhtml +81 -0
  23. data/examples/rails_openid/app/views/consumer/start.rhtml +8 -0
  24. data/examples/{rails_server → rails_openid}/app/views/layouts/server.rhtml +0 -0
  25. data/examples/{rails_server → rails_openid}/app/views/login/index.rhtml +1 -1
  26. data/examples/rails_openid/app/views/server/decide.rhtml +26 -0
  27. data/examples/{rails_server → rails_openid}/config/boot.rb +0 -0
  28. data/examples/{rails_server → rails_openid}/config/database.yml +0 -0
  29. data/examples/{rails_server → rails_openid}/config/environment.rb +0 -0
  30. data/examples/{rails_server → rails_openid}/config/environments/development.rb +0 -0
  31. data/examples/{rails_server → rails_openid}/config/environments/production.rb +0 -0
  32. data/examples/{rails_server → rails_openid}/config/environments/test.rb +0 -0
  33. data/examples/{rails_server → rails_openid}/config/routes.rb +2 -1
  34. data/examples/{rails_server → rails_openid}/doc/README_FOR_APP +0 -0
  35. data/examples/{rails_server → rails_openid}/public/404.html +0 -0
  36. data/examples/{rails_server → rails_openid}/public/500.html +0 -0
  37. data/examples/{rails_server → rails_openid}/public/dispatch.cgi +0 -0
  38. data/examples/{rails_server → rails_openid}/public/dispatch.fcgi +0 -0
  39. data/examples/{rails_server → rails_openid}/public/dispatch.rb +0 -0
  40. data/examples/{rails_server → rails_openid}/public/favicon.ico +0 -0
  41. data/examples/rails_openid/public/images/openid_login_bg.gif +0 -0
  42. data/examples/{rails_server → rails_openid}/public/javascripts/controls.js +0 -0
  43. data/examples/{rails_server → rails_openid}/public/javascripts/dragdrop.js +0 -0
  44. data/examples/{rails_server → rails_openid}/public/javascripts/effects.js +0 -0
  45. data/examples/{rails_server → rails_openid}/public/javascripts/prototype.js +0 -0
  46. data/examples/{rails_server → rails_openid}/public/robots.txt +0 -0
  47. data/examples/{rails_server → rails_openid}/script/about +0 -0
  48. data/examples/{rails_server → rails_openid}/script/breakpointer +0 -0
  49. data/examples/{rails_server → rails_openid}/script/console +0 -0
  50. data/examples/{rails_server → rails_openid}/script/destroy +0 -0
  51. data/examples/{rails_server → rails_openid}/script/generate +0 -0
  52. data/examples/{rails_server → rails_openid}/script/performance/benchmarker +0 -0
  53. data/examples/{rails_server → rails_openid}/script/performance/profiler +0 -0
  54. data/examples/{rails_server → rails_openid}/script/plugin +0 -0
  55. data/examples/{rails_server → rails_openid}/script/process/reaper +0 -0
  56. data/examples/{rails_server → rails_openid}/script/process/spawner +0 -0
  57. data/examples/{rails_server → rails_openid}/script/process/spinner +0 -0
  58. data/examples/{rails_server → rails_openid}/script/runner +0 -0
  59. data/examples/{rails_server → rails_openid}/script/server +0 -0
  60. data/examples/{rails_server → rails_openid}/test/functional/login_controller_test.rb +0 -0
  61. data/examples/{rails_server → rails_openid}/test/functional/server_controller_test.rb +0 -0
  62. data/examples/{rails_server → rails_openid}/test/test_helper.rb +0 -0
  63. data/lib/{hmac.rb → hmac/hmac.rb} +0 -0
  64. data/lib/{hmac-sha1.rb → hmac/sha1.rb} +1 -1
  65. data/lib/{hmac-sha2.rb → hmac/sha2.rb} +1 -1
  66. data/lib/openid/association.rb +213 -73
  67. data/lib/openid/consumer/associationmanager.rb +338 -0
  68. data/lib/openid/consumer/checkid_request.rb +175 -0
  69. data/lib/openid/consumer/discovery.rb +480 -0
  70. data/lib/openid/consumer/discovery_manager.rb +123 -0
  71. data/lib/openid/consumer/html_parse.rb +136 -0
  72. data/lib/openid/consumer/idres.rb +525 -0
  73. data/lib/openid/consumer/responses.rb +133 -0
  74. data/lib/openid/consumer.rb +280 -807
  75. data/lib/openid/cryptutil.rb +85 -0
  76. data/lib/openid/dh.rb +60 -23
  77. data/lib/openid/extension.rb +31 -0
  78. data/lib/openid/extensions/ax.rb +506 -0
  79. data/lib/openid/extensions/pape.rb +182 -0
  80. data/lib/openid/extensions/sreg.rb +275 -0
  81. data/lib/openid/extras.rb +11 -0
  82. data/lib/openid/fetchers.rb +132 -93
  83. data/lib/openid/kvform.rb +133 -0
  84. data/lib/openid/kvpost.rb +56 -0
  85. data/lib/openid/message.rb +534 -0
  86. data/lib/openid/protocolerror.rb +6 -0
  87. data/lib/openid/server.rb +1215 -666
  88. data/lib/openid/store/filesystem.rb +271 -0
  89. data/lib/openid/store/interface.rb +75 -0
  90. data/lib/openid/store/memory.rb +84 -0
  91. data/lib/openid/store/nonce.rb +68 -0
  92. data/lib/openid/trustroot.rb +314 -87
  93. data/lib/openid/urinorm.rb +37 -34
  94. data/lib/openid/util.rb +42 -220
  95. data/lib/openid/yadis/accept.rb +148 -0
  96. data/lib/openid/yadis/constants.rb +21 -0
  97. data/lib/openid/yadis/discovery.rb +153 -0
  98. data/lib/openid/yadis/filters.rb +205 -0
  99. data/lib/openid/{htmltokenizer.rb → yadis/htmltokenizer.rb} +1 -54
  100. data/lib/openid/yadis/parsehtml.rb +36 -0
  101. data/lib/openid/yadis/services.rb +42 -0
  102. data/lib/openid/yadis/xrds.rb +171 -0
  103. data/lib/openid/yadis/xri.rb +90 -0
  104. data/lib/openid/yadis/xrires.rb +106 -0
  105. data/lib/openid.rb +1 -4
  106. data/test/data/accept.txt +124 -0
  107. data/test/data/dh.txt +29 -0
  108. data/test/data/example-xrds.xml +14 -0
  109. data/test/data/linkparse.txt +587 -0
  110. data/test/data/n2b64 +650 -0
  111. data/test/data/test1-discover.txt +137 -0
  112. data/test/data/test1-parsehtml.txt +128 -0
  113. data/test/data/test_discover/openid.html +11 -0
  114. data/test/data/test_discover/openid2.html +11 -0
  115. data/test/data/test_discover/openid2_xrds.xml +12 -0
  116. data/test/data/test_discover/openid2_xrds_no_local_id.xml +11 -0
  117. data/test/data/test_discover/openid_1_and_2.html +11 -0
  118. data/test/data/test_discover/openid_1_and_2_xrds.xml +16 -0
  119. data/test/data/test_discover/openid_1_and_2_xrds_bad_delegate.xml +17 -0
  120. data/test/data/test_discover/openid_and_yadis.html +12 -0
  121. data/test/data/test_discover/openid_no_delegate.html +10 -0
  122. data/test/data/test_discover/yadis_0entries.xml +12 -0
  123. data/test/data/test_discover/yadis_2_bad_local_id.xml +15 -0
  124. data/test/data/test_discover/yadis_2entries_delegate.xml +22 -0
  125. data/test/data/test_discover/yadis_2entries_idp.xml +21 -0
  126. data/test/data/test_discover/yadis_another_delegate.xml +14 -0
  127. data/test/data/test_discover/yadis_idp.xml +12 -0
  128. data/test/data/test_discover/yadis_idp_delegate.xml +13 -0
  129. data/test/data/test_discover/yadis_no_delegate.xml +11 -0
  130. data/test/data/test_xrds/=j3h.2007.11.14.xrds +25 -0
  131. data/test/data/test_xrds/README +12 -0
  132. data/test/data/test_xrds/delegated-20060809-r1.xrds +34 -0
  133. data/test/data/test_xrds/delegated-20060809-r2.xrds +34 -0
  134. data/test/data/test_xrds/delegated-20060809.xrds +34 -0
  135. data/test/data/test_xrds/no-xrd.xml +7 -0
  136. data/test/data/test_xrds/not-xrds.xml +2 -0
  137. data/test/data/test_xrds/prefixsometimes.xrds +34 -0
  138. data/test/data/test_xrds/ref.xrds +109 -0
  139. data/test/data/test_xrds/sometimesprefix.xrds +34 -0
  140. data/test/data/test_xrds/spoof1.xrds +25 -0
  141. data/test/data/test_xrds/spoof2.xrds +25 -0
  142. data/test/data/test_xrds/spoof3.xrds +37 -0
  143. data/test/data/test_xrds/status222.xrds +9 -0
  144. data/test/data/test_xrds/valid-populated-xrds.xml +39 -0
  145. data/test/data/trustroot.txt +147 -0
  146. data/test/discoverdata.rb +131 -0
  147. data/test/test_accept.rb +170 -0
  148. data/test/test_association.rb +266 -0
  149. data/test/test_associationmanager.rb +899 -0
  150. data/test/test_ax.rb +587 -0
  151. data/test/test_checkid_request.rb +297 -0
  152. data/test/test_consumer.rb +257 -0
  153. data/test/test_cryptutil.rb +117 -0
  154. data/test/test_dh.rb +86 -0
  155. data/test/test_discover.rb +772 -0
  156. data/test/test_discovery_manager.rb +262 -0
  157. data/test/test_extras.rb +35 -0
  158. data/test/test_fetchers.rb +472 -0
  159. data/test/test_filters.rb +270 -0
  160. data/test/test_idres.rb +816 -0
  161. data/test/test_kvform.rb +165 -0
  162. data/test/test_kvpost.rb +65 -0
  163. data/test/test_linkparse.rb +101 -0
  164. data/test/test_message.rb +1058 -0
  165. data/test/test_nonce.rb +89 -0
  166. data/test/test_openid_yadis.rb +178 -0
  167. data/test/test_pape.rb +233 -0
  168. data/test/test_parsehtml.rb +80 -0
  169. data/test/test_responses.rb +63 -0
  170. data/test/test_server.rb +2270 -0
  171. data/test/test_sreg.rb +479 -0
  172. data/test/test_stores.rb +269 -0
  173. data/test/test_trustroot.rb +112 -0
  174. data/test/{urinorm.rb → test_urinorm.rb} +6 -3
  175. data/test/test_util.rb +144 -0
  176. data/test/test_xrds.rb +160 -0
  177. data/test/test_xri.rb +48 -0
  178. data/test/test_xrires.rb +63 -0
  179. data/test/test_yadis_discovery.rb +207 -0
  180. data/test/testutil.rb +116 -0
  181. data/test/util.rb +47 -50
  182. metadata +233 -143
  183. data/examples/consumer.rb +0 -290
  184. data/examples/rails_openid_login_generator/openid_login_generator-0.1.gem +0 -0
  185. data/examples/rails_server/app/controllers/server_controller.rb +0 -190
  186. data/examples/rails_server/app/views/server/decide.rhtml +0 -11
  187. data/examples/rails_server/public/images/rails.png +0 -0
  188. data/lib/hmac-md5.rb +0 -11
  189. data/lib/hmac-rmd160.rb +0 -11
  190. data/lib/openid/discovery.rb +0 -122
  191. data/lib/openid/filestore.rb +0 -315
  192. data/lib/openid/parse.rb +0 -23
  193. data/lib/openid/service.rb +0 -147
  194. data/lib/openid/stores.rb +0 -178
  195. data/test/assoc.rb +0 -38
  196. data/test/consumer.rb +0 -376
  197. data/test/data/brian.xrds +0 -16
  198. data/test/data/brianellin.mylid.xrds +0 -42
  199. data/test/dh.rb +0 -20
  200. data/test/extensions.rb +0 -30
  201. data/test/linkparse.rb +0 -305
  202. data/test/runtests.rb +0 -22
  203. data/test/server2.rb +0 -1053
  204. data/test/service.rb +0 -47
  205. data/test/storetestcase.rb +0 -172
  206. data/test/teststore.rb +0 -47
  207. data/test/trustroot.rb +0 -117
@@ -0,0 +1,816 @@
1
+ require "testutil"
2
+ require "util"
3
+ require "test/unit"
4
+ require "openid/consumer/idres"
5
+ require "openid/protocolerror"
6
+ require "openid/store/memory"
7
+ require "openid/store/nonce"
8
+
9
+ module OpenID
10
+ class Consumer
11
+ class IdResHandler
12
+
13
+ # Subclass of IdResHandler that doesn't do verification upon
14
+ # construction. All of the tests call this, except for the ones
15
+ # explicitly for id_res.
16
+ class IdResHandler < OpenID::Consumer::IdResHandler
17
+ def id_res
18
+ end
19
+ end
20
+
21
+ class CheckForFieldsTest < Test::Unit::TestCase
22
+ include ProtocolErrorMixin
23
+
24
+ BASE_FIELDS = ['return_to', 'assoc_handle', 'sig', 'signed']
25
+ OPENID2_FIELDS = BASE_FIELDS + ['op_endpoint']
26
+ OPENID1_FIELDS = BASE_FIELDS + ['identity']
27
+
28
+ OPENID1_SIGNED = ['return_to', 'identity']
29
+ OPENID2_SIGNED =
30
+ OPENID1_SIGNED + ['response_nonce', 'claimed_id', 'assoc_handle']
31
+
32
+ def mkMsg(ns, fields, signed_fields)
33
+ msg = Message.new(ns)
34
+ fields.each do |field|
35
+ msg.set_arg(OPENID_NS, field, "don't care")
36
+ end
37
+ if fields.member?('signed')
38
+ msg.set_arg(OPENID_NS, 'signed', signed_fields.join(','))
39
+ end
40
+ msg
41
+ end
42
+
43
+ 1.times do # so as not to bleed into the outer namespace
44
+ n = 0
45
+ [[],
46
+ ['foo'],
47
+ ['bar', 'baz'],
48
+ ].each do |signed_fields|
49
+ test = lambda do
50
+ msg = mkMsg(OPENID2_NS, OPENID2_FIELDS, signed_fields)
51
+ idres = IdResHandler.new(msg, nil)
52
+ assert_equal(signed_fields, idres.send(:signed_list))
53
+ # Do it again to make sure logic for caching is correct
54
+ assert_equal(signed_fields, idres.send(:signed_list))
55
+ end
56
+ define_method("test_signed_list_#{n += 1}", test)
57
+ end
58
+ end
59
+
60
+ # test all missing fields for OpenID 1 and 2
61
+ 1.times do
62
+ [["openid1", OPENID1_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
+ ["openid2", OPENID2_NS, OPENID2_FIELDS, OPENID2_SIGNED],
84
+ ].each do |ver, ns, all_fields, signed_fields|
85
+ signed_fields.each do |signed_field|
86
+ test = lambda do
87
+ fields = signed_fields.dup
88
+ fields.delete(signed_field)
89
+ msg = mkMsg(ns, all_fields, fields)
90
+ # Make sure the signed field is actually in the request
91
+ msg.set_arg(OPENID_NS, signed_field, "don't care")
92
+ idres = IdResHandler.new(msg, nil)
93
+ assert_protocol_error("#{signed_field.inspect} not signed") {
94
+ idres.send(:check_for_fields)
95
+ }
96
+ end
97
+ define_method("test_#{ver}_check_missing_signed_#{signed_field}", test)
98
+ end
99
+ end
100
+ end
101
+
102
+ def test_no_signed_list
103
+ msg = Message.new(OPENID2_NS)
104
+ idres = IdResHandler.new(msg, nil)
105
+ assert_protocol_error("Response missing signed") {
106
+ idres.send(:signed_list)
107
+ }
108
+ end
109
+
110
+ def test_success_openid1
111
+ msg = mkMsg(OPENID1_NS, OPENID1_FIELDS, OPENID1_SIGNED)
112
+ idres = IdResHandler.new(msg, nil)
113
+ assert_nothing_raised {
114
+ idres.send(:check_for_fields)
115
+ }
116
+ end
117
+ end
118
+
119
+ class ReturnToArgsTest < Test::Unit::TestCase
120
+ include OpenID::ProtocolErrorMixin
121
+
122
+ def check_return_to_args(query)
123
+ idres = IdResHandler.new(Message.from_post_args(query), nil)
124
+ class << idres
125
+ def verify_return_to_base(unused)
126
+ end
127
+ end
128
+ idres.send(:verify_return_to)
129
+ end
130
+
131
+ def assert_bad_args(msg, query)
132
+ assert_protocol_error(msg) {
133
+ check_return_to_args(query)
134
+ }
135
+ end
136
+
137
+ def test_return_to_args_okay
138
+ assert_nothing_raised {
139
+ check_return_to_args({
140
+ 'openid.mode' => 'id_res',
141
+ 'openid.return_to' => 'http://example.com/?foo=bar',
142
+ 'foo' => 'bar',
143
+ })
144
+ }
145
+ end
146
+
147
+ def test_unexpected_arg_okay
148
+ assert_bad_args("Parameter foo does", {
149
+ 'openid.mode' => 'id_res',
150
+ 'openid.return_to' => 'http://example.com/',
151
+ 'foo' => 'bar',
152
+ })
153
+ end
154
+
155
+ def test_return_to_mismatch
156
+ assert_bad_args('Message missing ret', {
157
+ 'openid.mode' => 'id_res',
158
+ 'openid.return_to' => 'http://example.com/?foo=bar',
159
+ })
160
+
161
+ assert_bad_args('Parameter foo val', {
162
+ 'openid.mode' => 'id_res',
163
+ 'openid.return_to' => 'http://example.com/?foo=bar',
164
+ 'foo' => 'foos',
165
+ })
166
+ end
167
+ end
168
+
169
+ class ReturnToVerifyTest < Test::Unit::TestCase
170
+ def test_bad_return_to
171
+ return_to = "http://some.url/path?foo=bar"
172
+
173
+ m = Message.new(OPENID1_NS)
174
+ m.set_arg(OPENID_NS, 'mode', 'cancel')
175
+ m.set_arg(BARE_NS, 'foo', 'bar')
176
+
177
+ # Scheme, authority, and path differences are checked by
178
+ # IdResHandler.verify_return_to_base. Query args checked by
179
+ # IdResHandler.verify_return_to_args.
180
+ [
181
+ # Scheme only
182
+ "https://some.url/path?foo=bar",
183
+ # Authority only
184
+ "http://some.url.invalid/path?foo=bar",
185
+ # Path only
186
+ "http://some.url/path_extra?foo=bar",
187
+ # Query args differ
188
+ "http://some.url/path?foo=bar2",
189
+ "http://some.url/path?foo2=bar",
190
+ ].each do |bad|
191
+ m.set_arg(OPENID_NS, 'return_to', bad)
192
+ idres = IdResHandler.new(m, return_to)
193
+ assert_raises(ProtocolError) {
194
+ idres.send(:verify_return_to)
195
+ }
196
+ end
197
+ end
198
+
199
+ def test_good_return_to
200
+ base = 'http://example.janrain.com/path'
201
+ [ [base, {}],
202
+ [base + "?another=arg", {'another' => 'arg'}],
203
+ [base + "?another=arg#frag", {'another' => 'arg'}],
204
+ ].each do |return_to, args|
205
+ args['openid.return_to'] = return_to
206
+ msg = Message.from_post_args(args)
207
+ idres = IdResHandler.new(msg, base)
208
+ assert_nothing_raised {
209
+ idres.send(:verify_return_to)
210
+ }
211
+ end
212
+ end
213
+ end
214
+
215
+ class DummyEndpoint
216
+ attr_accessor :server_url
217
+ def initialize(server_url)
218
+ @server_url = server_url
219
+ end
220
+ end
221
+
222
+ class CheckSigTest < Test::Unit::TestCase
223
+ include ProtocolErrorMixin
224
+ include TestUtil
225
+
226
+ def setup
227
+ @assoc = GoodAssoc.new('{not_dumb}')
228
+ @store = Store::Memory.new
229
+ @server_url = 'http://server.url/'
230
+ @endpoint = DummyEndpoint.new(@server_url)
231
+ @store.store_association(@server_url, @assoc)
232
+
233
+ @message = Message.from_post_args({
234
+ 'openid.mode' => 'id_res',
235
+ 'openid.identity' => '=example',
236
+ 'openid.sig' => GOODSIG,
237
+ 'openid.assoc_handle' => @assoc.handle,
238
+ 'openid.signed' => 'mode,identity,assoc_handle,signed',
239
+ 'frobboz' => 'banzit',
240
+ })
241
+ end
242
+
243
+ def call_idres_method(method_name)
244
+ idres = IdResHandler.new(@message, nil, @store, @endpoint)
245
+ idres.extend(InstanceDefExtension)
246
+ yield idres
247
+ idres.send(method_name)
248
+ end
249
+
250
+ def call_check_sig(&proc)
251
+ call_idres_method(:check_signature, &proc)
252
+ end
253
+
254
+ def no_check_auth(idres)
255
+ idres.instance_def(:check_auth) { fail "Called check_auth" }
256
+ end
257
+
258
+ def test_sign_good
259
+ assert_nothing_raised {
260
+ call_check_sig(&method(:no_check_auth))
261
+ }
262
+ end
263
+
264
+ def test_bad_sig
265
+ @message.set_arg(OPENID_NS, 'sig', 'bad sig!')
266
+ assert_protocol_error('Bad signature') {
267
+ call_check_sig(&method(:no_check_auth))
268
+ }
269
+ end
270
+
271
+ def test_check_auth_ok
272
+ @message.set_arg(OPENID_NS, 'assoc_handle', 'dumb-handle')
273
+ check_auth_called = false
274
+ call_check_sig do |idres|
275
+ idres.instance_def(:check_auth) do
276
+ check_auth_called = true
277
+ end
278
+ end
279
+ assert(check_auth_called)
280
+ end
281
+
282
+ def test_check_auth_ok_no_store
283
+ @store = nil
284
+ check_auth_called = false
285
+ call_check_sig do |idres|
286
+ idres.instance_def(:check_auth) do
287
+ check_auth_called = true
288
+ end
289
+ end
290
+ assert(check_auth_called)
291
+ end
292
+
293
+ def test_expired_assoc
294
+ @assoc.expires_in = -1
295
+ @store.store_association(@server_url, @assoc)
296
+ assert_protocol_error('Association with') {
297
+ call_check_sig(&method(:no_check_auth))
298
+ }
299
+ end
300
+
301
+ def call_check_auth(&proc)
302
+ assert_log_matches("Using 'check_authentication'") {
303
+ call_idres_method(:check_auth, &proc)
304
+ }
305
+ end
306
+
307
+ def test_check_auth_create_fail
308
+ assert_protocol_error("Could not generate") {
309
+ call_check_auth do |idres|
310
+ idres.instance_def(:create_check_auth_request) do
311
+ raise Message::KeyNotFound, "Testing"
312
+ end
313
+ end
314
+ }
315
+ end
316
+
317
+ def test_kv_server_error
318
+ OpenID.extend(OverrideMethodMixin)
319
+ send_error = lambda do |req, server_url|
320
+ msg = Message.new(OPENID2_NS)
321
+ raise ServerError.from_message(msg), 'For you!'
322
+ end
323
+
324
+ OpenID.with_method_overridden(:make_kv_post, send_error) do
325
+ assert_protocol_error("Error from") {
326
+ call_check_auth do |idres|
327
+ idres.instance_def(:create_check_auth_request) { nil }
328
+ end
329
+ }
330
+ end
331
+ end
332
+
333
+ def test_check_auth_okay
334
+ OpenID.extend(OverrideMethodMixin)
335
+ me = self
336
+ send_resp = Proc.new do |req, server_url|
337
+ me.assert_equal(:req, req)
338
+ :expected_response
339
+ end
340
+
341
+ OpenID.with_method_overridden(:make_kv_post, send_resp) do
342
+ final_resp = call_check_auth do |idres|
343
+ idres.instance_def(:create_check_auth_request) {
344
+ :req
345
+ }
346
+ idres.instance_def(:process_check_auth_response) do |resp|
347
+ me.assert_equal(:expected_response, resp)
348
+ end
349
+ end
350
+ end
351
+ end
352
+
353
+ def test_check_auth_process_fail
354
+ OpenID.extend(OverrideMethodMixin)
355
+ me = self
356
+ send_resp = Proc.new do |req, server_url|
357
+ me.assert_equal(:req, req)
358
+ :expected_response
359
+ end
360
+
361
+ OpenID.with_method_overridden(:make_kv_post, send_resp) do
362
+ assert_protocol_error("Testing") do
363
+ final_resp = call_check_auth do |idres|
364
+ idres.instance_def(:create_check_auth_request) { :req }
365
+ idres.instance_def(:process_check_auth_response) do |resp|
366
+ me.assert_equal(:expected_response, resp)
367
+ raise ProtocolError, "Testing"
368
+ end
369
+ end
370
+ end
371
+ end
372
+ end
373
+
374
+ 1.times do
375
+ # Fields from the signed list
376
+ ['mode', 'identity', 'assoc_handle'
377
+ ].each do |field|
378
+ test = lambda do
379
+ @message.del_arg(OPENID_NS, field)
380
+ assert_raises(Message::KeyNotFound) {
381
+ call_idres_method(:create_check_auth_request) {}
382
+ }
383
+ end
384
+ define_method("test_create_check_auth_missing_#{field}", test)
385
+ end
386
+ end
387
+
388
+ def test_create_check_auth_request_success
389
+ msg = call_idres_method(:create_check_auth_request) {}
390
+ openid_args = @message.get_args(OPENID_NS)
391
+ openid_args['mode'] = 'check_authentication'
392
+ assert_equal(openid_args, msg.to_args)
393
+ end
394
+
395
+ def test_create_check_auth_request_success_extra
396
+ @message.set_arg(OPENID_NS, 'cookies', 'chocolate_chip')
397
+ msg = call_idres_method(:create_check_auth_request) {}
398
+ openid_args = @message.get_args(OPENID_NS)
399
+ openid_args['mode'] = 'check_authentication'
400
+ openid_args.delete('cookies')
401
+ assert_equal(openid_args, msg.to_args)
402
+ end
403
+ end
404
+
405
+ class CheckAuthResponseTest < Test::Unit::TestCase
406
+ include TestUtil
407
+ include ProtocolErrorMixin
408
+
409
+ def setup
410
+ @message = Message.from_openid_args({
411
+ 'is_valid' => 'true',
412
+ })
413
+ @assoc = GoodAssoc.new
414
+ @store = Store::Memory.new
415
+ @server_url = 'http://invalid/'
416
+ @endpoint = DummyEndpoint.new(@server_url)
417
+ @idres = IdResHandler.new(nil, nil, @store, @endpoint)
418
+ end
419
+
420
+ def call_process
421
+ @idres.send(:process_check_auth_response, @message)
422
+ end
423
+
424
+ def test_valid
425
+ assert_log_matches() { call_process }
426
+ end
427
+
428
+ def test_invalid
429
+ for is_valid in ['false', 'monkeys']
430
+ @message.set_arg(OPENID_NS, 'is_valid', 'false')
431
+ assert_protocol_error("Server #{@server_url} responds") {
432
+ assert_log_matches() { call_process }
433
+ }
434
+ end
435
+ end
436
+
437
+ def test_valid_invalidate
438
+ @message.set_arg(OPENID_NS, 'invalidate_handle', 'cheese')
439
+ assert_log_matches("Received 'invalidate_handle'") { call_process }
440
+ end
441
+
442
+ def test_invalid_invalidate
443
+ @message.set_arg(OPENID_NS, 'invalidate_handle', 'cheese')
444
+ for is_valid in ['false', 'monkeys']
445
+ @message.set_arg(OPENID_NS, 'is_valid', 'false')
446
+ assert_protocol_error("Server #{@server_url} responds") {
447
+ assert_log_matches("Received 'invalidate_handle'") {
448
+ call_process
449
+ }
450
+ }
451
+ end
452
+ end
453
+
454
+ def test_invalidate_no_store
455
+ @idres.instance_variable_set(:@store, nil)
456
+ @message.set_arg(OPENID_NS, 'invalidate_handle', 'cheese')
457
+ assert_log_matches("Received 'invalidate_handle'",
458
+ 'Unexpectedly got "invalidate_handle"') {
459
+ call_process
460
+ }
461
+ end
462
+ end
463
+
464
+ class NonceTest < Test::Unit::TestCase
465
+ include TestUtil
466
+ include ProtocolErrorMixin
467
+
468
+ def setup
469
+ @store = Object.new
470
+ class << @store
471
+ attr_accessor :nonces, :succeed
472
+ def use_nonce(server_url, time, extra)
473
+ @nonces << [server_url, time, extra]
474
+ @succeed
475
+ end
476
+ end
477
+ @store.nonces = []
478
+ @nonce = Nonce.mk_nonce
479
+ end
480
+
481
+ def call_check_nonce(post_args, succeed=false)
482
+ response = Message.from_post_args(post_args)
483
+ if !@store.nil?
484
+ @store.succeed = succeed
485
+ end
486
+ idres = IdResHandler.new(response, nil, @store, nil)
487
+ idres.send(:check_nonce)
488
+ end
489
+
490
+ def test_openid1_success
491
+ assert_nothing_raised {
492
+ call_check_nonce({'rp_nonce' => @nonce}, true)
493
+ }
494
+ end
495
+
496
+ def test_openid1_missing
497
+ assert_protocol_error('Nonce missing') { call_check_nonce({}) }
498
+ end
499
+
500
+ def test_openid2_ignore_rp_nonce
501
+ assert_protocol_error('Nonce missing') {
502
+ call_check_nonce({'rp_nonce' => @nonce,
503
+ 'openid.ns' => OPENID2_NS})
504
+ }
505
+ end
506
+
507
+ def test_openid2_success
508
+ assert_nothing_raised {
509
+ call_check_nonce({'openid.response_nonce' => @nonce,
510
+ 'openid.ns' => OPENID2_NS}, true)
511
+ }
512
+ end
513
+
514
+ def test_openid1_ignore_response_nonce
515
+ assert_protocol_error('Nonce missing') {
516
+ call_check_nonce({'openid.response_nonce' => @nonce})
517
+ }
518
+ end
519
+
520
+ def test_no_store
521
+ @store = nil
522
+ assert_nothing_raised {
523
+ call_check_nonce({'rp_nonce' => @nonce})
524
+ }
525
+ end
526
+
527
+ def test_already_used
528
+ assert_protocol_error('Nonce already used') {
529
+ call_check_nonce({'rp_nonce' => @nonce}, false)
530
+ }
531
+ end
532
+
533
+ def test_malformed_nonce
534
+ assert_protocol_error('Malformed nonce') {
535
+ call_check_nonce({'rp_nonce' => 'whee!'})
536
+ }
537
+ end
538
+ end
539
+
540
+ class DiscoveryVerificationTest < Test::Unit::TestCase
541
+ include ProtocolErrorMixin
542
+ include TestUtil
543
+
544
+ def setup
545
+ @endpoint = OpenIDServiceEndpoint.new
546
+ end
547
+
548
+ def call_verify(msg_args)
549
+ call_verify_modify(msg_args){}
550
+ end
551
+
552
+ def call_verify_modify(msg_args)
553
+ msg = Message.from_openid_args(msg_args)
554
+ idres = IdResHandler.new(msg, nil, nil, @endpoint)
555
+ idres.extend(InstanceDefExtension)
556
+ yield idres
557
+ idres.send(:verify_discovery_results)
558
+ idres.instance_variable_get(:@endpoint)
559
+ end
560
+
561
+ def assert_verify_protocol_error(error_prefix, openid_args)
562
+ assert_protocol_error(error_prefix) {call_verify(openid_args)}
563
+ end
564
+
565
+ def test_openid1_no_local_id
566
+ @endpoint.claimed_id = 'http://invalid/'
567
+ assert_verify_protocol_error("Missing required field: "\
568
+ "<#{OPENID1_NS}>identity", {})
569
+ end
570
+
571
+ def test_openid1_no_endpoint
572
+ @endpoint = nil
573
+ assert_raises(StandardError) {
574
+ call_verify({'identity' => 'snakes on a plane'})
575
+ }
576
+ end
577
+
578
+ def test_openid2_no_op_endpoint
579
+ assert_protocol_error("Missing required field: "\
580
+ "<#{OPENID2_NS}>op_endpoint") {
581
+ call_verify({'ns'=>OPENID2_NS})
582
+ }
583
+ end
584
+
585
+ def test_openid2_local_id_no_claimed
586
+ assert_verify_protocol_error('openid.identity is present without',
587
+ {'ns' => OPENID2_NS,
588
+ 'op_endpoint' => 'Phone Home',
589
+ 'identity' => 'Jorge Lius Borges'})
590
+ end
591
+
592
+ def test_openid2_no_local_id_claimed
593
+ assert_log_matches() {
594
+ assert_protocol_error('openid.claimed_id is present without') {
595
+ call_verify({'ns' => OPENID2_NS,
596
+ 'op_endpoint' => 'Phone Home',
597
+ 'claimed_id' => 'Manuel Noriega'})
598
+ }
599
+ }
600
+ end
601
+
602
+ def test_openid2_no_identifiers
603
+ op_endpoint = 'Phone Home'
604
+ result_endpoint = assert_log_matches() {
605
+ call_verify({'ns' => OPENID2_NS,
606
+ 'op_endpoint' => op_endpoint})
607
+ }
608
+ assert(result_endpoint.is_op_identifier)
609
+ assert_equal(op_endpoint, result_endpoint.server_url)
610
+ assert(result_endpoint.claimed_id.nil?)
611
+ end
612
+
613
+ def test_openid2_no_endpoint_does_disco
614
+ endpoint = OpenIDServiceEndpoint.new
615
+ endpoint.claimed_id = 'monkeysoft'
616
+ @endpoint = nil
617
+ result = assert_log_matches('No pre-discovered') {
618
+ call_verify_modify({'ns' => OPENID2_NS,
619
+ 'identity' => 'sour grapes',
620
+ 'claimed_id' => 'monkeysoft',
621
+ 'op_endpoint' => 'Phone Home'}) do |idres|
622
+ idres.instance_def(:discover_and_verify) {@endpoint = endpoint}
623
+ end
624
+ }
625
+ assert(endpoint.equal?(result))
626
+ end
627
+
628
+
629
+ def test_openid2_mismatched_does_disco
630
+ @endpoint.claimed_id = 'nothing special, but different'
631
+ @endpoint.local_id = 'green cheese'
632
+
633
+ endpoint = OpenIDServiceEndpoint.new
634
+ endpoint.claimed_id = 'monkeysoft'
635
+
636
+ result = assert_log_matches('Error attempting to use stored',
637
+ 'Attempting discovery') {
638
+ call_verify_modify({'ns' => OPENID2_NS,
639
+ 'identity' => 'sour grapes',
640
+ 'claimed_id' => 'monkeysoft',
641
+ 'op_endpoint' => 'Green Cheese'}) do |idres|
642
+ idres.extend(InstanceDefExtension)
643
+ idres.instance_def(:discover_and_verify) {@endpoint = endpoint}
644
+ end
645
+ }
646
+ assert(endpoint.equal?(result))
647
+ end
648
+
649
+ def test_openid2_use_pre_discovered
650
+ @endpoint.local_id = 'my identity'
651
+ @endpoint.claimed_id = 'http://i-am-sam/'
652
+ @endpoint.server_url = 'Phone Home'
653
+ @endpoint.type_uris = [OPENID_2_0_TYPE]
654
+
655
+ result = assert_log_matches() {
656
+ call_verify({'ns' => OPENID2_NS,
657
+ 'identity' => @endpoint.local_id,
658
+ 'claimed_id' => @endpoint.claimed_id,
659
+ 'op_endpoint' => @endpoint.server_url
660
+ })
661
+ }
662
+ assert(result.equal?(@endpoint))
663
+ end
664
+
665
+ def test_openid2_use_pre_discovered_wrong_type
666
+ text = "verify failed"
667
+ me = self
668
+
669
+ @endpoint.local_id = 'my identity'
670
+ @endpoint.claimed_id = 'i am sam'
671
+ @endpoint.server_url = 'Phone Home'
672
+ @endpoint.type_uris = [OPENID_1_1_TYPE]
673
+ endpoint = @endpoint
674
+
675
+ msg = Message.from_openid_args({'ns' => OPENID2_NS,
676
+ 'identity' => @endpoint.local_id,
677
+ 'claimed_id' =>
678
+ @endpoint.claimed_id,
679
+ 'op_endpoint' =>
680
+ @endpoint.server_url})
681
+
682
+ idres = IdResHandler.new(msg, nil, nil, @endpoint)
683
+ idres.extend(InstanceDefExtension)
684
+ idres.instance_def(:discover_and_verify) { |to_match|
685
+ me.assert_equal(endpoint.claimed_id, to_match.claimed_id)
686
+ raise ProtocolError, text
687
+ }
688
+ assert_log_matches('Error attempting to use stored',
689
+ 'Attempting discovery') {
690
+ assert_protocol_error(text) {
691
+ idres.send(:verify_discovery_results)
692
+ }
693
+ }
694
+ end
695
+
696
+
697
+ def test_openid1_use_pre_discovered
698
+ @endpoint.local_id = 'my identity'
699
+ @endpoint.claimed_id = 'http://i-am-sam/'
700
+ @endpoint.server_url = 'Phone Home'
701
+ @endpoint.type_uris = [OPENID_1_1_TYPE]
702
+
703
+ result = assert_log_matches() {
704
+ call_verify({'ns' => OPENID1_NS,
705
+ 'identity' => @endpoint.local_id})
706
+ }
707
+ assert(result.equal?(@endpoint))
708
+ end
709
+
710
+
711
+ def test_openid1_use_pre_discovered_wrong_type
712
+ verified_error = Class.new(Exception)
713
+
714
+ @endpoint.local_id = 'my identity'
715
+ @endpoint.claimed_id = 'i am sam'
716
+ @endpoint.server_url = 'Phone Home'
717
+ @endpoint.type_uris = [OPENID_2_0_TYPE]
718
+
719
+ assert_log_matches('Error attempting to use stored',
720
+ 'Attempting discovery') {
721
+ assert_raises(verified_error) {
722
+ call_verify_modify({'ns' => OPENID1_NS,
723
+ 'identity' => @endpoint.local_id}) { |idres|
724
+ idres.instance_def(:discover_and_verify) do
725
+ raise verified_error
726
+ end
727
+ }
728
+ }
729
+ }
730
+ end
731
+
732
+ def test_openid2_fragment
733
+ claimed_id = "http://unittest.invalid/"
734
+ claimed_id_frag = claimed_id + "#fragment"
735
+
736
+ @endpoint.local_id = 'my identity'
737
+ @endpoint.claimed_id = claimed_id
738
+ @endpoint.server_url = 'Phone Home'
739
+ @endpoint.type_uris = [OPENID_2_0_TYPE]
740
+
741
+ result = assert_log_matches() {
742
+ call_verify({'ns' => OPENID2_NS,
743
+ 'identity' => @endpoint.local_id,
744
+ 'claimed_id' => claimed_id_frag,
745
+ 'op_endpoint' => @endpoint.server_url})
746
+ }
747
+
748
+ [:local_id, :server_url, :type_uris].each do |sym|
749
+ assert_equal(@endpoint.send(sym), result.send(sym))
750
+ end
751
+ assert_equal(claimed_id_frag, result.claimed_id)
752
+ end
753
+
754
+ def test_endpoint_without_local_id
755
+ # An endpoint like this with no local_id is generated as a result of
756
+ # e.g. Yadis discovery with no LocalID tag.
757
+ @endpoint.server_url = "http://localhost:8000/openidserver"
758
+ @endpoint.claimed_id = "http://localhost:8000/id/id-jo"
759
+
760
+ to_match = OpenIDServiceEndpoint.new
761
+ to_match.server_url = "http://localhost:8000/openidserver"
762
+ to_match.claimed_id = "http://localhost:8000/id/id-jo"
763
+ to_match.local_id = "http://localhost:8000/id/id-jo"
764
+
765
+ idres = IdResHandler.new(nil, nil)
766
+ assert_log_matches() {
767
+ result = idres.send(:verify_discovery_single, @endpoint, to_match)
768
+ }
769
+ end
770
+ end
771
+
772
+ class IdResTopLevelTest < Test::Unit::TestCase
773
+ def test_id_res
774
+ endpoint = OpenIDServiceEndpoint.new
775
+ endpoint.server_url = 'http://invalid/server'
776
+ endpoint.claimed_id = 'http://my.url/'
777
+ endpoint.local_id = 'http://invalid/username'
778
+ endpoint.type_uris = [OPENID_2_0_TYPE]
779
+
780
+ assoc = GoodAssoc.new
781
+ store = Store::Memory.new
782
+ store.store_association(endpoint.server_url, assoc)
783
+
784
+ signed_fields =
785
+ [
786
+ 'response_nonce',
787
+ 'op_endpoint',
788
+ 'assoc_handle',
789
+ 'identity',
790
+ 'claimed_id',
791
+ 'ns',
792
+ 'return_to',
793
+ ]
794
+
795
+ return_to = 'http://return.to/'
796
+ args = {
797
+ 'ns' => OPENID2_NS,
798
+ 'return_to' => return_to,
799
+ 'claimed_id' => endpoint.claimed_id,
800
+ 'identity' => endpoint.local_id,
801
+ 'assoc_handle' => assoc.handle,
802
+ 'op_endpoint' => endpoint.server_url,
803
+ 'response_nonce' => Nonce.mk_nonce,
804
+ 'signed' => signed_fields.join(','),
805
+ 'sig' => GOODSIG,
806
+ }
807
+ msg = Message.from_openid_args(args)
808
+ idres = OpenID::Consumer::IdResHandler.new(msg, return_to,
809
+ store, endpoint)
810
+ assert_equal(idres.signed_fields,
811
+ signed_fields.map {|f|'openid.' + f})
812
+ end
813
+ end
814
+ end
815
+ end
816
+ end