Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 730 lines (595 sloc) 22.658 kb
dc084906 » tailor
2007-11-10 [project @ [INCOMPLETE] Yadis / OpenID discovery code and tests]
1
2 require 'test/unit'
3 require 'openid/fetchers'
4 require 'openid/yadis/discovery'
5 require 'openid/consumer/discovery'
6 require 'openid/yadis/xrires'
7 require 'openid/yadis/xri'
8 require 'openid/message'
9 require 'openid/util'
10
11 ### Tests for conditions that trigger DiscoveryFailure
12
13 module OpenID
14 class SimpleMockFetcher
15 def initialize(responses)
16 @responses = responses.dup
17 end
18
19 def fetch(url, body=nil, headers=nil, limit=nil)
20 response = @responses.shift
21 Util.assert(body.nil?)
22 Util.assert(response.final_url == url)
23 return response
24 end
25 end
26
27 class TestDiscoveryFailure < Test::Unit::TestCase
28 def initialize(*args)
29 super(*args)
30
31 @responses = [
32 [HTTPResponse._from_raw_data(nil, nil, {}, 'http://network.error/')],
33 [HTTPResponse._from_raw_data(404, nil, {}, 'http://not.found/')],
34 [HTTPResponse._from_raw_data(400, nil, {}, 'http://bad.request/')],
35 [HTTPResponse._from_raw_data(500, nil, {}, 'http://server.error/')],
36 [HTTPResponse._from_raw_data(200, nil, {'x-xrds-location' => 'http://xrds.missing/'},
37 'http://header.found/'),
38 HTTPResponse._from_raw_data(404, nil, {}, 'http://xrds.missing/')],
39 ]
40 end
41
42 def test_discovery_failure
43
44 @responses.each { |response_set|
45 @url = response_set[0].final_url
46 OpenID.fetcher = SimpleMockFetcher.new(response_set)
47
48 expected_status = response_set[-1].code
49 begin
50 OpenID.discover(@url)
51 rescue Yadis::DiscoveryFailure => why
52 assert_equal(why.http_response.code, expected_status)
53 else
54 flunk('Did not raise DiscoveryFailure')
55 end
56
57 OpenID.fetcher = nil
58 }
59 end
60 end
61
62 ### Tests for raising/catching exceptions from the fetcher through
63 ### the discover function
64
65 class ErrorRaisingFetcher
66 # Just raise an exception when fetch is called
67
68 def initialize(thing_to_raise)
69 @thing_to_raise = thing_to_raise
70 end
71
72 def fetch(url, body=nil, headers=nil, limit=nil)
73 raise @thing_to_raise
74 end
75 end
76
77 class DidFetch < Exception
78 # Custom exception just to make sure it's not handled differently
79 end
80
81 class TestFetchException < Test::Unit::TestCase
82 # Make sure exceptions get passed through discover function from
83 # fetcher.
84
85 def initialize(*args)
86 super(*args)
87
88 @cases = [
89 Exception.new(),
90 DidFetch.new(),
91 ArgumentError.new(),
92 RuntimeError.new(),
93 ]
94 end
95
96 def test_fetch_exception
97 @cases.each { |exc|
98 OpenID.fetcher = ErrorRaisingFetcher.new(exc)
99 begin
100 OpenID.discover('http://doesnt.matter/')
101 rescue Object => thing
102 assert(thing.is_a?(exc.class), [thing.class, exc.class, thing].inspect)
103 end
104 OpenID.fetcher = nil
105 }
106 end
107 end
108
109 ### Tests for openid.consumer.discover.discover
110
111 class TestNormalization < Test::Unit::TestCase
112 def test_addingProtocol
113 f = ErrorRaisingFetcher.new(RuntimeError.new())
114 OpenID.fetcher = f
115
116 begin
117 OpenID.discover('users.stompy.janrain.com:8000/x')
118 rescue Yadis::DiscoveryFailure => why
119 flunk("failed to parse url with port correctly: #{why}")
120 rescue RuntimeError
121 end
122
123 OpenID.fetcher = nil
124 end
125 end
126
127 class DiscoveryMockFetcher
128 def initialize(documents)
129 @redirect = nil
130 @documents = documents
131 @fetchlog = []
132 end
133
134 def fetch(url, body=nil, headers=nil, limit=nil)
135 @fetchlog << [url, body, headers]
136 if @redirect
137 final_url = @redirect
138 else
139 final_url = url
140 end
141
142 begin
143 ctype, body = @documents.fetch(url)
144 rescue IndexError
145 status = 404
146 ctype = 'text/plain'
147 body = ''
148 else
149 status = 200
150 end
151
152 return HTTPResponse._from_raw_data(status, body, {'content-type' => ctype}, final_url)
153 end
154 end
155
156 class BaseTestDiscovery < Test::Unit::TestCase
157 attr_accessor :id_url, :fetcher_class
158
159 def initialize(*args)
160 super(*args)
161 @id_url = "http://someuser.unittest/"
162 @documents = {}
163 @fetcher_class = DiscoveryMockFetcher
164 end
165
166 def _checkService(s, server_url, claimed_id=nil,
167 local_id=nil, canonical_id=nil,
168 types=nil, used_yadis=false)
169 assert_equal(server_url, s.server_url)
170 if types == ['2.0 OP']
171 assert(!claimed_id)
172 assert(!local_id)
173 assert(!s.claimed_id)
174 assert(!s.local_id)
175 assert(!s.get_local_id())
176 assert(!s.compatibility_mode())
177 assert(s.is_op_identifier())
178 assert_equal(s.preferred_namespace(),
179 OPENID_2_0_MESSAGE_NS)
180 else
181 assert_equal(claimed_id, s.claimed_id)
182 assert_equal(local_id, s.get_local_id())
183 end
184
185 if used_yadis
186 assert(s.used_yadis, "Expected to use Yadis")
187 else
188 assert(!s.used_yadis,
189 "Expected to use old-style discovery")
190 end
191
192 openid_types = {
193 '1.1' => OPENID_1_1_TYPE,
194 '1.0' => OPENID_1_0_TYPE,
195 '2.0' => OPENID_2_0_TYPE,
196 '2.0 OP' => OPENID_IDP_2_0_TYPE,
197 }
198
199 type_uris = types.collect { |t| openid_types[t] }
200
201 assert_equal(type_uris, s.type_uris)
202 assert_equal(canonical_id, s.canonicalID)
203 end
204
205 def setup
206 # @documents = @documents.dup
207 @fetcher = @fetcher_class.new(@documents)
208 OpenID.fetcher = @fetcher
209 end
210
211 def teardown
212 OpenID.fetcher = nil
213 end
214
215 def test_blank
216 # XXX to avoid > 0 test requirement
217 end
218 end
219
220 # def readDataFile(filename):
221 # module_directory = os.path.dirname(os.path.abspath(__file__))
222 # filename = os.path.join(
223 # module_directory, 'data', 'test_discover', filename)
224 # return file(filename).read()
225
226 class TestDiscovery < BaseTestDiscovery
227 include TestDataMixin
228
229 def _discover(content_type, data,
230 expected_services, expected_id=nil)
231 if expected_id.nil?
232 expected_id = @id_url
233 end
234
235 @documents[@id_url] = [content_type, data]
236 id_url, services = OpenID.discover(@id_url)
237
238 assert_equal(expected_services, services.length)
239 assert_equal(expected_id, id_url)
240 return services
241 end
242
243 def test_404
244 assert_raise(Yadis::DiscoveryFailure) {
245 OpenID.discover(@id_url + '/404')
246 }
247 end
248
249 def test_noOpenID
250 services = _discover('text/plain',
251 "junk", 0)
252
253 services = _discover(
254 'text/html',
255 read_data_file('test_discover/openid_no_delegate.html', false),
256 1)
257
258 _checkService(
259 services[0],
260 "http://www.myopenid.com/server",
261 @id_url,
262 @id_url,
263 nil,
264 ['1.1'],
265 false)
266 end
267
268 def test_html1
269 services = _discover('text/html',
270 read_data_file('test_discover/openid.html', false),
271 1)
272
273 _checkService(services[0],
274 "http://www.myopenid.com/server",
275 @id_url,
276 'http://smoker.myopenid.com/',
277 nil,
278 ['1.1'],
279 false)
280 end
281
282 def test_html1Fragment
283 # Ensure that the Claimed Identifier does not have a fragment if
284 # one is supplied in the User Input.
285 content_type = 'text/html'
286 data = read_data_file('test_discover/openid.html', false)
287 expected_services = 1
288
289 @documents[@id_url] = [content_type, data]
290 expected_id = @id_url
291 @id_url = @id_url + '#fragment'
292 id_url, services = OpenID.discover(@id_url)
293
294 assert_equal(expected_services, services.length)
295 assert_equal(expected_id, id_url)
296
297 _checkService(services[0],
298 "http://www.myopenid.com/server",
299 expected_id,
300 'http://smoker.myopenid.com/',
301 nil,
302 ['1.1'],
303 false)
304 end
305
306 def test_html2
307 services = _discover('text/html',
308 read_data_file('test_discover/openid2.html', false),
309 1)
310
311 _checkService(services[0],
312 "http://www.myopenid.com/server",
313 @id_url,
314 'http://smoker.myopenid.com/',
315 nil,
316 ['2.0'],
317 false)
318 end
319
320 def test_html1And2
321 services = _discover(
322 'text/html',
323 read_data_file('test_discover/openid_1_and_2.html', false),
324 2)
325
326 services.zip(['2.0', '1.1']).each { |s, t|
327 _checkService(s,
328 "http://www.myopenid.com/server",
329 @id_url,
330 'http://smoker.myopenid.com/',
331 nil,
332 [t],
333 false)
334 }
335 end
336
337 def test_yadisEmpty
338 services = _discover('application/xrds+xml',
339 read_data_file('test_discover/yadis_0entries.xml', false),
340 0)
341 end
342
343 def test_htmlEmptyYadis
344 # HTML document has discovery information, but points to an
345 # empty Yadis document. The XRDS document pointed to by
346 # "openid_and_yadis.html"
347 @documents[@id_url + 'xrds'] = ['application/xrds+xml',
348 read_data_file('test_discover/yadis_0entries.xml', false)]
349
350 services = _discover('text/html',
351 read_data_file('test_discover/openid_and_yadis.html', false),
352 1)
353
354 _checkService(services[0],
355 "http://www.myopenid.com/server",
356 @id_url,
357 'http://smoker.myopenid.com/',
358 nil,
359 ['1.1'],
360 false)
361 end
362
363 def test_yadis1NoDelegate
364 services = _discover('application/xrds+xml',
365 read_data_file('test_discover/yadis_no_delegate.xml', false),
366 1)
367
368 _checkService(services[0],
369 "http://www.myopenid.com/server",
370 @id_url,
371 @id_url,
372 nil,
373 ['1.0'],
374 true)
375 end
376
377 def test_yadis2NoLocalID
378 services = _discover('application/xrds+xml',
379 read_data_file('test_discover/openid2_xrds_no_local_id.xml', false),
380 1)
381
382 _checkService(services[0],
383 "http://www.myopenid.com/server",
384 @id_url,
385 @id_url,
386 nil,
387 ['2.0'],
388 true)
389 end
390
391 def test_yadis2
392 services = _discover('application/xrds+xml',
393 read_data_file('test_discover/openid2_xrds.xml', false),
394 1)
395
396 _checkService(services[0],
397 "http://www.myopenid.com/server",
398 @id_url,
399 'http://smoker.myopenid.com/',
400 nil,
401 ['2.0'],
402 true)
403 end
404
405 def test_yadis2OP
406 services = _discover('application/xrds+xml',
407 read_data_file('test_discover/yadis_idp.xml', false),
408 1)
409
410 _checkService(services[0],
411 "http://www.myopenid.com/server",
412 nil, nil, nil,
413 ['2.0 OP'],
414 true)
415 end
416
417 def test_yadis2OPDelegate
418 # The delegate tag isn't meaningful for OP entries.
419 services = _discover('application/xrds+xml',
420 read_data_file('test_discover/yadis_idp_delegate.xml', false),
421 1)
422
423 _checkService(services[0],
424 "http://www.myopenid.com/server",
425 nil, nil, nil,
426 ['2.0 OP'],
427 true)
428 end
429
430 def test_yadis2BadLocalID
431 assert_raise(Yadis::DiscoveryFailure) {
432 _discover('application/xrds+xml',
433 read_data_file('test_discover/yadis_2_bad_local_id.xml', false),
434 1)
435 }
436 end
437
438 def test_yadis1And2
439 services = _discover('application/xrds+xml',
440 read_data_file('test_discover/openid_1_and_2_xrds.xml', false),
441 1)
442
443 _checkService(services[0],
444 "http://www.myopenid.com/server",
445 @id_url,
446 'http://smoker.myopenid.com/',
447 nil,
448 ['2.0', '1.1'],
449 true)
450 end
451
452 def test_yadis1And2BadLocalID
453 assert_raise(Yadis::DiscoveryFailure) {
454 _discover('application/xrds+xml',
455 read_data_file('test_discover/openid_1_and_2_xrds_bad_delegate.xml', false),
456 1)
457 }
458 end
459 end
460 end
461
462 =begin
463
464 class MockFetcherForXRIProxy(object):
465
466 def __init__(self, documents, proxy_url=xrires.DEFAULT_PROXY):
467 self.documents = documents
468 self.fetchlog = []
469 self.proxy_url = nil
470
471
472 def fetch(self, url, body=nil, headers=nil):
473 self.fetchlog.append((url, body, headers))
474
475 u = urlsplit(url)
476 proxy_host = u[1]
477 xri = u[2]
478 query = u[3]
479
480 if not headers and not query:
481 raise ValueError("No headers or query; you probably didn't "
482 "mean to do that.")
483
484 if xri.startswith('/'):
485 xri = xri[1:]
486
487 try:
488 ctype, body = self.documents[xri]
489 except KeyError:
490 status = 404
491 ctype = 'text/plain'
492 body = ''
493 else:
494 status = 200
495
496 return HTTPResponse(url, status, {'content-type': ctype}, body)
497
498
499 class TestXRIDiscovery(BaseTestDiscovery):
500 fetcherClass = MockFetcherForXRIProxy
501
502 documents = {'=smoker': ('application/xrds+xml',
503 readDataFile('yadis_2entries_delegate.xml')),
504 '=smoker*bad': ('application/xrds+xml',
505 readDataFile('yadis_another_delegate.xml')) }
506
507 def test_xri(self):
508 user_xri, services = discover.discoverXRI('=smoker')
509
510 self._checkService(
511 services[0],
512 used_yadis=True,
513 types=['1.0'],
514 server_url="http://www.myopenid.com/server",
515 claimed_id=XRI("=!1000"),
516 canonical_id=XRI("=!1000"),
517 local_id='http://smoker.myopenid.com/',
518 )
519
520 self._checkService(
521 services[1],
522 used_yadis=True,
523 types=['1.0'],
524 server_url="http://www.livejournal.com/openid/server.bml",
525 claimed_id=XRI("=!1000"),
526 canonical_id=XRI("=!1000"),
527 local_id='http://frank.livejournal.com/',
528 )
529
530 def test_xriNoCanonicalID(self):
531 user_xri, services = discover.discoverXRI('=smoker*bad')
532 assert(!services)
533
534 def test_useCanonicalID(self):
535 """When there is no delegate, the CanonicalID should be used with XRI.
536 """
537 endpoint = discover.OpenIDServiceEndpoint()
538 endpoint.claimed_id = XRI("=!1000")
539 endpoint.canonicalID = XRI("=!1000")
540 assert_equal(endpoint.getLocalID(), XRI("=!1000"))
541
542
543 class TestXRIDiscoveryIDP(BaseTestDiscovery):
544 fetcherClass = MockFetcherForXRIProxy
545
546 documents = {'=smoker': ('application/xrds+xml',
547 readDataFile('yadis_2entries_idp.xml')) }
548
549 def test_xri(self):
550 user_xri, services = discover.discoverXRI('=smoker')
551 assert(services, "Expected services, got zero")
552 assert_equal(services[0].server_url,
553 "http://www.livejournal.com/openid/server.bml")
554
555
556 class TestPreferredNamespace(datadriven.DataDrivenTestCase):
557 def __init__(self, expected_ns, type_uris):
558 datadriven.DataDrivenTestCase.__init__(
559 self, 'Expecting %s from %s' % (expected_ns, type_uris))
560 self.expected_ns = expected_ns
561 self.type_uris = type_uris
562
563 def runOneTest(self):
564 endpoint = discover.OpenIDServiceEndpoint()
565 endpoint.type_uris = self.type_uris
566 actual_ns = endpoint.preferredNamespace()
567 assert_equal(actual_ns, self.expected_ns)
568
569 cases = [
570 (message.OPENID1_NS, []),
571 (message.OPENID1_NS, ['http://jyte.com/']),
572 (message.OPENID1_NS, [discover.OPENID_1_0_TYPE]),
573 (message.OPENID1_NS, [discover.OPENID_1_1_TYPE]),
574 (message.OPENID2_NS, [discover.OPENID_2_0_TYPE]),
575 (message.OPENID2_NS, [discover.OPENID_IDP_2_0_TYPE]),
576 (message.OPENID2_NS, [discover.OPENID_2_0_TYPE,
577 discover.OPENID_1_0_TYPE]),
578 (message.OPENID2_NS, [discover.OPENID_1_0_TYPE,
579 discover.OPENID_2_0_TYPE]),
580 ]
581
582 class TestIsOPIdentifier(unittest.TestCase):
583 def setUp(self):
584 self.endpoint = discover.OpenIDServiceEndpoint()
585
586 def test_none(self):
587 assert(!self.endpoint.isOPIdentifier())
588
589 def test_openid1_0(self):
590 self.endpoint.type_uris = [discover.OPENID_1_0_TYPE]
591 assert(!self.endpoint.isOPIdentifier())
592
593 def test_openid1_1(self):
594 self.endpoint.type_uris = [discover.OPENID_1_1_TYPE]
595 assert(!self.endpoint.isOPIdentifier())
596
597 def test_openid2(self):
598 self.endpoint.type_uris = [discover.OPENID_2_0_TYPE]
599 assert(!self.endpoint.isOPIdentifier())
600
601 def test_openid2OP(self):
602 self.endpoint.type_uris = [discover.OPENID_IDP_2_0_TYPE]
603 assert(self.endpoint.isOPIdentifier())
604
605 def test_multipleMissing(self):
606 self.endpoint.type_uris = [discover.OPENID_2_0_TYPE,
607 discover.OPENID_1_0_TYPE]
608 assert(!self.endpoint.isOPIdentifier())
609
610 def test_multiplePresent(self):
611 self.endpoint.type_uris = [discover.OPENID_2_0_TYPE,
612 discover.OPENID_1_0_TYPE,
613 discover.OPENID_IDP_2_0_TYPE]
614 assert(self.endpoint.isOPIdentifier())
615
616 class TestFromOPEndpointURL(unittest.TestCase):
617 def setUp(self):
618 self.op_endpoint_url = 'http://example.com/op/endpoint'
619 self.endpoint = discover.OpenIDServiceEndpoint.fromOPEndpointURL(
620 self.op_endpoint_url)
621
622 def test_isOPEndpoint(self):
623 assert(self.endpoint.isOPIdentifier())
624
625 def test_noIdentifiers(self):
626 assert_equal(self.endpoint.getLocalID(), nil)
627 assert_equal(self.endpoint.claimed_id, nil)
628
629 def test_compatibility(self):
630 assert(!self.endpoint.compatibilityMode())
631
632 def test_canonicalID(self):
633 assert_equal(self.endpoint.canonicalID, nil)
634
635 def test_serverURL(self):
636 assert_equal(self.endpoint.server_url, self.op_endpoint_url)
637
638 class TestDiscoverFunction(unittest.TestCase):
639 def setUp(self):
640 self._old_discoverURI = discover.discoverURI
641 self._old_discoverXRI = discover.discoverXRI
642
643 discover.discoverXRI = self.discoverXRI
644 discover.discoverURI = self.discoverURI
645
646 def tearDown(self):
647 discover.discoverURI = self._old_discoverURI
648 discover.discoverXRI = self._old_discoverXRI
649
650 def discoverXRI(self, identifier):
651 return 'XRI'
652
653 def discoverURI(self, identifier):
654 return 'URI'
655
656 def test_uri(self):
657 assert_equal('URI', discover.discover('http://woo!'))
658
659 def test_uriForBogus(self):
660 assert_equal('URI', discover.discover('not a URL or XRI'))
661
662 def test_xri(self):
663 assert_equal('XRI', discover.discover('xri://=something'))
664
665 def test_xriChar(self):
666 assert_equal('XRI', discover.discover('=something'))
667
668 class TestEndpointSupportsType(unittest.TestCase):
669 def setUp(self):
670 self.endpoint = discover.OpenIDServiceEndpoint()
671
672 def failUnlessSupportsOnly(self, *types):
673 for t in [
674 'foo',
675 discover.OPENID_1_1_TYPE,
676 discover.OPENID_1_0_TYPE,
677 discover.OPENID_2_0_TYPE,
678 discover.OPENID_IDP_2_0_TYPE,
679 ]:
680 if t in types:
681 assert(self.endpoint.supportsType(t),
682 "Must support %r" % (t,))
683 else:
684 assert(!self.endpoint.supportsType(t),
685 "Shouldn't support %r" % (t,))
686
687 def test_supportsNothing(self):
688 self.failUnlessSupportsOnly()
689
690 def test_openid2(self):
691 self.endpoint.type_uris = [discover.OPENID_2_0_TYPE]
692 self.failUnlessSupportsOnly(discover.OPENID_2_0_TYPE)
693
694 def test_openid2provider(self):
695 self.endpoint.type_uris = [discover.OPENID_IDP_2_0_TYPE]
696 self.failUnlessSupportsOnly(discover.OPENID_IDP_2_0_TYPE,
697 discover.OPENID_2_0_TYPE)
698
699 def test_openid1_0(self):
700 self.endpoint.type_uris = [discover.OPENID_1_0_TYPE]
701 self.failUnlessSupportsOnly(discover.OPENID_1_0_TYPE)
702
703 def test_openid1_1(self):
704 self.endpoint.type_uris = [discover.OPENID_1_1_TYPE]
705 self.failUnlessSupportsOnly(discover.OPENID_1_1_TYPE)
706
707 def test_multiple(self):
708 self.endpoint.type_uris = [discover.OPENID_1_1_TYPE,
709 discover.OPENID_2_0_TYPE]
710 self.failUnlessSupportsOnly(discover.OPENID_1_1_TYPE,
711 discover.OPENID_2_0_TYPE)
712
713 def test_multipleWithProvider(self):
714 self.endpoint.type_uris = [discover.OPENID_1_1_TYPE,
715 discover.OPENID_2_0_TYPE,
716 discover.OPENID_IDP_2_0_TYPE]
717 self.failUnlessSupportsOnly(discover.OPENID_1_1_TYPE,
718 discover.OPENID_2_0_TYPE,
719 discover.OPENID_IDP_2_0_TYPE,
720 )
721
722 def pyUnitTests():
723 return datadriven.loadTests(__name__)
724
725 if __name__ == '__main__':
726 suite = pyUnitTests()
727 runner = unittest.TextTestRunner()
728 runner.run(suite)
729
730 =end
Something went wrong with that request. Please try again.