Merge branch 'MDL-42816-master' of https://github.com/StudiUM/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 1 Apr 2014 23:52:41 +0000 (01:52 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 1 Apr 2014 23:52:41 +0000 (01:52 +0200)
auth/manual/auth.php
auth/manual/config.html
auth/manual/lang/en/auth_manual.php
auth/manual/tests/manual_test.php [new file with mode: 0644]
lib/classes/user.php
lib/testing/generator/data_generator.php
lib/tests/user_test.php

index 1c7ff9e..2803711 100644 (file)
@@ -37,12 +37,17 @@ require_once($CFG->libdir.'/authlib.php');
  */
 class auth_plugin_manual extends auth_plugin_base {
 
+    /**
+     * The name of the component. Used by the configuration.
+     */
+    const COMPONENT_NAME = 'auth_manual';
+
     /**
      * Constructor.
      */
     function auth_plugin_manual() {
         $this->authtype = 'manual';
-        $this->config = get_config('auth/manual');
+        $this->config = get_config(self::COMPONENT_NAME);
     }
 
     /**
@@ -81,6 +86,7 @@ class auth_plugin_manual extends auth_plugin_base {
      */
     function user_update_password($user, $newpassword) {
         $user = get_complete_user_data('id', $user->id);
+        set_user_preference('auth_manual_passwordupdatetime', time(), $user->id);
         // This will also update the stored hash to the latest algorithm
         // if the existing hash is using an out-of-date algorithm (or the
         // legacy md5 algorithm).
@@ -153,13 +159,56 @@ class auth_plugin_manual extends auth_plugin_base {
         include 'config.html';
     }
 
+    /**
+     * Return number of days to user password expires.
+     *
+     * If user password does not expire, it should return 0 or a positive value.
+     * If user password is already expired, it should return negative value.
+     *
+     * @param mixed $username username (with system magic quotes)
+     * @return integer
+     */
+    public function password_expire($username) {
+        $result = 0;
+
+        if (!empty($this->config->expirationtime)) {
+            $user = core_user::get_user_by_username($username, 'id,timecreated');
+            $lastpasswordupdatetime = get_user_preferences('auth_manual_passwordupdatetime', $user->timecreated, $user->id);
+            $expiretime = $lastpasswordupdatetime + $this->config->expirationtime * DAYSECS;
+            $now = time();
+            $result = ($expiretime - $now) / DAYSECS;
+            if ($expiretime > $now) {
+                $result = ceil($result);
+            } else {
+                $result = floor($result);
+            }
+        }
+
+        return $result;
+    }
+
     /**
      * Processes and stores configuration data for this authentication plugin.
      *
-     * @param array $config
+     * @param stdClass $config
      * @return void
      */
     function process_config($config) {
+        // Set to defaults if undefined.
+        if (!isset($config->expiration)) {
+            $config->expiration = '';
+        }
+        if (!isset($config->expiration_warning)) {
+            $config->expiration_warning = '';
+        }
+        if (!isset($config->expirationtime)) {
+            $config->expirationtime = '';
+        }
+
+        // Save settings.
+        set_config('expiration', $config->expiration, self::COMPONENT_NAME);
+        set_config('expiration_warning', $config->expiration_warning, self::COMPONENT_NAME);
+        set_config('expirationtime', $config->expirationtime, self::COMPONENT_NAME);
         return true;
     }
 
index 8c03ce0..f622ab1 100644 (file)
@@ -1,5 +1,78 @@
-<table cellspacing="0" cellpadding="5" border="0">
 <?php
-print_auth_lock_options($this->authtype, $user_fields, get_string('auth_fieldlocks_help', 'auth'), false, false);
+    // Set to defaults if undefined.
+    if (!isset($config->expiration)) {
+        $config->expiration = '';
+    }
+    if (!isset($config->expiration_warning)) {
+        $config->expiration_warning = '';
+    }
+    if (!isset($config->expirationtime)) {
+        $config->expirationtime = '';
+    }
+    $expirationoptions = array(
+        new lang_string('no'),
+        new lang_string('yes'),
+    );
+    $expirationtimeoptions = array(
+        '30' => new lang_string('numdays', '', 30),
+        '60' => new lang_string('numdays', '', 60),
+        '90' => new lang_string('numdays', '', 90),
+        '120' => new lang_string('numdays', '', 120),
+        '150' => new lang_string('numdays', '', 150),
+        '180' => new lang_string('numdays', '', 180),
+        '365' => new lang_string('numdays', '', 365),
+    );
+    $expirationwarningoptions = array(
+        '0' => new lang_string('never'),
+        '1' => new lang_string('numdays', '', 1),
+        '2' => new lang_string('numdays', '', 2),
+        '3' => new lang_string('numdays', '', 3),
+        '4' => new lang_string('numdays', '', 4),
+        '5' => new lang_string('numdays', '', 5),
+        '6' => new lang_string('numdays', '', 6),
+        '7' => new lang_string('numdays', '', 7),
+        '10' => new lang_string('numdays', '', 10),
+        '14' => new lang_string('numdays', '', 14),
+    );
 ?>
+<table cellspacing="0" cellpadding="5" border="0">
+    <tr>
+        <td colspan="3">
+            <h3><?php print_string('passwdexpire_settings', 'auth_manual') ?></h3>
+        </td>
+    </tr>
+    <tr>
+        <td align="right">
+            <label for="menuexpiration">
+                <?php print_string('expiration', 'auth_manual') ?>
+            </label>
+        </td>
+        <td>
+            <?php echo html_writer::select($expirationoptions, 'expiration', $config->expiration, false) ?>
+        </td>
+        <td><?php print_string('expiration_desc', 'auth_manual') ?></td>
+    </tr>
+    <tr>
+        <td align="right">
+            <label for="menuexpirationtime">
+                <?php print_string('passwdexpiretime', 'auth_manual') ?>
+            </label>
+        </td>
+        <td>
+            <?php echo html_writer::select($expirationtimeoptions, 'expirationtime', $config->expirationtime, false) ?>
+        </td>
+        <td><?php print_string('passwdexpiretime_desc', 'auth_manual') ?></td>
+    </tr>
+    <tr>
+        <td align="right">
+            <label for="menuexpiration_warning">
+                <?php print_string('expiration_warning', 'auth_manual') ?>
+            </label>
+        </td>
+        <td>
+            <?php echo html_writer::select($expirationwarningoptions, 'expiration_warning', $config->expiration_warning, false) ?>
+        </td>
+        <td><?php print_string('expiration_warning_desc', 'auth_manual') ?></td>
+    </tr>
+    <?php print_auth_lock_options($this->authtype, $user_fields, get_string('auth_fieldlocks_help', 'auth'), false, false) ?>
 </table>
index 53d8909..a919797 100644 (file)
  */
 
 $string['auth_manualdescription'] = 'This method removes any way for users to create their own accounts.  All accounts must be manually created by the admin user.';
+$string['expiration'] = 'Enable password expiry';
+$string['expiration_desc'] = 'Allow passwords to expire after a specified time.';
+$string['expiration_warning'] = 'Notification threshold';
+$string['expiration_warning_desc'] = 'Number of days before password expiry that a notification is issued.';
+$string['passwdexpiretime'] = 'Password duration';
+$string['passwdexpiretime_desc'] = 'Length of time for which a password is valid.';
 $string['pluginname'] = 'Manual accounts';
+$string['passwdexpire_settings'] = 'Password expiry settings';
diff --git a/auth/manual/tests/manual_test.php b/auth/manual/tests/manual_test.php
new file mode 100644 (file)
index 0000000..087721a
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Manual authentication tests.
+ *
+ * @package    auth_manual
+ * @category   test
+ * @copyright  2014 Gilles-Philippe Leblanc <gilles-philippe.leblanc@umontreal.ca>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot.'/auth/manual/auth.php');
+
+/**
+ * Manual authentication tests class.
+ *
+ * @package    auth_manual
+ * @category   test
+ * @copyright  2014 Gilles-Philippe Leblanc <gilles-philippe.leblanc@umontreal.ca>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class auth_manual_testcase extends advanced_testcase {
+
+    /** @var auth_plugin_manual Keeps the authentication plugin. */
+    protected $authplugin;
+
+    /** @var stdClass Keeps authentication plugin config */
+    protected $config;
+
+    /**
+     * Setup test data.
+     */
+    protected function setUp() {
+        $this->resetAfterTest(true);
+        $this->authplugin = new auth_plugin_manual();
+        $this->config = new stdClass();
+        $this->config->expiration = '1';
+        $this->config->expiration_warning = '2';
+        $this->config->expirationtime = '30';
+        $this->authplugin->process_config($this->config);
+        $this->authplugin->config = get_config(auth_plugin_manual::COMPONENT_NAME);
+    }
+
+    /**
+     * Test user_update_password method.
+     */
+    public function test_user_update_password() {
+        $user = $this->getDataGenerator()->create_user();
+        $expectedtime = time();
+        $passwordisupdated = $this->authplugin->user_update_password($user, 'MyNewPassword*');
+
+        // Assert that the actual time should be equal or a little greater than the expected time.
+        $this->assertGreaterThanOrEqual($expectedtime, get_user_preferences('auth_manual_passwordupdatetime', 0, $user->id));
+
+        // Assert that the password was successfully updated.
+        $this->assertTrue($passwordisupdated);
+    }
+
+    /**
+     * Test test_password_expire method.
+     */
+    public function test_password_expire() {
+        $userrecord = array();
+        $expirationtime = 31 * DAYSECS;
+        $userrecord['timecreated'] = time() - $expirationtime;
+        $user1 = $this->getDataGenerator()->create_user($userrecord);
+        $user2 = $this->getDataGenerator()->create_user();
+
+        // The user 1 was created 31 days ago and has not changed his password yet, so the password has expirated.
+        $this->assertLessThanOrEqual(-1, $this->authplugin->password_expire($user1->username));
+
+        // The user 2 just came to be created and has not changed his password yet, so the password has not expirated.
+        $this->assertEquals(30, $this->authplugin->password_expire($user2->username));
+
+        $this->authplugin->user_update_password($user1, 'MyNewPassword*');
+
+        // The user 1 just updated his password so the password has not expirated.
+        $this->assertEquals(30, $this->authplugin->password_expire($user1->username));
+    }
+
+    /**
+     * Test test_process_config method.
+     */
+    public function test_process_config() {
+        $this->assertTrue($this->authplugin->process_config($this->config));
+        $config = get_config(auth_plugin_manual::COMPONENT_NAME);
+        $this->assertEquals($this->config->expiration, $config->expiration);
+        $this->assertEquals($this->config->expiration_warning, $config->expiration_warning);
+        $this->assertEquals($this->config->expirationtime, $config->expirationtime);
+    }
+}
index 7bcee34..bad53f5 100644 (file)
@@ -79,6 +79,31 @@ class core_user {
         }
     }
 
+
+    /**
+     * Return user object from db based on their username.
+     *
+     * @param string $username The username of the user searched.
+     * @param string $fields A comma separated list of user fields to be returned, support and noreply user.
+     * @param int $mnethostid The id of the remote host.
+     * @param int $strictness IGNORE_MISSING means compatible mode, false returned if user not found, debug message if more found;
+     *                        IGNORE_MULTIPLE means return first user, ignore multiple user records found(not recommended);
+     *                        MUST_EXIST means throw an exception if no user record or multiple records found.
+     * @return stdClass|bool user record if found, else false.
+     * @throws dml_exception if user record not found and respective $strictness is set.
+     */
+    public static function get_user_by_username($username, $fields = '*', $mnethostid = null, $strictness = IGNORE_MISSING) {
+        global $DB, $CFG;
+
+        // Because we use the username as the search criteria, we must also restrict our search based on mnet host.
+        if (empty($mnethostid)) {
+            // If empty, we restrict to local users.
+            $mnethostid = $CFG->mnet_localhost_id;
+        }
+
+        return $DB->get_record('user', array('username' => $username, 'mnethostid' => $mnethostid), $fields, $strictness);
+    }
+
     /**
      * Helper function to return dummy noreply user record.
      *
index b0efa09..ea316a7 100644 (file)
@@ -226,7 +226,10 @@ EOD;
             $record['deleted'] = 0;
         }
 
-        $record['timecreated'] = time();
+        if (!isset($record['timecreated'])) {
+            $record['timecreated'] = time();
+        }
+
         $record['timemodified'] = $record['timecreated'];
         $record['lastip'] = '0.0.0.0';
 
index ea379e8..a0d2e68 100644 (file)
  */
 class core_user_testcase extends advanced_testcase {
 
+    /**
+     * Setup test data.
+     */
+    protected function setUp() {
+        $this->resetAfterTest(true);
+    }
+
     public function test_get_user() {
         global $CFG;
 
-        $this->resetAfterTest(true);
 
         // Create user and try fetach it with api.
         $user = $this->getDataGenerator()->create_user();
@@ -78,4 +84,36 @@ class core_user_testcase extends advanced_testcase {
         $this->assertEquals($user, $supportuser);
         $this->assertTrue(core_user::is_real_user($supportuser->id));
     }
+
+    /**
+     * Test get_user_by_username method.
+     */
+    public function test_get_user_by_username() {
+        $record = array();
+        $record['username'] = 'johndoe';
+        $record['email'] = 'johndoe@example.com';
+        $record['timecreated'] = time();
+
+        // Create a default user for the test.
+        $userexpected = $this->getDataGenerator()->create_user($record);
+
+        // Assert that the returned user is the espected one.
+        $this->assertEquals($userexpected, core_user::get_user_by_username('johndoe'));
+
+        // Assert that a subset of fields is correctly returned.
+        $this->assertEquals((object) $record, core_user::get_user_by_username('johndoe', 'username,email,timecreated'));
+
+        // Assert that a user with a different mnethostid will no be returned.
+        $this->assertFalse(core_user::get_user_by_username('johndoe', 'username,email,timecreated', 2));
+
+        // Create a new user from a different host.
+        $record['mnethostid'] = 2;
+        $userexpected2 = $this->getDataGenerator()->create_user($record);
+
+        // Assert that the new user is returned when specified the correct mnethostid.
+        $this->assertEquals($userexpected2, core_user::get_user_by_username('johndoe', '*', 2));
+
+        // Assert that a user not in the db return false.
+        $this->assertFalse(core_user::get_user_by_username('janedoe'));
+    }
 }