Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

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