DigestTest.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. declare(strict_types=1);
  3. namespace Sabre\HTTP\Auth;
  4. use Sabre\HTTP\Request;
  5. use Sabre\HTTP\Response;
  6. class DigestTest extends \PHPUnit\Framework\TestCase
  7. {
  8. /**
  9. * @var Sabre\HTTP\Response
  10. */
  11. private $response;
  12. /**
  13. * request.
  14. *
  15. * @var Sabre\HTTP\Request
  16. */
  17. private $request;
  18. /**
  19. * @var Sabre\HTTP\Auth\Digest
  20. */
  21. private $auth;
  22. public const REALM = 'SabreDAV unittest';
  23. public function setUp(): void
  24. {
  25. $this->response = new Response();
  26. $this->request = new Request('GET', '/');
  27. $this->auth = new Digest(self::REALM, $this->request, $this->response);
  28. }
  29. public function testDigest()
  30. {
  31. list($nonce, $opaque) = $this->getServerTokens();
  32. $username = 'admin';
  33. $password = '12345';
  34. $nc = '00002';
  35. $cnonce = uniqid();
  36. $digestHash = md5(
  37. md5($username.':'.self::REALM.':'.$password).':'.
  38. $nonce.':'.
  39. $nc.':'.
  40. $cnonce.':'.
  41. 'auth:'.
  42. md5('GET:/')
  43. );
  44. $this->request->setMethod('GET');
  45. $this->request->setHeader('Authorization', 'Digest username="'.$username.'", realm="'.self::REALM.'", nonce="'.$nonce.'", uri="/", response="'.$digestHash.'", opaque="'.$opaque.'", qop=auth,nc='.$nc.',cnonce="'.$cnonce.'"');
  46. $this->auth->init();
  47. $this->assertEquals($username, $this->auth->getUsername());
  48. $this->assertEquals(self::REALM, $this->auth->getRealm());
  49. $this->assertTrue($this->auth->validateA1(md5($username.':'.self::REALM.':'.$password)), 'Authentication is deemed invalid through validateA1');
  50. $this->assertTrue($this->auth->validatePassword($password), 'Authentication is deemed invalid through validatePassword');
  51. }
  52. public function testInvalidDigest()
  53. {
  54. list($nonce, $opaque) = $this->getServerTokens();
  55. $username = 'admin';
  56. $password = 12345;
  57. $nc = '00002';
  58. $cnonce = uniqid();
  59. $digestHash = md5(
  60. md5($username.':'.self::REALM.':'.$password).':'.
  61. $nonce.':'.
  62. $nc.':'.
  63. $cnonce.':'.
  64. 'auth:'.
  65. md5('GET:/')
  66. );
  67. $this->request->setMethod('GET');
  68. $this->request->setHeader('Authorization', 'Digest username="'.$username.'", realm="'.self::REALM.'", nonce="'.$nonce.'", uri="/", response="'.$digestHash.'", opaque="'.$opaque.'", qop=auth,nc='.$nc.',cnonce="'.$cnonce.'"');
  69. $this->auth->init();
  70. $this->assertFalse($this->auth->validateA1(md5($username.':'.self::REALM.':'.($password.'randomness'))), 'Authentication is deemed invalid through validateA1');
  71. }
  72. public function testInvalidDigest2()
  73. {
  74. $this->request->setMethod('GET');
  75. $this->request->setHeader('Authorization', 'basic blablabla');
  76. $this->auth->init();
  77. $this->assertFalse($this->auth->validateA1(md5('user:realm:password')));
  78. }
  79. public function testDigestAuthInt()
  80. {
  81. $this->auth->setQOP(Digest::QOP_AUTHINT);
  82. list($nonce, $opaque) = $this->getServerTokens(Digest::QOP_AUTHINT);
  83. $username = 'admin';
  84. $password = 12345;
  85. $nc = '00003';
  86. $cnonce = uniqid();
  87. $digestHash = md5(
  88. md5($username.':'.self::REALM.':'.$password).':'.
  89. $nonce.':'.
  90. $nc.':'.
  91. $cnonce.':'.
  92. 'auth-int:'.
  93. md5('POST:/:'.md5('body'))
  94. );
  95. $this->request->setMethod('POST');
  96. $this->request->setHeader('Authorization', 'Digest username="'.$username.'", realm="'.self::REALM.'", nonce="'.$nonce.'", uri="/", response="'.$digestHash.'", opaque="'.$opaque.'", qop=auth-int,nc='.$nc.',cnonce="'.$cnonce.'"');
  97. $this->request->setBody('body');
  98. $this->auth->init();
  99. $this->assertTrue($this->auth->validateA1(md5($username.':'.self::REALM.':'.$password)), 'Authentication is deemed invalid through validateA1');
  100. }
  101. public function testDigestAuthBoth()
  102. {
  103. $this->auth->setQOP(Digest::QOP_AUTHINT | Digest::QOP_AUTH);
  104. list($nonce, $opaque) = $this->getServerTokens(Digest::QOP_AUTHINT | Digest::QOP_AUTH);
  105. $username = 'admin';
  106. $password = 12345;
  107. $nc = '00003';
  108. $cnonce = uniqid();
  109. $digestHash = md5(
  110. md5($username.':'.self::REALM.':'.$password).':'.
  111. $nonce.':'.
  112. $nc.':'.
  113. $cnonce.':'.
  114. 'auth-int:'.
  115. md5('POST:/:'.md5('body'))
  116. );
  117. $this->request->setMethod('POST');
  118. $this->request->setHeader('Authorization', 'Digest username="'.$username.'", realm="'.self::REALM.'", nonce="'.$nonce.'", uri="/", response="'.$digestHash.'", opaque="'.$opaque.'", qop=auth-int,nc='.$nc.',cnonce="'.$cnonce.'"');
  119. $this->request->setBody('body');
  120. $this->auth->init();
  121. $this->assertTrue($this->auth->validateA1(md5($username.':'.self::REALM.':'.$password)), 'Authentication is deemed invalid through validateA1');
  122. }
  123. private function getServerTokens($qop = Digest::QOP_AUTH)
  124. {
  125. $this->auth->requireLogin();
  126. switch ($qop) {
  127. case Digest::QOP_AUTH: $qopstr = 'auth';
  128. break;
  129. case Digest::QOP_AUTHINT: $qopstr = 'auth-int';
  130. break;
  131. default: $qopstr = 'auth,auth-int';
  132. break;
  133. }
  134. $test = preg_match('/Digest realm="'.self::REALM.'",qop="'.$qopstr.'",nonce="([0-9a-f]*)",opaque="([0-9a-f]*)"/',
  135. $this->response->getHeader('WWW-Authenticate'), $matches);
  136. $this->assertTrue(true == $test, 'The WWW-Authenticate response didn\'t match our pattern. We received: '.$this->response->getHeader('WWW-Authenticate'));
  137. $nonce = $matches[1];
  138. $opaque = $matches[2];
  139. // Reset our environment
  140. $this->setUp();
  141. $this->auth->setQOP($qop);
  142. return [$nonce, $opaque];
  143. }
  144. }