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,259 @@
1
+ require "test_helper"
2
+ require 'openid/consumer/discovery_manager'
3
+ require 'openid/extras'
4
+
5
+ module OpenID
6
+ class TestDiscoveredServices < Test::Unit::TestCase
7
+ def setup
8
+ @starting_url = "http://starting.url.com/"
9
+ @yadis_url = "http://starting.url.com/xrds"
10
+ @services = ["bogus", "not_a_service"]
11
+
12
+ @disco_services = Consumer::DiscoveredServices.new(@starting_url,
13
+ @yadis_url,
14
+ @services.dup)
15
+ end
16
+
17
+ def test_next
18
+ assert_equal(@disco_services.next, @services[0])
19
+ assert_equal(@disco_services.current, @services[0])
20
+
21
+ assert_equal(@disco_services.next, @services[1])
22
+ assert_equal(@disco_services.current, @services[1])
23
+
24
+ assert_equal(@disco_services.next, nil)
25
+ assert_equal(@disco_services.current, nil)
26
+ end
27
+
28
+ def test_for_url
29
+ assert(@disco_services.for_url?(@starting_url))
30
+ assert(@disco_services.for_url?(@yadis_url))
31
+
32
+ assert(!@disco_services.for_url?(nil))
33
+ assert(!@disco_services.for_url?("invalid"))
34
+ end
35
+
36
+ def test_started
37
+ assert(!@disco_services.started?)
38
+ @disco_services.next
39
+ assert(@disco_services.started?)
40
+ @disco_services.next
41
+ assert(@disco_services.started?)
42
+ @disco_services.next
43
+ assert(!@disco_services.started?)
44
+ end
45
+
46
+ def test_empty
47
+ assert(Consumer::DiscoveredServices.new(nil, nil, []).empty?)
48
+
49
+ assert(!@disco_services.empty?)
50
+
51
+ @disco_services.next
52
+ @disco_services.next
53
+
54
+ assert(@disco_services.started?)
55
+ end
56
+ end
57
+
58
+ # I need to be able to test the protected methods; this lets me do
59
+ # that.
60
+ class PassthroughDiscoveryManager < Consumer::DiscoveryManager
61
+ def method_missing(m, *args)
62
+ method(m).call(*args)
63
+ end
64
+ end
65
+
66
+ class TestDiscoveryManager < Test::Unit::TestCase
67
+ def setup
68
+ @session = {}
69
+ @url = "http://unittest.com/"
70
+ @key_suffix = "testing"
71
+ @yadis_url = "http://unittest.com/xrds"
72
+ @manager = PassthroughDiscoveryManager.new(@session, @url, @key_suffix)
73
+ @key = @manager.session_key
74
+ end
75
+
76
+ def test_construct
77
+ # Make sure the default session key suffix is not nil.
78
+ m = Consumer::DiscoveryManager.new(nil, nil)
79
+ assert(!m.instance_variable_get("@session_key_suffix").nil?)
80
+
81
+ m = Consumer::DiscoveryManager.new(nil, nil, "override")
82
+ assert_equal(m.instance_variable_get("@session_key_suffix"), "override")
83
+ end
84
+
85
+ def test_get_next_service
86
+ assert_equal(@session[@key], nil)
87
+
88
+ next_service = @manager.get_next_service {
89
+ [@yadis_url, ["one", "two", "three"]]
90
+ }
91
+
92
+ disco = @session[@key]
93
+ assert_equal(disco.current, "one")
94
+ assert_equal(next_service, "one")
95
+ assert(disco.for_url?(@url))
96
+ assert(disco.for_url?(@yadis_url))
97
+
98
+ # The first two calls to get_next_service should return the
99
+ # services in @disco.
100
+ assert_equal(@manager.get_next_service, "two")
101
+ assert_equal(@manager.get_next_service, "three")
102
+ assert_equal(@session[@key], disco)
103
+
104
+ # The manager is exhausted and should be deleted and a new one
105
+ # should be created.
106
+ @manager.get_next_service {
107
+ [@yadis_url, ["four"]]
108
+ }
109
+
110
+ disco2 = @session[@key]
111
+ assert_equal(disco2.current, "four")
112
+
113
+ # create_manager may return a nil manager, in which case the
114
+ # next service should be nil.
115
+ @manager.extend(OpenID::InstanceDefExtension)
116
+ @manager.instance_def(:create_manager) do |yadis_url, services|
117
+ nil
118
+ end
119
+
120
+ result = @manager.get_next_service { |url|
121
+ ["unused", []]
122
+ }
123
+
124
+ assert_equal(result, nil)
125
+ end
126
+
127
+ def test_cleanup
128
+ # With no preexisting manager, cleanup() returns nil.
129
+ assert_equal(@manager.cleanup, nil)
130
+
131
+ # With a manager, it returns the manager's current service.
132
+ disco = Consumer::DiscoveredServices.new(@url, @yadis_url, ["one", "two"])
133
+
134
+ @session[@key] = disco
135
+ assert_equal(@manager.cleanup, nil)
136
+ assert_equal(@session[@key], nil)
137
+
138
+ @session[@key] = disco
139
+ disco.next
140
+ assert_equal(@manager.cleanup, "one")
141
+ assert_equal(@session[@key], nil)
142
+
143
+ # The force parameter should be passed through to get_manager
144
+ # and destroy_manager.
145
+ force_value = "yo"
146
+ testcase = self
147
+
148
+ m = Consumer::DiscoveredServices.new(nil, nil, ["inner"])
149
+ m.next
150
+
151
+ @manager.extend(OpenID::InstanceDefExtension)
152
+ @manager.instance_def(:get_manager) do |force|
153
+ testcase.assert_equal(force, force_value)
154
+ m
155
+ end
156
+
157
+ @manager.instance_def(:destroy_manager) do |force|
158
+ testcase.assert_equal(force, force_value)
159
+ end
160
+
161
+ assert_equal("inner", @manager.cleanup(force_value))
162
+ end
163
+
164
+ def test_get_manager
165
+ # get_manager should always return the loaded manager when
166
+ # forced.
167
+ @session[@key] = "bogus"
168
+ assert_equal("bogus", @manager.get_manager(true))
169
+
170
+ # When not forced, only managers for @url should be returned.
171
+ disco = Consumer::DiscoveredServices.new(@url, @yadis_url, ["one"])
172
+ @session[@key] = disco
173
+ assert_equal(@manager.get_manager, disco)
174
+
175
+ # Try to get_manager for a manger that doesn't manage @url:
176
+ disco2 = Consumer::DiscoveredServices.new("http://not.this.url.com/",
177
+ "http://other.yadis.url/", ["one"])
178
+ @session[@key] = disco2
179
+ assert_equal(@manager.get_manager, nil)
180
+ assert_equal(@manager.get_manager(true), disco2)
181
+ end
182
+
183
+ def test_create_manager
184
+ assert(@session[@key].nil?)
185
+
186
+ services = ["created", "manager"]
187
+ returned_disco = @manager.create_manager(@yadis_url, services)
188
+
189
+ stored_disco = @session[@key]
190
+ assert(stored_disco.for_url?(@yadis_url))
191
+ assert_equal(stored_disco.next, "created")
192
+
193
+ assert_equal(stored_disco, returned_disco)
194
+
195
+ # Calling create_manager with a preexisting manager should
196
+ # result in StandardError.
197
+ assert_raise(StandardError) {
198
+ @manager.create_manager(@yadis_url, services)
199
+ }
200
+
201
+ # create_manager should do nothing (and return nil) if given no
202
+ # services.
203
+ @session[@key] = nil
204
+ result = @manager.create_manager(@yadis_url, [])
205
+ assert(result.nil?)
206
+ assert(@session[@key].nil?)
207
+ end
208
+
209
+ class DestroyCalledException < StandardError; end
210
+
211
+ def test_destroy_manager
212
+ # destroy_manager should remove the manager from the session,
213
+ # forcibly if necessary.
214
+ valid_disco = Consumer::DiscoveredServices.new(@url, @yadis_url, ["serv"])
215
+ invalid_disco = Consumer::DiscoveredServices.new("http://not.mine.com/",
216
+ "http://different.url.com/",
217
+ ["serv"])
218
+
219
+ @session[@key] = valid_disco
220
+ @manager.destroy_manager
221
+ assert(@session[@key].nil?)
222
+
223
+ @session[@key] = invalid_disco
224
+ @manager.destroy_manager
225
+ assert_equal(@session[@key], invalid_disco)
226
+
227
+ # Force destruction of manager, no matter which URLs it's for.
228
+ @manager.destroy_manager(true)
229
+ assert(@session[@key].nil?)
230
+ end
231
+
232
+ def test_session_key
233
+ assert(@manager.session_key.ends_with?(
234
+ @manager.instance_variable_get("@session_key_suffix")))
235
+ end
236
+
237
+ def test_store
238
+ thing = "opaque"
239
+ assert(@session[@key].nil?)
240
+ @manager.store(thing)
241
+ assert_equal(@session[@key], thing)
242
+ end
243
+
244
+ def test_load
245
+ thing = "opaque"
246
+ @session[@key] = thing
247
+ assert_equal(@manager.load, thing)
248
+ end
249
+
250
+ def test_destroy!
251
+ thing = "opaque"
252
+ @manager.store(thing)
253
+ assert_equal(@manager.load, thing)
254
+ @manager.destroy!
255
+ assert(@session[@key].nil?)
256
+ assert(@manager.load.nil?)
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+ require 'openid/extension'
3
+ require 'openid/message'
4
+
5
+ module OpenID
6
+ class DummyExtension < OpenID::Extension
7
+ TEST_URI = 'http://an.extension'
8
+ TEST_ALIAS = 'dummy'
9
+ def initialize
10
+ @ns_uri = TEST_URI
11
+ @ns_alias = TEST_ALIAS
12
+ end
13
+
14
+ def get_extension_args
15
+ return {}
16
+ end
17
+ end
18
+
19
+ class ToMessageTest < Test::Unit::TestCase
20
+ def test_OpenID1
21
+ oid1_msg = Message.new(OPENID1_NS)
22
+ ext = DummyExtension.new
23
+ ext.to_message(oid1_msg)
24
+ namespaces = oid1_msg.namespaces
25
+ assert(namespaces.implicit?(DummyExtension::TEST_URI))
26
+ assert_equal(
27
+ DummyExtension::TEST_URI,
28
+ namespaces.get_namespace_uri(DummyExtension::TEST_ALIAS))
29
+ assert_equal(DummyExtension::TEST_ALIAS,
30
+ namespaces.get_alias(DummyExtension::TEST_URI))
31
+ end
32
+
33
+ def test_OpenID2
34
+ oid2_msg = Message.new(OPENID2_NS)
35
+ ext = DummyExtension.new
36
+ ext.to_message(oid2_msg)
37
+ namespaces = oid2_msg.namespaces
38
+ assert(!namespaces.implicit?(DummyExtension::TEST_URI))
39
+ assert_equal(
40
+ DummyExtension::TEST_URI,
41
+ namespaces.get_namespace_uri(DummyExtension::TEST_ALIAS))
42
+ assert_equal(DummyExtension::TEST_ALIAS,
43
+ namespaces.get_alias(DummyExtension::TEST_URI))
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ require "test_helper"
2
+ require 'openid/extras'
3
+
4
+ class StartsWithTestCase < Test::Unit::TestCase
5
+ def test_starts_with
6
+ [["anything", ""],
7
+ ["something else", ""],
8
+ ["", ""],
9
+ ["foos", "foo"],
10
+ ].each{|str,target| assert(str.starts_with?(target))}
11
+ end
12
+
13
+ def test_not_starts_with
14
+ [["x", "y"],
15
+ ["foos", "ball"],
16
+ ["xx", "xy"],
17
+ ].each{|str,target| assert(!(str.starts_with? target)) }
18
+ end
19
+
20
+ def test_ends_with
21
+ [["anything", ""],
22
+ ["something else", " else"],
23
+ ["", ""],
24
+ ["foos", "oos"],
25
+ ].each{|str,target| assert(str.ends_with?(target))}
26
+ end
27
+
28
+ def test_not_ends_with
29
+ [["x", "y"],
30
+ ["foos", "ball"],
31
+ ["xx", "xy"],
32
+ ["foosball", "foosbal"],
33
+ ].each{|str,target| assert(!(str.ends_with? target)) }
34
+ end
35
+ end
@@ -0,0 +1,554 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "test_helper"
3
+ require 'net/http'
4
+ require 'webrick'
5
+ require 'openid/fetchers'
6
+ require 'stringio'
7
+
8
+ begin
9
+ require 'net/https'
10
+ rescue LoadError
11
+ # We need these names for testing.
12
+
13
+ module OpenSSL
14
+ module SSL
15
+ class SSLError < StandardError; end
16
+ end
17
+ end
18
+ end
19
+
20
+ module HttpResultAssertions
21
+ def assert_http_result_is(expected, result)
22
+ assert_equal expected.code, result.code
23
+ assert_equal expected.body, result.body
24
+ assert_equal expected.final_url, result.final_url
25
+ end
26
+ end
27
+
28
+ class BogusFetcher
29
+ RESPONSE = "bogus"
30
+
31
+ def fetch(url, body=nil, headers=nil, redirect_limit=5)
32
+ return BogusFetcher::RESPONSE
33
+ end
34
+ end
35
+
36
+ class FetcherTestCase < Test::Unit::TestCase
37
+ include HttpResultAssertions
38
+ include OpenID::TestUtil
39
+
40
+ @@test_header_name = 'X-test-header'
41
+ @@test_header_value = 'marmoset'
42
+
43
+ class ExpectedResponse < Net::HTTPResponse
44
+ attr_reader :final_url
45
+
46
+ def initialize(code, final_url, body="the expected body",
47
+ httpv="1.1", msg=nil)
48
+ super(httpv, code, msg)
49
+ @code = code
50
+ @body = body
51
+ @final_url = final_url
52
+ end
53
+
54
+ def body
55
+ @body
56
+ end
57
+ end
58
+
59
+ @@cases =
60
+ [
61
+ # path, status code, expected url (nil = default to path)
62
+ ['/success', 200, nil],
63
+ ['/notfound', 404, nil],
64
+ ['/badreq', 400, nil],
65
+ ['/forbidden', 403, nil],
66
+ ['/error', 500, nil],
67
+ ['/server_error', 503, nil],
68
+ ['/301redirect', 200, '/success'],
69
+ ['/302redirect', 200, '/success'],
70
+ ['/303redirect', 200, '/success'],
71
+ ['/307redirect', 200, '/success'],
72
+ ]
73
+
74
+ def _redirect_with_code(code)
75
+ lambda { |req, resp|
76
+ resp.status = code
77
+ resp['Location'] = _uri_build('/success')
78
+ }
79
+ end
80
+
81
+ def _respond_with_code(code)
82
+ lambda { |req, resp|
83
+ resp.status = code
84
+ resp.body = "the expected body"
85
+ }
86
+ end
87
+
88
+ def _require_header
89
+ lambda { |req, resp|
90
+ assert_equal @@test_header_value, req[@@test_header_name]
91
+ assert_match 'ruby-openid', req['User-agent']
92
+ }
93
+ end
94
+
95
+ def _require_post
96
+ lambda { |req, resp|
97
+ assert_equal 'POST', req.request_method
98
+ assert_equal "postbody\n", req.body
99
+ }
100
+ end
101
+
102
+ def _redirect_loop
103
+ lambda { |req, resp|
104
+ @_redirect_counter += 1
105
+ resp.status = 302
106
+ resp['Location'] = _uri_build('/redirect_loop')
107
+ resp.body = "Fetched #{@_redirect_counter} times."
108
+ assert_block("Fetched too many times.") { @_redirect_counter < 10 }
109
+ }
110
+ end
111
+
112
+ UTF8_PAGE_CONTENT = <<-EOHTML
113
+ <html>
114
+ <head><title>UTF-8</title></head>
115
+ <body>こんにちは</body>
116
+ </html>
117
+ EOHTML
118
+ def _utf8_page
119
+ lambda { |req, resp|
120
+ resp['Content-Type'] = "text/html; charset=utf-8"
121
+ body = UTF8_PAGE_CONTENT.dup
122
+ body.force_encoding("ASCII-8BIT") if body.respond_to?(:force_encoding)
123
+ resp.body = body
124
+ }
125
+ end
126
+
127
+ def setup
128
+ @fetcher = OpenID::StandardFetcher.new
129
+ @logfile = StringIO.new
130
+ @weblog = WEBrick::Log.new(logfile=@logfile)
131
+ @server = WEBrick::HTTPServer.new(:Port => 0,
132
+ :Logger => @weblog,
133
+ :AccessLog => [])
134
+ @server_thread = Thread.new {
135
+ @server.mount_proc('/success', _respond_with_code(200))
136
+ @server.mount_proc('/301redirect', _redirect_with_code(301))
137
+ @server.mount_proc('/302redirect', _redirect_with_code(302))
138
+ @server.mount_proc('/303redirect', _redirect_with_code(303))
139
+ @server.mount_proc('/307redirect', _redirect_with_code(307))
140
+ @server.mount_proc('/badreq', _respond_with_code(400))
141
+ @server.mount_proc('/forbidden', _respond_with_code(403))
142
+ @server.mount_proc('/notfound', _respond_with_code(404))
143
+ @server.mount_proc('/error', _respond_with_code(500))
144
+ @server.mount_proc('/server_error', _respond_with_code(503))
145
+ @server.mount_proc('/require_header', _require_header)
146
+ @server.mount_proc('/redirect_to_reqheader') { |req, resp|
147
+ resp.status = 302
148
+ resp['Location'] = _uri_build('/require_header')
149
+ }
150
+ @server.mount_proc('/post', _require_post)
151
+ @server.mount_proc('/redirect_loop', _redirect_loop)
152
+ @server.mount_proc('/utf8_page', _utf8_page)
153
+ @server.start
154
+ }
155
+ @uri = _uri_build
156
+ sleep 0.2
157
+ end
158
+
159
+ def _uri_build(path='/')
160
+ u = URI::HTTP.build({
161
+ :host => @server.config[:ServerName],
162
+ :port => @server.config[:Port],
163
+ :path => path,
164
+ })
165
+ return u.to_s
166
+ end
167
+
168
+ def teardown
169
+ @server.shutdown
170
+ # Sleep a little because sometimes this blocks forever.
171
+ @server_thread.join
172
+ end
173
+
174
+ =begin
175
+ # XXX This test no longer works since we're not dealing with URI
176
+ # objects internally.
177
+ def test_final_url_tainted
178
+ uri = _uri_build('/301redirect')
179
+ result = @fetcher.fetch(uri)
180
+
181
+ final_url = URI::parse(result.final_url)
182
+
183
+ assert final_url.host.tainted?
184
+ assert final_url.path.tainted?
185
+ end
186
+ =end
187
+
188
+ def test_headers
189
+ headers = {
190
+ @@test_header_name => @@test_header_value
191
+ }
192
+ uri = _uri_build('/require_header')
193
+ result = @fetcher.fetch(uri, nil, headers)
194
+ # The real test runs under the WEBrick handler _require_header,
195
+ # this just checks the return code from that.
196
+ assert_equal '200', result.code, @logfile.string
197
+ end
198
+
199
+ def test_headers_after_redirect
200
+ headers = {
201
+ @@test_header_name => @@test_header_value
202
+ }
203
+ uri = _uri_build('/redirect_to_reqheader')
204
+ result = @fetcher.fetch(uri, nil, headers)
205
+ # The real test runs under the WEBrick handler _require_header,
206
+ # this just checks the return code from that.
207
+ assert_equal '200', result.code, @logfile.string
208
+ end
209
+
210
+ def test_post
211
+ uri = _uri_build('/post')
212
+ result = @fetcher.fetch(uri, "postbody\n")
213
+ # The real test runs under the WEBrick handler _require_header,
214
+ # this just checks the return code from that.
215
+ assert_equal '200', result.code, @logfile.string
216
+ end
217
+
218
+ def test_redirect_limit
219
+ @_redirect_counter = 0
220
+ uri = _uri_build('/redirect_loop')
221
+ assert_raise(OpenID::HTTPRedirectLimitReached) {
222
+ @fetcher.fetch(uri)
223
+ }
224
+ end
225
+
226
+ def test_utf8_page
227
+ uri = _uri_build('/utf8_page')
228
+ response = @fetcher.fetch(uri)
229
+ assert_equal(UTF8_PAGE_CONTENT, response.body)
230
+ if response.body.respond_to?(:encoding)
231
+ assert_equal(Encoding::UTF_8, response.body.encoding)
232
+ end
233
+ end
234
+
235
+ def test_cases
236
+ for path, expected_code, expected_url in @@cases
237
+ uri = _uri_build(path)
238
+ if expected_url.nil?
239
+ expected_url = uri
240
+ else
241
+ expected_url = _uri_build(expected_url)
242
+ end
243
+
244
+ expected = ExpectedResponse.new(expected_code.to_s, expected_url)
245
+ result = @fetcher.fetch(uri)
246
+
247
+ begin
248
+ assert_http_result_is expected, result
249
+ rescue Test::Unit::AssertionFailedError => err
250
+ if result.code == '500' && expected_code != 500
251
+ # Looks like our WEBrick harness broke.
252
+ msg = <<EOF
253
+ Status #{result.code} from case #{path}. Logs:
254
+ #{@logfile.string}
255
+ EOF
256
+ raise msg
257
+ end
258
+
259
+ # Wrap failure messages so we can tell which case failed.
260
+ new_msg = "#{path}: #{err.message.to_s}"
261
+ new_err = Test::Unit::AssertionFailedError.new(new_msg)
262
+ new_err.set_backtrace(err.backtrace)
263
+ raise new_err
264
+ end
265
+ end
266
+ end
267
+
268
+ def test_https_no_openssl
269
+ # Override supports_ssl? to always claim that connections don't
270
+ # support SSL. Test the behavior of fetch() for HTTPS URLs in
271
+ # that case.
272
+ f = OpenID::StandardFetcher.new
273
+ f.extend(OpenID::InstanceDefExtension)
274
+
275
+ f.instance_def(:supports_ssl?) do |conn|
276
+ false
277
+ end
278
+
279
+ begin
280
+ f.fetch("https://someurl.com/")
281
+ flunk("Expected RuntimeError")
282
+ rescue RuntimeError => why
283
+ assert_equal(why.to_s, "SSL support not found; cannot fetch https://someurl.com/")
284
+ end
285
+ end
286
+
287
+ class FakeConnection < Net::HTTP
288
+ attr_reader :use_ssl, :ca_file
289
+
290
+ def initialize *args
291
+ super
292
+ @ca_file = nil
293
+ end
294
+
295
+ def use_ssl=(v)
296
+ @use_ssl = v
297
+ end
298
+
299
+ def ca_file=(ca_file)
300
+ @ca_file = ca_file
301
+ end
302
+ end
303
+
304
+ def test_ssl_with_ca_file
305
+ f = OpenID::StandardFetcher.new
306
+ ca_file = "BOGUS"
307
+ f.ca_file = ca_file
308
+
309
+ f.extend(OpenID::InstanceDefExtension)
310
+ f.instance_def(:make_http) do |uri|
311
+ FakeConnection.new(uri.host, uri.port)
312
+ end
313
+
314
+ testcase = self
315
+
316
+ f.instance_def(:set_verified) do |conn, verified|
317
+ testcase.assert(verified)
318
+ end
319
+
320
+ conn = f.make_connection(URI::parse("https://someurl.com"))
321
+ assert_equal(conn.ca_file, ca_file)
322
+ end
323
+
324
+ def test_ssl_without_ca_file
325
+ f = OpenID::StandardFetcher.new
326
+
327
+ f.extend(OpenID::InstanceDefExtension)
328
+ f.instance_def(:make_http) do |uri|
329
+ FakeConnection.new(uri.host, uri.port)
330
+ end
331
+
332
+ testcase = self
333
+
334
+ f.instance_def(:set_verified) do |conn, verified|
335
+ testcase.assert(!verified)
336
+ end
337
+
338
+ conn = nil
339
+ assert_log_matches(/making https request to https:\/\/someurl.com without verifying/) {
340
+ conn = f.make_connection(URI::parse("https://someurl.com"))
341
+ }
342
+
343
+ assert(conn.ca_file.nil?)
344
+ end
345
+
346
+ def test_make_http_nil
347
+ f = OpenID::StandardFetcher.new
348
+
349
+ f.extend(OpenID::InstanceDefExtension)
350
+ f.instance_def(:make_http) do |uri|
351
+ nil
352
+ end
353
+
354
+ assert_raise(RuntimeError) {
355
+ f.make_connection(URI::parse("http://example.com/"))
356
+ }
357
+ end
358
+
359
+ def test_make_http_invalid
360
+ f = OpenID::StandardFetcher.new
361
+
362
+ f.extend(OpenID::InstanceDefExtension)
363
+ f.instance_def(:make_http) do |uri|
364
+ "not a Net::HTTP object"
365
+ end
366
+
367
+ assert_raise(RuntimeError) {
368
+ f.make_connection(URI::parse("http://example.com/"))
369
+ }
370
+ end
371
+
372
+ class BrokenSSLConnection
373
+ def start(&block)
374
+ raise OpenSSL::SSL::SSLError
375
+ end
376
+ end
377
+
378
+ def test_sslfetchingerror
379
+ f = OpenID::StandardFetcher.new
380
+
381
+ f.extend(OpenID::InstanceDefExtension)
382
+ f.instance_def(:make_connection) do |uri|
383
+ BrokenSSLConnection.new
384
+ end
385
+
386
+ assert_raise(OpenID::SSLFetchingError) {
387
+ f.fetch("https://bogus.com/")
388
+ }
389
+ end
390
+
391
+ class TimeoutConnection
392
+ def start(&block)
393
+ raise Timeout::Error
394
+ end
395
+ end
396
+
397
+ def test_fetchingerror
398
+ f = OpenID::StandardFetcher.new
399
+ f.extend(OpenID::InstanceDefExtension)
400
+ assert_raise(OpenID::FetchingError) {
401
+ f.fetch("https://bogus2010.com/")
402
+ }
403
+ end
404
+
405
+ class TestingException < OpenID::FetchingError; end
406
+
407
+ class NoSSLSupportConnection
408
+ def supports_ssl?
409
+ false
410
+ end
411
+
412
+ def start
413
+ yield
414
+ end
415
+
416
+ def request_get(*args)
417
+ raise TestingException
418
+ end
419
+
420
+ def post_connection_check(hostname)
421
+ raise RuntimeError
422
+ end
423
+
424
+ def use_ssl?
425
+ true
426
+ end
427
+ end
428
+
429
+ class NoUseSSLConnection < NoSSLSupportConnection
430
+ def use_ssl?
431
+ false
432
+ end
433
+ end
434
+
435
+ def test_post_connection_check_no_support_ssl
436
+ f = OpenID::StandardFetcher.new
437
+
438
+ f.extend(OpenID::InstanceDefExtension)
439
+ f.instance_def(:make_connection) do |uri|
440
+ NoSSLSupportConnection.new
441
+ end
442
+
443
+ # post_connection_check should not be called.
444
+ assert_raise(TestingException) {
445
+ f.fetch("https://bogus.com/")
446
+ }
447
+ end
448
+
449
+ def test_post_connection_check_no_use_ssl
450
+ f = OpenID::StandardFetcher.new
451
+
452
+ f.extend(OpenID::InstanceDefExtension)
453
+ f.instance_def(:make_connection) do |uri|
454
+ NoUseSSLConnection.new
455
+ end
456
+
457
+ # post_connection_check should not be called.
458
+ assert_raise(TestingException) {
459
+ f.fetch("https://bogus.com/")
460
+ }
461
+ end
462
+
463
+ class PostConnectionCheckException < OpenID::FetchingError; end
464
+
465
+ class UseSSLConnection < NoSSLSupportConnection
466
+ def use_ssl?
467
+ true
468
+ end
469
+
470
+ def post_connection_check(hostname)
471
+ raise PostConnectionCheckException
472
+ end
473
+ end
474
+
475
+ def test_post_connection_check
476
+ f = OpenID::StandardFetcher.new
477
+
478
+ f.extend(OpenID::InstanceDefExtension)
479
+ f.instance_def(:make_connection) do |uri|
480
+ UseSSLConnection.new
481
+ end
482
+
483
+ f.instance_def(:supports_ssl?) do |conn|
484
+ true
485
+ end
486
+
487
+ # post_connection_check should be called.
488
+ assert_raise(PostConnectionCheckException) {
489
+ f.fetch("https://bogus.com/")
490
+ }
491
+ end
492
+ end
493
+
494
+ class DefaultFetcherTest < Test::Unit::TestCase
495
+ def setup
496
+ OpenID.fetcher = nil
497
+ end
498
+
499
+ def test_default_fetcher
500
+ assert(OpenID.fetcher.is_a?(OpenID::StandardFetcher))
501
+
502
+ # A custom fetcher can be set
503
+ OpenID.fetcher = BogusFetcher.new
504
+
505
+ # A test fetch should call the new fetcher
506
+ assert(OpenID.fetch('not-a-url') == BogusFetcher::RESPONSE)
507
+
508
+ # Set the fetcher to nil again
509
+ OpenID.fetcher = nil
510
+ assert(OpenID.fetcher.is_a?(OpenID::StandardFetcher))
511
+ end
512
+ end
513
+
514
+ class ProxyTest < Test::Unit::TestCase
515
+ def test_proxy_unreachable
516
+ begin
517
+ f = OpenID::StandardFetcher.new('127.0.0.1', 1)
518
+ # If this tries to connect to the proxy (on port 1), I expect
519
+ # a 'connection refused' error. If it tries to contact the below
520
+ # URI first, it will get some other sort of error.
521
+ f.fetch("http://unittest.invalid")
522
+ rescue OpenID::FetchingError => why
523
+ # XXX: Is this a translatable string that is going to break?
524
+ if why.message =~ /Connection refused/
525
+ return
526
+ end
527
+ raise why
528
+ end
529
+ flunk "expected Connection Refused, but it passed."
530
+ end
531
+
532
+ def test_proxy_env
533
+ ENV['http_proxy'] = 'http://127.0.0.1:3128/'
534
+ OpenID.fetcher_use_env_http_proxy
535
+
536
+ # make_http just to give us something with readable attributes to inspect.
537
+ conn = OpenID.fetcher.make_http(URI.parse('http://127.0.0.2'))
538
+ assert_equal('127.0.0.1', conn.proxy_address)
539
+ assert_equal(3128, conn.proxy_port)
540
+ end
541
+ # These aren't fully automated tests, but if you start a proxy
542
+ # on port 8888 (tinyproxy's default) and check its logs...
543
+ # def test_proxy
544
+ # f = OpenID::StandardFetcher.new('127.0.0.1', 8888)
545
+ # result = f.fetch("http://www.example.com/")
546
+ # assert_match(/RFC.*2606/, result.body)
547
+ # end
548
+
549
+ # def test_proxy_https
550
+ # f = OpenID::StandardFetcher.new('127.0.0.1', 8888)
551
+ # result = f.fetch("https://www.myopenid.com/")
552
+ # assert_match(/myOpenID/, result.body)
553
+ # end
554
+ end