JWSTest.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <?php
  2. namespace Namshi\JOSE\Test;
  3. use DateTime;
  4. use Namshi\JOSE\JWS;
  5. use PHPUnit_Framework_TestCase as TestCase;
  6. use Prophecy\Argument;
  7. use Namshi\JOSE\Signer\OpenSSL\HS256;
  8. use Namshi\JOSE\Base64\Base64UrlSafeEncoder;
  9. class JWSTest extends TestCase
  10. {
  11. const SSL_KEY_PASSPHRASE = 'tests';
  12. public function setup()
  13. {
  14. $date = new DateTime('tomorrow');
  15. $data = array(
  16. 'a' => 'b',
  17. );
  18. $this->jws = new JWS(array('alg' => 'RS256'));
  19. $this->jws->setPayload($data);
  20. }
  21. /**
  22. * @expectedException InvalidArgumentException
  23. */
  24. public function testLoadingUnsecureJwsWithNoneAlgo()
  25. {
  26. $date = new DateTime('tomorrow');
  27. $data = array(
  28. 'a' => 'b',
  29. 'exp' => $date->format('U'),
  30. );
  31. $this->jws = new JWS(array('alg' => 'None'));
  32. $this->jws->setPayload($data);
  33. $this->jws->sign('111');
  34. $jws = JWS::load($this->jws->getTokenString());
  35. $this->assertFalse($jws->verify('111'));
  36. $payload = $jws->getPayload();
  37. $this->assertEquals('b', $payload['a']);
  38. }
  39. /**
  40. * @expectedException InvalidArgumentException
  41. */
  42. public function testLoadingUnsecureJwsWithLowercaseNone()
  43. {
  44. $date = new DateTime('tomorrow');
  45. $data = array(
  46. 'a' => 'b',
  47. 'exp' => $date->format('U'),
  48. );
  49. $this->jws = new JWS(array('alg' => 'none'));
  50. $this->jws->setPayload($data);
  51. $this->jws->sign('111');
  52. $jws = JWS::load($this->jws->getTokenString());
  53. $this->assertFalse($jws->verify('111'));
  54. $payload = $jws->getPayload();
  55. $this->assertEquals('b', $payload['a']);
  56. }
  57. public function testAllowingUnsecureJws()
  58. {
  59. $date = new DateTime('tomorrow');
  60. $data = array(
  61. 'a' => 'b',
  62. 'exp' => $date->format('U'),
  63. );
  64. $this->jws = new JWS(array('alg' => 'None'));
  65. $this->jws->setPayload($data);
  66. $this->jws->sign('111');
  67. $jws = JWS::load($this->jws->getTokenString(), true);
  68. $this->assertTrue($jws->verify('111'));
  69. $payload = $jws->getPayload();
  70. $this->assertEquals('b', $payload['a']);
  71. }
  72. public function testRestrictingTheAlgorithmsKo()
  73. {
  74. $this->jws = new JWS(array('alg' => 'HS256'));
  75. $this->jws->sign('12345');
  76. $jws = JWS::load($this->jws->getTokenString());
  77. $this->assertFalse($jws->verify('12345', 'RS256'));
  78. }
  79. public function testRestrictingTheAlgorithmsOk()
  80. {
  81. $date = new DateTime('tomorrow');
  82. $data = array(
  83. 'a' => 'b',
  84. 'exp' => $date->format('U'),
  85. );
  86. $this->jws = new JWS(array('alg' => 'HS256'));
  87. $this->jws->setPayload($data);
  88. $this->jws->sign('123');
  89. $jws = JWS::load($this->jws->getTokenString());
  90. $this->assertTrue($jws->verify('123', 'HS256'));
  91. }
  92. public function testVerificationRS256()
  93. {
  94. $privateKey = openssl_pkey_get_private(SSL_KEYS_PATH.'private.key', self::SSL_KEY_PASSPHRASE);
  95. $this->jws->sign($privateKey);
  96. $jws = JWS::load($this->jws->getTokenString());
  97. $public_key = openssl_pkey_get_public(SSL_KEYS_PATH.'public.key');
  98. $this->assertTrue($jws->verify($public_key));
  99. $payload = $jws->getPayload();
  100. $this->assertEquals('b', $payload['a']);
  101. }
  102. public function testVerificationRS256KeyAsString()
  103. {
  104. $privateKey = file_get_contents(TEST_DIR.'/private.key');
  105. $this->jws->sign($privateKey, self::SSL_KEY_PASSPHRASE);
  106. $jws = JWS::load($this->jws->getTokenString());
  107. $public_key = openssl_pkey_get_public(SSL_KEYS_PATH.'public.key');
  108. $this->assertTrue($jws->verify($public_key));
  109. $payload = $jws->getPayload();
  110. $this->assertEquals('b', $payload['a']);
  111. }
  112. public function testUseOfCustomEncoder()
  113. {
  114. $encoder = $this->prophesize('Namshi\JOSE\Base64\Encoder');
  115. $encoder
  116. ->decode(Argument::any())
  117. ->willReturn('{"whatever": "the payload should be"}')
  118. ->shouldBeCalled();
  119. $encoder
  120. ->decode(Argument::any())
  121. ->willReturn('{"alg": "test"}')
  122. ->shouldBeCalled();
  123. JWS::load($this->jws->getTokenString(), false, $encoder->reveal());
  124. }
  125. public function testVerificationThatTheJWSIsSigned()
  126. {
  127. $privateKey = openssl_pkey_get_private(SSL_KEYS_PATH.'private.key', self::SSL_KEY_PASSPHRASE);
  128. $this->jws->sign($privateKey);
  129. $this->assertTrue($this->jws->isSigned());
  130. }
  131. public function testVerificationThatTheJWSIsNotSigned()
  132. {
  133. $this->assertFalse($this->jws->isSigned());
  134. }
  135. /**
  136. * @expectedException InvalidArgumentException
  137. */
  138. public function testWrongVerificationRS256()
  139. {
  140. $privateKey = openssl_pkey_get_private(SSL_KEYS_PATH.'private.key', self::SSL_KEY_PASSPHRASE);
  141. $this->jws->sign($privateKey);
  142. $jws = JWS::load('eyJhbGciOiJ0ZXN0In0=.eyJhbGciOiJ0ZXN0In0=.eyJhbGciOiJ0ZXN0In0=');
  143. $public_key = openssl_pkey_get_public(SSL_KEYS_PATH.'public.key');
  144. $this->assertFalse($jws->verify($public_key));
  145. }
  146. /**
  147. * @expectedException InvalidArgumentException
  148. */
  149. public function testLoadingAMalformedTokenString()
  150. {
  151. JWS::load('test.Test.TEST');
  152. }
  153. /**
  154. * @expectedException InvalidArgumentException
  155. */
  156. public function testLoadingAMalformedTokenString2()
  157. {
  158. JWS::load('test');
  159. }
  160. public function testSignAndVerifyWithFalsePublicKey()
  161. {
  162. $public_key = false;
  163. $jwsHMAC = new JWS(array('alg' => 'HS256'));
  164. $jwsHMAC->sign(false);
  165. $jws = JWS::load($jwsHMAC->getTokenString());
  166. $this->assertFalse($jws->verify($public_key));
  167. }
  168. public function testSignAndVerifyWithEmptyStringPublicKey()
  169. {
  170. $public_key = false;
  171. $jwsHMAC = new JWS(array('alg' => 'HS256'));
  172. $jwsHMAC->sign('');
  173. $jws = JWS::load($jwsHMAC->getTokenString());
  174. $this->assertFalse($jws->verify($public_key));
  175. }
  176. public function testLoadingWithAnyOrderOfHeaders()
  177. {
  178. $privateKey = openssl_pkey_get_private(SSL_KEYS_PATH.'private.key', self::SSL_KEY_PASSPHRASE);
  179. $public_key = openssl_pkey_get_public(SSL_KEYS_PATH.'public.key');
  180. $this->jws = new JWS(array('alg' => 'RS256', 'custom' => '1'));
  181. $header = $this->jws->getHeader();
  182. $reversedHeader = array_reverse($header);
  183. $this->assertFalse($header === $reversedHeader);
  184. $this->jws->setHeader($reversedHeader);
  185. $this->jws->sign($privateKey);
  186. $tokenString = $this->jws->getTokenString();
  187. $jws = JWS::load($tokenString);
  188. $this->assertTrue($reversedHeader === $jws->getHeader());
  189. }
  190. public function testSignAndVerifyWithSecLib()
  191. {
  192. if (version_compare(PHP_VERSION, '7.0.0-dev') >= 0) {
  193. $this->setExpectedException('InvalidArgumentException');
  194. }
  195. $jwsRSA = new JWS(array('alg' => 'RS256'), 'SecLib');
  196. $data = array('a' => 'b');
  197. $jwsRSA->setPayload($data);
  198. $jwsRSA->sign(file_get_contents(SSL_KEYS_PATH.'private.key'), 'tests');
  199. $jws = JWS::load($jwsRSA->getTokenString(), false, null, 'SecLib');
  200. $this->assertTrue($jws->verify(file_get_contents(SSL_KEYS_PATH.'public.key', 'RS256')));
  201. }
  202. public function testConstructionFromHeader()
  203. {
  204. $header = array('alg' => 'RS256', 'test' => true);
  205. $jws = new JWS($header);
  206. $this->assertTrue($header == $jws->getHeader());
  207. }
  208. public function testVerificationCustomizedHeader()
  209. {
  210. $header = $this->jws->getHeader();
  211. $header['test'] = true;
  212. $this->jws->setHeader($header);
  213. $privateKey = openssl_pkey_get_private(SSL_KEYS_PATH.'private.key', self::SSL_KEY_PASSPHRASE);
  214. $this->jws->sign($privateKey);
  215. $jws = JWS::load($this->jws->getTokenString());
  216. $public_key = openssl_pkey_get_public(SSL_KEYS_PATH.'public.key');
  217. $headerFromSig = $jws->getHeader();
  218. $this->assertSame($headerFromSig['test'], true);
  219. $this->assertTrue($jws->verify($public_key));
  220. }
  221. public function testVerificationWithJsonThatContainsWhitespace()
  222. {
  223. $header = '{
  224. "alg": "HS256"
  225. }';
  226. $payload = '{
  227. "a": "b"
  228. }';
  229. $encoder = new Base64UrlSafeEncoder();
  230. $signer = new HS256();
  231. $token = sprintf('%s.%s', $encoder->encode($header), $encoder->encode($payload));
  232. $signature = $encoder->encode($signer->sign($token, '123'));
  233. $jwsToken = sprintf('%s.%s', $token, $signature);
  234. $jws = JWS::load($jwsToken);
  235. $this->assertTrue($jws->verify('123'));
  236. }
  237. }