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