Negotiation.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. <?php
  2. require_once "PHPUnit.php";
  3. require_once "Tests/Auth/OpenID/TestUtil.php";
  4. require_once "Tests/Auth/OpenID/MemStore.php";
  5. require_once "Auth/OpenID/Message.php";
  6. require_once "Auth/OpenID/Consumer.php";
  7. /**
  8. * A consumer whose _requestAssocation will return predefined results
  9. * instead of trying to actually perform association requests.
  10. */
  11. class ErrorRaisingConsumer extends Auth_OpenID_GenericConsumer {
  12. // The list of objects to be returned by successive calls to
  13. // _requestAssocation. Each call will pop the first element from
  14. // this list and return it to _negotiateAssociation. If the
  15. // element is a Message object, it will be wrapped in a
  16. // ServerErrorContainer exception. Otherwise it will be returned
  17. // as-is.
  18. var $return_messages = array();
  19. function _requestAssociation($endpoint, $assoc_type, $session_type)
  20. {
  21. $m = array_pop($this->return_messages);
  22. if (is_a($m, 'Auth_OpenID_Message')) {
  23. return Auth_OpenID_ServerErrorContainer::fromMessage($m);
  24. } else if (Auth_OpenID::isFailure($m)) {
  25. return $m;
  26. } else {
  27. return $m;
  28. }
  29. }
  30. }
  31. /**
  32. * Test the session type negotiation behavior of an OpenID 2 consumer.
  33. */
  34. class TestOpenID2SessionNegotiation extends PHPUnit_TestCase {
  35. function setUp()
  36. {
  37. $dumb = null;
  38. $this->consumer = new ErrorRaisingConsumer($dumb);
  39. $this->endpoint = new Auth_OpenID_ServiceEndpoint();
  40. $this->endpoint->type_uris = array(Auth_OpenID_TYPE_2_0);
  41. $this->endpoint->server_url = 'bogus';
  42. }
  43. /**
  44. * Test the case where the response to an associate request is a
  45. * server error or is otherwise undecipherable.
  46. */
  47. function testBadResponse()
  48. {
  49. $this->consumer->return_messages = array(
  50. new Auth_OpenID_Message($this->endpoint->preferredNamespace()));
  51. $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
  52. // $this->failUnlessLogMatches('Server error when requesting an association')
  53. }
  54. /**
  55. * Test the case where the response to an associate request is a
  56. * a failure response object.
  57. */
  58. function testBadResponseWithFailure()
  59. {
  60. $this->consumer->return_messages = array(
  61. new Auth_OpenID_FailureResponse($this->endpoint));
  62. $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
  63. // $this->failUnlessLogMatches('Server error when requesting an association')
  64. }
  65. /**
  66. * Test the case where the association type (assoc_type) returned
  67. * in an unsupported-type response is absent.
  68. */
  69. function testEmptyAssocType()
  70. {
  71. $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
  72. $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
  73. $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
  74. $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', null);
  75. $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'new-session-type');
  76. $this->consumer->return_messages = array($msg);
  77. $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
  78. // $this->failUnlessLogMatches('Unsupported association type',
  79. // 'Server responded with unsupported association ' +
  80. // 'session but did not supply a fallback.')
  81. }
  82. /**
  83. * Test the case where the session type (session_type) returned in
  84. * an unsupported-type response is absent.
  85. */
  86. function testEmptySessionType()
  87. {
  88. $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
  89. $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
  90. $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
  91. $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'new-assoc-type');
  92. $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', null);
  93. $this->consumer->return_messages = array($msg);
  94. $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
  95. // $this->failUnlessLogMatches('Unsupported association type',
  96. // 'Server responded with unsupported association ' +
  97. // 'session but did not supply a fallback.')
  98. }
  99. /**
  100. * Test the case where an unsupported-type response specifies a
  101. * preferred (assoc_type, session_type) combination that is not
  102. * allowed by the consumer's SessionNegotiator.
  103. */
  104. function testNotAllowed()
  105. {
  106. $allowed_types = array();
  107. $negotiator = new Auth_OpenID_SessionNegotiator($allowed_types);
  108. $this->consumer->negotiator = $negotiator;
  109. $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
  110. $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
  111. $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
  112. $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'not-allowed');
  113. $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'not-allowed');
  114. $this->consumer->return_messages = array($msg);
  115. $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
  116. // $this->failUnlessLogMatches('Unsupported association type',
  117. // 'Server sent unsupported session/association type:')
  118. }
  119. /**
  120. * Test the case where an unsupported-type response triggers a
  121. * retry to get an association with the new preferred type.
  122. */
  123. function testUnsupportedWithRetry()
  124. {
  125. $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
  126. $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
  127. $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
  128. $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'HMAC-SHA1');
  129. $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'DH-SHA1');
  130. $assoc = new Auth_OpenID_Association(
  131. 'handle', 'secret', 'issued', 10000, 'HMAC-SHA1');
  132. $this->consumer->return_messages = array($msg, $assoc);
  133. $this->assertTrue($this->consumer->_negotiateAssociation($this->endpoint) === $assoc);
  134. // $this->failUnlessLogMatches('Unsupported association type');
  135. }
  136. /**
  137. * Test the case where an unsupported-typ response triggers a
  138. * retry, but the retry fails and None is returned instead.
  139. */
  140. function testUnsupportedWithRetryAndFail()
  141. {
  142. $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
  143. $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
  144. $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
  145. $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'HMAC-SHA1');
  146. $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'DH-SHA1');
  147. $this->consumer->return_messages = array($msg,
  148. new Auth_OpenID_Message($this->endpoint->preferredNamespace()));
  149. $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
  150. // $this->failUnlessLogMatches('Unsupported association type',
  151. // 'Server %s refused' % ($this->endpoint.server_url))
  152. }
  153. /**
  154. * Test the valid case, wherein an association is returned on the
  155. * first attempt to get one.
  156. */
  157. function testValid()
  158. {
  159. $assoc = new Auth_OpenID_Association(
  160. 'handle', 'secret', 'issued', 10000, 'HMAC-SHA1');
  161. $this->consumer->return_messages = array($assoc);
  162. $this->assertTrue($this->consumer->_negotiateAssociation($this->endpoint) === $assoc);
  163. // $this->failUnlessLogEmpty()
  164. }
  165. }
  166. /**
  167. * Tests for the OpenID 1 consumer association session behavior. See
  168. * the docs for TestOpenID2SessionNegotiation. Notice that this class
  169. * is not a subclass of the OpenID 2 tests. Instead, it uses many of
  170. * the same inputs but inspects the log messages logged with
  171. * oidutil.log. See the calls to $this->failUnlessLogMatches. Some
  172. * of these tests pass openid2-style messages to the openid 1
  173. * association processing logic to be sure it ignores the extra data.
  174. */
  175. class TestOpenID1SessionNegotiation extends PHPUnit_TestCase {
  176. function setUp()
  177. {
  178. $dumb = null;
  179. $this->consumer = new ErrorRaisingConsumer($dumb);
  180. $this->endpoint = new Auth_OpenID_ServiceEndpoint();
  181. $this->endpoint->type_uris = array(Auth_OpenID_OPENID1_NS);
  182. $this->endpoint->server_url = 'bogus';
  183. }
  184. function testBadResponse()
  185. {
  186. $this->consumer->return_messages =
  187. array(new Auth_OpenID_Message($this->endpoint->preferredNamespace()));
  188. $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
  189. // $this->failUnlessLogMatches('Server error when requesting an association')
  190. }
  191. function testEmptyAssocType()
  192. {
  193. $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
  194. $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
  195. $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
  196. $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', null);
  197. $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'new-session-type');
  198. $this->consumer->return_messages = array($msg);
  199. $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
  200. // $this->failUnlessLogMatches('Server error when requesting an association')
  201. }
  202. function testEmptySessionType()
  203. {
  204. $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
  205. $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
  206. $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
  207. $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'new-assoc-type');
  208. $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', null);
  209. $this->consumer->return_messages = array($msg);
  210. $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
  211. // $this->failUnlessLogMatches('Server error when requesting an association');
  212. }
  213. function testNotAllowed()
  214. {
  215. $allowed_types = array();
  216. $negotiator = new Auth_OpenID_SessionNegotiator($allowed_types);
  217. $this->consumer->negotiator = $negotiator;
  218. $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
  219. $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
  220. $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
  221. $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'not-allowed');
  222. $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'not-allowed');
  223. $this->consumer->return_messages = array($msg);
  224. $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
  225. // $this->failUnlessLogMatches('Server error when requesting an association')
  226. }
  227. function testUnsupportedWithRetry()
  228. {
  229. $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
  230. $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
  231. $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
  232. $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'HMAC-SHA1');
  233. $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'DH-SHA1');
  234. $assoc = new Auth_OpenID_Association(
  235. 'handle', 'secretxx', 'issued', 10000, 'HMAC-SHA1');
  236. $this->consumer->return_messages = array($assoc, $msg);
  237. $result = $this->consumer->_negotiateAssociation($this->endpoint);
  238. $this->assertTrue($result === null);
  239. // $this->failUnlessLogMatches('Server error when requesting an association')
  240. }
  241. function testValid()
  242. {
  243. $assoc = new Auth_OpenID_Association(
  244. 'handle', 'secret', 'issued', 10000, 'HMAC-SHA1');
  245. $this->consumer->return_messages = array($assoc);
  246. $this->assertTrue($this->consumer->_negotiateAssociation($this->endpoint) === $assoc);
  247. // $this->failUnlessLogEmpty()
  248. }
  249. }
  250. class TestNegotiatorBehaviors extends PHPUnit_TestCase {
  251. function setUp()
  252. {
  253. $this->allowed_types = array(
  254. array('HMAC-SHA1', 'no-encryption'),
  255. array('HMAC-SHA256', 'no-encryption')
  256. );
  257. $this->n = new Auth_OpenID_SessionNegotiator($this->allowed_types);
  258. }
  259. function testAddAllowedTypeNoSessionTypes()
  260. {
  261. $this->assertFalse($this->n->addAllowedType('invalid'));
  262. }
  263. function testAddAllowedTypeBadSessionType()
  264. {
  265. $this->assertFalse($this->n->addAllowedType('assoc1', 'invalid'));
  266. }
  267. function testAddAllowedTypeContents()
  268. {
  269. $assoc_type = 'HMAC-SHA1';
  270. $this->assertTrue($this->n->addAllowedType($assoc_type));
  271. foreach (Auth_OpenID_getSessionTypes($assoc_type) as $typ) {
  272. $this->assertTrue(in_array(array($assoc_type, $typ),
  273. $this->n->allowed_types));
  274. }
  275. }
  276. }
  277. class Tests_Auth_OpenID_Negotiation extends PHPUnit_TestSuite {
  278. function getName()
  279. {
  280. return 'Tests_Auth_OpenID_Negotiation';
  281. }
  282. function Tests_Auth_OpenID_Negotiation()
  283. {
  284. $this->addTestSuite('TestNegotiatorBehaviors');
  285. $this->addTestSuite('TestOpenID1SessionNegotiation');
  286. $this->addTestSuite('TestOpenID2SessionNegotiation');
  287. }
  288. }
  289. ?>