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