Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

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

   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      }
 383  
 384      /**
 385       * Test logging in via LDAP calls a user_loggedin event.
 386       */
 387      public function test_ldap_user_signup() {
 388          global $CFG, $DB;
 389  
 390          // User to create.
 391          $user = array(
 392              'username' => 'usersignuptest1',
 393              'password' => 'Moodle2014!',
 394              'idnumber' => 'idsignuptest1',
 395              'firstname' => 'First Name User Test 1',
 396              'lastname' => 'Last Name User Test 1',
 397              'middlename' => 'Middle Name User Test 1',
 398              'lastnamephonetic' => '最後のお名前のテスト一号',
 399              'firstnamephonetic' => 'お名前のテスト一号',
 400              'alternatename' => 'Alternate Name User Test 1',
 401              'email' => 'usersignuptest1@example.com',
 402              'description' => 'This is a description for user 1',
 403              'city' => 'Perth',
 404              'country' => 'AU',
 405              'mnethostid' => $CFG->mnet_localhost_id,
 406              'auth' => 'ldap'
 407              );
 408  
 409          if (!extension_loaded('ldap')) {
 410              $this->markTestSkipped('LDAP extension is not loaded.');
 411          }
 412  
 413          $this->resetAfterTest();
 414  
 415          require_once($CFG->dirroot.'/auth/ldap/auth.php');
 416          require_once($CFG->libdir.'/ldaplib.php');
 417  
 418          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')) {
 419              $this->markTestSkipped('External LDAP test server not configured.');
 420          }
 421  
 422          // Make sure we can connect the server.
 423          $debuginfo = '';
 424          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)) {
 425              $this->markTestSkipped('Can not connect to LDAP test server: '.$debuginfo);
 426          }
 427  
 428          $this->enable_plugin();
 429  
 430          // Create new empty test container.
 431          $topdn = 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN;
 432  
 433          $this->recursive_delete($connection, TEST_AUTH_LDAP_DOMAIN, 'dc=moodletest');
 434  
 435          $o = array();
 436          $o['objectClass'] = array('dcObject', 'organizationalUnit');
 437          $o['dc']         = 'moodletest';
 438          $o['ou']         = 'MOODLETEST';
 439          if (!ldap_add($connection, 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN, $o)) {
 440              $this->markTestSkipped('Can not create test LDAP container.');
 441          }
 442  
 443          // Create a few users.
 444          $o = array();
 445          $o['objectClass'] = array('organizationalUnit');
 446          $o['ou']          = 'users';
 447          ldap_add($connection, 'ou='.$o['ou'].','.$topdn, $o);
 448  
 449          // Configure the plugin a bit.
 450          set_config('host_url', TEST_AUTH_LDAP_HOST_URL, 'auth_ldap');
 451          set_config('start_tls', 0, 'auth_ldap');
 452          set_config('ldap_version', 3, 'auth_ldap');
 453          set_config('ldapencoding', 'utf-8', 'auth_ldap');
 454          set_config('pagesize', '2', 'auth_ldap');
 455          set_config('bind_dn', TEST_AUTH_LDAP_BIND_DN, 'auth_ldap');
 456          set_config('bind_pw', TEST_AUTH_LDAP_BIND_PW, 'auth_ldap');
 457          set_config('user_type', 'rfc2307', 'auth_ldap');
 458          set_config('contexts', 'ou=users,'.$topdn, 'auth_ldap');
 459          set_config('search_sub', 0, 'auth_ldap');
 460          set_config('opt_deref', LDAP_DEREF_NEVER, 'auth_ldap');
 461          set_config('user_attribute', 'cn', 'auth_ldap');
 462          set_config('memberattribute', 'memberuid', 'auth_ldap');
 463          set_config('memberattribute_isdn', 0, 'auth_ldap');
 464          set_config('creators', 'cn=creators,'.$topdn, 'auth_ldap');
 465          set_config('removeuser', AUTH_REMOVEUSER_KEEP, 'auth_ldap');
 466  
 467          set_config('field_map_email', 'mail', 'auth_ldap');
 468          set_config('field_updatelocal_email', 'oncreate', 'auth_ldap');
 469          set_config('field_updateremote_email', '0', 'auth_ldap');
 470          set_config('field_lock_email', 'unlocked', 'auth_ldap');
 471  
 472          set_config('field_map_firstname', 'givenName', 'auth_ldap');
 473          set_config('field_updatelocal_firstname', 'oncreate', 'auth_ldap');
 474          set_config('field_updateremote_firstname', '0', 'auth_ldap');
 475          set_config('field_lock_firstname', 'unlocked', 'auth_ldap');
 476  
 477          set_config('field_map_lastname', 'sn', 'auth_ldap');
 478          set_config('field_updatelocal_lastname', 'oncreate', 'auth_ldap');
 479          set_config('field_updateremote_lastname', '0', 'auth_ldap');
 480          set_config('field_lock_lastname', 'unlocked', 'auth_ldap');
 481          set_config('passtype', 'md5', 'auth_ldap');
 482          set_config('create_context', 'ou=users,'.$topdn, 'auth_ldap');
 483  
 484          $this->assertEquals(2, $DB->count_records('user'));
 485          $this->assertEquals(0, $DB->count_records('role_assignments'));
 486  
 487          /** @var \auth_plugin_ldap $auth */
 488          $auth = get_auth_plugin('ldap');
 489  
 490          $sink = $this->redirectEvents();
 491          $mailsink = $this->redirectEmails();
 492          $auth->user_signup((object)$user, false);
 493          $this->assertEquals(1, $mailsink->count());
 494          $events = $sink->get_events();
 495          $sink->close();
 496  
 497          // Verify 2 events get generated.
 498          $this->assertCount(2, $events);
 499  
 500          // Get record from db.
 501          $dbuser = $DB->get_record('user', array('username' => $user['username']));
 502          $user['id'] = $dbuser->id;
 503  
 504          // Last event is user_created.
 505          $event = array_pop($events);
 506          $this->assertInstanceOf('\core\event\user_created', $event);
 507          $this->assertEquals($user['id'], $event->objectid);
 508          $this->assertEquals(\context_user::instance($user['id']), $event->get_context());
 509  
 510          // First event is user_password_updated.
 511          $event = array_pop($events);
 512          $this->assertInstanceOf('\core\event\user_password_updated', $event);
 513          $this->assertEventContextNotUsed($event);
 514  
 515          // Delete user which we just created.
 516          ldap_delete($connection, 'cn='.$user['username'].',ou=users,'.$topdn);
 517      }
 518  
 519      protected function create_ldap_user($connection, $topdn, $i) {
 520          $o = array();
 521          $o['objectClass']   = array('inetOrgPerson', 'organizationalPerson', 'person', 'posixAccount');
 522          $o['cn']            = 'username'.$i;
 523          $o['sn']            = 'Lastname'.$i;
 524          $o['givenName']     = 'Firstname'.$i;
 525          $o['uid']           = $o['cn'];
 526          $o['uidnumber']     = 2000+$i;
 527          $o['gidNumber']     = 1000+$i;
 528          $o['homeDirectory'] = '/';
 529          $o['mail']          = 'user'.$i.'@example.com';
 530          $o['userPassword']  = 'pass'.$i;
 531          ldap_add($connection, 'cn='.$o['cn'].',ou=users,'.$topdn, $o);
 532      }
 533  
 534      protected function delete_ldap_user($connection, $topdn, $i) {
 535          ldap_delete($connection, 'cn=username'.$i.',ou=users,'.$topdn);
 536      }
 537  
 538      protected function enable_plugin() {
 539          $auths = get_enabled_auth_plugins();
 540          if (!in_array('ldap', $auths)) {
 541              $auths[] = 'ldap';
 542  
 543          }
 544          set_config('auth', implode(',', $auths));
 545      }
 546  
 547      protected function recursive_delete($connection, $dn, $filter) {
 548          if ($res = ldap_list($connection, $dn, $filter, array('dn'))) {
 549              $info = ldap_get_entries($connection, $res);
 550              ldap_free_result($res);
 551              if ($info['count'] > 0) {
 552                  if ($res = ldap_search($connection, "$filter,$dn", 'cn=*', array('dn'))) {
 553                      $info = ldap_get_entries($connection, $res);
 554                      ldap_free_result($res);
 555                      foreach ($info as $i) {
 556                          if (isset($i['dn'])) {
 557                              ldap_delete($connection, $i['dn']);
 558                          }
 559                      }
 560                  }
 561                  if ($res = ldap_search($connection, "$filter,$dn", 'ou=*', array('dn'))) {
 562                      $info = ldap_get_entries($connection, $res);
 563                      ldap_free_result($res);
 564                      foreach ($info as $i) {
 565                          if (isset($i['dn']) and $info[0]['dn'] != $i['dn']) {
 566                              ldap_delete($connection, $i['dn']);
 567                          }
 568                      }
 569                  }
 570                  ldap_delete($connection, "$filter,$dn");
 571              }
 572          }
 573      }
 574  }