Consumer.php 90 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557
  1. <?php
  2. /**
  3. * Tests for the OpenID consumer.
  4. *
  5. * PHP versions 4 and 5
  6. *
  7. * LICENSE: See the COPYING file included in this distribution.
  8. *
  9. * @package OpenID
  10. * @author JanRain, Inc. <openid@janrain.com>
  11. * @copyright 2005-2008 Janrain, Inc.
  12. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
  13. */
  14. @session_start();
  15. require_once 'Auth/OpenID/CryptUtil.php';
  16. require_once 'Auth/Yadis/HTTPFetcher.php';
  17. require_once 'Auth/OpenID/DiffieHellman.php';
  18. require_once 'Auth/OpenID/FileStore.php';
  19. require_once 'Auth/OpenID/KVForm.php';
  20. require_once 'Auth/OpenID/Consumer.php';
  21. require_once 'Auth/OpenID/Server.php';
  22. require_once 'Auth/OpenID/Nonce.php';
  23. require_once 'Auth/OpenID/SReg.php';
  24. require_once 'Auth/OpenID/Message.php';
  25. require_once 'Tests/Auth/OpenID/MemStore.php';
  26. require_once 'PHPUnit.php';
  27. /*
  28. * Convenience function to create a SuccessResponse with the given
  29. * arguments, all signed.
  30. */
  31. function mkSuccess($endpoint, $q)
  32. {
  33. $signed_list = array();
  34. foreach (array_keys($q) as $k) {
  35. $signed_list[] = 'openid.' . $k;
  36. }
  37. return new Auth_OpenID_SuccessResponse($endpoint,
  38. Auth_OpenID_Message::fromOpenIDArgs($q),
  39. $signed_list);
  40. }
  41. class FastConsumerSession extends Auth_OpenID_DiffieHellmanSHA1ConsumerSession {
  42. function FastConsumerSession($dh = null)
  43. {
  44. if ($dh === null) {
  45. $dh = new Auth_OpenID_DiffieHellman(100389557, 2);
  46. }
  47. $this->dh = $dh;
  48. }
  49. }
  50. function setConsumerSession(&$con)
  51. {
  52. $con->session_types = array('DH-SHA1' => 'FastConsumerSession');
  53. }
  54. global $_Auth_OpenID_assocs;
  55. $_Auth_OpenID_assocs = array(
  56. array('another 20-byte key.', 'Snarky'),
  57. array(str_repeat("\x00", 20), 'Zeros'),
  58. );
  59. function Auth_OpenID_parse($qs)
  60. {
  61. $result = array();
  62. $parts = explode("&", $qs);
  63. foreach ($parts as $pair) {
  64. list($key, $value) = explode("=", $pair, 2);
  65. assert(!array_key_exists($key, $result));
  66. $result[$key] = urldecode($value);
  67. }
  68. return $result;
  69. }
  70. function Auth_OpenID_associate($qs, $assoc_secret, $assoc_handle)
  71. {
  72. $query_data = Auth_OpenID_parse($qs);
  73. assert($query_data['openid.mode'] == 'associate');
  74. assert($query_data['openid.assoc_type'] == 'HMAC-SHA1');
  75. $reply_dict = array(
  76. 'assoc_type' => 'HMAC-SHA1',
  77. 'assoc_handle' => $assoc_handle,
  78. 'expires_in' => '600',
  79. );
  80. if (defined('Auth_OpenID_NO_MATH_SUPPORT')) {
  81. assert(count($query_data) == 2);
  82. $message = Auth_OpenID_Message::fromPostArgs($query_data);
  83. $session = Auth_OpenID_PlainTextServerSession::fromMessage($message);
  84. } else {
  85. assert((count($query_data) == 6) || (count($query_data) == 4));
  86. assert($query_data['openid.mode'] == 'associate');
  87. assert($query_data['openid.session_type'] == 'DH-SHA1');
  88. $message = Auth_OpenID_Message::fromPostArgs($query_data);
  89. $session = Auth_OpenID_DiffieHellmanSHA1ServerSession::fromMessage($message);
  90. $reply_dict['session_type'] = 'DH-SHA1';
  91. }
  92. $reply_dict = array_merge($reply_dict, $session->answer($assoc_secret));
  93. return Auth_OpenID_KVForm::fromArray($reply_dict);
  94. }
  95. class Auth_OpenID_TestFetcher extends Auth_Yadis_HTTPFetcher {
  96. function Auth_OpenID_TestFetcher($user_url, $user_page,
  97. $assoc_secret, $assoc_handle)
  98. {
  99. $this->get_responses = array($user_url =>
  100. new Auth_Yadis_HTTPResponse($user_url,
  101. 200,
  102. array(),
  103. $user_page));
  104. $this->assoc_secret = $assoc_secret;
  105. $this->assoc_handle = $assoc_handle;
  106. $this->num_assocs = 0;
  107. }
  108. function response($url, $body)
  109. {
  110. if ($body === null) {
  111. return new Auth_Yadis_HTTPResponse($url, 404, array(), 'Not found');
  112. } else {
  113. return new Auth_Yadis_HTTPResponse($url, 200, array(), $body);
  114. }
  115. }
  116. function get($url)
  117. {
  118. if (array_key_exists($url, $this->get_responses)) {
  119. return $this->get_responses[$url];
  120. } else {
  121. return $this->response($url, null);
  122. }
  123. }
  124. function _checkAuth($url, $body)
  125. {
  126. $query_data = Auth_OpenID_parse($body);
  127. $expected = array(
  128. 'openid.mode' => 'check_authentication',
  129. 'openid.signed' => 'assoc_handle,sig,signed',
  130. 'openid.sig' => 'fake',
  131. 'openid.assoc_handle' => $this->assoc_handle,
  132. );
  133. if ($query_data == $expected) {
  134. return new Auth_Yadis_HTTPResponse($url, 200, array(), "is_valid:true\n");
  135. } else {
  136. return new Auth_Yadis_HTTPResponse($url, 400, array(),
  137. "error:bad check_authentication query\n");
  138. }
  139. }
  140. function post($url, $body)
  141. {
  142. if (strpos($body, 'openid.mode=associate') !== false) {
  143. $response = Auth_OpenID_associate($body, $this->assoc_secret,
  144. $this->assoc_handle);
  145. $this->num_assocs++;
  146. return $this->response($url, $response);
  147. } elseif (strpos($body, 'openid.mode=check_authentication') !== false) {
  148. return $this->_checkAuth($url, $body);
  149. }
  150. return $this->response($url, null);
  151. }
  152. }
  153. global $_Auth_OpenID_user_page_pat;
  154. $_Auth_OpenID_user_page_pat = "<html>
  155. <head>
  156. <title>A user page</title>
  157. %s
  158. </head>
  159. <body>
  160. blah blah
  161. </body>
  162. </html>";
  163. global $_Auth_OpenID_server_url;
  164. $_Auth_OpenID_server_url = "http://server.example.com/";
  165. global $_Auth_OpenID_consumer_url;
  166. $_Auth_OpenID_consumer_url = "http://consumer.example.com/";
  167. class Tests_Auth_OpenID_Consumer extends PHPUnit_TestCase {
  168. function _run(&$consumer, $user_url, $mode, $delegate_url,
  169. &$fetcher, &$store, $immediate)
  170. {
  171. global $_Auth_OpenID_consumer_url,
  172. $_Auth_OpenID_server_url;
  173. if (!defined('Auth_OpenID_NO_MATH_SUPPORT')) {
  174. setConsumerSession($consumer);
  175. }
  176. $endpoint = new Auth_OpenID_ServiceEndpoint();
  177. $endpoint->claimed_id = $user_url;
  178. $endpoint->server_url = $_Auth_OpenID_server_url;
  179. $endpoint->local_id = $delegate_url;
  180. $endpoint->type_uris = array(Auth_OpenID_TYPE_1_1);
  181. $result = $consumer->begin($endpoint);
  182. $return_to = $_Auth_OpenID_consumer_url;
  183. $trust_root = $_Auth_OpenID_consumer_url;
  184. $redirect_url = $result->redirectURL($trust_root, $return_to,
  185. $immediate);
  186. $parsed = parse_url($redirect_url);
  187. $qs = $parsed['query'];
  188. $q = Auth_OpenID_parse($qs);
  189. $new_return_to = $q['openid.return_to'];
  190. unset($q['openid.return_to']);
  191. $expected = array(
  192. 'openid.mode' => $mode,
  193. 'openid.identity' => $delegate_url,
  194. 'openid.trust_root' => $trust_root,
  195. );
  196. if ($consumer->_use_assocs) {
  197. $expected['openid.assoc_handle'] = $fetcher->assoc_handle;
  198. }
  199. $this->assertEquals($expected, $q);
  200. $this->assertEquals(0, strpos($redirect_url, $_Auth_OpenID_server_url));
  201. $this->assertEquals(0, strpos($new_return_to, $return_to));
  202. $parsed = parse_url($new_return_to);
  203. $query = Auth_OpenID_parse($parsed['query']);
  204. $query = array_merge($query, array(
  205. 'openid.mode'=> 'id_res',
  206. 'openid.return_to'=> $new_return_to,
  207. 'openid.identity'=> $delegate_url,
  208. 'openid.assoc_handle'=> $fetcher->assoc_handle,
  209. ));
  210. if (!$consumer->_use_assocs) {
  211. $query['openid.signed'] =
  212. 'assoc_handle,mode,signed,identity';
  213. $query['openid.assoc_handle'] = $fetcher->assoc_handle;
  214. $query['openid.sig'] = 'fake';
  215. }
  216. $message = Auth_OpenID_Message::fromPostArgs($query);
  217. if ($consumer->_use_assocs) {
  218. $assoc = $store->getAssociation($_Auth_OpenID_server_url,
  219. $fetcher->assoc_handle);
  220. $message = $assoc->signMessage($message);
  221. }
  222. $result = $consumer->complete($message, $result->endpoint, $new_return_to);
  223. $this->assertEquals(Auth_OpenID_SUCCESS, $result->status);
  224. $this->assertEquals($result->identity_url, $user_url);
  225. }
  226. function _test_success($user_url, $delegate_url, $links, $immediate = false)
  227. {
  228. global $_Auth_OpenID_filestore_base_dir,
  229. $_Auth_OpenID_server_url,
  230. $_Auth_OpenID_user_page_pat,
  231. $_Auth_OpenID_assocs;
  232. $store = new Tests_Auth_OpenID_MemStore();
  233. if ($immediate) {
  234. $mode = 'checkid_immediate';
  235. } else {
  236. $mode = 'checkid_setup';
  237. }
  238. $user_page = sprintf($_Auth_OpenID_user_page_pat, $links);
  239. $fetcher = new Auth_OpenID_TestFetcher($user_url, $user_page,
  240. $_Auth_OpenID_assocs[0][0],
  241. $_Auth_OpenID_assocs[0][1]);
  242. $consumer = new Auth_OpenID_GenericConsumer($store);
  243. $consumer->fetcher =& $fetcher;
  244. $expected_num_assocs = 0;
  245. $this->assertEquals($expected_num_assocs, $fetcher->num_assocs);
  246. $this->_run($consumer, $user_url, $mode, $delegate_url,
  247. $fetcher, $store, $immediate);
  248. if ($consumer->_use_assocs) {
  249. $expected_num_assocs += 1;
  250. }
  251. $this->assertEquals($expected_num_assocs, $fetcher->num_assocs);
  252. // Test that doing it again uses the existing association
  253. $this->_run($consumer, $user_url, $mode, $delegate_url,
  254. $fetcher, $store, $immediate);
  255. $this->assertEquals($expected_num_assocs, $fetcher->num_assocs);
  256. // Another association is created if we remove the existing one
  257. $store->removeAssociation($_Auth_OpenID_server_url,
  258. $fetcher->assoc_handle);
  259. $this->_run($consumer, $user_url, $mode, $delegate_url,
  260. $fetcher, $store, $immediate);
  261. if ($consumer->_use_assocs) {
  262. $expected_num_assocs += 1;
  263. }
  264. $this->assertEquals($expected_num_assocs, $fetcher->num_assocs);
  265. // Test that doing it again uses the existing association
  266. $this->_run($consumer, $user_url, $mode, $delegate_url,
  267. $fetcher, $store, $immediate);
  268. $this->assertEquals($expected_num_assocs, $fetcher->num_assocs);
  269. }
  270. function test_success()
  271. {
  272. global $_Auth_OpenID_server_url;
  273. $user_url = 'http://www.example.com/user.html';
  274. $links = sprintf('<link rel="openid.server" href="%s" />',
  275. $_Auth_OpenID_server_url);
  276. $delegate_url = 'http://consumer.example.com/user';
  277. $delegate_links = sprintf('<link rel="openid.server" href="%s" />'.
  278. '<link rel="openid.delegate" href="%s" />',
  279. $_Auth_OpenID_server_url, $delegate_url);
  280. $this->_test_success($user_url, $user_url, $links);
  281. $this->_test_success($user_url, $user_url, $links, true);
  282. $this->_test_success($user_url, $delegate_url, $delegate_links);
  283. $this->_test_success($user_url, $delegate_url, $delegate_links, true);
  284. }
  285. }
  286. class ConfigurableConsumer extends Auth_OpenID_GenericConsumer {
  287. var $return_to_check_disabled = false;
  288. function disableReturnToChecking() {
  289. $this->return_to_check_disabled = true;
  290. }
  291. function complete($message, $endpoint, $return_to) {
  292. if ($this->return_to_check_disabled) {
  293. $return_to = null;
  294. }
  295. return parent::complete($message, $endpoint, $return_to);
  296. }
  297. function _checkReturnTo($unused, $unused2) {
  298. if ($this->return_to_check_disabled) {
  299. return true;
  300. } else {
  301. return parent::_checkReturnTo($unused, $unused2);
  302. }
  303. }
  304. }
  305. class _TestIdRes extends PHPUnit_TestCase {
  306. var $consumer_class = 'ConfigurableConsumer';
  307. function setUp()
  308. {
  309. $this->store = new Tests_Auth_OpenID_MemStore();
  310. $cl = $this->consumer_class;
  311. $this->consumer = new $cl($this->store);
  312. $this->return_to = "http://some.host/path";
  313. $this->endpoint = new Auth_OpenID_ServiceEndpoint();
  314. $this->server_id = "sirod";
  315. $this->server_url = "serlie";
  316. $this->consumer_id = "consu";
  317. $this->endpoint->claimed_id = $this->consumer_id;
  318. $this->endpoint->server_url = $this->server_url;
  319. $this->endpoint->local_id = $this->server_id;
  320. $this->endpoint->type_uris = array(Auth_OpenID_TYPE_1_1);
  321. }
  322. }
  323. class Tests_Auth_OpenID_Consumer_TestSetupNeeded extends _TestIdRes {
  324. function failUnlessSetupNeeded($expected_setup_url, $message)
  325. {
  326. if ($this->consumer._checkSetupNeeded($message)) {
  327. $this->assertEquals($expected_setup_url,
  328. $message->getArg(Auth_OpenID_OPENID_NS,
  329. 'user_setup_url'));
  330. } else {
  331. $this->fail("Expected to find an immediate-mode response");
  332. }
  333. }
  334. function test_setupNeededOpenID1()
  335. {
  336. // The minimum conditions necessary to trigger Setup Needed
  337. $setup_url = 'http://unittest/setup-here';
  338. $message = Auth_OpenID_Message::fromPostArgs(array(
  339. 'opaenid.mode' => 'id_res',
  340. 'openid.user_setup_url' => $setup_url
  341. ));
  342. $this->assertTrue($message->isOpenID1());
  343. $this->failUnlessSetupNeeded($setup_url, $message);
  344. }
  345. function test_setupNeededOpenID1_extra()
  346. {
  347. // Extra stuff along with setup_url still trigger Setup Needed
  348. $setup_url = 'http://unittest/setup-here';
  349. $message = Auth_OpenID_Message::fromPostArgs(array(
  350. 'openid.mode' => 'id_res',
  351. 'openid.user_setup_url' => $setup_url,
  352. 'openid.identity' => 'bogus'
  353. ));
  354. $this->assertTrue($message->isOpenID1());
  355. $this->failUnlessSetupNeeded($setup_url, $message);
  356. }
  357. function test_noSetupNeededOpenID1()
  358. {
  359. // When the user_setup_url is missing on an OpenID 1 message,
  360. // we assume that it's not a cancel response to
  361. // checkid_immediate
  362. $message = Auth_OpenID_Message::fromOpenIDArgs(array('mode' => 'id_res'));
  363. $this->assertTrue($message->isOpenID1());
  364. // No SetupNeededError raised
  365. $this->consumer->_checkSetupNeeded($message);
  366. }
  367. function test_setupNeededOpenID2()
  368. {
  369. $message = Auth_OpenID_Message::fromOpenIDArgs(array(
  370. 'mode' => 'setup_needed',
  371. 'ns' => Auth_OpenID_OPENID2_NS
  372. ));
  373. $this->assertTrue($message->isOpenID2());
  374. $response = $this->consumer->complete($message, null, null);
  375. $this->assertEquals('setup_needed', $response->status);
  376. $this->assertEquals(null, $response->setup_url);
  377. }
  378. function test_setupNeededDoesntWorkForOpenID1()
  379. {
  380. $message = Auth_OpenID_Message::fromOpenIDArgs(array(
  381. 'mode' => 'setup_needed'));
  382. $this->assertFalse($this->consumer._checkSetupNeeded($message));
  383. $response = $this->consumer->complete($message, null, null);
  384. $this->assertEquals('failure', $response->status);
  385. $this->assertTrue(strpos($response->message, 'Invalid openid.mode') === 0);
  386. }
  387. function test_noSetupNeededOpenID2()
  388. {
  389. $message = Auth_OpenID_Message::fromOpenIDArgs(array(
  390. 'mode' => 'id_res',
  391. 'game' => 'puerto_rico',
  392. 'ns' => Auth_OpenID_OPENID2_NS
  393. ));
  394. $this->assertTrue($message->isOpenID2());
  395. $this->assertFalse($this->consumer._checkSetupNeeded($message));
  396. }
  397. }
  398. class IdResCheckForFieldsTest extends _TestIdRes {
  399. function setUp() {
  400. # Argh.
  401. $v = null;
  402. $this->consumer = new Auth_OpenID_GenericConsumer($v);
  403. }
  404. function successTest($openid_args, $signed_list) {
  405. $message = Auth_OpenID_Message::fromOpenIDArgs($openid_args);
  406. $message->setArg(Auth_OpenID_OPENID_NS, 'signed', implode(',', $signed_list));
  407. $result = $this->consumer->_idResCheckForFields($message);
  408. $this->assertFalse(Auth_OpenID::isFailure($result));
  409. }
  410. function test_openid1Success() {
  411. $this->successTest(
  412. array('return_to' =>'return',
  413. 'assoc_handle' =>'assoc handle',
  414. 'sig' =>'a signature',
  415. 'identity' =>'someone',
  416. ),
  417. array('return_to', 'identity'));
  418. }
  419. function test_openid2Success() {
  420. $this->successTest(
  421. array('ns' => Auth_OpenID_OPENID2_NS,
  422. 'return_to' =>'return',
  423. 'assoc_handle' =>'assoc handle',
  424. 'sig' =>'a signature',
  425. 'op_endpoint' =>'my favourite server',
  426. 'response_nonce' =>'use only once',
  427. ),
  428. array('return_to', 'response_nonce', 'assoc_handle', 'op_endpoint'));
  429. }
  430. function test_openid2Success_identifiers() {
  431. $this->successTest(
  432. array('ns' =>Auth_OpenID_OPENID2_NS,
  433. 'return_to' =>'return',
  434. 'assoc_handle' =>'assoc handle',
  435. 'sig' =>'a signature',
  436. 'claimed_id' =>'i claim to be me',
  437. 'identity' =>'my server knows me as me',
  438. 'op_endpoint' =>'my favourite server',
  439. 'response_nonce' =>'use only once',
  440. ),
  441. array('return_to', 'response_nonce', 'identity',
  442. 'claimed_id', 'assoc_handle', 'op_endpoint'));
  443. }
  444. function endswith($str, $it) {
  445. $it_len = strlen($it);
  446. $total = strlen($str);
  447. return (strpos($str, $it) === $total - $it_len);
  448. }
  449. function missingFieldTest($openid_args) {
  450. $message = Auth_OpenID_Message::fromOpenIDArgs($openid_args);
  451. $result = $this->consumer->_idResCheckForFields($message);
  452. $this->assertTrue(Auth_OpenID::isFailure($result));
  453. $this->assertTrue(strpos($result->message, 'Missing required') === 0);
  454. }
  455. function missingSignedTest($openid_args) {
  456. $message = Auth_OpenID_Message::fromOpenIDArgs($openid_args);
  457. $result = $this->consumer->_idResCheckForFields($message);
  458. $this->assertTrue(Auth_OpenID::isFailure($result));
  459. if (Auth_OpenID::isFailure($result)) {
  460. $this->assertTrue($this->endswith($result->message, 'not signed'),
  461. $result->message);
  462. }
  463. }
  464. function test_openid1Missing_returnToSig() {
  465. $this->missingSignedTest(
  466. array('return_to' =>'return',
  467. 'assoc_handle' =>'assoc handle',
  468. 'sig' =>'a signature',
  469. 'identity' =>'someone',
  470. 'signed' => 'identity,assoc_handle'));
  471. }
  472. function test_openid2Missing_opEndpointSig() {
  473. $this->missingSignedTest(
  474. array('ns' => Auth_OpenID_OPENID2_NS,
  475. 'return_to' =>'return',
  476. 'assoc_handle' =>'assoc handle',
  477. 'sig' =>'a signature',
  478. 'identity' =>'someone',
  479. 'op_endpoint' => 'the endpoint',
  480. 'signed' => 'identity,return_to,assoc_handle'));
  481. }
  482. function test_openid1Missing_identitySig() {
  483. $this->missingSignedTest(
  484. array('return_to' =>'return',
  485. 'assoc_handle' =>'assoc handle',
  486. 'sig' =>'a signature',
  487. 'identity' =>'someone',
  488. 'signed' => 'eturn_to'));
  489. }
  490. function test_openid1MissingReturnTo() {
  491. $this->missingFieldTest(
  492. array('assoc_handle' =>'assoc handle',
  493. 'sig' =>'a signature',
  494. 'identity' =>'someone',
  495. 'signed' => 'return_to,identity'));
  496. }
  497. function test_openid1MissingAssocHandle() {
  498. $this->missingFieldTest(
  499. array('return_to' =>'return',
  500. 'sig' =>'a signature',
  501. 'identity' =>'someone',
  502. 'signed' => 'return_to,identity'
  503. ));
  504. }
  505. }
  506. define('E_CHECK_AUTH_HAPPENED', 'checkauth occurred');
  507. define('E_MOCK_FETCHER_EXCEPTION', 'mock fetcher exception');
  508. define('E_ASSERTION_ERROR', 'assertion error');
  509. class _CheckAuthDetectingConsumer extends ConfigurableConsumer {
  510. function _verifyDiscoveryResults($message, $endpoint)
  511. {
  512. return $endpoint;
  513. }
  514. function _idResCheckNonce($message, $endpoint)
  515. {
  516. return true;
  517. }
  518. function _checkAuth($query, $server_url)
  519. {
  520. __raiseError(E_CHECK_AUTH_HAPPENED);
  521. }
  522. }
  523. global $GOODSIG;
  524. $GOODSIG = "[A Good Signature]";
  525. class GoodAssociation {
  526. var $expiresIn = 3600;
  527. var $handle = "-blah-";
  528. function getExpiresIn()
  529. {
  530. return $this->expiresIn;
  531. }
  532. function checkMessageSignature($message)
  533. {
  534. global $GOODSIG;
  535. return $message->getArg(Auth_OpenID_OPENID_NS, 'sig') == $GOODSIG;
  536. }
  537. }
  538. class GoodAssocStore extends Tests_Auth_OpenID_MemStore {
  539. function getAssociation($server_url, $handle = null)
  540. {
  541. return new GoodAssociation();
  542. }
  543. }
  544. class TestIdResCheckSignature extends _TestIdRes {
  545. function setUp()
  546. {
  547. global $GOODSIG;
  548. parent::setUp();
  549. $this->assoc = new GoodAssociation();
  550. $this->assoc->handle = "{not_dumb}";
  551. $this->store->storeAssociation($this->endpoint->server_url, $this->assoc);
  552. $this->message = Auth_OpenID_Message::fromPostArgs(array(
  553. 'openid.mode'=> 'id_res',
  554. 'openid.identity'=> '=example',
  555. 'openid.sig'=> $GOODSIG,
  556. 'openid.assoc_handle'=> $this->assoc->handle,
  557. 'openid.signed'=> 'mode,identity,assoc_handle,signed',
  558. 'frobboz'=> 'banzit'));
  559. }
  560. function test_sign()
  561. {
  562. // assoc_handle to assoc with good sig
  563. $this->consumer->_idResCheckSignature($this->message,
  564. $this->endpoint->server_url);
  565. }
  566. function test_signFailsWithBadSig()
  567. {
  568. $this->message.setArg(Auth_OpenID_OPENID_NS, 'sig', 'BAD SIGNATURE');
  569. $result = $this->consumer->_idResCheckSignature($this->message, $this->endpoint->server_url);
  570. $this->assertTrue(Auth_OpenID::isFailure($result));
  571. }
  572. }
  573. class StatelessConsumer1 extends ConfigurableConsumer {
  574. function _processCheckAuthResponse($response, $server_url)
  575. {
  576. return true;
  577. }
  578. function _makeKVPost($args, $server_url)
  579. {
  580. return array();
  581. }
  582. }
  583. class Tests_Auth_OpenID_Stateless1 extends _TestIdRes {
  584. var $consumer_class = "StatelessConsumer1";
  585. function setUp()
  586. {
  587. global $GOODSIG;
  588. parent::setUp();
  589. $this->assoc = new GoodAssociation();
  590. $this->assoc->handle = "{not_dumb}";
  591. $this->store->storeAssociation($this->endpoint->server_url, $this->assoc);
  592. $this->message = Auth_OpenID_Message::fromPostArgs(array(
  593. 'openid.mode'=> 'id_res',
  594. 'openid.identity'=> '=example',
  595. 'openid.sig'=> $GOODSIG,
  596. 'openid.assoc_handle'=> $this->assoc->handle,
  597. 'openid.signed'=> 'mode,identity,assoc_handle,signed',
  598. 'frobboz'=> 'banzit'));
  599. }
  600. function test_stateless()
  601. {
  602. // assoc_handle missing assoc, consumer._checkAuth returns
  603. // goodthings
  604. $this->message->setArg(Auth_OpenID_OPENID_NS, "assoc_handle", "dumbHandle");
  605. $this->consumer->_idResCheckSignature($this->message,
  606. $this->endpoint->server_url);
  607. }
  608. }
  609. class StatelessConsumer2 extends ConfigurableConsumer {
  610. function _checkAuth($_, $__)
  611. {
  612. return false;
  613. }
  614. }
  615. class Tests_Auth_OpenID_Stateless2 extends _TestIdRes {
  616. var $consumer_class = "StatelessConsumer2";
  617. function setUp()
  618. {
  619. global $GOODSIG;
  620. parent::setUp();
  621. $this->assoc = new GoodAssociation();
  622. $this->assoc->handle = "{not_dumb}";
  623. $this->store->storeAssociation($this->endpoint->server_url, $this->assoc);
  624. $this->message = Auth_OpenID_Message::fromPostArgs(array(
  625. 'openid.mode'=> 'id_res',
  626. 'openid.identity'=> '=example',
  627. 'openid.sig'=> $GOODSIG,
  628. 'openid.assoc_handle'=> $this->assoc->handle,
  629. 'openid.signed'=> 'mode,identity,assoc_handle,signed',
  630. 'frobboz'=> 'banzit'));
  631. }
  632. function test_statelessRaisesError()
  633. {
  634. // assoc_handle missing assoc, consumer._checkAuth returns
  635. // goodthings
  636. $this->message->setArg(Auth_OpenID_OPENID_NS, "assoc_handle",
  637. "dumbHandle");
  638. $result = $this->consumer->_idResCheckSignature($this->message,
  639. $this->endpoint->server_url);
  640. $this->assertTrue(Auth_OpenID::isFailure($result));
  641. }
  642. }
  643. class Tests_Auth_OpenID_Consumer_CheckNonceTest extends _TestIdRes {
  644. function setUp()
  645. {
  646. parent::setUp();
  647. $this->consumer->openid1_nonce_query_arg_name = 'nonce';
  648. }
  649. function test_openid1Success()
  650. {
  651. // use consumer-generated nonce
  652. $nonce_value = Auth_OpenID_mkNonce();
  653. $this->return_to = sprintf('http://rt.unittest/?nonce=%s',
  654. $nonce_value);
  655. $this->response = Auth_OpenID_Message::fromOpenIDArgs(
  656. array('return_to' => $this->return_to));
  657. $this->response->setArg(Auth_OpenID_BARE_NS, 'nonce', $nonce_value);
  658. $result = $this->consumer->_idResCheckNonce($this->response, $this->endpoint);
  659. $this->assertFalse(Auth_OpenID::isFailure($result));
  660. }
  661. function test_openid1Missing()
  662. {
  663. // use consumer-generated nonce
  664. $this->response = Auth_OpenID_Message::fromOpenIDArgs(array());
  665. $n = $this->consumer->_idResGetNonceOpenID1($this->response, $this->endpoint);
  666. $this->assertTrue($n === null);
  667. }
  668. function test_consumerNonceOpenID2()
  669. {
  670. // OpenID 2 does not use consumer-generated nonce
  671. $this->return_to = sprintf('http://rt.unittest/?nonce=%s',
  672. Auth_OpenID_mkNonce());
  673. $this->response = Auth_OpenID_Message::fromOpenIDArgs(
  674. array('return_to' => $this->return_to,
  675. 'ns' => Auth_OpenID_OPENID2_NS));
  676. $result = $this->consumer->_idResCheckNonce($this->response, $this->endpoint);
  677. $this->assertTrue(Auth_OpenID::isFailure($result));
  678. }
  679. function test_serverNonce()
  680. {
  681. // use server-generated nonce
  682. $this->response = Auth_OpenID_Message::fromOpenIDArgs(
  683. array('ns' => Auth_OpenID_OPENID2_NS,
  684. 'response_nonce' => Auth_OpenID_mkNonce()));
  685. $this->consumer->_idResCheckNonce($this->response, $this->endpoint);
  686. }
  687. function test_serverNonceOpenID1()
  688. {
  689. // OpenID 1 does not use server-generated nonce
  690. $this->response = Auth_OpenID_Message::fromOpenIDArgs(
  691. array('ns' => Auth_OpenID_OPENID1_NS,
  692. 'return_to'=> 'http://return.to/',
  693. 'response_nonce'=> Auth_OpenID_mkNonce()));
  694. $result = $this->consumer->_idResCheckNonce($this->response, $this->endpoint);
  695. $this->assertTrue(Auth_OpenID::isFailure($result));
  696. }
  697. function test_badNonce()
  698. {
  699. // remove the nonce from the store
  700. $nonce = Auth_OpenID_mkNonce();
  701. list($timestamp, $salt) = Auth_OpenID_splitNonce($nonce);
  702. $this->store->useNonce($this->server_url, $timestamp, $salt);
  703. $response = Auth_OpenID_Message::fromOpenIDArgs(array(
  704. 'response_nonce' => $nonce,
  705. 'ns' => Auth_OpenID_OPENID2_NS
  706. ));
  707. $result = $this->consumer->_idResCheckNonce($response,
  708. $this->endpoint);
  709. $this->assertTrue(Auth_OpenID::isFailure($result));
  710. }
  711. function test_tamperedNonce()
  712. {
  713. // Malformed nonce
  714. $query = array('response_nonce' => 'malformed',
  715. 'ns' => Auth_OpenID_OPENID2_NS);
  716. $message = Auth_OpenID_Message::fromPostArgs($query);
  717. $result = $this->consumer->_idResCheckNonce($message,
  718. $this->endpoint);
  719. $this->assertTrue(Auth_OpenID::isFailure($result));
  720. }
  721. function test_missingNonce()
  722. {
  723. // no nonce parameter on the return_to
  724. $query = array('openid.return_to' => $this->return_to);
  725. $message = Auth_OpenID_Message::fromPostArgs($query);
  726. $result = $this->consumer->_idResCheckNonce($message,
  727. $this->endpoint);
  728. $this->assertTrue(Auth_OpenID::isFailure($result));
  729. }
  730. }
  731. class Tests_Auth_OpenID_Consumer_TestCheckAuthTriggered extends _TestIdRes {
  732. var $consumer_class = '_CheckAuthDetectingConsumer';
  733. function _doIdRes($message, $endpoint, $return_to)
  734. {
  735. return $this->consumer->_doIdRes($message, $endpoint, $return_to);
  736. }
  737. function test_checkAuthTriggered()
  738. {
  739. $query = array('openid.return_to' => $this->return_to,
  740. 'openid.identity' => $this->server_id,
  741. 'openid.assoc_handle' =>'not_found',
  742. 'openid.sig' => 'bogus',
  743. 'openid.signed' => 'identity,return_to');
  744. $message = Auth_OpenID_Message::fromPostArgs($query);
  745. $this->consumer->disableReturnToChecking();
  746. $result = $this->_doIdRes($message, $this->endpoint, null);
  747. $error = __getError();
  748. if ($error === null) {
  749. $this->fail('_checkAuth did not happen.');
  750. }
  751. }
  752. function test_checkAuthTriggeredWithAssoc()
  753. {
  754. // Store an association for this server that does not match
  755. // the handle that is in the query
  756. $issued = time();
  757. $lifetime = 1000;
  758. $assoc = new Auth_OpenID_Association(
  759. 'handle', 'secret', $issued, $lifetime, 'HMAC-SHA1');
  760. $this->store->storeAssociation($this->server_url, $assoc);
  761. $query = array(
  762. 'openid.return_to' => $this->return_to,
  763. 'openid.identity' => $this->server_id,
  764. 'openid.assoc_handle' => 'not_found',
  765. 'openid.sig' => 'bogus',
  766. 'openid.signed' => 'return_to,identity');
  767. $this->consumer->disableReturnToChecking();
  768. $message = Auth_OpenID_Message::fromPostArgs($query);
  769. $result = $this->_doIdRes($message, $this->endpoint, null);
  770. $error = __getError();
  771. if ($error === null) {
  772. $this->fail('_checkAuth did not happen.');
  773. }
  774. }
  775. function test_expiredAssoc()
  776. {
  777. // Store an expired association for the server with the handle
  778. // that is in the query
  779. $issued = time() - 10;
  780. $lifetime = 0;
  781. $handle = 'handle';
  782. $assoc = new Auth_OpenID_Association(
  783. $handle, 'secret', $issued, $lifetime, 'HMAC-SHA1');
  784. $this->assertTrue($assoc->getExpiresIn() <= 0);
  785. $this->store->storeAssociation($this->server_url, $assoc);
  786. $query = array(
  787. 'openid.return_to' => $this->return_to,
  788. 'openid.identity' => $this->server_id,
  789. 'openid.sig' => 'bogus',
  790. 'openid.signed' => 'identity,return_to',
  791. 'openid.assoc_handle' => $handle);
  792. $message = Auth_OpenID_Message::fromPostArgs($query);
  793. $this->consumer->disableReturnToChecking();
  794. $info = $this->_doIdRes($message, $this->endpoint, null);
  795. $this->assertEquals('failure', $info->status);
  796. $this->assertTrue(strpos($info->message, 'expired') !== false);
  797. }
  798. function test_newerAssoc()
  799. {
  800. // Store an expired association for the server with the handle
  801. // that is in the query
  802. $lifetime = 1000;
  803. $good_issued = time() - 10;
  804. $good_handle = 'handle';
  805. $good_assoc = new Auth_OpenID_Association(
  806. $good_handle, 'secret', $good_issued, $lifetime, 'HMAC-SHA1');
  807. $this->store->storeAssociation($this->server_url, $good_assoc);
  808. $bad_issued = time() - 5;
  809. $bad_handle = 'handle2';
  810. $bad_assoc = new Auth_OpenID_Association(
  811. $bad_handle, 'secret', $bad_issued, $lifetime, 'HMAC-SHA1');
  812. $this->store->storeAssociation($this->server_url, $bad_assoc);
  813. $query = array(
  814. 'openid.return_to' => $this->return_to,
  815. 'openid.identity' => $this->server_id,
  816. 'openid.assoc_handle' => $good_handle);
  817. $this->consumer->disableReturnToChecking();
  818. $message = Auth_OpenID_Message::fromPostArgs($query);
  819. $message = $good_assoc->signMessage($message);
  820. $info = $this->_doIdRes($message, $this->endpoint, null);
  821. $this->assertEquals($info->status, 'success');
  822. $this->assertEquals($this->consumer_id, $info->identity_url);
  823. }
  824. }
  825. class _MockFetcher {
  826. function _MockFetcher($response = null)
  827. {
  828. // response is (code, url, body)
  829. $this->response = $response;
  830. $this->fetches = array();
  831. }
  832. function post($url, $body)
  833. {
  834. $this->fetches[] = array($url, $body, array());
  835. return $this->response;
  836. }
  837. function get($url)
  838. {
  839. $this->fetches[] = array($url, null, array());
  840. return $this->response;
  841. }
  842. }
  843. class Tests_Auth_OpenID_Complete extends _TestIdRes {
  844. function test_cancel()
  845. {
  846. $query = array('openid.mode' => 'cancel');
  847. $message = Auth_OpenID_Message::fromPostArgs($query);
  848. $this->consumer->disableReturnToChecking();
  849. $r = $this->consumer->complete($message, $this->endpoint, null);
  850. $this->assertEquals($r->status, Auth_OpenID_CANCEL);
  851. $this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
  852. }
  853. function test_cancel_with_return_to() {
  854. $message = Auth_OpenID_Message::fromPostArgs(array('openid.mode' => 'cancel'));
  855. $r = $this->consumer->complete($message, $this->endpoint, $this->return_to);
  856. $this->assertEquals($r->status, Auth_OpenID_CANCEL);
  857. $this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
  858. }
  859. function test_errorWithNoOptionalKeys()
  860. {
  861. $msg = 'an error message';
  862. $contact = 'some contact info here';
  863. $message = Auth_OpenID_Message::fromPostArgs(array('openid.mode'=> 'error',
  864. 'openid.error'=> $msg,
  865. 'openid.contact'=> $contact));
  866. $this->consumer->disableReturnToChecking();
  867. $r = $this->consumer->complete($message, $this->endpoint, null);
  868. $this->assertEquals($r->status, Auth_OpenID_FAILURE);
  869. $this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
  870. $this->assertTrue($r->contact == $contact);
  871. $this->assertTrue($r->reference === null);
  872. $this->assertEquals($r->message, $msg);
  873. }
  874. function test_errorWithOptionalKeys()
  875. {
  876. $msg = 'an error message';
  877. $contact = 'me';
  878. $reference = 'support ticket';
  879. $message = Auth_OpenID_Message::fromPostArgs(array('openid.mode'=> 'error',
  880. 'openid.error'=> $msg, 'openid.reference'=> $reference,
  881. 'openid.contact'=> $contact, 'openid.ns'=> Auth_OpenID_OPENID2_NS
  882. ));
  883. $r = $this->consumer->complete($message, $this->endpoint, null);
  884. $this->assertEquals($r->status, Auth_OpenID_FAILURE);
  885. $this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
  886. $this->assertTrue($r->contact == $contact);
  887. $this->assertTrue($r->reference == $reference);
  888. $this->assertEquals($r->message, $msg);
  889. }
  890. function test_error()
  891. {
  892. $msg = 'an error message';
  893. $query = array('openid.mode' =>'error',
  894. 'openid.error' => $msg);
  895. $message = Auth_OpenID_Message::fromPostArgs($query);
  896. $this->consumer->disableReturnToChecking();
  897. $r = $this->consumer->complete($message, $this->endpoint, null);
  898. $this->assertEquals($r->status, Auth_OpenID_FAILURE);
  899. $this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
  900. $this->assertEquals($r->message, $msg);
  901. }
  902. function test_noMode()
  903. {
  904. $query = array();
  905. $message = Auth_OpenID_Message::fromPostArgs($query);
  906. $r = $this->consumer->complete($message, $this->endpoint, null);
  907. $this->assertEquals($r->status, Auth_OpenID_FAILURE);
  908. $this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
  909. }
  910. function test_idResMissingField()
  911. {
  912. $query = array('openid.mode' => 'id_res');
  913. $message = Auth_OpenID_Message::fromPostArgs($query);
  914. $r = $this->consumer->complete($message, $this->endpoint, null);
  915. $this->assertTrue(Auth_openID::isFailure($r));
  916. }
  917. }
  918. class _VerifiedError extends Auth_OpenID_FailureResponse {
  919. }
  920. class Consumer_idResURLMismatch extends ConfigurableConsumer {
  921. function _discoverAndVerify($to_match)
  922. {
  923. return new _VerifiedError(null, 'verified error');
  924. }
  925. }
  926. class Tests_idResURLMismatch extends _TestIdRes {
  927. var $consumer_class = 'Consumer_idResURLMismatch';
  928. function test_idResURLMismatch()
  929. {
  930. $query = array('openid.mode' => 'id_res',
  931. 'openid.return_to' => 'return_to (just anything)',
  932. 'openid.identity' => 'something wrong (not this->consumer_id)',
  933. 'openid.assoc_handle' => 'does not matter',
  934. 'openid.signed' => 'identity,return_to',
  935. 'openid.sig' => 'bogus');
  936. $this->consumer->disableReturnToChecking();
  937. $message = Auth_OpenID_Message::fromPostArgs($query);
  938. $r = $this->consumer->complete($message, $this->endpoint, null);
  939. $this->assertTrue(is_a($r, '_VerifiedError'));
  940. }
  941. }
  942. class SetupNeededConsumer extends Auth_OpenID_GenericConsumer {
  943. function _checkSetupNeeded($message)
  944. {
  945. return true;
  946. }
  947. }
  948. class Tests_Auth_OpenID_SetupNeeded extends _TestIdRes {
  949. function test_setupNeededIdRes()
  950. {
  951. $message = Auth_OpenID_Message::fromOpenIDArgs(array('mode'=> 'id_res'));
  952. $response = $this->consumer->complete($message, null, null);
  953. $this->assertEquals(Auth_OpenID_SETUP_NEEDED,
  954. $response->status);
  955. }
  956. }
  957. class TempConsumer extends ConfigurableConsumer {
  958. function _verifyDiscoveryResults($message, $endpoint)
  959. {
  960. return $endpoint;
  961. }
  962. }
  963. class TestCompleteMissingSig extends PHPUnit_TestCase {
  964. function setUp()
  965. {
  966. global $GOODSIG;
  967. $this->store = new GoodAssocStore();
  968. $this->consumer = new ConfigurableConsumer($this->store);
  969. $this->server_url = "http://idp.unittest/";
  970. $claimed_id = 'bogus.claimed';
  971. $this->message = Auth_OpenID_Message::fromOpenIDArgs(
  972. array('mode'=> 'id_res',
  973. 'return_to'=> 'return_to (just anything)',
  974. 'identity'=> $claimed_id,
  975. 'assoc_handle'=> 'does not matter',
  976. 'sig'=> $GOODSIG,
  977. 'response_nonce'=> Auth_OpenID_mkNonce(),
  978. 'signed'=> 'identity,return_to,response_nonce,assoc_handle,claimed_id,op_endpoint',
  979. 'claimed_id'=> $claimed_id,
  980. 'op_endpoint'=> $this->server_url,
  981. 'ns' => Auth_OpenID_OPENID2_NS));
  982. $this->endpoint = new Auth_OpenID_ServiceEndpoint();
  983. $this->endpoint->server_url = $this->server_url;
  984. $this->endpoint->claimed_id = $claimed_id;
  985. $this->consumer->disableReturnToChecking();
  986. }
  987. function test_idResMissingNoSigs()
  988. {
  989. $c = new TempConsumer($this->store);
  990. $c->disableReturnToChecking();
  991. $r = $c->complete($this->message, $this->endpoint, null);
  992. $this->failUnlessSuccess($r);
  993. }
  994. function test_idResNoIdentity()
  995. {
  996. $this->message->delArg(Auth_OpenID_OPENID_NS, 'identity');
  997. $this->message->delArg(Auth_OpenID_OPENID_NS, 'claimed_id');
  998. $this->endpoint->claimed_id = null;
  999. $this->message->setArg(Auth_OpenID_OPENID_NS,
  1000. 'signed', 'return_to,response_nonce,assoc_handle,op_endpoint');
  1001. $r = $this->consumer->complete($this->message, $this->endpoint, null);
  1002. $this->failUnlessSuccess($r);
  1003. }
  1004. function test_idResMissingIdentitySig()
  1005. {
  1006. $this->message->setArg(Auth_OpenID_OPENID_NS,
  1007. 'signed',
  1008. 'return_to,response_nonce,assoc_handle,claimed_id,op_endpoint');
  1009. $r = $this->consumer->complete($this->message, $this->endpoint, null);
  1010. $this->assertEquals($r->status, Auth_OpenID_FAILURE);
  1011. }
  1012. function test_idResMissingReturnToSig()
  1013. {
  1014. $this->message->setArg(Auth_OpenID_OPENID_NS,
  1015. 'signed',
  1016. 'identity,response_nonce,assoc_handle,claimed_id');
  1017. $r = $this->consumer->complete($this->message, $this->endpoint, null);
  1018. $this->assertEquals($r->status, Auth_OpenID_FAILURE);
  1019. }
  1020. function test_idResMissingAssocHandleSig()
  1021. {
  1022. $this->message->setArg(Auth_OpenID_OPENID_NS, 'signed',
  1023. 'identity,response_nonce,return_to,claimed_id');
  1024. $r = $this->consumer->complete($this->message, $this->endpoint, null);
  1025. $this->assertEquals($r->status, Auth_OpenID_FAILURE);
  1026. }
  1027. function test_idResMissingClaimedIDSig()
  1028. {
  1029. $this->message->setArg(Auth_OpenID_OPENID_NS, 'signed',
  1030. 'identity,response_nonce,return_to,assoc_handle');
  1031. $r = $this->consumer->complete($this->message, $this->endpoint, null);
  1032. $this->assertEquals($r->status, Auth_OpenID_FAILURE);
  1033. }
  1034. function failUnlessSuccess($response)
  1035. {
  1036. if ($response->status != Auth_OpenID_SUCCESS) {
  1037. $this->fail(sprintf("Non-successful response: %s", $response->status));
  1038. }
  1039. }
  1040. }
  1041. class TestReturnToArgs extends PHPUnit_TestCase {
  1042. function setUp()
  1043. {
  1044. $store = null;
  1045. $this->consumer = new Auth_OpenID_GenericConsumer($store);
  1046. }
  1047. function test_returnToArgsUnexpectedArg()
  1048. {
  1049. $query = array(
  1050. 'openid.mode' => 'id_res',
  1051. 'openid.return_to' => 'http://example.com/',
  1052. 'foo' => 'bar');
  1053. // no return value, success is assumed if there are no
  1054. // exceptions.
  1055. $this->assertTrue(Auth_OpenID::isFailure(
  1056. $this->consumer->_verifyReturnToArgs($query)));
  1057. }
  1058. function test_returnToArgsOkay()
  1059. {
  1060. $query = array(
  1061. 'openid.mode'=> 'id_res',
  1062. 'openid.return_to'=> 'http://example.com/?foo=bar',
  1063. 'foo'=> 'bar'
  1064. );
  1065. // no return value, success is assumed if there are no exceptions.
  1066. $result = $this->consumer->_verifyReturnToArgs($query);
  1067. $this->assertFalse(Auth_OpenID::isFailure($result));
  1068. $this->assertTrue($result);
  1069. }
  1070. function test_returnToMismatch()
  1071. {
  1072. $query = array(
  1073. 'openid.mode' => 'id_res',
  1074. 'openid.return_to' => 'http://example.com/?foo=bar');
  1075. // fail, query has no key 'foo'.
  1076. $result = $this->consumer->_verifyReturnToArgs($query);
  1077. $this->assertTrue(Auth_OpenID::isFailure($result));
  1078. $query['foo'] = 'baz';
  1079. // fail, values for 'foo' do not match.
  1080. $result = $this->consumer->_verifyReturnToArgs($query);
  1081. $this->assertTrue(Auth_OpenID::isFailure($result));
  1082. }
  1083. function test_noReturnTo()
  1084. {
  1085. $query = array('openid.mode'=> 'id_res');
  1086. $result = $this->consumer->_verifyReturnToArgs($query);
  1087. $this->assertTrue(Auth_OpenID::isFailure($result));
  1088. }
  1089. function test_completeBadReturnTo()
  1090. {
  1091. // Test GenericConsumer.complete()'s handling of bad return_to
  1092. // values.
  1093. $return_to = "http://some.url/path?foo=bar";
  1094. // Scheme, authority, and path differences are checked by
  1095. // GenericConsumer._checkReturnTo. Query args checked by
  1096. // GenericConsumer._verifyReturnToArgs.
  1097. $bad_return_tos = array(
  1098. // Scheme only
  1099. "https://some.url/path?foo=bar",
  1100. // Authority only
  1101. "http://some.url.invalid/path?foo=bar",
  1102. // Path only
  1103. "http://some.url/path_extra?foo=bar",
  1104. // Query args differ
  1105. "http://some.url/path?foo=bar2",
  1106. "http://some.url/path?foo2=bar"
  1107. );
  1108. $m = new Auth_OpenID_Message(Auth_OpenID_OPENID1_NS);
  1109. $m->setArg(Auth_OpenID_OPENID_NS, 'mode', 'cancel');
  1110. $m->setArg(Auth_OpenID_BARE_NS, 'foo', 'bar');
  1111. $endpoint = null;
  1112. foreach ($bad_return_tos as $bad) {
  1113. $m->setArg(Auth_OpenID_OPENID_NS, 'return_to', $bad);
  1114. $this->assertFalse($this->consumer->_checkReturnTo($m, $return_to));
  1115. }
  1116. }
  1117. function test_completeGoodReturnTo()
  1118. {
  1119. // Test GenericConsumer.complete()'s handling of good
  1120. // return_to values.
  1121. $return_to = "http://some.url/path";
  1122. $good_return_tos = array(
  1123. array($return_to,
  1124. array()),
  1125. array($return_to . "?another=arg",
  1126. array(array(
  1127. array(Auth_OpenID_BARE_NS, 'another'),
  1128. 'arg'))),
  1129. array($return_to . "?another=arg#fragment",
  1130. array(array(
  1131. array(Auth_OpenID_BARE_NS, 'another'),
  1132. 'arg'))),
  1133. array("HTTP://some.url/path",array()),
  1134. array("http://some.URL/path",array()),
  1135. array("http://some.url:80/path",array()),
  1136. array("http://some.url/./path",array())
  1137. );
  1138. $endpoint = null;
  1139. foreach ($good_return_tos as $pair) {
  1140. list($good_return_to, $extra) = $pair;
  1141. $m = new Auth_OpenID_Message(Auth_OpenID_OPENID1_NS);
  1142. $m->setArg(Auth_OpenID_OPENID_NS, 'mode', 'cancel');
  1143. for ($i = 0; $i < count($extra); $i++) {
  1144. list($ckey, $value) = $extra[$i];
  1145. $ns = $ckey[0];
  1146. $key = $ckey[1];
  1147. $m->setArg($ns, $key, $value);
  1148. }
  1149. $m->setArg(Auth_OpenID_OPENID_NS, 'return_to', $good_return_to);
  1150. $result = $this->consumer->complete($m, $endpoint, $return_to);
  1151. $this->assertTrue(is_a($result, 'Auth_OpenID_CancelResponse'));
  1152. }
  1153. }
  1154. }
  1155. class Tests_Auth_OpenID_CheckAuthResponse extends _TestIdRes {
  1156. function _createAssoc()
  1157. {
  1158. $issued = time();
  1159. $lifetime = 1000;
  1160. $assoc = new Auth_OpenID_Association(
  1161. 'handle', 'secret', $issued, $lifetime, 'HMAC-SHA1');
  1162. $store =& $this->consumer->store;
  1163. $store->storeAssociation($this->server_url, $assoc);
  1164. $assoc2 = $store->getAssociation($this->server_url);
  1165. $this->assertEquals($assoc, $assoc2);
  1166. }
  1167. function test_goodResponse()
  1168. {
  1169. // successful response to check_authentication
  1170. $response = array('is_valid' => 'true');
  1171. $message = Auth_OpenID_Message::fromOpenIDArgs($response);
  1172. $r = $this->consumer->_processCheckAuthResponse($message, $this->server_url);
  1173. $this->assertTrue($r);
  1174. }
  1175. function test_missingAnswer()
  1176. {
  1177. // check_authentication returns false when the server sends no
  1178. // answer
  1179. $response = array();
  1180. $message = Auth_OpenID_Message::fromPostArgs($response);
  1181. $r = $this->consumer->_processCheckAuthResponse($message, $this->server_url);
  1182. $this->assertFalse($r);
  1183. }
  1184. function test_badResponse()
  1185. {
  1186. // check_authentication returns false when is_valid is false
  1187. $response = array('is_valid' => 'false');
  1188. $message = Auth_OpenID_Message::fromOpenIDArgs($response);
  1189. $r = $this->consumer->_processCheckAuthResponse($message, $this->server_url);
  1190. $this->assertFalse($r);
  1191. }
  1192. function test_badResponseInvalidate()
  1193. {
  1194. // Make sure that the handle is invalidated when is_valid is
  1195. // false
  1196. $this->_createAssoc();
  1197. $response = array('is_valid' => 'false',
  1198. 'invalidate_handle' => 'handle');
  1199. $message = Auth_OpenID_Message::fromOpenIDArgs($response);
  1200. $r = $this->consumer->_processCheckAuthResponse($message,
  1201. $this->server_url);
  1202. $this->assertFalse($r);
  1203. $this->assertTrue(
  1204. $this->consumer->store->getAssociation($this->server_url) === null);
  1205. }
  1206. function test_invalidateMissing()
  1207. {
  1208. // invalidate_handle with a handle that is not present
  1209. $response = array('is_valid' => 'true',
  1210. 'invalidate_handle' => 'missing');
  1211. $message = Auth_OpenID_Message::fromOpenIDArgs($response);
  1212. $r = $this->consumer->_processCheckAuthResponse($message, $this->server_url);
  1213. $this->assertTrue($r);
  1214. }
  1215. function test_invalidatePresent()
  1216. {
  1217. // invalidate_handle with a handle that exists"""
  1218. $this->_createAssoc();
  1219. $response = array('is_valid' => 'true',
  1220. 'invalidate_handle' => 'handle');
  1221. $message = Auth_OpenID_Message::fromOpenIDArgs($response);
  1222. $r = $this->consumer->_processCheckAuthResponse($message, $this->server_url);
  1223. $this->assertTrue($r);
  1224. $this->assertTrue(
  1225. $this->consumer->store->getAssociation($this->server_url) === null);
  1226. }
  1227. }
  1228. class _IdResFetchFailingConsumer extends Auth_OpenID_GenericConsumer {
  1229. var $message = 'fetch failed';
  1230. function _doIdRes($message, $endpoint)
  1231. {
  1232. return new Auth_OpenID_FailureResponse($endpoint,
  1233. $this->message);
  1234. }
  1235. }
  1236. class Tests_Auth_OpenID_FetchErrorInIdRes extends _TestIdRes {
  1237. var $consumer_class = '_IdResFetchFailingConsumer';
  1238. function test_idResFailure()
  1239. {
  1240. $query = array('openid.mode' => 'id_res');
  1241. $message = Auth_OpenID_Message::fromPostArgs($query);
  1242. $r = $this->consumer->complete($message, $this->endpoint, null);
  1243. $this->assertEquals($r->status, Auth_OpenID_FAILURE);
  1244. $this->assertEquals($r->identity_url, $this->consumer_id);
  1245. $this->assertEquals($this->consumer->message, $r->message);
  1246. }
  1247. }
  1248. class _ExceptionRaisingMockFetcher {
  1249. function get($url)
  1250. {
  1251. __raiseError(E_MOCK_FETCHER_EXCEPTION);
  1252. }
  1253. function post($url, $body)
  1254. {
  1255. __raiseError(E_MOCK_FETCHER_EXCEPTION);
  1256. return new Auth_Yadis_HTTPResponse($url, 400,
  1257. array(), '');
  1258. }
  1259. }
  1260. class _BadArgCheckingConsumer extends Auth_OpenID_GenericConsumer {
  1261. function _makeKVPost($message, $tmp)
  1262. {
  1263. $args = $message->toPostArgs();
  1264. if ($args != array(
  1265. 'openid.mode' => 'check_authentication',
  1266. 'openid.signed' => 'foo')) {
  1267. __raiseError(E_ASSERTION_ERROR);
  1268. }
  1269. return null;
  1270. }
  1271. }
  1272. class Tests_Auth_OpenID_Consumer_TestCheckAuth extends _TestIdRes {
  1273. function setUp()
  1274. {
  1275. $this->store = new Tests_Auth_OpenID_MemStore();
  1276. $this->consumer = new Auth_OpenID_GenericConsumer($this->store);
  1277. $this->fetcher = new _MockFetcher();
  1278. $this->consumer->fetcher =& $this->fetcher;
  1279. }
  1280. function test_checkauth_error()
  1281. {
  1282. global $_Auth_OpenID_server_url;
  1283. $this->fetcher->response = new Auth_Yadis_HTTPResponse("http://some_url",
  1284. 404,
  1285. array(),
  1286. "blah:blah\n");
  1287. $query = array('openid.signed' => 'stuff, things');
  1288. $message = Auth_OpenID_Message::fromPostArgs($query);
  1289. $r = $this->consumer->_checkAuth($message, $_Auth_OpenID_server_url);
  1290. if ($r !== false) {
  1291. $this->fail("Expected _checkAuth result to be false");
  1292. }
  1293. }
  1294. function test_bad_args()
  1295. {
  1296. $query = array('openid.signed' => 'foo',
  1297. 'closid.foo' => 'something');
  1298. $consumer = new _BadArgCheckingConsumer($this->store);
  1299. $message = Auth_OpenID_Message::fromPostArgs($query);
  1300. $this->assertFalse($consumer->_checkAuth($message, 'does://not.matter'));
  1301. }
  1302. function test_signedList()
  1303. {
  1304. $signed = 'identity,mode,ns.sreg,sreg.email';
  1305. $query = Auth_OpenID_Message::fromOpenIDArgs(array(
  1306. 'mode'=> 'id_res',
  1307. 'sig'=> 'rabbits',
  1308. 'identity'=> '=example',
  1309. 'assoc_handle'=> 'munchkins',
  1310. 'ns.sreg' => 'urn:sreg',
  1311. 'sreg.email' => 'bogus@example.com',
  1312. 'signed'=> $signed,
  1313. 'foo'=> 'bar'));
  1314. $args = $this->consumer->_createCheckAuthRequest($query);
  1315. $this->assertTrue($args->isOpenID1());
  1316. $signed_list = explode(',',$signed);
  1317. foreach ($signed_list as $k) {
  1318. $this->assertTrue($args->getAliasedArg($k));
  1319. }
  1320. }
  1321. function test_112()
  1322. {
  1323. $args = array('openid.assoc_handle' => 'fa1f5ff0-cde4-11dc-a183-3714bfd55ca8',
  1324. 'openid.claimed_id' => 'http://binkley.lan/user/test01',
  1325. 'openid.identity' => 'http://test01.binkley.lan/',
  1326. 'openid.mode' => 'id_res',
  1327. 'openid.ns' => 'http://specs.openid.net/auth/2.0',
  1328. 'openid.ns.pape' => 'http://specs.openid.net/extensions/pape/1.0',
  1329. 'openid.op_endpoint' => 'http://binkley.lan/server',
  1330. 'openid.pape.auth_policies' => 'none',
  1331. 'openid.pape.auth_time' => '2008-01-28T20 =>42 =>36Z',
  1332. 'openid.pape.nist_auth_level' => '0',
  1333. 'openid.response_nonce' => '2008-01-28T21 =>07 =>04Z99Q=',
  1334. 'openid.return_to' => 'http://binkley.lan =>8001/process?janrain_nonce=2008-01-28T21%3A07%3A02Z0tMIKx',
  1335. 'openid.sig' => 'YJlWH4U6SroB1HoPkmEKx9AyGGg=',
  1336. 'openid.signed' => 'assoc_handle,identity,response_nonce,return_to,claimed_id,op_endpoint,pape.auth_time,ns.pape,pape.nist_auth_level,pape.auth_policies'
  1337. );
  1338. $this->assertEquals(Auth_OpenID_OPENID2_NS, $args['openid.ns']);
  1339. $incoming = Auth_OpenID_Message::fromPostArgs($args);
  1340. $this->assertTrue($incoming->isOpenID2());
  1341. $car = $this->consumer->_createCheckAuthRequest($incoming);
  1342. $expected_args = $args;
  1343. $expected_args['openid.mode'] = 'check_authentication';
  1344. $expected = Auth_OpenID_Message::fromPostArgs($expected_args);
  1345. $this->assertTrue($expected->isOpenID2());
  1346. $this->assertEquals($expected, $car);
  1347. $this->assertEquals($expected_args, $car->toPostArgs());
  1348. }
  1349. }
  1350. class Tests_Auth_OpenID_Consumer_TestFetchAssoc extends PHPUnit_TestCase {
  1351. function setUp()
  1352. {
  1353. $this->store = new Tests_Auth_OpenID_MemStore();
  1354. $this->fetcher = new _MockFetcher();
  1355. $this->consumer = new Auth_OpenID_GenericConsumer($this->store);
  1356. $this->consumer->fetcher =& $this->fetcher;
  1357. }
  1358. function test_kvpost_error()
  1359. {
  1360. $this->fetcher->response = new Auth_Yadis_HTTPResponse("http://some_url",
  1361. 404,
  1362. array(),
  1363. "blah:blah\n");
  1364. $query = array('openid.mode' => 'associate');
  1365. $message = Auth_OpenID_Message::fromPostArgs($query);
  1366. $r = $this->consumer->_makeKVPost($message,
  1367. "http://server_url");
  1368. if ($r !== null) {
  1369. $this->fail("Expected _makeKVPost result to be null");
  1370. }
  1371. }
  1372. function test_error_404()
  1373. {
  1374. // 404 from a kv post raises HTTPFetchingError
  1375. $this->fetcher->response = new Auth_Yadis_HTTPResponse(
  1376. "http://some_url", 404, array('Hea'=> 'der'), 'blah:blah\n');
  1377. $result = $this->consumer->_makeKVPost(
  1378. Auth_OpenID_Message::fromPostArgs(array('mode'=>'associate')),
  1379. "http://server_url");
  1380. $this->assertTrue($result === null);
  1381. }
  1382. function test_error_exception()
  1383. {
  1384. $this->consumer->fetcher = new _ExceptionRaisingMockFetcher();
  1385. $query = array('openid.mode' => 'associate');
  1386. $message = Auth_OpenID_Message::fromPostArgs($query);
  1387. $this->consumer->_makeKVPost($message,
  1388. "http://server_url");
  1389. if (__getError() !== E_MOCK_FETCHER_EXCEPTION) {
  1390. $this->fail("Expected ExceptionRaisingMockFetcher to " .
  1391. "raise E_MOCK_FETCHER_EXCEPTION");
  1392. }
  1393. $endpoint = new Auth_OpenID_ServiceEndpoint();
  1394. $endpoint->server_url = 'some://url';
  1395. // exception fetching returns no association
  1396. $this->assertEquals($this->consumer->_getAssociation($endpoint),
  1397. null);
  1398. $query = array('openid.signed' => '');
  1399. $message = Auth_OpenID_Message::fromPostArgs($query);
  1400. $this->consumer->_checkAuth($message,
  1401. 'some://url');
  1402. if (__getError() !== E_MOCK_FETCHER_EXCEPTION) {
  1403. $this->fail("Expected ExceptionRaisingMockFetcher to " .
  1404. "raise E_MOCK_FETCHER_EXCEPTION (_checkAuth)");
  1405. }
  1406. }
  1407. }
  1408. class Tests_Auth_OpenID_AuthRequestHTMLMarkup extends PHPUnit_TestCase {
  1409. function setUp()
  1410. {
  1411. $this->endpoint = new Auth_OpenID_ServiceEndpoint();
  1412. $this->endpoint->claimed_id = 'identity_url';
  1413. $this->request = new Auth_OpenID_AuthRequest($this->endpoint, null);
  1414. }
  1415. function test_htmlMarkup()
  1416. {
  1417. $html = $this->request->htmlMarkup('http://realm.com/',
  1418. 'http://realm.com/return_to');
  1419. $this->assertTrue(substr($html,"<html>") !== false);
  1420. $this->assertTrue(substr($html,"</html>") !== false);
  1421. $this->assertTrue(substr($html,"<body onload") !== false);
  1422. $this->assertTrue(substr($html,"</body>") !== false);
  1423. $this->assertTrue(substr($html,"<form") !== false);
  1424. $this->assertTrue(substr($html,"</form>") !== false);
  1425. }
  1426. }
  1427. class Tests_Auth_OpenID_SuccessResponse extends PHPUnit_TestCase {
  1428. function setUp()
  1429. {
  1430. $this->endpoint = new Auth_OpenID_ServiceEndpoint();
  1431. $this->endpoint->claimed_id = 'identity_url';
  1432. }
  1433. function test_extensionResponse()
  1434. {
  1435. $uri = "http://bogus.unittest/1.0";
  1436. $query = array(
  1437. 'openid.ns.unittest' => $uri,
  1438. 'openid.unittest.one' => '1',
  1439. 'openid.unittest.two' =>'2',
  1440. 'openid.sreg.nickname' => 'j3h',
  1441. 'openid.return_to' => 'return_to');
  1442. $message = Auth_OpenID_Message::fromPostArgs($query);
  1443. $resp = new Auth_OpenID_SuccessResponse($this->endpoint, $message);
  1444. $utargs = $resp->extensionResponse($uri, false);
  1445. $this->assertEquals($utargs, array('one' => '1', 'two' => '2'));
  1446. $sregargs = $resp->extensionResponse(Auth_OpenID_SREG_NS_URI, false);
  1447. $this->assertEquals($sregargs, array('nickname' => 'j3h'));
  1448. }
  1449. function test_extensionResponseSigned()
  1450. {
  1451. $args = array(
  1452. 'ns.sreg' => 'urn:sreg',
  1453. 'ns.unittest' => 'urn:unittest',
  1454. 'unittest.one' => '1',
  1455. 'unittest.two' => '2',
  1456. 'sreg.nickname' => 'j3h',
  1457. 'sreg.dob' => 'yesterday',
  1458. 'return_to' => 'return_to',
  1459. 'signed' => 'sreg.nickname,unittest.one,sreg.dob');
  1460. $signed_list = array('openid.sreg.nickname',
  1461. 'openid.unittest.one',
  1462. 'openid.sreg.dob',
  1463. 'openid.ns.sreg');
  1464. $msg = Auth_OpenID_Message::fromOpenIDArgs($args);
  1465. $resp = new Auth_OpenID_SuccessResponse($this->endpoint, $msg, $signed_list);
  1466. // All args in this NS are signed, so expect all.
  1467. $sregargs = $resp->extensionResponse('urn:sreg', true);
  1468. $this->assertEquals($sregargs,
  1469. array('nickname' => 'j3h',
  1470. 'dob' => 'yesterday'));
  1471. // Not all args in this NS are signed, so expect null when
  1472. // asking for them.
  1473. $utargs = $resp->extensionResponse('urn:unittest', true);
  1474. $this->assertEquals($utargs, null);
  1475. }
  1476. function test_noReturnTo()
  1477. {
  1478. $message = Auth_OpenID_Message::fromPostArgs(array());
  1479. $resp = new Auth_OpenID_SuccessResponse($this->endpoint, $message);
  1480. $this->assertTrue($resp->getReturnTo() === null);
  1481. }
  1482. function test_returnTo()
  1483. {
  1484. $query = array('openid.return_to' => 'return_to');
  1485. $message = Auth_OpenID_Message::fromPostArgs($query);
  1486. $resp = new Auth_OpenID_SuccessResponse($this->endpoint,
  1487. $message, array('openid.return_to'));
  1488. $this->assertEquals($resp->getReturnTo(), 'return_to');
  1489. }
  1490. }
  1491. class _StubConsumer {
  1492. function _StubConsumer()
  1493. {
  1494. $this->assoc = null;
  1495. $this->response = null;
  1496. $this->endpoint = null;
  1497. $this->fetcher = new _MockFetcher();
  1498. }
  1499. function begin($service)
  1500. {
  1501. $auth_req = new Auth_OpenID_AuthRequest($service, $this->assoc);
  1502. $this->endpoint = $service;
  1503. return $auth_req;
  1504. }
  1505. function complete($message, $endpoint, $return_to)
  1506. {
  1507. return $this->response;
  1508. }
  1509. }
  1510. class Tests_Auth_OpenID_DiscoFailure extends PHPUnit_TestCase {
  1511. var $consumerClass = null;
  1512. function setUp()
  1513. {
  1514. foreach ($_SESSION as $k => $v) {
  1515. unset($_SESSION[$k]);
  1516. }
  1517. $this->endpoint = new Auth_OpenID_ServiceEndpoint();
  1518. $this->claimed_id = 'http://identity.url/';
  1519. $this->endpoint->claimed_id = $this->claimed_id;
  1520. $this->store = null;
  1521. $this->session = new Auth_Yadis_PHPSession();
  1522. $cls = $this->consumerClass;
  1523. $this->consumer =& new $cls($this->store, &$this->session);
  1524. $this->consumer->consumer =& new _StubConsumer();
  1525. $this->discovery =& new Auth_Yadis_Discovery(&$this->session,
  1526. $this->claimed_id,
  1527. $this->consumer->session_key_prefix);
  1528. }
  1529. }
  1530. class Consumer_completeEmptySession extends Auth_OpenID_GenericConsumer {
  1531. var $test_case = null;
  1532. var $text = "failed complete";
  1533. function complete($message, $endpoint, $return_to)
  1534. {
  1535. $this->test_case->assertTrue($endpoint === null);
  1536. return new Auth_OpenID_FailureResponse($endpoint, $this->text);
  1537. }
  1538. }
  1539. class Tests_Auth_OpenID_ConsumerTest2 extends PHPUnit_TestCase {
  1540. function setUp()
  1541. {
  1542. foreach ($_SESSION as $k => $v) {
  1543. unset($_SESSION[$k]);
  1544. }
  1545. $this->endpoint = new Auth_OpenID_ServiceEndpoint();
  1546. $this->claimed_id = 'http://identity.url/';
  1547. $this->endpoint->claimed_id = $this->claimed_id;
  1548. $this->store = null;
  1549. $this->session = new Auth_Yadis_PHPSession();
  1550. $this->consumer =& new Auth_OpenID_Consumer($this->store, $this->session);
  1551. $this->consumer->consumer =& new _StubConsumer();
  1552. $this->discovery =& new Auth_Yadis_Discovery(&$this->session,
  1553. $this->claimed_id,
  1554. $this->consumer->session_key_prefix);
  1555. }
  1556. function test_beginWithoutDiscovery()
  1557. {
  1558. // Does this really test anything non-trivial?
  1559. $result = $this->consumer->beginWithoutDiscovery($this->endpoint);
  1560. // The result is an auth request
  1561. $this->assertTrue(strtolower(get_class($result)) ==
  1562. 'auth_openid_authrequest');
  1563. $loader = new Auth_OpenID_ServiceEndpointLoader();
  1564. // Side-effect of calling beginWithoutDiscovery is setting the
  1565. // session value to the endpoint attribute of the result
  1566. $this->assertTrue(
  1567. $loader->fromSession(
  1568. $this->session->get($this->consumer->_token_key)) ==
  1569. $result->endpoint);
  1570. // The endpoint that we passed in is the endpoint on the
  1571. // auth_request
  1572. $this->assertTrue($result->endpoint == $this->endpoint);
  1573. }
  1574. function test_completeEmptySession()
  1575. {
  1576. $this->consumer->consumer = new Consumer_completeEmptySession($this->store);
  1577. $this->consumer->consumer->test_case =& $this;
  1578. $response = $this->consumer->complete(null);
  1579. $this->assertTrue(Auth_OpenID::isFailure($response));
  1580. $this->assertEquals($this->consumer->consumer->text, $response->message);
  1581. $this->assertTrue($response->identity_url === null);
  1582. }
  1583. function _doResp($auth_req, $exp_resp)
  1584. {
  1585. // complete a transaction, using the expected response from
  1586. // the generic consumer.
  1587. $this->consumer->consumer->response = $exp_resp;
  1588. // endpoint is stored in the session
  1589. // $this->assertTrue($this->session->data);
  1590. $this->assertTrue($_SESSION);
  1591. $resp = $this->consumer->complete(null);
  1592. // All responses should have the same identity URL, and the
  1593. // session should be cleaned out
  1594. if ($this->endpoint->claimed_id != Auth_OpenID_IDENTIFIER_SELECT) {
  1595. $this->assertTrue($resp->identity_url == $this->claimed_id);
  1596. }
  1597. $this->assertFalse(in_array($this->consumer->_token_key,
  1598. $_SESSION)); // this->session->data));
  1599. // Expected status response
  1600. $this->assertEquals($resp->status, $exp_resp->status);
  1601. return $resp;
  1602. }
  1603. function _doRespNoDisco($exp_resp)
  1604. {
  1605. // Set up a transaction without discovery
  1606. $auth_req = $this->consumer->beginWithoutDiscovery($this->endpoint);
  1607. $resp = $this->_doResp($auth_req, $exp_resp);
  1608. // There should be nothing left in the session once we have
  1609. // completed.
  1610. $this->assertFalse($this->session->contents());
  1611. return $resp;
  1612. }
  1613. /*
  1614. * Be sure that the session gets cleaned up when the response is
  1615. * successful and has a different URL than the one in the request.
  1616. */
  1617. function test_successDifferentURL()
  1618. {
  1619. // Set up a request endpoint describing an IDP URL
  1620. $this->identity_url = 'http://idp.url/';
  1621. $this->endpoint->claimed_id = $this->endpoint->local_id = Auth_OpenID_IDENTIFIER_SELECT;
  1622. // Use a response endpoint with a different URL (asserted by
  1623. // the IDP)
  1624. $resp_endpoint = new Auth_OpenID_ServiceEndpoint();
  1625. $resp_endpoint->claimed_id = "http://user.url/";
  1626. $resp = $this->_doRespDisco(
  1627. true,
  1628. mkSuccess($resp_endpoint, array()));
  1629. $this->assertTrue($this->discovery->getManager(true) === null);
  1630. }
  1631. function test_noDiscoCompleteSuccessWithToken()
  1632. {
  1633. $message = Auth_OpenID_Message::fromPostArgs(array());
  1634. $this->_doRespNoDisco(new Auth_OpenID_SuccessResponse($this->endpoint,
  1635. $message));
  1636. }
  1637. function test_noDiscoCompleteCancelWithToken()
  1638. {
  1639. $this->_doRespNoDisco(new Auth_OpenID_CancelResponse($this->endpoint));
  1640. }
  1641. function test_noDiscoCompleteFailure()
  1642. {
  1643. $msg = 'failed!';
  1644. $resp = $this->_doRespNoDisco(new Auth_OpenID_FailureResponse($this->endpoint, $msg));
  1645. $this->assertTrue($resp->message == $msg);
  1646. }
  1647. function test_noDiscoCompleteSetupNeeded()
  1648. {
  1649. $setup_url = 'http://setup.url/';
  1650. $resp = $this->_doRespNoDisco(
  1651. new Auth_OpenID_SetupNeededResponse($this->endpoint, $setup_url));
  1652. $this->assertTrue($resp->setup_url == $setup_url);
  1653. }
  1654. // To test that discovery is cleaned up, we need to initialize a
  1655. // Yadis manager, and have it put its values in the session.
  1656. function _doRespDisco($is_clean, $exp_resp)
  1657. {
  1658. // Set up and execute a transaction, with discovery
  1659. $this->discovery->createManager(array($this->endpoint),
  1660. $this->claimed_id);
  1661. $auth_req = $this->consumer->begin($this->claimed_id);
  1662. $resp = $this->_doResp($auth_req, $exp_resp);
  1663. $manager = $this->discovery->getManager();
  1664. if ($is_clean) {
  1665. $this->assertTrue($this->discovery->getManager() === null);
  1666. } else {
  1667. $this->assertFalse($this->discovery->getManager() === null);
  1668. }
  1669. return $resp;
  1670. }
  1671. // Cancel and success DO clean up the discovery process
  1672. function test_completeSuccess()
  1673. {
  1674. $message = Auth_OpenID_Message::fromPostArgs(array());
  1675. $this->_doRespDisco(true,
  1676. new Auth_OpenID_SuccessResponse($this->endpoint,
  1677. $message));
  1678. }
  1679. function test_completeCancel()
  1680. {
  1681. $this->_doRespDisco(true,
  1682. new Auth_OpenID_CancelResponse($this->endpoint));
  1683. }
  1684. // Failure and setup_needed don't clean up the discovery process
  1685. function test_completeFailure()
  1686. {
  1687. $msg = 'failed!';
  1688. $resp = $this->_doRespDisco(false,
  1689. new Auth_OpenID_FailureResponse($this->endpoint, $msg));
  1690. $this->assertTrue($resp->message == $msg);
  1691. }
  1692. function test_completeSetupNeeded()
  1693. {
  1694. $setup_url = 'http://setup.url/';
  1695. $resp = $this->_doRespDisco(false,
  1696. new Auth_OpenID_SetupNeededResponse($this->endpoint, $setup_url));
  1697. $this->assertTrue($resp->status == Auth_OpenID_SETUP_NEEDED);
  1698. $this->assertTrue($resp->setup_url == $setup_url);
  1699. }
  1700. function test_begin()
  1701. {
  1702. $this->discovery->createManager(array($this->endpoint),
  1703. $this->claimed_id);
  1704. // Should not raise an exception
  1705. $auth_req = $this->consumer->begin($this->claimed_id);
  1706. $this->assertTrue(strtolower(get_class($auth_req)) === 'auth_openid_authrequest');
  1707. $this->assertTrue($auth_req->endpoint == $this->endpoint);
  1708. $this->assertTrue($auth_req->endpoint == $this->consumer->consumer->endpoint);
  1709. $this->assertTrue($auth_req->assoc == $this->consumer->consumer->assoc);
  1710. }
  1711. }
  1712. class IDPDrivenTest_Consumer1 extends ConfigurableConsumer {
  1713. var $iverified = array();
  1714. var $endpoint = null;
  1715. var $failure_cb = null;
  1716. var $check_endpoint = null;
  1717. function _idResCheckNonce($message, $endpoint)
  1718. {
  1719. return true;
  1720. }
  1721. function _verifyDiscoveryResults($identifier, $endpoint)
  1722. {
  1723. call_user_func($this->failure_cb,
  1724. $endpoint === $this->check_endpoint);
  1725. $this->iverified[] = $this->endpoint;
  1726. return $this->endpoint;
  1727. }
  1728. }
  1729. class IDPDrivenTest_Consumer2 extends ConfigurableConsumer {
  1730. function verifyDiscoveryResults($identifier, $endp)
  1731. {
  1732. return new Auth_OpenID_FailureResponse(null,
  1733. "Bogus");
  1734. }
  1735. }
  1736. class IDPDrivenTest extends PHPUnit_TestCase {
  1737. function setUp()
  1738. {
  1739. $this->store = new GoodAssocStore();
  1740. $this->consumer = new ConfigurableConsumer($this->store);
  1741. $this->endpoint = new Auth_OpenID_ServiceEndpoint();
  1742. $this->endpoint->server_url = "http://idp.unittest/";
  1743. }
  1744. function test_idpDrivenBegin()
  1745. {
  1746. // Testing here that the token-handling doesn't explode...
  1747. $this->assertTrue($this->consumer->begin($this->endpoint) !== null);
  1748. }
  1749. function test_idpDrivenComplete()
  1750. {
  1751. global $GOODSIG;
  1752. $this->consumer = new IDPDrivenTest_Consumer1($this->store);
  1753. $this->consumer->failure_cb = array(&$this, "assertTrue");
  1754. $this->consumer->check_endpoint =& $this->endpoint;
  1755. $identifier = '=directed_identifier';
  1756. $message = Auth_OpenID_Message::fromPostArgs(array(
  1757. 'openid.identity'=> '=directed_identifier',
  1758. 'openid.return_to'=> 'x',
  1759. 'openid.assoc_handle'=> 'z',
  1760. 'openid.signed'=> 'identity,return_to',
  1761. 'openid.sig'=> $GOODSIG));
  1762. $endpoint = new Auth_OpenID_ServiceEndpoint();
  1763. $endpoint->claimed_id = $identifier;
  1764. $endpoint->server_url = $this->endpoint->server_url;
  1765. $endpoint->local_id = $identifier;
  1766. $this->consumer->disableReturnToChecking();
  1767. $this->consumer->endpoint =& $endpoint;
  1768. $response = $this->consumer->_doIdRes($message, $this->endpoint, null);
  1769. $this->failUnlessSuccess($response);
  1770. $this->assertEquals($response->identity_url, "=directed_identifier");
  1771. // assert that discovery attempt happens and returns good
  1772. $this->assertEquals($this->consumer->iverified, array($endpoint));
  1773. }
  1774. function test_idpDrivenCompleteFraud()
  1775. {
  1776. global $GOODSIG;
  1777. $this->consumer = new IDPDrivenTest_Consumer2($this->store);
  1778. // crap with an identifier that doesn't match discovery info
  1779. $message = Auth_OpenID_Message::fromPostArgs(array(
  1780. 'openid.identity'=> '=directed_identifier',
  1781. 'openid.return_to'=> 'x',
  1782. 'openid.assoc_handle'=> 'z',
  1783. 'openid.signed'=> 'identity,return_to',
  1784. 'openid.sig'=> $GOODSIG));
  1785. $this->consumer->disableReturnToChecking();
  1786. $result = $this->consumer->_doIdRes($message, $this->endpoint, null);
  1787. $this->assertTrue(Auth_OpenID::isFailure($result));
  1788. }
  1789. function failUnlessSuccess($response)
  1790. {
  1791. if ($response->status != Auth_OpenID_SUCCESS) {
  1792. $this->fail("Non-successful response (status is ".$response->status.")");
  1793. }
  1794. }
  1795. }
  1796. global $__test_otherServer_text;
  1797. $__test_otherServer_text = "__test_otherServer";
  1798. class TestDiscoveryVerification_test_otherServer extends Auth_OpenID_GenericConsumer {
  1799. function _discoverAndVerify($to_match)
  1800. {
  1801. global $__test_otherServer_text;
  1802. return new Auth_OpenID_FailureResponse(null, $__test_otherServer_text);
  1803. }
  1804. }
  1805. class TestDiscoveryVerification extends PHPUnit_TestCase {
  1806. var $services = array();
  1807. function discoveryFunc($identifier)
  1808. {
  1809. return array($identifier, $this->services);
  1810. }
  1811. function setUp()
  1812. {
  1813. $this->store = new GoodAssocStore();
  1814. $this->consumer = new Auth_OpenID_GenericConsumer($this->store);
  1815. $this->consumer->discoverMethod = array($this,
  1816. 'discoveryFunc');
  1817. $this->identifier = "http://idp.unittest/1337";
  1818. $this->server_url = "http://endpoint.unittest/";
  1819. $this->message = Auth_OpenID_Message::fromPostArgs(array(
  1820. 'openid.ns'=> Auth_OpenID_OPENID2_NS,
  1821. 'openid.identity'=> $this->identifier,
  1822. 'openid.claimed_id'=> $this->identifier,
  1823. 'openid.op_endpoint'=> $this->server_url));
  1824. $this->endpoint = new Auth_OpenID_ServiceEndpoint();
  1825. $this->endpoint->server_url = $this->server_url;
  1826. }
  1827. function test_theGoodStuff()
  1828. {
  1829. $endpoint = new Auth_OpenID_ServiceEndpoint();
  1830. $endpoint->type_uris = array(Auth_OpenID_TYPE_2_0);
  1831. $endpoint->claimed_id = $this->identifier;
  1832. $endpoint->server_url = $this->server_url;
  1833. $endpoint->local_id = $this->identifier;
  1834. $this->services = array($endpoint);
  1835. $r = $this->consumer->_verifyDiscoveryResults($this->message, $endpoint);
  1836. $this->assertEquals($r, $endpoint);
  1837. }
  1838. function test_otherServer()
  1839. {
  1840. global $__test_otherServer_text;
  1841. // setup
  1842. $this->consumer = new TestDiscoveryVerification_test_otherServer($this->store);
  1843. $this->consumer->discoverMethod = array($this,
  1844. 'discoveryFunc');
  1845. // a set of things without the stuff
  1846. $endpoint = new Auth_OpenID_ServiceEndpoint();
  1847. $endpoint->type_uris = array(Auth_OpenID_TYPE_2_0);
  1848. $endpoint->claimed_id = $this->identifier;
  1849. $endpoint->server_url = "http://the-MOON.unittest/";
  1850. $endpoint->local_id = $this->identifier;
  1851. $this->services = array($endpoint);
  1852. $result = $this->consumer->_verifyDiscoveryResults(
  1853. $this->message, $endpoint);
  1854. $this->assertTrue(Auth_OpenID::isFailure($result));
  1855. $this->assertTrue(strpos($result->message, $__test_otherServer_text) !== false);
  1856. }
  1857. function test_foreignDelegate()
  1858. {
  1859. global $__test_otherServer_text;
  1860. // setup
  1861. $this->consumer = new TestDiscoveryVerification_test_otherServer($this->store);
  1862. $this->consumer->discoverMethod = array($this,
  1863. 'discoveryFunc');
  1864. // a set of things with the server stuff but other delegate
  1865. $endpoint = new Auth_OpenID_ServiceEndpoint();
  1866. $endpoint->type_uris = array(Auth_OpenID_TYPE_2_0);
  1867. $endpoint->claimed_id = $this->identifier;
  1868. $endpoint->server_url = $this->server_url;
  1869. $endpoint->local_id = "http://unittest/juan-carlos";
  1870. $result = $this->consumer->_verifyDiscoveryResults(
  1871. $this->message, $endpoint);
  1872. $this->assertTrue(Auth_OpenID::isFailure($result));
  1873. $this->assertTrue(strpos($result->message, $__test_otherServer_text) !== false);
  1874. }
  1875. function test_nothingDiscovered()
  1876. {
  1877. // a set of no things.
  1878. $this->services = array();
  1879. $result = $this->consumer->_verifyDiscoveryResults(
  1880. $this->message, $this->endpoint);
  1881. $this->assertTrue(Auth_OpenID::isFailure($result));
  1882. }
  1883. }
  1884. class DummyEndpoint {
  1885. var $use_compatibility = false;
  1886. function compatibilityMode()
  1887. {
  1888. return $this->use_compatibility;
  1889. }
  1890. }
  1891. class TestCreateAssociationRequest extends PHPUnit_TestCase {
  1892. function setUp()
  1893. {
  1894. $this->endpoint = new DummyEndpoint();
  1895. $s = null;
  1896. $this->consumer = new Auth_OpenID_GenericConsumer($s);
  1897. $this->assoc_type = 'HMAC-SHA1';
  1898. }
  1899. function test_noEncryptionSendsType()
  1900. {
  1901. $session_type = 'no-encryption';
  1902. list($session, $args) = $this->consumer->_createAssociateRequest(
  1903. $this->endpoint, $this->assoc_type, $session_type);
  1904. $this->assertTrue(is_a($session, 'Auth_OpenID_PlainTextConsumerSession'));
  1905. $expected = Auth_OpenID_Message::fromOpenIDArgs(
  1906. array('ns' => Auth_OpenID_OPENID2_NS,
  1907. 'session_type'=>$session_type,
  1908. 'mode'=>'associate',
  1909. 'assoc_type'=>$this->assoc_type));
  1910. $this->assertEquals($expected->toPostArgs(),
  1911. $args->toPostArgs());
  1912. }
  1913. function test_noEncryptionSendsTypeHMACSHA256()
  1914. {
  1915. if (!Auth_OpenID_HMACSHA256_SUPPORTED) {
  1916. $this->pass();
  1917. return;
  1918. }
  1919. $session_type = 'no-encryption';
  1920. $this->assoc_type = 'HMAC-SHA256';
  1921. list($session, $args) = $this->consumer->_createAssociateRequest(
  1922. $this->endpoint, $this->assoc_type, $session_type);
  1923. $this->assertTrue(is_a($session, 'Auth_OpenID_PlainTextConsumerSession'));
  1924. $expected = Auth_OpenID_Message::fromOpenIDArgs(
  1925. array('ns' => Auth_OpenID_OPENID2_NS,
  1926. 'session_type'=>$session_type,
  1927. 'mode'=>'associate',
  1928. 'assoc_type'=>$this->assoc_type));
  1929. $this->assertEquals($expected->toPostArgs(),
  1930. $args->toPostArgs());
  1931. $response = Auth_OpenID_Message::fromOpenIDArgs(
  1932. array('ns' => Auth_OpenID_OPENID2_NS,
  1933. 'session_type'=>$session_type,
  1934. 'assoc_type'=>$this->assoc_type,
  1935. 'expires_in' => '10000000000',
  1936. 'mac_key' => 'ZM9v',
  1937. 'assoc_handle' => 'turnme'
  1938. )
  1939. );
  1940. $assoc = $this->consumer->_extractAssociation($response, $session);
  1941. $this->assertTrue($assoc !== null);
  1942. $this->assertTrue(is_a($assoc, 'Auth_OpenID_Association'));
  1943. $this->assertTrue($assoc->assoc_type = $this->assoc_type);
  1944. $this->assertTrue($assoc->session_type = $session_type);
  1945. }
  1946. function test_noEncryptionCompatibility()
  1947. {
  1948. $this->endpoint->use_compatibility = true;
  1949. $session_type = 'no-encryption';
  1950. list($session, $args) = $this->consumer->_createAssociateRequest(
  1951. $this->endpoint, $this->assoc_type, $session_type);
  1952. $this->assertTrue(is_a($session, 'Auth_OpenID_PlainTextConsumerSession'));
  1953. $this->assertEquals(Auth_OpenID_Message::fromOpenIDArgs(array('mode'=>'associate',
  1954. 'assoc_type'=>$this->assoc_type)),
  1955. $args);
  1956. }
  1957. function test_dhSHA1Compatibility()
  1958. {
  1959. // Set the consumer's session type to a fast session since we
  1960. // need it here.
  1961. setConsumerSession($this->consumer);
  1962. $this->endpoint->use_compatibility = true;
  1963. $session_type = 'DH-SHA1';
  1964. list($session, $args) = $this->consumer->_createAssociateRequest(
  1965. $this->endpoint, $this->assoc_type, $session_type);
  1966. $this->assertTrue(is_a($session,
  1967. 'Auth_OpenID_DiffieHellmanSHA1ConsumerSession'));
  1968. // This is a random base-64 value, so just check that it's
  1969. // present.
  1970. $this->assertTrue($args->hasKey(Auth_OpenID_OPENID1_NS, 'dh_consumer_public'));
  1971. $args->delArg(Auth_OpenID_OPENID1_NS, 'dh_consumer_public');
  1972. // OK, session_type is set here and not for no-encryption
  1973. // compatibility
  1974. $expected = Auth_OpenID_Message::fromOpenIDArgs(array('mode'=>'associate',
  1975. 'session_type'=>'DH-SHA1',
  1976. 'assoc_type'=>$this->assoc_type,
  1977. 'dh_modulus'=> 'BfvStQ==',
  1978. 'dh_gen'=> 'Ag=='));
  1979. $this->assertEquals($expected->toPostArgs(),
  1980. $args->toPostArgs());
  1981. }
  1982. }
  1983. class TestDiffieHellmanResponseParameters extends PHPUnit_TestCase {
  1984. var $session_cls = null;
  1985. var $message_namespace = null;
  1986. function setUp()
  1987. {
  1988. // Pre-compute DH with small prime so tests run quickly.
  1989. $this->server_dh = new Auth_OpenID_DiffieHellman(100389557, 2);
  1990. $this->consumer_dh = new Auth_OpenID_DiffieHellman(100389557, 2);
  1991. $lib =& Auth_OpenID_getMathLib();
  1992. $cls = $this->session_cls;
  1993. $this->consumer_session = new $cls($this->consumer_dh);
  1994. // base64(btwoc(g ^ xb mod p))
  1995. $this->dh_server_public = $lib->longToBase64($this->server_dh->public);
  1996. $this->secret = Auth_OpenID_CryptUtil::randomString(
  1997. $this->consumer_session->secret_size);
  1998. $this->enc_mac_key = base64_encode(
  1999. $this->server_dh->xorSecret($this->consumer_dh->public,
  2000. $this->secret,
  2001. $this->consumer_session->hash_func));
  2002. $this->msg = new Auth_OpenID_Message($this->message_namespace);
  2003. }
  2004. function testExtractSecret()
  2005. {
  2006. $this->msg->setArg(Auth_OpenID_OPENID_NS, 'dh_server_public',
  2007. $this->dh_server_public);
  2008. $this->msg->setArg(Auth_OpenID_OPENID_NS, 'enc_mac_key',
  2009. $this->enc_mac_key);
  2010. $extracted = $this->consumer_session->extractSecret($this->msg);
  2011. $this->assertEquals($extracted, $this->secret);
  2012. }
  2013. function testAbsentServerPublic()
  2014. {
  2015. $this->msg->setArg(Auth_OpenID_OPENID_NS, 'enc_mac_key',
  2016. $this->enc_mac_key);
  2017. $this->assertTrue($this->consumer_session->extractSecret($this->msg) === null);
  2018. }
  2019. function testAbsentMacKey()
  2020. {
  2021. $this->msg->setArg(Auth_OpenID_OPENID_NS, 'dh_server_public',
  2022. $this->dh_server_public);
  2023. $this->assertTrue($this->consumer_session->extractSecret($this->msg) === null);
  2024. }
  2025. /*
  2026. function testInvalidBase64Public()
  2027. {
  2028. $this->msg->setArg(Auth_OpenID_OPENID_NS, 'dh_server_public',
  2029. 'n o t b a s e 6 4.');
  2030. $this->msg->setArg(Auth_OpenID_OPENID_NS, 'enc_mac_key',
  2031. $this->enc_mac_key);
  2032. $this->assertTrue($this->consumer_session->extractSecret($this->msg) === null);
  2033. }
  2034. function testInvalidBase64MacKey()
  2035. {
  2036. $this->msg->setArg(Auth_OpenID_OPENID_NS, 'dh_server_public',
  2037. $this->dh_server_public);
  2038. $this->msg->setArg(Auth_OpenID_OPENID_NS, 'enc_mac_key',
  2039. 'n o t base 64');
  2040. $this->assertTrue($this->consumer_session->extractSecret($this->msg) === null);
  2041. }
  2042. */
  2043. }
  2044. class TestOpenID1SHA1 extends TestDiffieHellmanResponseParameters {
  2045. var $session_cls = 'Auth_OpenID_DiffieHellmanSHA1ConsumerSession';
  2046. var $message_namespace = Auth_OpenID_OPENID1_NS;
  2047. }
  2048. class TestOpenID2SHA1 extends TestDiffieHellmanResponseParameters {
  2049. var $session_cls = 'Auth_OpenID_DiffieHellmanSHA1ConsumerSession';
  2050. var $message_namespace = Auth_OpenID_OPENID2_NS;
  2051. }
  2052. if (!defined('Auth_OpenID_NO_MATH_SUPPORT') &&
  2053. Auth_OpenID_SHA256_SUPPORTED) {
  2054. class TestOpenID2SHA256 extends TestDiffieHellmanResponseParameters {
  2055. var $session_cls = 'Auth_OpenID_DiffieHellmanSHA256ConsumerSession';
  2056. var $message_namespace = Auth_OpenID_OPENID2_NS;
  2057. }
  2058. }
  2059. class Tests_Auth_OpenID_KVPost extends PHPUnit_TestCase {
  2060. function setUp()
  2061. {
  2062. $this->server_url = 'http://unittest/bogus';
  2063. }
  2064. function test_200()
  2065. {
  2066. $response = new Auth_Yadis_HTTPResponse();
  2067. $response->status = 200;
  2068. $response->body = "foo:bar\nbaz:quux\n";
  2069. $r = Auth_OpenID_GenericConsumer::_httpResponseToMessage($response, $this->server_url);
  2070. $expected_msg = Auth_OpenID_Message::fromOpenIDArgs(array('foo' => 'bar', 'baz' => 'quux'));
  2071. $this->assertEquals($expected_msg, $r);
  2072. }
  2073. function test_400()
  2074. {
  2075. $response = new Auth_Yadis_HTTPResponse();
  2076. $response->status = 400;
  2077. $response->body = "error:bonk\nerror_code:7\n";
  2078. $result = Auth_OpenID_GenericConsumer::_httpResponseToMessage($response, $this->server_url);
  2079. $this->assertTrue(is_a($result, 'Auth_OpenID_ServerErrorContainer'));
  2080. $this->assertEquals($result->error_text, 'bonk');
  2081. $this->assertEquals($result->error_code, '7');
  2082. }
  2083. function test_500()
  2084. {
  2085. // 500 as an example of any non-200, non-400 code.
  2086. $response = new Auth_Yadis_HTTPResponse();
  2087. $response->status = 500;
  2088. $response->body = "foo:bar\nbaz:quux\n";
  2089. $result = Auth_OpenID_GenericConsumer::_httpResponseToMessage($response, $this->server_url);
  2090. $this->assertTrue($result === null);
  2091. }
  2092. }
  2093. // Add other test cases to be run.
  2094. global $Tests_Auth_OpenID_Consumer_other;
  2095. $Tests_Auth_OpenID_Consumer_other = array(
  2096. // new Tests_Auth_OpenID_Consumer_TestSetupNeeded(),
  2097. new Tests_Auth_OpenID_AuthRequestHTMLMarkup(),
  2098. new Tests_Auth_OpenID_Consumer_TestCheckAuth(),
  2099. new Tests_Auth_OpenID_Consumer_TestCheckAuthTriggered(),
  2100. new Tests_Auth_OpenID_Consumer_TestFetchAssoc(),
  2101. new Tests_Auth_OpenID_Consumer_CheckNonceTest(),
  2102. new Tests_Auth_OpenID_Complete(),
  2103. new Tests_Auth_OpenID_SuccessResponse(),
  2104. new Tests_Auth_OpenID_CheckAuthResponse(),
  2105. new Tests_Auth_OpenID_FetchErrorInIdRes(),
  2106. new Tests_Auth_OpenID_ConsumerTest2(),
  2107. new Tests_Auth_OpenID_Stateless1(),
  2108. new Tests_Auth_OpenID_Stateless2(),
  2109. new TestCompleteMissingSig(),
  2110. new TestReturnToArgs(),
  2111. new IDPDrivenTest(),
  2112. new TestDiscoveryVerification(),
  2113. new Tests_Auth_OpenID_KVPost(),
  2114. new Tests_idResURLMismatch(),
  2115. new IdResCheckForFieldsTest(),
  2116. );
  2117. if (!defined('Auth_OpenID_NO_MATH_SUPPORT')) {
  2118. $Tests_Auth_OpenID_Consumer_other[] = new TestCreateAssociationRequest();
  2119. $Tests_Auth_OpenID_Consumer_other[] = new TestOpenID1SHA1();
  2120. $Tests_Auth_OpenID_Consumer_other[] = new TestOpenID2SHA1();
  2121. }
  2122. if (!defined('Auth_OpenID_NO_MATH_SUPPORT') &&
  2123. Auth_OpenID_SHA256_SUPPORTED) {
  2124. $Tests_Auth_OpenID_Consumer_other[] = new TestOpenID2SHA256();
  2125. }
  2126. ?>