Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]

   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  
  35  defined('MOODLE_INTERNAL') || die();
  36  
  37  class 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  }