PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/vendor/gems/ruby-openid-1.1.4/test/server2.rb

https://github.com/pochi/xtt
Ruby | 1053 lines | 881 code | 166 blank | 6 comment | 10 complexity | d4ec1b20ff24438293ba0a98534e1942 MD5 | raw file
Possible License(s): GPL-2.0, Apache-2.0
  1. require 'test/unit'
  2. require 'uri'
  3. require 'openid/server'
  4. require 'openid/stores'
  5. include OpenID::Server
  6. ALT_MODULUS = 0xCAADDDEC1667FC68B5FA15D53C4E1532DD24561A1A2D47A12C01ABEA1E00731F6921AAC40742311FDF9E634BB7131BEE1AF240261554389A910425E044E88C8359B010F5AD2B80E29CB1A5B027B19D9E01A6F63A6F45E5D7ED2FF6A2A0085050A7D0CF307C3DB51D2490355907B4427C23A98DF1EB8ABEF2BA209BB7AFFE86A7
  7. ALT_GEN = 5
  8. class TestProtocolError < Test::Unit::TestCase
  9. def test_browser_with_return_to
  10. return_to = 'http://rp.unittest/consumer'
  11. # will be a ProtocolError raised by Decode or CheckAuthRequest.answer
  12. args = {
  13. 'openid.mode' => 'monkeydance',
  14. 'openid.identity' => 'http://wagu.unittest/',
  15. 'openid.return_to' => return_to
  16. }
  17. e = ProtocolError.new(args, 'plucky')
  18. assert_equal(true, e.has_return_to?)
  19. expected_args = {
  20. 'openid.mode' => 'error',
  21. 'openid.error' => 'plucky'
  22. }
  23. actual_args = OpenID::Util.parse_query(URI.parse(e.encode_to_url).query)
  24. assert_equal(expected_args, actual_args)
  25. assert_equal(ENCODE_URL, e.which_encoding?)
  26. end
  27. def test_no_return_to
  28. args = {
  29. 'openid.mode' => 'zebradance',
  30. 'openid.identity' => 'http://wagu.unittest/',
  31. }
  32. e = ProtocolError.new(args, "waffles")
  33. assert_equal(false, e.has_return_to?)
  34. expected = {
  35. 'error' => 'waffles',
  36. 'mode' => 'error'
  37. }
  38. actual = OpenID::Util.parsekv(e.encode_to_kvform)
  39. assert_equal(expected, actual)
  40. assert_equal(ENCODE_KVFORM, e.which_encoding?)
  41. end
  42. end
  43. class TestDecode < Test::Unit::TestCase
  44. def setup
  45. @id_url = "http://decoder.am.unittest/"
  46. @rt_url = "http://rp.unittest/foobot/?qux=zam"
  47. @tr_url = "http://rp.unittest/"
  48. @assoc_handle = "{assoc}{handle}"
  49. end
  50. def decode(args)
  51. Decoder.new.decode(args)
  52. end
  53. def test_nil
  54. args = {}
  55. r = self.decode(args)
  56. assert_equal(nil, r)
  57. end
  58. def test_irrelevant
  59. args = {
  60. 'pony' => 'spotted',
  61. 'sreg.mutant_power' => 'decaffinator',
  62. }
  63. r = self.decode(args)
  64. assert_equal(nil, r)
  65. end
  66. def test_bad
  67. args = {
  68. 'openid.mode' => 'twos-compliment',
  69. 'openid.pants' => 'zippered'
  70. }
  71. begin
  72. self.decode(args)
  73. rescue ProtocolError
  74. assert true
  75. else
  76. assert false, 'failed to raise ProtocolError'
  77. end
  78. end
  79. def test_dict_of_lists
  80. args = {
  81. 'openid.mode' => ['checkid_setup'],
  82. 'openid.identity' => @id_url,
  83. 'openid.assoc_handle' => @assoc_handle,
  84. 'openid.return_to' => @rt_url,
  85. 'openid.trust_root' => @tr_url
  86. }
  87. # this should raise an argument error
  88. begin
  89. result = self.decode(args)
  90. rescue ArgumentError
  91. assert true
  92. end
  93. end
  94. def test_checkid_immediate
  95. args = {
  96. 'openid.mode' => 'checkid_immediate',
  97. 'openid.identity' => @id_url,
  98. 'openid.assoc_handle' => @assoc_handle,
  99. 'openid.return_to' => @rt_url,
  100. 'openid.trust_root' => @tr_url,
  101. # should be ignored
  102. 'openid.some.extension' => 'junk'
  103. }
  104. r = self.decode(args)
  105. assert_equal(CheckIDRequest, r.class)
  106. assert_equal('checkid_immediate', r.mode)
  107. assert_equal(true, r.immediate)
  108. assert_equal(@id_url, r.identity)
  109. assert_equal(@tr_url, r.trust_root)
  110. assert_equal(@rt_url, r.return_to)
  111. assert_equal(@assoc_handle, r.assoc_handle)
  112. end
  113. def test_checkid_setup_no_identity
  114. args = {
  115. 'openid.mode' => 'checkid_setup',
  116. 'openid.assoc_handle' => @assoc_handle,
  117. 'openid.return_to' => @rt_url,
  118. 'openid.trust_root' => @tr_url,
  119. }
  120. begin
  121. result = self.decode(args)
  122. rescue ProtocolError => e
  123. assert e.query == args
  124. else
  125. flunk('Expected a ProtocolError, but did not get one')
  126. end
  127. end
  128. def test_checkid_setup_no_return_to
  129. args = {
  130. 'openid.mode' => 'checkid_setup',
  131. 'openid.identity' => @id_url,
  132. 'openid.assoc_handle' => @assoc_handle,
  133. 'openid.trust_root' => @tr_url,
  134. }
  135. begin
  136. result = self.decode(args)
  137. rescue ProtocolError => e
  138. assert e.query == args
  139. else
  140. flunk('Expected a ProtocolError, but did not get one')
  141. end
  142. end
  143. def test_checkid_setup_bad_return_to
  144. args = {
  145. 'openid.mode' => 'checkid_setup',
  146. 'openid.identity' => @id_url,
  147. 'openid.assoc_handle' => @assoc_handle,
  148. 'openid.return_to' => 'not a url',
  149. 'openid.trust_root' => @tr_url,
  150. }
  151. begin
  152. result = self.decode(args)
  153. rescue MalformedReturnURL => e
  154. assert e.query == args
  155. else
  156. flunk('Expected a MalformedReturnURL, but did not get one')
  157. end
  158. end
  159. def test_checkid_setup_untrusted_return_to
  160. args = {
  161. 'openid.mode' => 'checkid_setup',
  162. 'openid.identity' => @id_url,
  163. 'openid.assoc_handle' => @assoc_handle,
  164. 'openid.return_to' => 'http://incorrect.example.com/',
  165. 'openid.trust_root' => @tr_url,
  166. }
  167. begin
  168. result = self.decode(args)
  169. rescue UntrustedReturnURL => e
  170. assert true
  171. else
  172. flunk('Expected a UntrustedReturnURL, but did not get one')
  173. end
  174. end
  175. def test_check_auth
  176. args = {
  177. 'openid.mode' => 'check_authentication',
  178. 'openid.assoc_handle' => '{dumb}{handle}',
  179. 'openid.sig' => 'sigblob',
  180. 'openid.signed' => 'foo,bar,mode',
  181. 'openid.foo' => 'signedval1',
  182. 'openid.bar' => 'signedval2',
  183. 'openid.baz' => 'unsigned',
  184. }
  185. r = self.decode(args)
  186. assert_equal(r.class, CheckAuthRequest)
  187. assert_equal('check_authentication', r.mode)
  188. assert_equal('sigblob', r.sig)
  189. assert_equal([['foo', 'signedval1'],
  190. ['bar', 'signedval2'],
  191. ['mode', 'id_res']], r.signed)
  192. end
  193. def test_check_auth_missing_signed_field
  194. args = {
  195. 'openid.mode' => 'check_authentication',
  196. 'openid.assoc_handle' => '{dumb}{handle}',
  197. 'openid.sig' => 'sigblob',
  198. 'openid.signed' => 'foo,bar,mode',
  199. 'openid.foo' => 'signedval1',
  200. 'openid.baz' => 'unsigned'
  201. }
  202. begin
  203. r = self.decode(args)
  204. rescue ProtocolError => e
  205. assert e.query == args
  206. else
  207. flunk('Expected a ProtocolError, but did not get one')
  208. end
  209. end
  210. def test_check_auth_missing_signature
  211. args = {
  212. 'openid.mode' => 'check_authentication',
  213. 'openid.assoc_handle' => '{dumb}{handle}',
  214. 'openid.signed' => 'foo,bar,mode',
  215. 'openid.foo' => 'signedval1',
  216. 'openid.bar' => 'signedval2',
  217. 'openid.baz' => 'unsigned'
  218. }
  219. begin
  220. r = self.decode(args)
  221. rescue ProtocolError => e
  222. assert e.query == args
  223. else
  224. flunk('Expected a ProtocolError, but did not get one')
  225. end
  226. end
  227. def test_check_auth_and_invalidate
  228. args = {
  229. 'openid.mode' => 'check_authentication',
  230. 'openid.assoc_handle' => '{dumb}{handle}',
  231. 'openid.invalidate_handle' => '[[SMART_handle]]',
  232. 'openid.sig' => 'sigblob',
  233. 'openid.signed' => 'foo,bar,mode',
  234. 'openid.foo' => 'signedval1',
  235. 'openid.bar' => 'signedval2',
  236. 'openid.baz' => 'unsigned'
  237. }
  238. r = self.decode(args)
  239. assert_equal(CheckAuthRequest, r.class)
  240. assert_equal('[[SMART_handle]]', r.invalidate_handle)
  241. end
  242. def test_associate_DH
  243. args = {
  244. 'openid.mode' => 'associate',
  245. 'openid.session_type' => 'DH-SHA1',
  246. 'openid.dh_consumer_public' => "Rzup9265tw=="
  247. }
  248. r = self.decode(args)
  249. assert_equal(AssociateRequest, r.class)
  250. assert_equal("associate", r.mode)
  251. assert_equal("DH-SHA1", r.session.session_type)
  252. assert_equal("HMAC-SHA1", r.assoc_type)
  253. assert(r.session.consumer_pubkey)
  254. end
  255. # Trying DH assoc w/o public key
  256. def test_associate_DH_missing_key
  257. args = {
  258. 'openid.mode' => 'associate',
  259. 'openid.session_type' => 'DH-SHA1'
  260. }
  261. # Using DH-SHA1 without supplying dh_consumer_public is an error.
  262. begin
  263. self.decode(args)
  264. rescue ProtocolError => e
  265. assert e.query == args
  266. else
  267. flunk('Wanted a ProtocolError')
  268. end
  269. end
  270. # test associate w/ non default mod and gen
  271. def test_associate_DH_mod_gen
  272. args = {
  273. 'openid.mode' => 'associate',
  274. 'openid.session_type' => 'DH-SHA1',
  275. 'openid.dh_consumer_public' => "Rzup9265tw==",
  276. 'openid.dh_modulus' => OpenID::Util.num_to_base64(ALT_MODULUS),
  277. 'openid.dh_gen' => OpenID::Util.num_to_base64(ALT_GEN)
  278. }
  279. r = self.decode(args)
  280. assert_equal(AssociateRequest, r.class)
  281. assert_equal('DH-SHA1', r.session.session_type)
  282. assert_equal('HMAC-SHA1', r.assoc_type)
  283. assert_equal(ALT_MODULUS, r.session.dh.p)
  284. assert_equal(ALT_GEN, r.session.dh.g)
  285. assert r.session.consumer_pubkey
  286. end
  287. def test_associate_weird_session
  288. args = {
  289. 'openid.mode' => 'associate',
  290. 'openid.session_type' => 'FLCL6',
  291. 'openid.dh_consumer_public' => "YQ==\n"
  292. }
  293. begin
  294. self.decode(args)
  295. rescue ProtocolError => e
  296. assert e.query == args
  297. else
  298. flunk('Wanted a ProtocolError')
  299. end
  300. end
  301. def test_associate_plain_session
  302. args = {'openid.mode' => 'associate'}
  303. r = self.decode(args)
  304. assert_equal(AssociateRequest, r.class)
  305. assert_equal('associate', r.mode)
  306. assert_equal('plaintext', r.session.session_type)
  307. assert_equal('HMAC-SHA1', r.assoc_type)
  308. end
  309. end
  310. class TestEncode < Test::Unit::TestCase
  311. def setup
  312. @encoder = Encoder.new
  313. end
  314. def test_id_res
  315. request = CheckIDRequest.new('checkid_setup',
  316. 'http://bombom.unittest/',
  317. 'http://burr.unittest/999',
  318. 'http://burr.unittest/')
  319. response = OpenIDResponse.new(request)
  320. response.fields = {
  321. 'mode' => 'id_res',
  322. 'identity' => request.identity,
  323. 'return_to' => request.return_to
  324. }
  325. webresponse = @encoder.encode(response)
  326. assert_equal(HTTP_REDIRECT, webresponse.code)
  327. assert webresponse.headers.has_key?('location')
  328. loc = webresponse.headers['location']
  329. assert loc.starts_with?(request.return_to)
  330. query = OpenID::Util.parse_query(URI.parse(loc).query)
  331. expected = {}
  332. response.fields.each {|k,v| expected['openid.'+k] = v}
  333. assert_equal(expected, query)
  334. end
  335. def test_cancel
  336. request = CheckIDRequest.new('checkid_setup',
  337. 'http://bombom.unittest/',
  338. 'http://burr.unittest/999',
  339. 'http://burr.unittest/')
  340. response = OpenIDResponse.new(request)
  341. response.fields = {'mode' => 'cancel'}
  342. wr = @encoder.encode(response)
  343. assert_equal(HTTP_REDIRECT, wr.code)
  344. assert wr.headers.has_key?('location')
  345. assert wr.headers['location'].starts_with?(request.return_to)
  346. end
  347. def test_assoc_reply
  348. req = AssociateRequest.from_query({})
  349. resp = OpenIDResponse.new(req)
  350. resp.fields = {'assoc_handle' => 'every-zig'}
  351. wr = @encoder.encode(resp)
  352. assert_equal(HTTP_OK, wr.code)
  353. assert_equal({}, wr.headers)
  354. assert_equal("assoc_handle:every-zig\n", wr.body)
  355. end
  356. def test_check_auth_reply
  357. req = CheckAuthRequest.new('sock', 'sigg', [])
  358. res = OpenIDResponse.new(req)
  359. res.fields = {'is_valid' => 'true', 'invalidate_handle' => 'xxx:xxx'}
  360. wr = @encoder.encode(res)
  361. expected = "invalidate_handle:xxx:xxx\nis_valid:true\n"
  362. expected = OpenID::Util.parsekv(expected)
  363. assert_equal(HTTP_OK, wr.code)
  364. assert_equal({}, wr.headers)
  365. assert_equal(expected, OpenID::Util.parsekv(wr.body))
  366. end
  367. def test_unencodable_error
  368. args = {'openid.identity' => 'http://limu.unittest/'}
  369. e = ProtocolError.new(args, 'foo')
  370. begin
  371. @encoder.encode(e)
  372. rescue EncodingError => e
  373. assert true
  374. else
  375. flunk('Expected an EncodingError')
  376. end
  377. end
  378. def test_encodable_error
  379. args = {
  380. 'openid.mode' => 'associate',
  381. 'openid.identity' => 'http://limu.unittest/'
  382. }
  383. e = ProtocolError.new(args, 'snoot')
  384. expected_body = "error:snoot\nmode:error\n"
  385. expected_body = OpenID::Util.parsekv(expected_body)
  386. wr = @encoder.encode(e)
  387. assert_equal(HTTP_ERROR, wr.code)
  388. assert_equal({}, wr.headers)
  389. assert_equal(expected_body, OpenID::Util.parsekv(wr.body))
  390. end
  391. end
  392. class TestSigningEncode < Test::Unit::TestCase
  393. def setup
  394. @dumb_key = 'http://localhost/|dumb'
  395. @normal_key = 'http://localhost/|normal'
  396. @store = OpenID::MemoryStore.new
  397. @request = CheckIDRequest.new('checkid_setup',
  398. 'http://bombom.unittest/',
  399. 'http://burr.unittest/999',
  400. 'http://burr.unittest/')
  401. @response = OpenIDResponse.new(@request)
  402. @response.fields = {
  403. 'mode' => 'id_res',
  404. 'identity' => @request.identity,
  405. 'return_to' => @request.return_to
  406. }
  407. @response.signed += ['mode','identity','return_to']
  408. @signatory = Signatory.new(@store)
  409. @encoder = SigningEncoder.new(@signatory)
  410. end
  411. def test_id_res
  412. assoc_handle = '{bicycle}{shed}'
  413. assoc = OpenID::Association.from_expires_in(60, assoc_handle,
  414. 'sekrit','HMAC-SHA1')
  415. @store.store_association(@normal_key, assoc)
  416. @request.assoc_handle = assoc_handle
  417. wr = @encoder.encode(@response)
  418. assert_equal(HTTP_REDIRECT, wr.code)
  419. assert wr.headers.has_key?('location')
  420. loc = wr.headers['location']
  421. query = OpenID::Util.parse_query(URI.parse(loc).query)
  422. assert query.has_key?('openid.sig')
  423. assert query.has_key?('openid.signed')
  424. assert query.has_key?('openid.assoc_handle')
  425. end
  426. def test_id_res_dumb
  427. wr = @encoder.encode(@response)
  428. assert_equal(HTTP_REDIRECT, wr.code)
  429. assert wr.headers.has_key?('location')
  430. loc = wr.headers['location']
  431. query = OpenID::Util.parse_query(URI.parse(loc).query)
  432. assert query.has_key?('openid.sig')
  433. assert query.has_key?('openid.signed')
  434. assert query.has_key?('openid.assoc_handle')
  435. end
  436. def test_cancel
  437. response = OpenIDResponse.new(@request)
  438. response.fields['mode'] = 'cancel'
  439. response.signed.clear
  440. wr = @encoder.encode(response)
  441. assert_equal(HTTP_REDIRECT, wr.code)
  442. assert wr.headers.has_key?('location')
  443. loc = wr.headers['location']
  444. query = OpenID::Util.parse_query(URI.parse(loc).query)
  445. assert(!query.has_key?('openid.sig'))
  446. end
  447. def test_assoc_reply
  448. req = AssociateRequest.from_query({})
  449. res = OpenIDResponse.new(req)
  450. res.fields = {'assoc_handle' => 'every-zig'}
  451. wr = @encoder.encode(res)
  452. assert_equal(HTTP_OK, wr.code)
  453. assert_equal({}, wr.headers)
  454. assert_equal("assoc_handle:every-zig\n", wr.body)
  455. end
  456. def test_already_signed
  457. @response.fields['sig'] = 'priorSig=='
  458. begin
  459. @encoder.encode(@response)
  460. rescue AlreadySigned => e
  461. assert true
  462. else
  463. flunk('Wanted an AlreadySigned exception')
  464. end
  465. end
  466. end
  467. class TestCheckID < Test::Unit::TestCase
  468. def setup
  469. @request = CheckIDRequest.new('checkid_setup',
  470. 'http://bombom.unittest/',
  471. 'http://burr.unittest/999',
  472. 'http://burr.unittest/')
  473. end
  474. def test_trust_root_invalid
  475. @request.trust_root = 'http://foo.un/17'
  476. @request.return_to = 'http://foo.un/39'
  477. assert !@request.trust_root_valid
  478. end
  479. def test_trust_root_hvalid
  480. @request.trust_root = 'http://foo.un/'
  481. @request.return_to = 'http://foo.un/39'
  482. assert @request.trust_root_valid
  483. end
  484. def test_answer_allow
  485. answer = @request.answer(true)
  486. assert_equal(@request, answer.request)
  487. assert_equal({'mode'=>'id_res','identity'=>@request.identity,
  488. 'return_to'=>@request.return_to}, answer.fields)
  489. signed = answer.signed.dup.sort
  490. assert_equal(['identity','mode','return_to'], signed)
  491. end
  492. def test_answer_allow_no_trust_root
  493. @request.trust_root = nil
  494. answer = @request.answer(true)
  495. assert_equal(@request, answer.request)
  496. assert_equal({'mode'=>'id_res','identity'=>@request.identity,
  497. 'return_to'=>@request.return_to}, answer.fields)
  498. signed = answer.signed.dup.sort
  499. assert_equal(['identity','mode','return_to'], signed)
  500. end
  501. def test_answer_immediate_deny
  502. @request.mode = 'checkid_immediate'
  503. @request.immediate = true
  504. server_url = 'http://server-url.unittest/'
  505. answer = @request.answer(false, server_url)
  506. assert_equal(@request, answer.request)
  507. assert_equal(2, answer.fields.length)
  508. assert_equal('id_res', answer.fields['mode'])
  509. assert answer.fields['user_setup_url'].starts_with?(server_url)
  510. assert_equal([], answer.signed)
  511. end
  512. def test_answer_setup_deny
  513. answer = @request.answer(false)
  514. assert_equal({'mode' => 'cancel'}, answer.fields)
  515. assert_equal([], answer.signed)
  516. end
  517. def test_encode_to_url
  518. server_url = 'http://openid-server.un/'
  519. url = @request.encode_to_url(server_url)
  520. query = OpenID::Util.parse_query(URI.parse(url).query)
  521. req = CheckIDRequest.from_query(query)
  522. assert_equal(@request.mode, req.mode)
  523. assert_equal(@request.identity, req.identity)
  524. assert_equal(@request.return_to, req.return_to)
  525. assert_equal(@request.trust_root, req.trust_root)
  526. assert_equal(@request.immediate, req.immediate)
  527. assert_equal(@request.assoc_handle, req.assoc_handle)
  528. end
  529. def test_cancel_url
  530. url = @request.cancel_url
  531. expected = OpenID::Util.append_args(@request.return_to,
  532. {'openid.mode'=>'cancel'})
  533. assert_equal(expected, url)
  534. end
  535. def test_cancel_url_immediate
  536. @request.immediate = true
  537. begin
  538. url = @request.cancel_url
  539. rescue ProtocolError => e
  540. assert true
  541. else
  542. flunk('Wanted a ProtoclError')
  543. end
  544. end
  545. end
  546. class TestCheckIDExtension < Test::Unit::TestCase
  547. def setup
  548. @request = CheckIDRequest.new('checkid_setup',
  549. 'http://bombom.unittest/',
  550. 'http://burr.unittest/999',
  551. 'http://burr.unittest/')
  552. @response = OpenIDResponse.new(@request)
  553. @response.fields['mode'] = 'id_res'
  554. @response.fields['blue'] = 'star'
  555. @response.signed += ['mode','identity','return_to']
  556. end
  557. def test_add_field
  558. ns = 'mj12'
  559. @response.add_field(ns, 'bright', 'potato')
  560. assert_equal({'blue'=>'star',
  561. 'mode'=>'id_res',
  562. 'mj12.bright'=>'potato'}, @response.fields)
  563. assert_equal(['mode','identity','return_to','mj12.bright'], @response.signed)
  564. end
  565. def test_add_field_unsigned
  566. ns = 'mj12'
  567. @response.add_field(ns, 'bright', 'potato', false)
  568. assert_equal({'blue'=>'star',
  569. 'mode'=>'id_res',
  570. 'mj12.bright'=>'potato'}, @response.fields)
  571. assert_equal(['mode','identity','return_to'], @response.signed)
  572. end
  573. def test_add_fields
  574. ns = 'mj12'
  575. @response.add_fields(ns, {'bright'=>'potato', 'xxx'=>'yyy'})
  576. assert_equal({'blue'=>'star',
  577. 'mode'=>'id_res',
  578. 'mj12.bright'=>'potato',
  579. 'mj12.xxx'=>'yyy'}, @response.fields)
  580. assert_equal(['mode','identity','return_to','mj12.bright','mj12.xxx'].sort, @response.signed.sort)
  581. end
  582. def test_add_fields_unsigned
  583. ns = 'mj12'
  584. @response.add_fields(ns, {'bright'=>'potato', 'xxx'=>'yyy'}, false)
  585. assert_equal({'blue'=>'star',
  586. 'mode'=>'id_res',
  587. 'mj12.bright'=>'potato',
  588. 'mj12.xxx'=>'yyy'}, @response.fields)
  589. assert_equal(['mode','identity','return_to'].sort, @response.signed.sort)
  590. end
  591. def test_update
  592. eres = OpenIDResponse.new(nil)
  593. eres.fields.update({'a'=>'b','c'=>'d'})
  594. eres.signed = ['c']
  595. @response.update('ns', eres)
  596. assert_equal({'blue'=>'star','mode'=>'id_res','ns.a'=>'b','ns.c'=>'d'},
  597. @response.fields)
  598. assert_equal(['mode', 'identity', 'return_to', 'ns.c'], @response.signed)
  599. end
  600. def test_update_no_namespace
  601. eres = OpenIDResponse.new(nil)
  602. eres.fields.update({'a'=>'b','c'=>'d'})
  603. eres.signed = ['c']
  604. @response.update(nil, eres)
  605. assert_equal({'blue'=>'star','mode'=>'id_res','a'=>'b','c'=>'d'},
  606. @response.fields)
  607. assert_equal(['mode', 'identity', 'return_to', 'c'], @response.signed)
  608. end
  609. end
  610. class MockSignatory
  611. attr_accessor :is_valid, :assocs
  612. def initialize(assoc)
  613. @assocs = [assoc]
  614. @is_valid = true
  615. end
  616. def is_valid?
  617. @is_valid
  618. end
  619. def verify(assoc_handle, sig, signed_pairs)
  620. if @assocs.member?([true, assoc_handle])
  621. return self.is_valid?
  622. else
  623. return false
  624. end
  625. end
  626. def get_association(assoc_handle, dumb)
  627. if @assocs.member?([dumb, assoc_handle])
  628. return true
  629. else
  630. return nil
  631. end
  632. end
  633. def invalidate(assoc_handle, dumb)
  634. @assocs.delete([dumb, assoc_handle])
  635. end
  636. end
  637. class TestCheckAuthServer < Test::Unit::TestCase
  638. def setup
  639. @assoc_handle = 'moo'
  640. @request = CheckAuthRequest.new(@assoc_handle, 'signature',
  641. [['one','alpha'],['two','beta']])
  642. @signatory = MockSignatory.new([true, @assoc_handle])
  643. end
  644. def test_valid
  645. r = @request.answer(@signatory)
  646. assert_equal({'is_valid'=>'true'}, r.fields)
  647. assert_equal(r.request, @request)
  648. end
  649. def test_invalid
  650. assert_not_nil(@signatory)
  651. @signatory.is_valid = false
  652. r = @request.answer(@signatory)
  653. assert_equal({'is_valid'=>'false'}, r.fields)
  654. assert_equal(r.request, @request)
  655. end
  656. def test_replay
  657. r = @request.answer(@signatory)
  658. r = @request.answer(@signatory)
  659. assert_equal({'is_valid'=>'false'}, r.fields)
  660. end
  661. def test_invalidate_handle
  662. @request.invalidate_handle = 'bogushandle'
  663. r = @request.answer(@signatory)
  664. assert_equal({'is_valid'=>'true',
  665. 'invalidate_handle'=>'bogushandle'}, r.fields)
  666. assert_equal(r.request, @request)
  667. end
  668. def test_invalidate_handle_no
  669. assoc_handle = 'goodhandle'
  670. @signatory.assocs << [false, assoc_handle]
  671. @request.invalidate_handle = assoc_handle
  672. r = @request.answer(@signatory)
  673. assert_equal({'is_valid'=>'true'}, r.fields)
  674. end
  675. end
  676. class TestAssociate < Test::Unit::TestCase
  677. def setup
  678. @request = AssociateRequest.from_query({})
  679. @store = OpenID::MemoryStore.new
  680. @signatory = Signatory.new(@store)
  681. @assoc = @signatory.create_association(false)
  682. end
  683. def test_dh
  684. consumer_dh = OpenID::DiffieHellman.new
  685. cpub = consumer_dh.public
  686. session = DiffieHellmanServerSession.new(OpenID::DiffieHellman.new, cpub)
  687. @request = AssociateRequest.new(session)
  688. response = @request.answer(@assoc)
  689. rf = response.fields
  690. assert_equal('HMAC-SHA1', rf['assoc_type'])
  691. assert_equal('DH-SHA1', rf['session_type'])
  692. assert_equal(@assoc.handle, rf['assoc_handle'])
  693. assert_nil(rf['mac_key'])
  694. assert_not_nil(rf['enc_mac_key'])
  695. assert_not_nil(rf['dh_server_public'])
  696. enc_key = OpenID::Util.from_base64(rf['enc_mac_key'])
  697. spub = OpenID::Util.base64_to_num(rf['dh_server_public'])
  698. secret = consumer_dh.xor_secrect(spub, enc_key)
  699. assert_equal(@assoc.secret, secret)
  700. end
  701. def test_plaintext
  702. response = @request.answer(@assoc)
  703. rf = response.fields
  704. assert_equal('HMAC-SHA1', rf['assoc_type'])
  705. assert_equal(@assoc.handle, rf['assoc_handle'])
  706. assert_equal(OpenID::Util.to_base64(@assoc.secret), rf['mac_key'])
  707. assert_equal("#{14 * 24 * 60 * 6}", rf['expires_in'])
  708. assert_nil(rf['session_type'])
  709. assert_nil(rf['enc_mac_key'])
  710. assert_nil(rf['dh_server_public'])
  711. end
  712. end
  713. class Counter
  714. attr_accessor :count
  715. def initialize
  716. @count = 0
  717. end
  718. def inc
  719. @count += 1
  720. end
  721. end
  722. class TestServer < Test::Unit::TestCase
  723. def setup
  724. @store = OpenID::MemoryStore.new
  725. @server = Server.new(@store)
  726. end
  727. def test_associate
  728. req = AssociateRequest.from_query({})
  729. res = @server.openid_associate(req)
  730. assert res.fields.has_key?('assoc_handle')
  731. end
  732. def test_check_auth
  733. req = CheckAuthRequest.new('arrrrg', '0x3999', [])
  734. res = @server.openid_check_authentication(req)
  735. assert res.fields.has_key?('is_valid')
  736. end
  737. end
  738. class TestSignatory < Test::Unit::TestCase
  739. def setup
  740. @store = OpenID::MemoryStore.new
  741. @signatory = Signatory.new(@store)
  742. @dumb_key = 'http://localhost/|dumb'
  743. @normal_key = 'http://localhost/|normal'
  744. end
  745. def test_sign
  746. request = CheckIDRequest.new('checkid_setup','foo','bar','baz')
  747. assoc_handle = '{assoc}{lookatme}'
  748. @store.store_association(@normal_key,
  749. OpenID::Association.from_expires_in(60,
  750. assoc_handle,
  751. 'sekrit',
  752. 'HMAC-SHA1'))
  753. request.assoc_handle = assoc_handle
  754. response = OpenIDResponse.new(request)
  755. response.fields = {
  756. 'foo' => 'amsigned',
  757. 'bar' => 'notsigned',
  758. 'azu' => 'alsosigned'
  759. }
  760. response.signed = ['foo','azu']
  761. sresponse = @signatory.sign(response)
  762. assert_equal(assoc_handle, sresponse.fields['assoc_handle'])
  763. assert_equal('foo,azu', sresponse.fields['signed'])
  764. assert_not_nil(sresponse.fields['sig'])
  765. end
  766. def test_sign_dumb
  767. request = CheckIDRequest.new('checkid_setup','foo','bar','baz')
  768. request.assoc_handle = nil
  769. response = OpenIDResponse.new(request)
  770. response.fields = {
  771. 'foo' => 'amsigned',
  772. 'bar' => 'notsigned',
  773. 'azu' => 'alsosigned'
  774. }
  775. response.signed = ['foo','azu']
  776. sresponse = @signatory.sign(response)
  777. assoc_handle = sresponse.fields['assoc_handle']
  778. assert_not_nil(assoc_handle)
  779. assoc = @signatory.get_association(assoc_handle, true)
  780. assert_not_nil(assoc)
  781. assert_equal('foo,azu', sresponse.fields['signed'])
  782. assert_not_nil(sresponse.fields['sig'])
  783. end
  784. def test_sign_expired
  785. request = CheckIDRequest.new('checkid_setup','foo','bar','baz')
  786. assoc_handle = '{assoc}{lookatme}'
  787. @store.store_association(@normal_key,
  788. OpenID::Association.from_expires_in(-10,
  789. assoc_handle,
  790. 'sekrit',
  791. 'HMAC-SHA1'))
  792. assert_not_nil(@store.get_association(@normal_key, assoc_handle))
  793. request.assoc_handle = assoc_handle
  794. response = OpenIDResponse.new(request)
  795. response.fields = {
  796. 'foo' => 'amsigned',
  797. 'bar' => 'notsigned',
  798. 'azu' => 'alsosigned'
  799. }
  800. response.signed = ['foo','azu']
  801. sresponse = @signatory.sign(response)
  802. new_assoc_handle = sresponse.fields['assoc_handle']
  803. assert_not_nil(new_assoc_handle)
  804. assert new_assoc_handle != assoc_handle
  805. assert_equal(assoc_handle, sresponse.fields['invalidate_handle'])
  806. assert_equal('foo,azu', sresponse.fields['signed'])
  807. assert_not_nil(sresponse.fields['sig'])
  808. assert_nil(@store.get_association(@normal_key, assoc_handle))
  809. assert_not_nil(@store.get_association(@dumb_key, new_assoc_handle))
  810. assert_nil(@store.get_association(@normal_key, new_assoc_handle))
  811. end
  812. def test_verify
  813. assoc_handle = '{vroom}{zoom}'
  814. assoc = OpenID::Association.from_expires_in(60, assoc_handle,
  815. 'sekrit', 'HMAC-SHA1')
  816. @store.store_association(@dumb_key, assoc)
  817. signed_pairs = [['foo', 'bar'],['apple', 'orange']]
  818. sig = "Ylu0KcIR7PvNegB/K41KpnRgJl0="
  819. verified = @signatory.verify(assoc_handle, sig, signed_pairs)
  820. assert_not_nil(verified)
  821. end
  822. def test_verify_bad_sig
  823. assoc_handle = '{vroom}{zoom}'
  824. assoc = OpenID::Association.from_expires_in(60, assoc_handle,
  825. 'sekrit', 'HMAC-SHA1')
  826. @store.store_association(@dumb_key, assoc)
  827. signed_pairs = [['foo', 'bar'],['apple', 'orange']]
  828. sig = "Ylu0KcIR7PvNegB/K41KpnRgXXX="
  829. verified = @signatory.verify(assoc_handle, sig, signed_pairs)
  830. assert(!verified)
  831. end
  832. def test_verify_bad_handle
  833. assoc_handle = '{vroom}{zoom}'
  834. signed_pairs = [['foo', 'bar'],['apple', 'orange']]
  835. sig = "Ylu0KcIR7PvNegB/K41KpnRgJl0="
  836. verified = @signatory.verify(assoc_handle, sig, signed_pairs)
  837. assert(!verified)
  838. end
  839. def make_assoc(dumb, lifetime=60)
  840. assoc_handle = '{bling}'
  841. assoc = OpenID::Association.from_expires_in(lifetime, assoc_handle,
  842. 'sekrit', 'HMAC-SHA1')
  843. key = dumb ? @dumb_key : @normal_key
  844. @store.store_association(key, assoc)
  845. return assoc_handle
  846. end
  847. def test_get_assoc
  848. assoc_handle = self.make_assoc(true)
  849. assoc = @signatory.get_association(assoc_handle, true)
  850. assert_not_nil(assoc)
  851. assert_equal(assoc_handle, assoc.handle)
  852. end
  853. def test_get_assoc_expired
  854. assoc_handle = self.make_assoc(true, -10)
  855. assoc = @signatory.get_association(assoc_handle, true)
  856. assert_nil(assoc)
  857. end
  858. def test_get_assoc_invalid
  859. assoc_handle = 'no-such-handle'
  860. assoc = @signatory.get_association(assoc_handle, false)
  861. assert_nil(assoc)
  862. end
  863. def test_get_assoc_dumb_vs_normal
  864. assoc_handle = self.make_assoc(true)
  865. assoc = @signatory.get_association(assoc_handle, false)
  866. assert_nil(assoc)
  867. end
  868. def test_create_assoc
  869. assoc = @signatory.create_association(false)
  870. assoc2 = @signatory.get_association(assoc.handle, false)
  871. assert_not_nil(assoc2)
  872. assert_equal(assoc, assoc2)
  873. end
  874. def test_invalidate
  875. assoc_handle = '-squash-'
  876. assoc = OpenID::Association.from_expires_in(60, assoc_handle,
  877. 'sekrit', 'HMAC-SHA1')
  878. @store.store_association(@dumb_key, assoc)
  879. assoc = @signatory.get_association(assoc_handle, true)
  880. assert_not_nil(assoc)
  881. assoc = @signatory.get_association(assoc_handle, true)
  882. assert_not_nil(assoc)
  883. @signatory.invalidate(assoc_handle, true)
  884. assoc = @signatory.get_association(assoc_handle, true)
  885. assert_nil(assoc)
  886. end
  887. end