1<?php
2/**
3 * Test the test driver.
4 *
5 * PHP version 5
6 *
7 * @category Kolab
8 * @package  Kolab_Server
9 * @author   Gunnar Wrobel <wrobel@pardus.de>
10 * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
11 * @link     http://pear.horde.org/index.php?package=Kolab_Server
12 */
13
14/**
15 * Require our basic test case definition
16 */
17require_once __DIR__ . '/../../../../LdapTestCase.php';
18
19/**
20 * Test the test backend.
21 *
22 * Copyright 2008-2016 Horde LLC (http://www.horde.org/)
23 *
24 * See the enclosed file COPYING for license information (LGPL). If you
25 * did not receive this file, see http://www.horde.org/licenses/lgpl21.
26 *
27 * @category Kolab
28 * @package  Kolab_Server
29 * @author   Gunnar Wrobel <wrobel@pardus.de>
30 * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
31 * @link     http://pear.horde.org/index.php?package=Kolab_Server
32 */
33class Horde_Kolab_Server_Class_Server_Connection_Mock_LdapTest
34extends Horde_Kolab_Server_LdapTestCase
35{
36    /**
37     * Test parsing of LDAP filters.
38     *
39     * @return NULL
40     */
41    public function testFilterParse()
42    {
43        $this->skipIfNoLdap();
44
45        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(array(), array());
46
47        $a = $conn->parse('(a=b)');
48        $this->assertEquals(array('att' => 'a', 'log' => '=', 'val' => 'b'),
49                            $a);
50
51        $a = $conn->parse('(&(a=b)(c=d))');
52        $this->assertEquals(array('op' => '&', 'sub' => array(
53                                      array('att' => 'a', 'log' => '=', 'val' => 'b'),
54                                      array('att' => 'c', 'log' => '=', 'val' => 'd'),
55                                  )), $a);
56
57        $a = $conn->parse('(&(a=1)(|(b=2)(c=3)))');
58        $this->assertEquals(array('op' => '&', 'sub' => array(
59                                      array('att' => 'a', 'log' => '=', 'val' => '1'),
60                                      array('op' => '|', 'sub' =>
61                                            array(
62                                                array('att' => 'b', 'log' => '=', 'val' => '2'),
63                                                array('att' => 'c', 'log' => '=', 'val' => '3'),
64                                            )))), $a);
65
66        $a = $conn->parseSub('(!(x=2))(b=1)');
67        $this->assertEquals(array(array('op' => '!', 'sub' =>
68                                        array(
69                                            array('att' => 'x', 'log' => '=', 'val' => '2'),
70                                        )
71                                  ),
72                                  array('att' => 'b', 'log' => '=', 'val' => '1'),
73                            ), $a);
74
75        $a = $conn->parse('(&(!(x=2))(b=1))');
76        $this->assertEquals(array('op' => '&', 'sub' => array(
77                                      array('op' => '!', 'sub' =>
78                                            array(
79                                                array('att' => 'x', 'log' => '=', 'val' => '2'),
80                                            )
81                                      ),
82                                      array('att' => 'b', 'log' => '=', 'val' => '1'),
83                                  )), $a);
84
85        try {
86            $a = $conn->parse('dummy');
87            $this->fail('No exception!');
88        } catch (Horde_Kolab_Server_Exception $e) {
89            $this->assertEquals('Filter parsing error: dummy - filter components must be enclosed in round brackets', $e->getMessage());
90        }
91
92        try {
93            $a = $conn->parse('(a/b)');
94            $this->fail('No exception!');
95        } catch (Horde_Kolab_Server_Exception $e) {
96            $this->assertEquals('Filter parsing error: invalid filter syntax - unknown matching rule used', $e->getMessage());
97        }
98
99        try {
100            $a = $conn->parse('(a=b)(c=d)');
101            $this->fail('No exception!');
102        } catch (Horde_Kolab_Server_Exception $e) {
103            $this->assertEquals('Filter parsing error: invalid filter syntax - multiple leaf components detected!', $e->getMessage());
104        }
105    }
106
107    /**
108     * Test searching in the simulated LDAP data.
109     *
110     * @return NULL
111     */
112    public function testSearch()
113    {
114        $this->skipIfNoLdap();
115
116        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
117            array(),
118            array(
119                'cn=a' => array(
120                    'dn' => 'cn=a',
121                    'data' => array(
122                        'a' => '1',
123                        'b' => '1',
124                        'c' => '1',
125                    )
126                ),
127                'cn=b' => array(
128                    'dn' => 'cn=b',
129                    'data' => array(
130                        'a' => '1',
131                        'b' => '2',
132                        'c' => '2',
133                    )
134                ),
135                'cn=c' => array(
136                    'dn' => 'cn=c',
137                    'data' => array(
138                        'a' => '1',
139                        'b' => '2',
140                        'c' => '3',
141                    )
142                ),
143                'cn=d' => array(
144                    'dn' => 'cn=d',
145                    'data' => array(
146                        'a' => '2',
147                        'b' => '2',
148                        'c' => '1',
149                    )
150                ),
151            )
152        );
153        $conn->bind();
154
155        $a = $conn->search(null, '(c=1)');
156        $this->assertEquals(
157            array(
158                'cn=a' => array(
159                    'a' => '1',
160                    'b' => '1',
161                    'c' => '1',
162                    'dn' => 'cn=a',
163                ),
164                'cn=d' => array(
165                    'a' => '2',
166                    'b' => '2',
167                    'c' => '1',
168                    'dn' => 'cn=d',
169                ),
170            ),
171            $a->asArray()
172        );
173
174        $a = $conn->search(null, '(c=3)');
175        $this->assertEquals(
176            array(
177                'cn=c' => array(
178                    'a' => '1',
179                    'b' => '2',
180                    'c' => '3',
181                    'dn' => 'cn=c',
182                ),
183            ),
184            $a->asArray()
185        );
186
187        $a = $conn->search(null, '(c=3)', array('attributes' => array('a')));
188        $this->assertEquals(
189            array(
190                'cn=c' => array(
191                    'a' => '1',
192                    'dn' => 'cn=c',
193                ),
194            ),
195            $a->asArray()
196        );
197
198        $a = $conn->search(null, '(&(a=1)(b=2))', array('attributes' => array('a', 'b')));
199        $this->assertEquals(
200            array(
201                'cn=b' => array(
202                    'a' => '1',
203                    'b' => '2',
204                    'dn' => 'cn=b',
205                ),
206                'cn=c' => array(
207                    'a' => '1',
208                    'b' => '2',
209                    'dn' => 'cn=c',
210                ),
211            ),
212            $a->asArray()
213        );
214
215        $a = $conn->search(null, '(|(a=1)(b=2))', array('attributes' => array('a', 'b')));
216        $this->assertEquals(
217            array(
218                'cn=a' => array(
219                    'a' => '1',
220                    'b' => '1',
221                    'dn' => 'cn=a',
222                ),
223                'cn=b' => array(
224                    'a' => '1',
225                    'b' => '2',
226                    'dn' => 'cn=b',
227                ),
228                'cn=c' => array(
229                    'a' => '1',
230                    'b' => '2',
231                    'dn' => 'cn=c',
232                ),
233                'cn=d' => array(
234                    'a' => '2',
235                    'b' => '2',
236                    'dn' => 'cn=d',
237                )
238            ),
239            $a->asArray()
240        );
241
242        $a = $conn->search(null, '(&(b=2))', array('attributes' => array('b')));
243        $this->assertEquals(
244            array(
245                'cn=b' => array(
246                    'b' => '2',
247                    'dn' => 'cn=b',
248                ),
249                'cn=c' => array(
250                    'b' => '2',
251                    'dn' => 'cn=c',
252                ),
253                'cn=d' => array(
254                    'b' => '2',
255                    'dn' => 'cn=d',
256                ),
257            ),
258            $a->asArray()
259        );
260
261        $a = $conn->search(null, '(!(b=2))', array('attributes' => array('a', 'b')));
262        $this->assertEquals(
263            array(
264                'cn=a' => array(
265                    'a' => '1',
266                    'b' => '1',
267                    'dn' => 'cn=a',
268                ),
269            ),
270            $a->asArray()
271        );
272
273        $a = $conn->search(null, '(&(!(x=2))(b=1))', array('attributes' => array('b')));
274        $this->assertEquals(
275            array(
276                'cn=a' => array(
277                    'b' => '1',
278                    'dn' => 'cn=a',
279                ),
280            ),
281            $a->asArray()
282        );
283
284        $a = $conn->search(null, '(c=t)', array('attributes' => array('a')));
285        $this->assertEquals(
286            array(),
287            $a->asArray()
288        );
289
290        try {
291            $a = $conn->search(null, '(c>t)', array('attributes' => array('a')));
292            $this->fail('No exception!');
293        } catch (Horde_Kolab_Server_Exception $e) {
294            $this->assertEquals('Not implemented!', $e->getMessage());
295        }
296    }
297
298    public function testMethodBindHasPostconditionThatBindingOccursWithDefaultDnAndPwIfSpecified()
299    {
300        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
301            array('binddn' => 'test', 'bindpw' => 'test'),
302            array()
303        );
304        try {
305            $conn->bind('', '');
306            $this->fail('No exception!');
307        } catch (Horde_Kolab_Server_Exception $e) {
308            $this->assertEquals('User does not exist!', $e->getMessage());
309        }
310    }
311
312    public function testMethodBindThrowsExceptionIfTheUserDoesNotExist()
313    {
314        $this->testMethodBindHasPostconditionThatBindingOccursWithDefaultDnAndPwIfSpecified();
315    }
316
317    public function testMethodBindThrowsExceptionIfTheUserHasNoPassword()
318    {
319        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
320            array('binddn' => 'test', 'bindpw' => 'test'),
321            array('test' =>
322                  array('data' =>
323                        array()
324                  )
325            )
326        );
327        try {
328            $conn->bind('', '');
329            $this->fail('No exception!');
330        } catch (Horde_Kolab_Server_Exception $e) {
331            $this->assertEquals('User has no password entry!', $e->getMessage());
332        }
333    }
334
335    public function testMethodBindThrowsExceptionIfThePasswordWasIncorrect()
336    {
337        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
338            array('binddn' => 'test', 'bindpw' => 'test'),
339            array('test' =>
340                  array('data' =>
341                        array(
342                            'userPassword' => array('something')
343                        )
344                  )
345            )
346        );
347        try {
348            $conn->bind('', '');
349            $this->fail('No exception!');
350        } catch (Horde_Kolab_Server_Exception $e) {
351            $this->assertEquals('Incorrect password!', $e->getMessage());
352        }
353    }
354
355    public function testMethodBindThrowsExceptionIfAnonymousLoginIsDisabledAndTheDnIsUnset()
356    {
357        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
358            array('no_anonymous_bind' => true),
359            array()
360        );
361        try {
362            $conn->bind('', '');
363            $this->fail('No exception!');
364        } catch (Horde_Kolab_Server_Exception $e) {
365            $this->assertEquals('Anonymous bind is not allowed!', $e->getMessage());
366        }
367    }
368
369    public function testMethodSearchHasResultMocksearchSingleElementIfNoFilterIsSetAndSearchScopeIsBase()
370    {
371        $this->skipIfNoLdap();
372
373        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
374            array(),
375            array('test' =>
376                  array('dn' => 'test',
377                        'data' =>
378                        array(
379                            'userPassword' => array('something')
380                        )
381                  ),
382                  'testnot' =>
383                  array('dn' => 'test',
384                        'data' =>
385                        array(
386                            'userPassword' => array('something')
387                        )
388                  )
389            )
390        );
391        $conn->bind('', '');
392        $result = $conn->search('test', null, array('scope' => 'base'));
393        $this->assertEquals(
394            array('test' => array(
395                      'userPassword' => array('something'),
396                      'dn' => 'test'
397                  )
398            ),
399            $result->asArray()
400        );
401    }
402
403    public function testMethodSearchHasResultMocksearchEmptyIfNoFilterIsSetSearchScopeIsBaseAndTheSpecifiedBaseDoesNotExist()
404    {
405        $this->skipIfNoLdap();
406
407        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
408            array(),
409            array()
410        );
411        $conn->bind('', '');
412        $result = $conn->search('test', null, array('scope' => 'base'));
413        $this->assertEquals(
414            array(),
415            $result->asArray()
416        );
417    }
418
419    public function testMethodSearchHasResultMocksearchSingleElementIfNoFilterIsSetSearchScopeIsSubAndOnlyOneElementMatchesBase()
420    {
421        $this->skipIfNoLdap();
422
423        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
424            array(),
425            array('test' =>
426                  array('dn' => 'test',
427                        'data' =>
428                        array(
429                            'userPassword' => array('something')
430                        )
431                  ),
432                  'testnot' =>
433                  array('dn' => 'test',
434                        'data' =>
435                        array(
436                            'userPassword' => array('something')
437                        )
438                  )
439            )
440        );
441        $conn->bind('', '');
442        $result = $conn->search('test', null, array('scope' => 'sub'));
443        $this->assertEquals(
444            array('test' => array(
445                      'userPassword' => array('something'),
446                      'dn' => 'test'
447                  )
448            ),
449            $result->asArray()
450        );
451    }
452
453    public function testMethodSearchHasResultMocksearchWithMatchingElementsIfNoSearchScopeIsSet()
454    {
455        $this->skipIfNoLdap();
456
457        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
458            array(),
459            array('test' =>
460                  array('dn' => 'test',
461                        'data' =>
462                        array(
463                            'userPassword' => array('something')
464                        )
465                  ),
466                  'yestest' =>
467                  array('dn' => 'yestest',
468                        'data' =>
469                        array(
470                            'userPassword' => array('something')
471                        )
472                  ),
473                  'testnot' =>
474                  array('dn' => 'testnot',
475                        'data' =>
476                        array(
477                            'userPassword' => array('something')
478                        )
479                  )
480            )
481        );
482        $conn->bind('', '');
483        $result = $conn->search('test');
484        $this->assertEquals(
485            array('test', 'yestest'),
486            array_keys($result->asArray())
487        );
488    }
489
490    public function testMethodSearchHasResultMocksearchWithSelectedAttributesIfSpecificAttributesWereSet()
491    {
492        $this->skipIfNoLdap();
493
494        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
495            array(),
496            array('test' =>
497                  array('dn' => 'test',
498                        'data' =>
499                        array(
500                            'userPassword' => array('something'),
501                            'name' => array('name1')
502                        )
503                  ),
504                  'yestest' =>
505                  array('dn' => 'yestest',
506                        'data' =>
507                        array(
508                            'userPassword' => array('something'),
509                            'name' => array('name2')
510                        )
511                  ),
512                  'testnot' =>
513                  array('dn' => 'testnot',
514                        'data' =>
515                        array(
516                            'userPassword' => array('something'),
517                            'name' => array('name2')
518                        )
519                  )
520            )
521        );
522        $conn->bind('', '');
523        $result = $conn->search('test', null, array('attributes' => 'name'));
524        $this->assertEquals(
525            array(
526                'test' => array(
527                    'name' => array('name1'),
528                    'dn' => 'test'
529                ),
530                'yestest' => array(
531                    'name' => array('name2'),
532                    'dn' => 'yestest'
533                ),
534            ),
535            $result->asArray()
536        );
537    }
538
539    public function testMethodSearchThrowsExceptionIfSearchScopeIsOne()
540    {
541        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
542            array(),
543            array()
544        );
545        $conn->bind('', '');
546        try {
547            $result = $conn->search('test', null, array('scope' => 'one'));
548            $this->fail('No exception!');
549        } catch (Horde_Kolab_Server_Exception $e) {
550            $this->assertEquals('Not implemented!', $e->getMessage());
551        }
552    }
553
554    public function testMethodSearchThrowsExceptionIfTheConnectionIsNotBound()
555    {
556        $conn = new Horde_Kolab_Server_Connection_Mock_Ldap(
557            array(),
558            array()
559        );
560        try {
561            $conn->search();
562            $this->fail('No exception!');
563        } catch (Horde_Kolab_Server_Exception $e) {
564            $this->assertEquals('Unbound connection!', $e->getMessage());
565        }
566    }
567
568}
569