3 require_once 'Sabre/HTTP/ResponseMock.php';
5 class Sabre_HTTP_DigestAuthTest extends PHPUnit_Framework_TestCase {
8 * @var Sabre_HTTP_ResponseMock
12 * @var Sabre_HTTP_DigestAuth
16 const REALM = 'SabreDAV unittest';
18 public function setUp() {
20 $this->response = new Sabre_HTTP_ResponseMock();
21 $this->auth = new Sabre_HTTP_DigestAuth();
22 $this->auth->setRealm(self::REALM);
23 $this->auth->setHTTPResponse($this->response);
27 public function testDigest() {
29 list($nonce,$opaque) = $this->getServerTokens();
37 md5($username . ':' . self::REALM . ':' . $password) . ':' .
42 md5('GET' . ':' . '/')
45 $request = new Sabre_HTTP_Request(array(
46 'REQUEST_METHOD' => 'GET',
47 'PHP_AUTH_DIGEST' => 'username="'.$username.'", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth,nc='.$nc.',cnonce="' . $cnonce . '"',
50 $this->auth->setHTTPRequest($request);
53 $this->assertEquals($username,$this->auth->getUserName());
54 $this->assertEquals(self::REALM,$this->auth->getRealm());
55 $this->assertTrue($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . $password)),'Authentication is deemed invalid through validateA1');
56 $this->assertTrue($this->auth->validatePassword($password),'Authentication is deemed invalid through validatePassword');
60 public function testDigestCGIFormat() {
62 list($nonce,$opaque) = $this->getServerTokens();
70 md5($username . ':' . self::REALM . ':' . $password) . ':' .
75 md5('GET' . ':' . '/')
78 $request = new Sabre_HTTP_Request(array(
79 'REQUEST_METHOD' => 'GET',
80 'HTTP_AUTHORIZATION' => 'Digest username="'.$username.'", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth,nc='.$nc.',cnonce="' . $cnonce . '"',
83 $this->auth->setHTTPRequest($request);
86 $this->assertTrue($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . $password)),'Authentication is deemed invalid through validateA1');
87 $this->assertTrue($this->auth->validatePassword($password),'Authentication is deemed invalid through validatePassword');
91 public function testDigestApacheEdgeCase() {
93 list($nonce,$opaque) = $this->getServerTokens();
101 md5($username . ':' . self::REALM . ':' . $password) . ':' .
106 md5('GET' . ':' . '/')
109 $request = new Sabre_HTTP_Request(array(
110 'REQUEST_METHOD' => 'GET',
111 'REDIRECT_HTTP_AUTHORIZATION' => 'Digest username="'.$username.'", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth,nc='.$nc.',cnonce="' . $cnonce . '"',
114 $this->auth->setHTTPRequest($request);
117 $this->assertTrue($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . $password)),'Authentication is deemed invalid through validateA1');
118 $this->assertTrue($this->auth->validatePassword($password),'Authentication is deemed invalid through validatePassword');
122 public function testInvalidDigest() {
124 list($nonce,$opaque) = $this->getServerTokens();
132 md5($username . ':' . self::REALM . ':' . $password) . ':' .
137 md5('GET' . ':' . '/')
140 $request = new Sabre_HTTP_Request(array(
141 'REQUEST_METHOD' => 'GET',
142 'PHP_AUTH_DIGEST' => 'username="'.$username.'", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth,nc='.$nc.',cnonce="' . $cnonce . '"',
145 $this->auth->setHTTPRequest($request);
148 $this->assertFalse($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . ($password . 'randomness'))),'Authentication is deemed invalid through validateA1');
152 public function testInvalidDigest2() {
154 $request = new Sabre_HTTP_Request(array(
155 'REQUEST_METHOD' => 'GET',
156 'HTTP_AUTHORIZATION' => 'basic blablabla',
159 $this->auth->setHTTPRequest($request);
162 $this->assertFalse($this->auth->validateA1(md5('user:realm:password')));
167 public function testDigestAuthInt() {
169 $this->auth->setQOP(Sabre_HTTP_DigestAuth::QOP_AUTHINT | Sabre_HTTP_DigestAuth::QOP_AUTH);
170 list($nonce,$opaque) = $this->getServerTokens(Sabre_HTTP_DigestAuth::QOP_AUTHINT| Sabre_HTTP_DigestAuth::QOP_AUTH);
178 md5($username . ':' . self::REALM . ':' . $password) . ':' .
183 md5('POST' . ':' . '/' . ':' . md5('body'))
186 $request = new Sabre_HTTP_Request(array(
187 'REQUEST_METHOD' => 'POST',
188 'PHP_AUTH_DIGEST' => 'username="'.$username.'", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth-int,nc='.$nc.',cnonce="' . $cnonce . '"',
190 $request->setBody('body');
192 $this->auth->setHTTPRequest($request);
196 $this->assertTrue($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . $password)),'Authentication is deemed invalid through validateA1');
200 private function getServerTokens($qop = Sabre_HTTP_DigestAuth::QOP_AUTH) {
202 $this->auth->requireLogin();
205 case Sabre_HTTP_DigestAuth::QOP_AUTH : $qopstr='auth'; break;
206 case Sabre_HTTP_DigestAuth::QOP_AUTHINT : $qopstr='auth-int'; break;
207 default : $qopstr='auth,auth-int'; break;
210 $test = preg_match('/Digest realm="'.self::REALM.'",qop="'.$qopstr.'",nonce="([0-9a-f]*)",opaque="([0-9a-f]*)"/',
211 $this->response->headers['WWW-Authenticate'],$matches);
213 $this->assertTrue($test==true,'The WWW-Authenticate response didn\'t match our pattern. We received: ' . $this->response->headers['WWW-Authenticate']);
215 $nonce = $matches[1];
216 $opaque = $matches[2];
218 // Reset our environment
220 $this->auth->setQOP($qop);
222 return array($nonce,$opaque);