new config to disallow webdav clients using user agent strings
[tine20] / tests / tine20 / Tinebase / Server / WebDAVTests.php
1 <?php
2 /**
3  * Tine 2.0 - http://www.tine20.org
4  * 
5  * @package     Tinebase
6  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
7  * @copyright   Copyright (c) 2012-2014 Metaways Infosystems GmbH (http://www.metaways.de)
8  * @author      Lars Kneschke <l.kneschke@metaways.de>
9  */
10
11 /**
12  * Test class for Tinebase_Server_WebDAV
13  * 
14  * @package     Tinebase
15  */
16 class Tinebase_Server_WebDAVTests extends ServerTestCase
17 {
18     #protected $_logPriority = Zend_Log::DEBUG;
19     
20     /**
21      * test general functionality of Tinebase_Server_WebDAV
22      * @group ServerTests
23      */
24     public function testServer($noAssert = false)
25     {
26         $request = \Zend\Http\PhpEnvironment\Request::fromString(<<<EOS
27 PROPFIND /calendars/64d7fdf9202f7b1faf7467f5066d461c2e75cf2b/4/ HTTP/1.1
28 Host: localhost
29 Depth: 0
30 User-Agent: Mozilla/5.0 (X11; Linux i686; rv:15.0) Gecko/20120824 Thunderbird/15.0 Lightning/1.7
31 EOS
32         );
33         
34         $_SERVER['REQUEST_METHOD'] = $request->getMethod();
35         $_SERVER['REQUEST_URI']    = $request->getUri()->getPath();
36         $_SERVER['HTTP_DEPTH']     = '0';
37         
38         $credentials = $this->getTestCredentials();
39         
40         $request->getServer()->set('PHP_AUTH_USER', $credentials['username']);
41         $request->getServer()->set('PHP_AUTH_PW',   $credentials['password']);
42         $request->getServer()->set('REMOTE_ADDR',   'localhost');
43         
44         $body = fopen('php://temp', 'r+');
45         fwrite($body, '<?xml version="1.0" encoding="UTF-8"?><D:propfind xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/"><D:prop><CS:getctag/></D:prop></D:propfind>');
46         rewind($body);
47         
48         ob_start();
49         
50         $server = new Tinebase_Server_WebDAV();
51         
52         $server->handle($request, $body);
53         
54         $result = ob_get_contents();
55         
56         ob_end_clean();
57
58         if (true === $noAssert) {
59             return $result;
60         }
61
62         $this->assertEquals('PD94bWwgdmVyc2lvbj0iMS4wIiBlbm', substr(base64_encode($result),0,30));
63     }
64
65     public function testDenyingWebDavClient()
66     {
67         Tinebase_Config::getInstance()->set(Tinebase_Config::DENY_WEBDAV_CLIENT_LIST, array('/deniedClient/'));
68
69         $_SERVER['HTTP_USER_AGENT'] = 'deniedClient';
70         static::assertTrue(empty($this->testServer(true)));
71     }
72     
73     /**
74      * test general functionality of Tinebase_Server_WebDAV
75      * @group ServerTests
76      */
77     public function testServerWithAuthorizationHeader()
78     {
79         $credentials = $this->getTestCredentials();
80         
81         $hash = base64_encode($credentials['username'] . ':' . $credentials['password']);
82         
83         $request = \Zend\Http\PhpEnvironment\Request::fromString(
84 "PROPFIND /calendars/64d7fdf9202f7b1faf7467f5066d461c2e75cf2b/4/ HTTP/1.1\r\n"
85 . "Host: localhost\r\n"
86 . "Depth: 0\r\n"
87 . "User-Agent: Mozilla/5.0 (X11; Linux i686; rv:15.0) Gecko/20120824 Thunderbird/15.0 Lightning/1.7\r\n"
88 . "Authorization: Basic $hash\r\n"
89         );
90         
91         $_SERVER['REQUEST_METHOD'] = $request->getMethod();
92         $_SERVER['REQUEST_URI']    = $request->getUri()->getPath();
93         $_SERVER['HTTP_DEPTH']     = '0';
94         
95         $request->getServer()->set('REMOTE_ADDR', 'localhost');
96         
97         $body = fopen('php://temp', 'r+');
98         fwrite($body, '<?xml version="1.0" encoding="UTF-8"?><D:propfind xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/"><D:prop><CS:getctag/></D:prop></D:propfind>');
99         rewind($body);
100         
101         ob_start();
102         
103         $server = new Tinebase_Server_WebDAV();
104         
105         $server->handle($request, $body);
106         
107         $result = ob_get_contents();
108         
109         ob_end_clean();
110
111         print_r($request->getHeader('HTTP_AUTHORIZATION'));
112         print_r($request->getHeaders());
113         
114         $this->assertEquals('PD94bWwgdmVyc2lvbj0iMS4wIiBlbm', substr(base64_encode($result),0,30), $result);
115     }
116     
117     /**
118      * test general functionality of Tinebase_Server_WebDAV
119      * @group ServerTests
120      */
121     public function testServerWithAuthorizationEnv()
122     {
123         $credentials = $this->getTestCredentials();
124         
125         $hash = base64_encode($credentials['username'] . ':' . $credentials['password']);
126         
127         $request = \Zend\Http\PhpEnvironment\Request::fromString(<<<EOS
128 PROPFIND /calendars/64d7fdf9202f7b1faf7467f5066d461c2e75cf2b/4/ HTTP/1.1
129 Host: localhost
130 Depth: 0
131 User-Agent: Mozilla/5.0 (X11; Linux i686; rv:15.0) Gecko/20120824 Thunderbird/15.0 Lightning/1.7
132 EOS
133         );
134         
135         $_SERVER['REQUEST_METHOD'] = $request->getMethod();
136         $_SERVER['REQUEST_URI']    = $request->getUri()->getPath();
137         $_SERVER['HTTP_DEPTH']     = '0';
138         
139         $request->getServer()->set('HTTP_AUTHORIZATION', 'Basic ' . $hash);
140         $request->getServer()->set('REMOTE_ADDR',          'localhost');
141         
142         $body = fopen('php://temp', 'r+');
143         fwrite($body, '<?xml version="1.0" encoding="UTF-8"?><D:propfind xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/"><D:prop><CS:getctag/></D:prop></D:propfind>');
144         rewind($body);
145         
146         ob_start();
147         
148         $server = new Tinebase_Server_WebDAV();
149         
150         $server->handle($request, $body);
151         
152         $result = ob_get_contents();
153         
154         ob_end_clean();
155         
156         $this->assertEquals('PD94bWwgdmVyc2lvbj0iMS4wIiBlbm', substr(base64_encode($result),0,30));
157     }
158     
159     /**
160      * test general functionality of Tinebase_Server_WebDAV
161      * @group ServerTests
162      */
163     public function testServerWithAuthorizationRemoteUser()
164     {
165         $credentials = $this->getTestCredentials();
166         
167         $hash = base64_encode($credentials['username'] . ':' . $credentials['password']);
168         
169         $request = \Zend\Http\PhpEnvironment\Request::fromString(<<<EOS
170 PROPFIND /calendars/64d7fdf9202f7b1faf7467f5066d461c2e75cf2b/4/ HTTP/1.1
171 Host: localhost
172 Depth: 0
173 User-Agent: Mozilla/5.0 (X11; Linux i686; rv:15.0) Gecko/20120824 Thunderbird/15.0 Lightning/1.7
174 EOS
175         );
176         
177         $_SERVER['REQUEST_METHOD'] = $request->getMethod();
178         $_SERVER['REQUEST_URI']    = $request->getUri()->getPath();
179         $_SERVER['HTTP_DEPTH']     = '0';
180         
181         $request->getServer()->set('REDIRECT_REMOTE_USER', 'Basic ' . $hash);
182         $request->getServer()->set('REMOTE_ADDR',          'localhost');
183         
184         $body = fopen('php://temp', 'r+');
185         fwrite($body, '<?xml version="1.0" encoding="UTF-8"?><D:propfind xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/"><D:prop><CS:getctag/></D:prop></D:propfind>');
186         rewind($body);
187         
188         ob_start();
189         
190         $server = new Tinebase_Server_WebDAV();
191         
192         $server->handle($request, $body);
193         
194         $result = ob_get_contents();
195         
196         ob_end_clean();
197         
198         $this->assertEquals('PD94bWwgdmVyc2lvbj0iMS4wIiBlbm', substr(base64_encode($result),0,30));
199     }
200     
201     /**
202      * test propfind for current-user-principal
203      * 
204      * you have to provide a valid contactid
205      * @group ServerTests
206      */
207     public function testPropfindCurrentUserPrincipal()
208     {
209         $request = \Zend\Http\PhpEnvironment\Request::fromString(<<<EOS
210 PROPFIND /principals/users/ HTTP/1.1
211 Host: localhost
212 Depth: 0
213 User-Agent: Mozilla/5.0 (X11; Linux i686; rv:15.0) Gecko/20120824 Thunderbird/15.0 Lightning/1.7
214 EOS
215         );
216         
217         $_SERVER['REQUEST_METHOD'] = $request->getMethod();
218         $_SERVER['REQUEST_URI']    = $request->getUri()->getPath();
219         $_SERVER['HTTP_DEPTH']     = '0';
220         
221         $credentials = $this->getTestCredentials();
222         
223         $request->getServer()->set('PHP_AUTH_USER', $credentials['username']);
224         $request->getServer()->set('PHP_AUTH_PW',   $credentials['password']);
225         $request->getServer()->set('REMOTE_ADDR',   'localhost');
226         
227         $body = fopen('php://temp', 'r+');
228         fwrite($body, '<?xml version="1.0" encoding="UTF-8"?><D:propfind xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"><D:prop><D:current-user-principal/><D:principal-URL/><D:resourcetype/></D:prop></D:propfind>');
229         rewind($body);
230
231         $bbody = fopen('php://temp', 'r+');
232         fwrite($bbody, '<?xml version="1.0" encoding="UTF-8"?><D:propfind xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"><D:prop><C:calendar-home-set/><C:calendar-user-address-set/><C:schedule-inbox-URL/><C:schedule-outbox-URL/></D:prop></D:propfind>');
233         rewind($bbody);
234         
235         ob_start();
236         
237         $server = new Tinebase_Server_WebDAV();
238         
239         $server->handle($request, $body);
240         
241         $result = ob_get_contents();
242         
243         ob_end_clean();
244         
245         #error_log($result);
246         
247         $responseDoc = new DOMDocument();
248         $responseDoc->loadXML($result);
249         #$responseDoc->formatOutput = true; error_log($responseDoc->saveXML());
250         $xpath = new DomXPath($responseDoc);
251         $xpath->registerNamespace('d', 'DAV:');
252         
253         $nodes = $xpath->query('//d:multistatus/d:response/d:propstat/d:prop/d:current-user-principal/d:href');
254         $this->assertEquals(1, $nodes->length, $responseDoc->saveXML());
255         $this->assertNotEmpty($nodes->item(0)->nodeValue, $responseDoc->saveXML());
256     }
257     
258     /**
259      * test propfind for current-user-principal
260      * 
261      * you have to provide a valid contactid
262      * @group ServerTests
263      */
264     public function testPropfindPrincipal()
265     {
266         $credentials = $this->getTestCredentials();
267         
268         $account = $this->getAccountByName($credentials['username']);
269         
270         $this->assertInstanceOf('Tinebase_Model_FullUser', $account);
271         
272         $request = \Zend\Http\PhpEnvironment\Request::fromString(
273 "PROPFIND /principals/users/{$account->contact_id}/ HTTP/1.1\r\n"
274 . "Host: localhost\r\n"
275 . "Depth: 0\r\n"
276 . "User-Agent: Mozilla/5.0 (X11; Linux i686; rv:15.0) Gecko/20120824 Thunderbird/15.0 Lightning/1.7\r\n"
277 . "\r\n"
278 . "<?xml version=\"1.0\" encoding=\"UTF-8\"?><D:propfind xmlns:D=\"DAV:\" xmlns:C=\"urn:ietf:params:xml:ns:caldav\"><D:prop><C:calendar-home-set/><C:calendar-user-address-set/><C:schedule-inbox-URL/><C:schedule-outbox-URL/></D:prop></D:propfind>\r\n"
279         );
280         
281         $_SERVER['REQUEST_METHOD'] = $request->getMethod();
282         $_SERVER['REQUEST_URI']    = $request->getUri()->getPath();
283         $_SERVER['HTTP_DEPTH']     = '0';
284         
285         $request->getServer()->set('PHP_AUTH_USER', $credentials['username']);
286         $request->getServer()->set('PHP_AUTH_PW',   $credentials['password']);
287         $request->getServer()->set('REMOTE_ADDR',   'localhost');
288         
289         ob_start();
290         
291         $server = new Tinebase_Server_WebDAV();
292         
293         $server->handle($request);
294         
295         $result = ob_get_contents();
296         
297         ob_end_clean();
298         
299         #error_log($result);
300         
301         $responseDoc = new DOMDocument();
302         $responseDoc->loadXML($result);
303         #$responseDoc->formatOutput = true; error_log($responseDoc->saveXML());
304         $xpath = new DomXPath($responseDoc);
305         $xpath->registerNamespace('d', 'DAV:');
306         $xpath->registerNamespace('cal', 'urn:ietf:params:xml:ns:caldav');
307         
308         $nodes = $xpath->query('//d:multistatus/d:response/d:propstat/d:prop/cal:calendar-home-set');
309         $this->assertEquals(1, $nodes->length, $responseDoc->saveXML());
310         $this->assertNotEmpty($nodes->item(0)->nodeValue, $responseDoc->saveXML());
311         
312         $nodes = $xpath->query('//d:multistatus/d:response/d:propstat/d:prop/cal:calendar-user-address-set');
313         $this->assertEquals(1, $nodes->length, $responseDoc->saveXML());
314         $this->assertNotEmpty($nodes->item(0)->nodeValue, $responseDoc->saveXML());
315         
316         $nodes = $xpath->query('//d:multistatus/d:response/d:propstat/d:prop/cal:schedule-inbox-URL');
317         $this->assertEquals(1, $nodes->length, $responseDoc->saveXML());
318         $this->assertNotEmpty($nodes->item(0)->nodeValue, $responseDoc->saveXML());
319     }
320     
321     /**
322      * test general functionality of Tinebase_Server_WebDAV
323      * @group ServerTests
324      */
325     public function testReportQuery()
326     {
327         $credentials = $this->getTestCredentials();
328         
329         $account = $this->getAccountByName($credentials['username']);
330         
331         $this->assertInstanceOf('Tinebase_Model_FullUser', $account);
332         if (Tinebase_Core::getUser() === null) {
333             Tinebase_Core::set(Tinebase_Core::USER, $account);
334         }
335         
336         $containerId = $this->getPersonalContainer($account, 'Calendar_Model_Event')
337             ->getFirstRecord()
338             ->getId();
339         
340         $request = \Zend\Http\PhpEnvironment\Request::fromString(<<<EOS
341 REPORT /calendars/{$account->contact_id}/{$containerId}/ HTTP/1.1
342 Host: localhost
343 Depth: 1
344 Content-Type: application/xml; charset="utf-8"
345 User-Agent: Mozilla/5.0 (X11; Linux i686; rv:15.0) Gecko/20120824 Thunderbird/15.0 Lightning/1.7
346
347 <?xml version="1.0" encoding="utf-8" ?><C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"><D:prop><D:getetag/><C:calendar-data/></D:prop><C:filter><C:comp-filter name="VCALENDAR"><C:comp-filter name="VEVENT"><C:time-range start="20060104T000000Z" end="20160105T000000Z"/></C:comp-filter></C:comp-filter></C:filter></C:calendar-query>
348 EOS
349         );
350         
351         $_SERVER['REQUEST_METHOD'] = $request->getMethod();
352         $_SERVER['REQUEST_URI']    = $request->getUri()->getPath();
353         $_SERVER['HTTP_DEPTH']     = '0';
354         
355         $request->getServer()->set('PHP_AUTH_USER', $credentials['username']);
356         $request->getServer()->set('PHP_AUTH_PW',   $credentials['password']);
357         $request->getServer()->set('REMOTE_ADDR',   'localhost');
358         
359         ob_start();
360         
361         $server = new Tinebase_Server_WebDAV();
362         
363         $server->handle($request);
364         
365         $result = ob_get_contents();
366         
367         ob_end_clean();
368         
369         $responseDoc = new DOMDocument();
370         $responseDoc->loadXML($result);
371         #$responseDoc->formatOutput = true; error_log($responseDoc->saveXML());
372         
373         $xpath = new DomXPath($responseDoc);
374         $xpath->registerNamespace('cal', 'urn:ietf:params:xml:ns:caldav');
375         $xpath->registerNamespace('cs',  'http://calendarserver.org/ns/');
376         
377         #$nodes = $xpath->query('//d:multistatus/d:response/d:propstat/d:prop/d:current-user-principal');
378         #$this->assertEquals(1, $nodes->length, $responseDoc->saveXML());
379         
380         // emoty response
381         $this->assertEquals('PD94bWwgdmVyc2lvbj0iMS4wIiBlbm', substr(base64_encode($result),0,30));
382     }
383     
384     /**
385      * test PROPFIND on calendar
386      * 
387      * @group ServerTests
388      */
389     public function testPropfindThundebird()
390     {
391         $credentials = $this->getTestCredentials();
392         
393         $account = $this->getAccountByName($credentials['username']);
394         
395         $this->assertInstanceOf('Tinebase_Model_FullUser', $account);
396
397         if (Tinebase_Core::getUser() === null) {
398             Tinebase_Core::set(Tinebase_Core::USER, $account);
399         }
400         
401         $containerId = $this->getPersonalContainer($account, 'Calendar_Model_Event')
402             ->getFirstRecord()
403             ->getId();
404         
405         $request = \Zend\Http\PhpEnvironment\Request::fromString(
406 "PROPFIND /calendars/{$account->contact_id}/{$containerId}/ HTTP/1.1" . "\r\n"
407 . "Host: localhost" . "\r\n"
408 . "Depth: 1" . "\r\n"
409 . 'Content-Type: application/xml; charset="utf-8"' . "\r\n"
410 . "User-Agent: Mozilla/5.0 (X11; Linux i686; rv:15.0) Gecko/20120824 Thunderbird/15.0 Lightning/1.7" . "\r\n"
411 . "\r\n"
412 . '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n"
413 . '<D:propfind xmlns:D="DAV:" xmlns:CS="http://calendarserver.org/ns/" xmlns:C="urn:ietf:params:xml:ns:caldav"><D:prop><D:resourcetype/><D:owner/><D:current-user-principal/><D:supported-report-set/><C:supported-calendar-component-set/><CS:getctag/></D:prop></D:propfind>'
414 . "\r\n"
415         );
416
417         $_SERVER['REQUEST_METHOD'] = $request->getMethod();
418         $_SERVER['REQUEST_URI']    = $request->getUri()->getPath();
419         $_SERVER['HTTP_DEPTH']     = '0';
420         
421         $request->getServer()->set('PHP_AUTH_USER', $credentials['username']);
422         $request->getServer()->set('PHP_AUTH_PW',   $credentials['password']);
423         $request->getServer()->set('REMOTE_ADDR',   'localhost');
424         
425         ob_start();
426         
427         $server = new Tinebase_Server_WebDAV();
428         
429         $server->handle($request);
430         
431         $result = ob_get_contents();
432         
433         ob_end_clean();
434         
435         $responseDoc = new DOMDocument();
436         $responseDoc->loadXML($result);
437         #$responseDoc->formatOutput = true; error_log($responseDoc->saveXML());
438         
439         $xpath = new DomXPath($responseDoc);
440         $xpath->registerNamespace('cal', 'urn:ietf:params:xml:ns:caldav');
441         $xpath->registerNamespace('cs',  'http://calendarserver.org/ns/');
442         
443         $nodes = $xpath->query('//d:multistatus/d:response/d:propstat/d:prop/d:current-user-principal');
444         $this->assertEquals(1, $nodes->length, $responseDoc->saveXML());
445     }
446 }