1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * LDAP authentication plugin tests.
19 *
20 * NOTE: in order to execute this test you need to set up
21 *       OpenLDAP server with core, cosine, nis and internet schemas
22 *       and add configuration constants to config.php or phpunit.xml configuration file:
23 *
24 * define('TEST_AUTH_LDAP_HOST_URL', 'ldap://127.0.0.1');
25 * define('TEST_AUTH_LDAP_BIND_DN', 'cn=someuser,dc=example,dc=local');
26 * define('TEST_AUTH_LDAP_BIND_PW', 'somepassword');
27 * define('TEST_AUTH_LDAP_DOMAIN', 'dc=example,dc=local');
28 *
29 * @package    auth_ldap
30 * @category   phpunit
31 * @copyright  2013 Petr Skoda {@link http://skodak.org}
32 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33 */
34
35defined('MOODLE_INTERNAL') || die();
36
37class auth_ldap_plugin_testcase extends advanced_testcase {
38
39    /**
40     * Data provider for auth_ldap tests
41     *
42     * Used to ensure that all the paged stuff works properly, irrespectively
43     * of the pagesize configured (that implies all the chunking and paging
44     * built in the plugis is doing its work consistently). Both searching and
45     * not searching within subcontexts.
46     *
47     * @return array[]
48     */
49    public function auth_ldap_provider() {
50        $pagesizes = [1, 3, 5, 1000];
51        $subcontexts = [0, 1];
52        $combinations = [];
53        foreach ($pagesizes as $pagesize) {
54            foreach ($subcontexts as $subcontext) {
55                $combinations["pagesize {$pagesize}, subcontexts {$subcontext}"] = [$pagesize, $subcontext];
56            }
57        }
58        return $combinations;
59    }
60
61    /**
62     * General auth_ldap testcase
63     *
64     * @dataProvider auth_ldap_provider
65     * @param int $pagesize Value to be configured in settings controlling page size.
66     * @param int $subcontext Value to be configured in settings controlling searching in subcontexts.
67     */
68    public function test_auth_ldap(int $pagesize, int $subcontext) {
69        global $CFG, $DB;
70
71        if (!extension_loaded('ldap')) {
72            $this->markTestSkipped('LDAP extension is not loaded.');
73        }
74
75        $this->resetAfterTest();
76
77        require_once($CFG->dirroot.'/auth/ldap/auth.php');
78        require_once($CFG->libdir.'/ldaplib.php');
79
80        if (!defined('TEST_AUTH_LDAP_HOST_URL') or !defined('TEST_AUTH_LDAP_BIND_DN') or !defined('TEST_AUTH_LDAP_BIND_PW') or !defined('TEST_AUTH_LDAP_DOMAIN')) {
81            $this->markTestSkipped('External LDAP test server not configured.');
82        }
83
84        // Make sure we can connect the server.
85        $debuginfo = '';
86        if (!$connection = ldap_connect_moodle(TEST_AUTH_LDAP_HOST_URL, 3, 'rfc2307', TEST_AUTH_LDAP_BIND_DN, TEST_AUTH_LDAP_BIND_PW, LDAP_DEREF_NEVER, $debuginfo, false)) {
87            $this->markTestSkipped('Can not connect to LDAP test server: '.$debuginfo);
88        }
89
90        $this->enable_plugin();
91
92        // Create new empty test container.
93        $topdn = 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN;
94
95        $this->recursive_delete($connection, TEST_AUTH_LDAP_DOMAIN, 'dc=moodletest');
96
97        $o = array();
98        $o['objectClass'] = array('dcObject', 'organizationalUnit');
99        $o['dc']         = 'moodletest';
100        $o['ou']         = 'MOODLETEST';
101        if (!ldap_add($connection, 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN, $o)) {
102            $this->markTestSkipped('Can not create test LDAP container.');
103        }
104
105        // Create a few users.
106        $o = array();
107        $o['objectClass'] = array('organizationalUnit');
108        $o['ou']          = 'users';
109        ldap_add($connection, 'ou='.$o['ou'].','.$topdn, $o);
110
111        $createdusers = array();
112        for ($i=1; $i<=5; $i++) {
113            $this->create_ldap_user($connection, $topdn, $i);
114            $createdusers[] = 'username' . $i;
115        }
116
117        // Set up creators group.
118        $assignedroles = array('username1', 'username2');
119        $o = array();
120        $o['objectClass'] = array('posixGroup');
121        $o['cn']          = 'creators';
122        $o['gidNumber']   = 1;
123        $o['memberUid']   = $assignedroles;
124        ldap_add($connection, 'cn='.$o['cn'].','.$topdn, $o);
125
126        $creatorrole = $DB->get_record('role', array('shortname'=>'coursecreator'));
127        $this->assertNotEmpty($creatorrole);
128
129
130        // Configure the plugin a bit.
131        set_config('host_url', TEST_AUTH_LDAP_HOST_URL, 'auth_ldap');
132        set_config('start_tls', 0, 'auth_ldap');
133        set_config('ldap_version', 3, 'auth_ldap');
134        set_config('ldapencoding', 'utf-8', 'auth_ldap');
135        set_config('pagesize', $pagesize, 'auth_ldap');
136        set_config('bind_dn', TEST_AUTH_LDAP_BIND_DN, 'auth_ldap');
137        set_config('bind_pw', TEST_AUTH_LDAP_BIND_PW, 'auth_ldap');
138        set_config('user_type', 'rfc2307', 'auth_ldap');
139        set_config('contexts', 'ou=users,'.$topdn, 'auth_ldap');
140        set_config('search_sub', $subcontext, 'auth_ldap');
141        set_config('opt_deref', LDAP_DEREF_NEVER, 'auth_ldap');
142        set_config('user_attribute', 'cn', 'auth_ldap');
143        set_config('memberattribute', 'memberuid', 'auth_ldap');
144        set_config('memberattribute_isdn', 0, 'auth_ldap');
145        set_config('coursecreatorcontext', 'cn=creators,'.$topdn, 'auth_ldap');
146        set_config('removeuser', AUTH_REMOVEUSER_KEEP, 'auth_ldap');
147
148        set_config('field_map_email', 'mail', 'auth_ldap');
149        set_config('field_updatelocal_email', 'oncreate', 'auth_ldap');
150        set_config('field_updateremote_email', '0', 'auth_ldap');
151        set_config('field_lock_email', 'unlocked', 'auth_ldap');
152
153        set_config('field_map_firstname', 'givenName', 'auth_ldap');
154        set_config('field_updatelocal_firstname', 'oncreate', 'auth_ldap');
155        set_config('field_updateremote_firstname', '0', 'auth_ldap');
156        set_config('field_lock_firstname', 'unlocked', 'auth_ldap');
157
158        set_config('field_map_lastname', 'sn', 'auth_ldap');
159        set_config('field_updatelocal_lastname', 'oncreate', 'auth_ldap');
160        set_config('field_updateremote_lastname', '0', 'auth_ldap');
161        set_config('field_lock_lastname', 'unlocked', 'auth_ldap');
162
163
164        $this->assertEquals(2, $DB->count_records('user'));
165        $this->assertEquals(0, $DB->count_records('role_assignments'));
166
167        /** @var auth_plugin_ldap $auth */
168        $auth = get_auth_plugin('ldap');
169
170        ob_start();
171        $sink = $this->redirectEvents();
172        $auth->sync_users(true);
173        $events = $sink->get_events();
174        $sink->close();
175        ob_end_clean();
176
177        // Check events, 5 users created with 2 users having roles.
178        $this->assertCount(7, $events);
179        foreach ($events as $index => $event) {
180            $username = $DB->get_field('user', 'username', array('id' => $event->relateduserid)); // Get username.
181
182            if ($event->eventname === '\core\event\user_created') {
183                $this->assertContains($username, $createdusers);
184                unset($events[$index]); // Remove matching event.
185
186            } else if ($event->eventname === '\core\event\role_assigned') {
187                $this->assertContains($username, $assignedroles);
188                unset($events[$index]); // Remove matching event.
189
190            } else {
191                $this->fail('Unexpected event found: ' . $event->eventname);
192            }
193        }
194        // If all the user_created and role_assigned events have matched
195        // then the $events array should be now empty.
196        $this->assertCount(0, $events);
197
198        $this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
199        $this->assertEquals(2, $DB->count_records('role_assignments'));
200        $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
201
202        for ($i=1; $i<=5; $i++) {
203            $this->assertTrue($DB->record_exists('user', array('username'=>'username'.$i, 'email'=>'user'.$i.'@example.com', 'firstname'=>'Firstname'.$i, 'lastname'=>'Lastname'.$i)));
204        }
205
206        $this->delete_ldap_user($connection, $topdn, 1);
207
208        ob_start();
209        $sink = $this->redirectEvents();
210        $auth->sync_users(true);
211        $events = $sink->get_events();
212        $sink->close();
213        ob_end_clean();
214
215        // Check events, no new event.
216        $this->assertCount(0, $events);
217
218        $this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
219        $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
220        $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
221        $this->assertEquals(2, $DB->count_records('role_assignments'));
222        $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
223
224
225        set_config('removeuser', AUTH_REMOVEUSER_SUSPEND, 'auth_ldap');
226
227        /** @var auth_plugin_ldap $auth */
228        $auth = get_auth_plugin('ldap');
229
230        ob_start();
231        $sink = $this->redirectEvents();
232        $auth->sync_users(true);
233        $events = $sink->get_events();
234        $sink->close();
235        ob_end_clean();
236
237        // Check events, 1 user got updated.
238        $this->assertCount(1, $events);
239        $event = reset($events);
240        $this->assertInstanceOf('\core\event\user_updated', $event);
241
242        $this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
243        $this->assertEquals(0, $DB->count_records('user', array('auth'=>'nologin', 'username'=>'username1')));
244        $this->assertEquals(1, $DB->count_records('user', array('auth'=>'ldap', 'suspended'=>'1', 'username'=>'username1')));
245        $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
246        $this->assertEquals(2, $DB->count_records('role_assignments'));
247        $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
248
249        $this->create_ldap_user($connection, $topdn, 1);
250
251        ob_start();
252        $sink = $this->redirectEvents();
253        $auth->sync_users(true);
254        $events = $sink->get_events();
255        $sink->close();
256        ob_end_clean();
257
258        // Check events, 1 user got updated.
259        $this->assertCount(1, $events);
260        $event = reset($events);
261        $this->assertInstanceOf('\core\event\user_updated', $event);
262
263        $this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
264        $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
265        $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
266        $this->assertEquals(2, $DB->count_records('role_assignments'));
267        $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
268
269        $DB->set_field('user', 'auth', 'nologin', array('username'=>'username1'));
270
271        ob_start();
272        $sink = $this->redirectEvents();
273        $auth->sync_users(true);
274        $events = $sink->get_events();
275        $sink->close();
276        ob_end_clean();
277
278        // Check events, 1 user got updated.
279        $this->assertCount(1, $events);
280        $event = reset($events);
281        $this->assertInstanceOf('\core\event\user_updated', $event);
282
283        $this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
284        $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
285        $this->assertEquals(0, $DB->count_records('user', array('deleted'=>1)));
286        $this->assertEquals(2, $DB->count_records('role_assignments'));
287        $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
288
289        set_config('removeuser', AUTH_REMOVEUSER_FULLDELETE, 'auth_ldap');
290
291        /** @var auth_plugin_ldap $auth */
292        $auth = get_auth_plugin('ldap');
293
294        $this->delete_ldap_user($connection, $topdn, 1);
295
296        ob_start();
297        $sink = $this->redirectEvents();
298        $auth->sync_users(true);
299        $events = $sink->get_events();
300        $sink->close();
301        ob_end_clean();
302
303        // Check events, 2 events role_unassigned and user_deleted.
304        $this->assertCount(2, $events);
305        $event = array_pop($events);
306        $this->assertInstanceOf('\core\event\user_deleted', $event);
307        $event = array_pop($events);
308        $this->assertInstanceOf('\core\event\role_unassigned', $event);
309
310        $this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
311        $this->assertEquals(0, $DB->count_records('user', array('username'=>'username1')));
312        $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
313        $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1)));
314        $this->assertEquals(1, $DB->count_records('role_assignments'));
315        $this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
316
317        $this->create_ldap_user($connection, $topdn, 1);
318
319        ob_start();
320        $sink = $this->redirectEvents();
321        $auth->sync_users(true);
322        $events = $sink->get_events();
323        $sink->close();
324        ob_end_clean();
325
326        // Check events, 2 events role_assigned and user_created.
327        $this->assertCount(2, $events);
328        $event = array_pop($events);
329        $this->assertInstanceOf('\core\event\role_assigned', $event);
330        $event = array_pop($events);
331        $this->assertInstanceOf('\core\event\user_created', $event);
332
333        $this->assertEquals(6, $DB->count_records('user', array('auth'=>'ldap')));
334        $this->assertEquals(1, $DB->count_records('user', array('username'=>'username1')));
335        $this->assertEquals(0, $DB->count_records('user', array('suspended'=>1)));
336        $this->assertEquals(1, $DB->count_records('user', array('deleted'=>1)));
337        $this->assertEquals(2, $DB->count_records('role_assignments'));
338        $this->assertEquals(2, $DB->count_records('role_assignments', array('roleid'=>$creatorrole->id)));
339
340
341        $this->recursive_delete($connection, TEST_AUTH_LDAP_DOMAIN, 'dc=moodletest');
342        ldap_close($connection);
343    }
344
345    /**
346     * Test logging in via LDAP calls a user_loggedin event.
347     */
348    public function test_ldap_user_loggedin_event() {
349        global $CFG, $DB, $USER;
350
351        require_once($CFG->dirroot . '/auth/ldap/auth.php');
352
353        $this->resetAfterTest();
354
355        $this->assertFalse(isloggedin());
356        $user = $DB->get_record('user', array('username'=>'admin'));
357
358        // Note: we are just going to trigger the function that calls the event,
359        // not actually perform a LDAP login, for the sake of sanity.
360        $ldap = new auth_plugin_ldap();
361
362        // Set the key for the cache flag we want to set which is used by LDAP.
363        set_cache_flag($ldap->pluginconfig . '/ntlmsess', sesskey(), $user->username, AUTH_NTLMTIMEOUT);
364
365        // We are going to need to set the sesskey as the user's password in order for the LDAP log in to work.
366        update_internal_user_password($user, sesskey());
367
368        // The function ntlmsso_finish is responsible for triggering the event, so call it directly and catch the event.
369        $sink = $this->redirectEvents();
370        // We need to supress this function call, or else we will get the message "session_regenerate_id(): Cannot
371        // regenerate session id - headers already sent" as the ntlmsso_finish function calls complete_user_login
372        @$ldap->ntlmsso_finish();
373        $events = $sink->get_events();
374        $sink->close();
375
376        // Check that the event is valid.
377        $this->assertCount(1, $events);
378        $event = reset($events);
379        $this->assertInstanceOf('\core\event\user_loggedin', $event);
380        $this->assertEquals('user', $event->objecttable);
381        $this->assertEquals('2', $event->objectid);
382        $this->assertEquals(context_system::instance()->id, $event->contextid);
383        $expectedlog = array(SITEID, 'user', 'login', 'view.php?id=' . $USER->id . '&course=' . SITEID, $user->id,
384            0, $user->id);
385        $this->assertEventLegacyLogData($expectedlog, $event);
386    }
387
388    /**
389     * Test logging in via LDAP calls a user_loggedin event.
390     */
391    public function test_ldap_user_signup() {
392        global $CFG, $DB;
393
394        // User to create.
395        $user = array(
396            'username' => 'usersignuptest1',
397            'password' => 'Moodle2014!',
398            'idnumber' => 'idsignuptest1',
399            'firstname' => 'First Name User Test 1',
400            'lastname' => 'Last Name User Test 1',
401            'middlename' => 'Middle Name User Test 1',
402            'lastnamephonetic' => '最後のお名前のテスト一号',
403            'firstnamephonetic' => 'お名前のテスト一号',
404            'alternatename' => 'Alternate Name User Test 1',
405            'email' => 'usersignuptest1@example.com',
406            'description' => 'This is a description for user 1',
407            'city' => 'Perth',
408            'country' => 'AU',
409            'mnethostid' => $CFG->mnet_localhost_id,
410            'auth' => 'ldap'
411            );
412
413        if (!extension_loaded('ldap')) {
414            $this->markTestSkipped('LDAP extension is not loaded.');
415        }
416
417        $this->resetAfterTest();
418
419        require_once($CFG->dirroot.'/auth/ldap/auth.php');
420        require_once($CFG->libdir.'/ldaplib.php');
421
422        if (!defined('TEST_AUTH_LDAP_HOST_URL') or !defined('TEST_AUTH_LDAP_BIND_DN') or !defined('TEST_AUTH_LDAP_BIND_PW') or !defined('TEST_AUTH_LDAP_DOMAIN')) {
423            $this->markTestSkipped('External LDAP test server not configured.');
424        }
425
426        // Make sure we can connect the server.
427        $debuginfo = '';
428        if (!$connection = ldap_connect_moodle(TEST_AUTH_LDAP_HOST_URL, 3, 'rfc2307', TEST_AUTH_LDAP_BIND_DN, TEST_AUTH_LDAP_BIND_PW, LDAP_DEREF_NEVER, $debuginfo, false)) {
429            $this->markTestSkipped('Can not connect to LDAP test server: '.$debuginfo);
430        }
431
432        $this->enable_plugin();
433
434        // Create new empty test container.
435        $topdn = 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN;
436
437        $this->recursive_delete($connection, TEST_AUTH_LDAP_DOMAIN, 'dc=moodletest');
438
439        $o = array();
440        $o['objectClass'] = array('dcObject', 'organizationalUnit');
441        $o['dc']         = 'moodletest';
442        $o['ou']         = 'MOODLETEST';
443        if (!ldap_add($connection, 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN, $o)) {
444            $this->markTestSkipped('Can not create test LDAP container.');
445        }
446
447        // Create a few users.
448        $o = array();
449        $o['objectClass'] = array('organizationalUnit');
450        $o['ou']          = 'users';
451        ldap_add($connection, 'ou='.$o['ou'].','.$topdn, $o);
452
453        // Configure the plugin a bit.
454        set_config('host_url', TEST_AUTH_LDAP_HOST_URL, 'auth_ldap');
455        set_config('start_tls', 0, 'auth_ldap');
456        set_config('ldap_version', 3, 'auth_ldap');
457        set_config('ldapencoding', 'utf-8', 'auth_ldap');
458        set_config('pagesize', '2', 'auth_ldap');
459        set_config('bind_dn', TEST_AUTH_LDAP_BIND_DN, 'auth_ldap');
460        set_config('bind_pw', TEST_AUTH_LDAP_BIND_PW, 'auth_ldap');
461        set_config('user_type', 'rfc2307', 'auth_ldap');
462        set_config('contexts', 'ou=users,'.$topdn, 'auth_ldap');
463        set_config('search_sub', 0, 'auth_ldap');
464        set_config('opt_deref', LDAP_DEREF_NEVER, 'auth_ldap');
465        set_config('user_attribute', 'cn', 'auth_ldap');
466        set_config('memberattribute', 'memberuid', 'auth_ldap');
467        set_config('memberattribute_isdn', 0, 'auth_ldap');
468        set_config('creators', 'cn=creators,'.$topdn, 'auth_ldap');
469        set_config('removeuser', AUTH_REMOVEUSER_KEEP, 'auth_ldap');
470
471        set_config('field_map_email', 'mail', 'auth_ldap');
472        set_config('field_updatelocal_email', 'oncreate', 'auth_ldap');
473        set_config('field_updateremote_email', '0', 'auth_ldap');
474        set_config('field_lock_email', 'unlocked', 'auth_ldap');
475
476        set_config('field_map_firstname', 'givenName', 'auth_ldap');
477        set_config('field_updatelocal_firstname', 'oncreate', 'auth_ldap');
478        set_config('field_updateremote_firstname', '0', 'auth_ldap');
479        set_config('field_lock_firstname', 'unlocked', 'auth_ldap');
480
481        set_config('field_map_lastname', 'sn', 'auth_ldap');
482        set_config('field_updatelocal_lastname', 'oncreate', 'auth_ldap');
483        set_config('field_updateremote_lastname', '0', 'auth_ldap');
484        set_config('field_lock_lastname', 'unlocked', 'auth_ldap');
485        set_config('passtype', 'md5', 'auth_ldap');
486        set_config('create_context', 'ou=users,'.$topdn, 'auth_ldap');
487
488        $this->assertEquals(2, $DB->count_records('user'));
489        $this->assertEquals(0, $DB->count_records('role_assignments'));
490
491        /** @var auth_plugin_ldap $auth */
492        $auth = get_auth_plugin('ldap');
493
494        $sink = $this->redirectEvents();
495        $mailsink = $this->redirectEmails();
496        $auth->user_signup((object)$user, false);
497        $this->assertEquals(1, $mailsink->count());
498        $events = $sink->get_events();
499        $sink->close();
500
501        // Verify 2 events get generated.
502        $this->assertCount(2, $events);
503
504        // Get record from db.
505        $dbuser = $DB->get_record('user', array('username' => $user['username']));
506        $user['id'] = $dbuser->id;
507
508        // Last event is user_created.
509        $event = array_pop($events);
510        $this->assertInstanceOf('\core\event\user_created', $event);
511        $this->assertEquals($user['id'], $event->objectid);
512        $this->assertEquals('user_created', $event->get_legacy_eventname());
513        $this->assertEquals(context_user::instance($user['id']), $event->get_context());
514        $expectedlogdata = array(SITEID, 'user', 'add', '/view.php?id='.$event->objectid, fullname($dbuser));
515        $this->assertEventLegacyLogData($expectedlogdata, $event);
516
517        // First event is user_password_updated.
518        $event = array_pop($events);
519        $this->assertInstanceOf('\core\event\user_password_updated', $event);
520        $this->assertEventContextNotUsed($event);
521
522        // Delete user which we just created.
523        ldap_delete($connection, 'cn='.$user['username'].',ou=users,'.$topdn);
524    }
525
526    protected function create_ldap_user($connection, $topdn, $i) {
527        $o = array();
528        $o['objectClass']   = array('inetOrgPerson', 'organizationalPerson', 'person', 'posixAccount');
529        $o['cn']            = 'username'.$i;
530        $o['sn']            = 'Lastname'.$i;
531        $o['givenName']     = 'Firstname'.$i;
532        $o['uid']           = $o['cn'];
533        $o['uidnumber']     = 2000+$i;
534        $o['gidNumber']     = 1000+$i;
535        $o['homeDirectory'] = '/';
536        $o['mail']          = 'user'.$i.'@example.com';
537        $o['userPassword']  = 'pass'.$i;
538        ldap_add($connection, 'cn='.$o['cn'].',ou=users,'.$topdn, $o);
539    }
540
541    protected function delete_ldap_user($connection, $topdn, $i) {
542        ldap_delete($connection, 'cn=username'.$i.',ou=users,'.$topdn);
543    }
544
545    protected function enable_plugin() {
546        $auths = get_enabled_auth_plugins();
547        if (!in_array('ldap', $auths)) {
548            $auths[] = 'ldap';
549
550        }
551        set_config('auth', implode(',', $auths));
552    }
553
554    protected function recursive_delete($connection, $dn, $filter) {
555        if ($res = ldap_list($connection, $dn, $filter, array('dn'))) {
556            $info = ldap_get_entries($connection, $res);
557            ldap_free_result($res);
558            if ($info['count'] > 0) {
559                if ($res = ldap_search($connection, "$filter,$dn", 'cn=*', array('dn'))) {
560                    $info = ldap_get_entries($connection, $res);
561                    ldap_free_result($res);
562                    foreach ($info as $i) {
563                        if (isset($i['dn'])) {
564                            ldap_delete($connection, $i['dn']);
565                        }
566                    }
567                }
568                if ($res = ldap_search($connection, "$filter,$dn", 'ou=*', array('dn'))) {
569                    $info = ldap_get_entries($connection, $res);
570                    ldap_free_result($res);
571                    foreach ($info as $i) {
572                        if (isset($i['dn']) and $info[0]['dn'] != $i['dn']) {
573                            ldap_delete($connection, $i['dn']);
574                        }
575                    }
576                }
577                ldap_delete($connection, "$filter,$dn");
578            }
579        }
580    }
581}
582