lib.php 8.62 KB
Newer Older
1 2
<?php
/**
Francois Marier's avatar
Francois Marier committed
3
 * Mahara: Electronic portfolio, weblog, resume builder and social networking
4 5
 * Copyright (C) 2006-2009 Catalyst IT Ltd and others; see:
 *                         http://wiki.mahara.org/Contributors
6
 *
Francois Marier's avatar
Francois Marier committed
7 8 9 10
 * This program 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.
11
 *
Francois Marier's avatar
Francois Marier committed
12 13 14 15
 * This program 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.
16
 *
Francois Marier's avatar
Francois Marier committed
17 18
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 20
 *
 * @package    mahara
Penny Leach's avatar
Penny Leach committed
21
 * @subpackage auth-internal
22
 * @author     Catalyst IT Ltd
23
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL
24
 * @copyright  (C) 2006-2009 Catalyst IT Ltd http://catalyst.net.nz
25 26 27 28
 *
 */

defined('INTERNAL') || die();
29
require_once(get_config('docroot') . 'auth/lib.php');
30

31 32 33 34
/**
 * The internal authentication method, which authenticates users against the
 * Mahara database.
 */
35
class AuthInternal extends Auth {
36

37
    public function __construct($id = null) {
38
        $this->has_instance_config = false;
39
        $this->type       = 'internal';
40
        if (!empty($id)) {
41
            return $this->init($id);
42
        }
43
        return true;
44 45
    }

46 47 48
    public function init($id) {
        $this->ready = parent::init($id);
        return true;
49 50
    }

51
    /**
52
     * Attempt to authenticate user
53
     *
54 55 56 57 58
     * @param object $user     As returned from the usr table
     * @param string $password The password being used for authentication
     * @return bool            True/False based on whether the user
     *                         authenticated successfully
     * @throws AuthUnknownUserException If the user does not exist
59
     */
60 61 62
    public function authenticate_user_account($user, $password) {
        $this->must_be_ready();
        return $this->validate_password($password, $user->password, $user->salt);
63 64
    }

65 66 67 68 69 70 71 72
    /**
     * Internal authentication never auto-creates users - users instead 
     * register through register.php
     */
    public function can_auto_create_users() {
        return false;
    }

73 74 75 76 77 78 79 80
    /**
     * For internal authentication, passwords can contain a range of letters,
     * numbers and symbols. There is a minimum limit of six characters allowed
     * for the password, and no upper limit
     *
     * @param string $password The password to check
     * @return bool            Whether the password is valid
     */
81
    public function is_password_valid($password) {
82
        if (!preg_match('/^[a-zA-Z0-9 ~!@#\$%\^&\*\(\)_\-=\+\,\.<>\/\?;:"\[\]\{\}\\\|`\']{6,}$/', $password)) {
83 84 85 86 87 88 89 90 91 92 93 94
            return false;
        }
        // The password must have at least one digit and two letters in it
        if (!preg_match('/[0-9]/', $password)) {
            return false;
        }

        $password = preg_replace('/[a-zA-Z]/', "\0", $password);
        if (substr_count($password, "\0") < 2) {
            return false;
        }
        return true;
95 96
    }

Nigel McNie's avatar
Nigel McNie committed
97 98 99
    /**
     * Changes the user's password.
     *
100 101 102
     * This method is not strictly part of the authentication API, but if
     * defined allows the method to change a user's password.
     *
103 104
     * @param object  $user     The user to change the password for
     * @param string  $password The password to set for the user
105
     * @param boolean $resetpasswordchange Whether to reset the passwordchange variable or not
Nigel McNie's avatar
Nigel McNie committed
106 107
     * @return string The new password, or empty if the password could not be set
     */
108
    public function change_password(User $user, $password, $resetpasswordchange = true) {
109
        $this->must_be_ready();
Nigel McNie's avatar
Nigel McNie committed
110
        // Create a salted password and set it for the user
111
        $user->salt = substr(md5(rand(1000000, 9999999)), 2, 8);
112
        $user->password = $this->encrypt_password($password, $user->salt);
113 114 115
        if ($resetpasswordchange) {
            $user->passwordchange = 0;
        }
116
        $user->commit();
117 118 119 120
        return $user->password;
    }

    /**
121 122 123
     * Internal authentication allows most standard us-keyboard-typable characters
     * for username, as long as the username is between three and thirty 
     * characters in length.
124 125 126 127 128 129 130 131
     *
     * This method is NOT part of the authentication API. Other authentication
     * methods never have to do anything regarding usernames being validated on
     * the Mahara side, so they do not need this method.
     *
     * @param string $username The username to check
     * @return bool            Whether the username is valid
     */
132
    public function is_username_valid($username) {
133
        return preg_match('/^[a-zA-Z0-9!@#$%^&*()\-_=+\[{\]}\\|;:\'",<\.>\/?`]{3,30}$/', $username);
Nigel McNie's avatar
Nigel McNie committed
134
    }
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    /**


     * Internal authentication allows most standard us-keyboard-typable characters
     * for username, as long as the username is between three and 236 
     * characters in length.
     *
     * This method is NOT part of the authentication API. Other authentication
     * methods never have to do anything regarding usernames being validated on
     * the Mahara side, so they do not need this method.
     *
     * This method is meant to only be called for validation by an admin of the user
     * and is able to set a password longer than thirty characters in length
     *
     * @param string $username The username to check
     * @return bool            Whether the username is valid
     */
    public function is_username_valid_admin($username) {
        return preg_match('/^[a-zA-Z0-9!@#$%^&*()\-_=+\[{\]}\\|;:\'",<\.>\/?`]{3,236}$/', $username);
    }
Nigel McNie's avatar
Nigel McNie committed
155

156 157 158 159 160 161 162 163 164 165 166
    /**
     * Changes the user's username.
     *
     * This method is not strictly part of the authentication API, but if
     * defined allows the method to change a user's username.
     *
     * @param object  $user     The user to change the password for
     * @param string  $username The username to set for the user
     * @return string The new username, or the original username if it could not be set
     */
    public function change_username(User $user, $username) {
167 168
        global $USER;

169 170 171
        $this->must_be_ready();

        // proposed username must pass validation
172 173 174 175 176 177 178 179
        $valid = false;
        if ($USER->is_admin_for_user($user)) {
            $valid = $this->is_username_valid_admin($username);
        } else {
            $valid = $this->is_username_valid($username);
        }

        if ($valid) {
180 181 182 183 184 185 186 187
            $user->username = $username;
            $user->commit();
        }

        // return the new username, or the original one if it failed validation
        return $user->username;
    }

188 189 190 191 192
    /*
     The following two functions are inspired by Andrew McMillan's salted md5
     functions in AWL, adapted with his kind permission. Changed to use sha1
     and match the coding standards for Mahara.
    */
193 194 195 196 197 198 199 200

   /**
    * Given a password and an optional salt, encrypt the given password.
    *
    * Passwords are stored in SHA1 form.
    *
    * @param string $password The password to encrypt
    * @param string $salt     The salt to use to encrypt the password
201
    * @todo salt mandatory
202
    */
203
    public function encrypt_password($password, $salt='') {
204 205 206 207 208 209
        if ($salt == '') {
            $salt = substr(md5(rand(1000000, 9999999)), 2, 8);
        }
        return sha1($salt . $password);
    }

210 211 212 213 214 215
    /**
     * Given a password that the user has sent, the password we have for them
     * and the salt we have, see if the password they sent is correct.
     *
     * @param string $theysent The password the user sent
     * @param string $wehave   The password we have in the database for them
216
     * @param string $salt     The salt we have.
217
     */
218 219
    private function validate_password($theysent, $wehave, $salt) {
        $this->must_be_ready();
220

Martyn Smith's avatar
Martyn Smith committed
221 222 223 224 225 226
        if ($salt == '*') {
            // This is a special salt that means this user simply CAN'T log in.
            // It is used on the root user (id=0)
            return false;
        }

227
        // The main type - a salted sha1
228
        $sha1sent = $this->encrypt_password($theysent, $salt);
229 230
        return $sha1sent == $wehave;
    }
231

232 233
}

234
/**
235
 * Plugin configuration class
236
 */
237
class PluginAuthInternal extends PluginAuth {
238

239
    public static function has_config() {
240
        return false;
241
    }
242 243 244 245

    public static function get_config_options() {
        return array();
    }
246 247 248 249 250 251 252 253

    public static function has_instance_config() {
        return false;
    }

    public static function get_instance_config_options() {
        return array();
    }
254 255
}

256
?>