Negotiation.php 14 KB

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