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