Consumer.php 90 KB

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