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 AWSTest 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 * @var Sabre\HTTP\Request 17*a1a3b679SAndreas Boehler */ 18*a1a3b679SAndreas Boehler private $request; 19*a1a3b679SAndreas Boehler 20*a1a3b679SAndreas Boehler /** 21*a1a3b679SAndreas Boehler * @var Sabre\HTTP\Auth\AWS 22*a1a3b679SAndreas Boehler */ 23*a1a3b679SAndreas Boehler private $auth; 24*a1a3b679SAndreas Boehler 25*a1a3b679SAndreas Boehler const REALM = 'SabreDAV unittest'; 26*a1a3b679SAndreas Boehler 27*a1a3b679SAndreas Boehler function setUp() { 28*a1a3b679SAndreas Boehler 29*a1a3b679SAndreas Boehler $this->response = new Response(); 30*a1a3b679SAndreas Boehler $this->request = new Request(); 31*a1a3b679SAndreas Boehler $this->auth = new AWS(self::REALM, $this->request, $this->response); 32*a1a3b679SAndreas Boehler 33*a1a3b679SAndreas Boehler } 34*a1a3b679SAndreas Boehler 35*a1a3b679SAndreas Boehler function testNoHeader() { 36*a1a3b679SAndreas Boehler 37*a1a3b679SAndreas Boehler $this->request->setMethod('GET'); 38*a1a3b679SAndreas Boehler $result = $this->auth->init(); 39*a1a3b679SAndreas Boehler 40*a1a3b679SAndreas Boehler $this->assertFalse($result, 'No AWS Authorization header was supplied, so we should have gotten false'); 41*a1a3b679SAndreas Boehler $this->assertEquals(AWS::ERR_NOAWSHEADER, $this->auth->errorCode); 42*a1a3b679SAndreas Boehler 43*a1a3b679SAndreas Boehler } 44*a1a3b679SAndreas Boehler 45*a1a3b679SAndreas Boehler function testIncorrectContentMD5() { 46*a1a3b679SAndreas Boehler 47*a1a3b679SAndreas Boehler $accessKey = 'accessKey'; 48*a1a3b679SAndreas Boehler $secretKey = 'secretKey'; 49*a1a3b679SAndreas Boehler 50*a1a3b679SAndreas Boehler $this->request->setMethod('GET'); 51*a1a3b679SAndreas Boehler $this->request->setHeaders([ 52*a1a3b679SAndreas Boehler 'Authorization' => "AWS $accessKey:sig", 53*a1a3b679SAndreas Boehler 'Content-MD5' => 'garbage', 54*a1a3b679SAndreas Boehler ]); 55*a1a3b679SAndreas Boehler $this->request->setUrl('/'); 56*a1a3b679SAndreas Boehler 57*a1a3b679SAndreas Boehler $this->auth->init(); 58*a1a3b679SAndreas Boehler $result = $this->auth->validate($secretKey); 59*a1a3b679SAndreas Boehler 60*a1a3b679SAndreas Boehler $this->assertFalse($result); 61*a1a3b679SAndreas Boehler $this->assertEquals(AWS::ERR_MD5CHECKSUMWRONG, $this->auth->errorCode); 62*a1a3b679SAndreas Boehler 63*a1a3b679SAndreas Boehler } 64*a1a3b679SAndreas Boehler 65*a1a3b679SAndreas Boehler function testNoDate() { 66*a1a3b679SAndreas Boehler 67*a1a3b679SAndreas Boehler $accessKey = 'accessKey'; 68*a1a3b679SAndreas Boehler $secretKey = 'secretKey'; 69*a1a3b679SAndreas Boehler $content = 'thisisthebody'; 70*a1a3b679SAndreas Boehler $contentMD5 = base64_encode(md5($content, true)); 71*a1a3b679SAndreas Boehler 72*a1a3b679SAndreas Boehler $this->request->setMethod('POST'); 73*a1a3b679SAndreas Boehler $this->request->setHeaders([ 74*a1a3b679SAndreas Boehler 'Authorization' => "AWS $accessKey:sig", 75*a1a3b679SAndreas Boehler 'Content-MD5' => $contentMD5, 76*a1a3b679SAndreas Boehler ]); 77*a1a3b679SAndreas Boehler $this->request->setUrl('/'); 78*a1a3b679SAndreas Boehler $this->request->setBody($content); 79*a1a3b679SAndreas Boehler 80*a1a3b679SAndreas Boehler $this->auth->init(); 81*a1a3b679SAndreas Boehler $result = $this->auth->validate($secretKey); 82*a1a3b679SAndreas Boehler 83*a1a3b679SAndreas Boehler $this->assertFalse($result); 84*a1a3b679SAndreas Boehler $this->assertEquals(AWS::ERR_INVALIDDATEFORMAT, $this->auth->errorCode); 85*a1a3b679SAndreas Boehler 86*a1a3b679SAndreas Boehler } 87*a1a3b679SAndreas Boehler 88*a1a3b679SAndreas Boehler function testFutureDate() { 89*a1a3b679SAndreas Boehler 90*a1a3b679SAndreas Boehler $accessKey = 'accessKey'; 91*a1a3b679SAndreas Boehler $secretKey = 'secretKey'; 92*a1a3b679SAndreas Boehler $content = 'thisisthebody'; 93*a1a3b679SAndreas Boehler $contentMD5 = base64_encode(md5($content, true)); 94*a1a3b679SAndreas Boehler 95*a1a3b679SAndreas Boehler $date = new \DateTime('@' . (time() + (60 * 20))); 96*a1a3b679SAndreas Boehler $date->setTimeZone(new \DateTimeZone('GMT')); 97*a1a3b679SAndreas Boehler $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); 98*a1a3b679SAndreas Boehler 99*a1a3b679SAndreas Boehler $this->request->setMethod('POST'); 100*a1a3b679SAndreas Boehler $this->request->setHeaders([ 101*a1a3b679SAndreas Boehler 'Authorization' => "AWS $accessKey:sig", 102*a1a3b679SAndreas Boehler 'Content-MD5' => $contentMD5, 103*a1a3b679SAndreas Boehler 'Date' => $date, 104*a1a3b679SAndreas Boehler ]); 105*a1a3b679SAndreas Boehler 106*a1a3b679SAndreas Boehler $this->request->setBody($content); 107*a1a3b679SAndreas Boehler 108*a1a3b679SAndreas Boehler $this->auth->init(); 109*a1a3b679SAndreas Boehler $result = $this->auth->validate($secretKey); 110*a1a3b679SAndreas Boehler 111*a1a3b679SAndreas Boehler $this->assertFalse($result); 112*a1a3b679SAndreas Boehler $this->assertEquals(AWS::ERR_REQUESTTIMESKEWED, $this->auth->errorCode); 113*a1a3b679SAndreas Boehler 114*a1a3b679SAndreas Boehler } 115*a1a3b679SAndreas Boehler 116*a1a3b679SAndreas Boehler function testPastDate() { 117*a1a3b679SAndreas Boehler 118*a1a3b679SAndreas Boehler $accessKey = 'accessKey'; 119*a1a3b679SAndreas Boehler $secretKey = 'secretKey'; 120*a1a3b679SAndreas Boehler $content = 'thisisthebody'; 121*a1a3b679SAndreas Boehler $contentMD5 = base64_encode(md5($content, true)); 122*a1a3b679SAndreas Boehler 123*a1a3b679SAndreas Boehler $date = new \DateTime('@' . (time() - (60 * 20))); 124*a1a3b679SAndreas Boehler $date->setTimeZone(new \DateTimeZone('GMT')); 125*a1a3b679SAndreas Boehler $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); 126*a1a3b679SAndreas Boehler 127*a1a3b679SAndreas Boehler $this->request->setMethod('POST'); 128*a1a3b679SAndreas Boehler $this->request->setHeaders([ 129*a1a3b679SAndreas Boehler 'Authorization' => "AWS $accessKey:sig", 130*a1a3b679SAndreas Boehler 'Content-MD5' => $contentMD5, 131*a1a3b679SAndreas Boehler 'Date' => $date, 132*a1a3b679SAndreas Boehler ]); 133*a1a3b679SAndreas Boehler 134*a1a3b679SAndreas Boehler $this->request->setBody($content); 135*a1a3b679SAndreas Boehler 136*a1a3b679SAndreas Boehler $this->auth->init(); 137*a1a3b679SAndreas Boehler $result = $this->auth->validate($secretKey); 138*a1a3b679SAndreas Boehler 139*a1a3b679SAndreas Boehler $this->assertFalse($result); 140*a1a3b679SAndreas Boehler $this->assertEquals(AWS::ERR_REQUESTTIMESKEWED, $this->auth->errorCode); 141*a1a3b679SAndreas Boehler 142*a1a3b679SAndreas Boehler } 143*a1a3b679SAndreas Boehler 144*a1a3b679SAndreas Boehler function testIncorrectSignature() { 145*a1a3b679SAndreas Boehler 146*a1a3b679SAndreas Boehler $accessKey = 'accessKey'; 147*a1a3b679SAndreas Boehler $secretKey = 'secretKey'; 148*a1a3b679SAndreas Boehler $content = 'thisisthebody'; 149*a1a3b679SAndreas Boehler 150*a1a3b679SAndreas Boehler $contentMD5 = base64_encode(md5($content, true)); 151*a1a3b679SAndreas Boehler 152*a1a3b679SAndreas Boehler $date = new \DateTime('now'); 153*a1a3b679SAndreas Boehler $date->setTimeZone(new \DateTimeZone('GMT')); 154*a1a3b679SAndreas Boehler $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); 155*a1a3b679SAndreas Boehler 156*a1a3b679SAndreas Boehler $this->request->setUrl('/'); 157*a1a3b679SAndreas Boehler $this->request->setMethod('POST'); 158*a1a3b679SAndreas Boehler $this->request->setHeaders([ 159*a1a3b679SAndreas Boehler 'Authorization' => "AWS $accessKey:sig", 160*a1a3b679SAndreas Boehler 'Content-MD5' => $contentMD5, 161*a1a3b679SAndreas Boehler 'X-amz-date' => $date, 162*a1a3b679SAndreas Boehler ]); 163*a1a3b679SAndreas Boehler $this->request->setBody($content); 164*a1a3b679SAndreas Boehler 165*a1a3b679SAndreas Boehler $this->request->setBody($content); 166*a1a3b679SAndreas Boehler 167*a1a3b679SAndreas Boehler $this->auth->init(); 168*a1a3b679SAndreas Boehler $result = $this->auth->validate($secretKey); 169*a1a3b679SAndreas Boehler 170*a1a3b679SAndreas Boehler $this->assertFalse($result); 171*a1a3b679SAndreas Boehler $this->assertEquals(AWS::ERR_INVALIDSIGNATURE, $this->auth->errorCode); 172*a1a3b679SAndreas Boehler 173*a1a3b679SAndreas Boehler } 174*a1a3b679SAndreas Boehler 175*a1a3b679SAndreas Boehler function testValidRequest() { 176*a1a3b679SAndreas Boehler 177*a1a3b679SAndreas Boehler $accessKey = 'accessKey'; 178*a1a3b679SAndreas Boehler $secretKey = 'secretKey'; 179*a1a3b679SAndreas Boehler $content = 'thisisthebody'; 180*a1a3b679SAndreas Boehler $contentMD5 = base64_encode(md5($content, true)); 181*a1a3b679SAndreas Boehler 182*a1a3b679SAndreas Boehler $date = new \DateTime('now'); 183*a1a3b679SAndreas Boehler $date->setTimeZone(new \DateTimeZone('GMT')); 184*a1a3b679SAndreas Boehler $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); 185*a1a3b679SAndreas Boehler 186*a1a3b679SAndreas Boehler 187*a1a3b679SAndreas Boehler $sig = base64_encode($this->hmacsha1($secretKey, 188*a1a3b679SAndreas Boehler "POST\n$contentMD5\n\n$date\nx-amz-date:$date\n/evert" 189*a1a3b679SAndreas Boehler )); 190*a1a3b679SAndreas Boehler 191*a1a3b679SAndreas Boehler $this->request->setUrl('/evert'); 192*a1a3b679SAndreas Boehler $this->request->setMethod('POST'); 193*a1a3b679SAndreas Boehler $this->request->setHeaders([ 194*a1a3b679SAndreas Boehler 'Authorization' => "AWS $accessKey:$sig", 195*a1a3b679SAndreas Boehler 'Content-MD5' => $contentMD5, 196*a1a3b679SAndreas Boehler 'X-amz-date' => $date, 197*a1a3b679SAndreas Boehler ]); 198*a1a3b679SAndreas Boehler 199*a1a3b679SAndreas Boehler $this->request->setBody($content); 200*a1a3b679SAndreas Boehler 201*a1a3b679SAndreas Boehler $this->auth->init(); 202*a1a3b679SAndreas Boehler $result = $this->auth->validate($secretKey); 203*a1a3b679SAndreas Boehler 204*a1a3b679SAndreas Boehler $this->assertTrue($result, 'Signature did not validate, got errorcode ' . $this->auth->errorCode); 205*a1a3b679SAndreas Boehler $this->assertEquals($accessKey, $this->auth->getAccessKey()); 206*a1a3b679SAndreas Boehler 207*a1a3b679SAndreas Boehler } 208*a1a3b679SAndreas Boehler 209*a1a3b679SAndreas Boehler function test401() { 210*a1a3b679SAndreas Boehler 211*a1a3b679SAndreas Boehler $this->auth->requireLogin(); 212*a1a3b679SAndreas Boehler $test = preg_match('/^AWS$/', $this->response->getHeader('WWW-Authenticate'), $matches); 213*a1a3b679SAndreas Boehler $this->assertTrue($test == true, 'The WWW-Authenticate response didn\'t match our pattern'); 214*a1a3b679SAndreas Boehler 215*a1a3b679SAndreas Boehler } 216*a1a3b679SAndreas Boehler 217*a1a3b679SAndreas Boehler /** 218*a1a3b679SAndreas Boehler * Generates an HMAC-SHA1 signature 219*a1a3b679SAndreas Boehler * 220*a1a3b679SAndreas Boehler * @param string $key 221*a1a3b679SAndreas Boehler * @param string $message 222*a1a3b679SAndreas Boehler * @return string 223*a1a3b679SAndreas Boehler */ 224*a1a3b679SAndreas Boehler private function hmacsha1($key, $message) { 225*a1a3b679SAndreas Boehler 226*a1a3b679SAndreas Boehler $blocksize = 64; 227*a1a3b679SAndreas Boehler if (strlen($key) > $blocksize) 228*a1a3b679SAndreas Boehler $key = pack('H*', sha1($key)); 229*a1a3b679SAndreas Boehler $key = str_pad($key, $blocksize, chr(0x00)); 230*a1a3b679SAndreas Boehler $ipad = str_repeat(chr(0x36), $blocksize); 231*a1a3b679SAndreas Boehler $opad = str_repeat(chr(0x5c), $blocksize); 232*a1a3b679SAndreas Boehler $hmac = pack('H*', sha1(($key ^ $opad) . pack('H*', sha1(($key ^ $ipad) . $message)))); 233*a1a3b679SAndreas Boehler return $hmac; 234*a1a3b679SAndreas Boehler 235*a1a3b679SAndreas Boehler } 236*a1a3b679SAndreas Boehler 237*a1a3b679SAndreas Boehler} 238