Merge branch 'wip_MDL-49125_m27_install' of https://github.com/skodak/moodle into...
[moodle.git] / lib / authlib.php
blob8d227bcd0c49744ca264a25e87f09d39d7ab3b22
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 /**
19 * Multiple plugin authentication Support library
21 * 2006-08-28 File created, AUTH return values defined.
23 * @package core
24 * @subpackage auth
25 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 defined('MOODLE_INTERNAL') || die();
31 /**
32 * Returned when the login was successful.
34 define('AUTH_OK', 0);
36 /**
37 * Returned when the login was unsuccessful.
39 define('AUTH_FAIL', 1);
41 /**
42 * Returned when the login was denied (a reason for AUTH_FAIL).
44 define('AUTH_DENIED', 2);
46 /**
47 * Returned when some error occurred (a reason for AUTH_FAIL).
49 define('AUTH_ERROR', 4);
51 /**
52 * Authentication - error codes for user confirm
54 define('AUTH_CONFIRM_FAIL', 0);
55 define('AUTH_CONFIRM_OK', 1);
56 define('AUTH_CONFIRM_ALREADY', 2);
57 define('AUTH_CONFIRM_ERROR', 3);
59 # MDL-14055
60 define('AUTH_REMOVEUSER_KEEP', 0);
61 define('AUTH_REMOVEUSER_SUSPEND', 1);
62 define('AUTH_REMOVEUSER_FULLDELETE', 2);
64 /** Login attempt successful. */
65 define('AUTH_LOGIN_OK', 0);
67 /** Can not login because user does not exist. */
68 define('AUTH_LOGIN_NOUSER', 1);
70 /** Can not login because user is suspended. */
71 define('AUTH_LOGIN_SUSPENDED', 2);
73 /** Can not login, most probably password did not match. */
74 define('AUTH_LOGIN_FAILED', 3);
76 /** Can not login because user is locked out. */
77 define('AUTH_LOGIN_LOCKOUT', 4);
80 /**
81 * Abstract authentication plugin.
83 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
84 * @package moodlecore
86 class auth_plugin_base {
88 /**
89 * The configuration details for the plugin.
90 * @var object
92 var $config;
94 /**
95 * Authentication plugin type - the same as db field.
96 * @var string
98 var $authtype;
100 * The fields we can lock and update from/to external authentication backends
101 * @var array
103 var $userfields = array(
104 'firstname',
105 'lastname',
106 'email',
107 'city',
108 'country',
109 'lang',
110 'description',
111 'url',
112 'idnumber',
113 'institution',
114 'department',
115 'phone1',
116 'phone2',
117 'address',
118 'firstnamephonetic',
119 'lastnamephonetic',
120 'middlename',
121 'alternatename'
125 * Moodle custom fields to sync with.
126 * @var array()
128 var $customfields = null;
131 * This is the primary method that is used by the authenticate_user_login()
132 * function in moodlelib.php.
134 * This method should return a boolean indicating
135 * whether or not the username and password authenticate successfully.
137 * Returns true if the username and password work and false if they are
138 * wrong or don't exist.
140 * @param string $username The username (with system magic quotes)
141 * @param string $password The password (with system magic quotes)
143 * @return bool Authentication success or failure.
145 function user_login($username, $password) {
146 print_error('mustbeoveride', 'debug', '', 'user_login()' );
150 * Returns true if this authentication plugin can change the users'
151 * password.
153 * @return bool
155 function can_change_password() {
156 //override if needed
157 return false;
161 * Returns the URL for changing the users' passwords, or empty if the default
162 * URL can be used.
164 * This method is used if can_change_password() returns true.
165 * This method is called only when user is logged in, it may use global $USER.
166 * If you are using a plugin config variable in this method, please make sure it is set before using it,
167 * as this method can be called even if the plugin is disabled, in which case the config values won't be set.
169 * @return moodle_url url of the profile page or null if standard used
171 function change_password_url() {
172 //override if needed
173 return null;
177 * Returns true if this authentication plugin can edit the users'
178 * profile.
180 * @return bool
182 function can_edit_profile() {
183 //override if needed
184 return true;
188 * Returns the URL for editing the users' profile, or empty if the default
189 * URL can be used.
191 * This method is used if can_edit_profile() returns true.
192 * This method is called only when user is logged in, it may use global $USER.
194 * @return moodle_url url of the profile page or null if standard used
196 function edit_profile_url() {
197 //override if needed
198 return null;
202 * Returns true if this authentication plugin is "internal".
204 * Internal plugins use password hashes from Moodle user table for authentication.
206 * @return bool
208 function is_internal() {
209 //override if needed
210 return true;
214 * Indicates if password hashes should be stored in local moodle database.
215 * @return bool true means md5 password hash stored in user table, false means flag 'not_cached' stored there instead
217 function prevent_local_passwords() {
218 return !$this->is_internal();
222 * Indicates if moodle should automatically update internal user
223 * records with data from external sources using the information
224 * from get_userinfo() method.
226 * @return bool true means automatically copy data from ext to user table
228 function is_synchronised_with_external() {
229 return !$this->is_internal();
233 * Updates the user's password.
235 * In previous versions of Moodle, the function
236 * auth_user_update_password accepted a username as the first parameter. The
237 * revised function expects a user object.
239 * @param object $user User table object
240 * @param string $newpassword Plaintext password
242 * @return bool True on success
244 function user_update_password($user, $newpassword) {
245 //override if needed
246 return true;
250 * Called when the user record is updated.
251 * Modifies user in external database. It takes olduser (before changes) and newuser (after changes)
252 * compares information saved modified information to external db.
254 * @param mixed $olduser Userobject before modifications (without system magic quotes)
255 * @param mixed $newuser Userobject new modified userobject (without system magic quotes)
256 * @return boolean true if updated or update ignored; false if error
259 function user_update($olduser, $newuser) {
260 //override if needed
261 return true;
265 * User delete requested - internal user record is mared as deleted already, username not present anymore.
267 * Do any action in external database.
269 * @param object $user Userobject before delete (without system magic quotes)
270 * @return void
272 function user_delete($olduser) {
273 //override if needed
274 return;
278 * Returns true if plugin allows resetting of internal password.
280 * @return bool
282 function can_reset_password() {
283 //override if needed
284 return false;
288 * Returns true if plugin allows resetting of internal password.
290 * @return bool
292 function can_signup() {
293 //override if needed
294 return false;
298 * Sign up a new user ready for confirmation.
299 * Password is passed in plaintext.
301 * @param object $user new user object
302 * @param boolean $notify print notice with link and terminate
304 function user_signup($user, $notify=true) {
305 //override when can signup
306 print_error('mustbeoveride', 'debug', '', 'user_signup()' );
310 * Return a form to capture user details for account creation.
311 * This is used in /login/signup.php.
312 * @return moodle_form A form which edits a record from the user table.
314 function signup_form() {
315 global $CFG;
317 require_once($CFG->dirroot.'/login/signup_form.php');
318 return new login_signup_form(null, null, 'post', '', array('autocomplete'=>'on'));
322 * Returns true if plugin allows confirming of new users.
324 * @return bool
326 function can_confirm() {
327 //override if needed
328 return false;
332 * Confirm the new user as registered.
334 * @param string $username
335 * @param string $confirmsecret
337 function user_confirm($username, $confirmsecret) {
338 //override when can confirm
339 print_error('mustbeoveride', 'debug', '', 'user_confirm()' );
343 * Checks if user exists in external db
345 * @param string $username (with system magic quotes)
346 * @return bool
348 function user_exists($username) {
349 //override if needed
350 return false;
354 * return number of days to user password expires
356 * If userpassword does not expire it should return 0. If password is already expired
357 * it should return negative value.
359 * @param mixed $username username (with system magic quotes)
360 * @return integer
362 function password_expire($username) {
363 return 0;
366 * Sync roles for this user - usually creator
368 * @param $user object user object (without system magic quotes)
370 function sync_roles($user) {
371 //override if needed
375 * Read user information from external database and returns it as array().
376 * Function should return all information available. If you are saving
377 * this information to moodle user-table you should honour synchronisation flags
379 * @param string $username username
381 * @return mixed array with no magic quotes or false on error
383 function get_userinfo($username) {
384 //override if needed
385 return array();
389 * Prints a form for configuring this authentication plugin.
391 * This function is called from admin/auth.php, and outputs a full page with
392 * a form for configuring this plugin.
394 * @param object $config
395 * @param object $err
396 * @param array $user_fields
398 function config_form($config, $err, $user_fields) {
399 //override if needed
403 * A chance to validate form data, and last chance to
404 * do stuff before it is inserted in config_plugin
405 * @param object object with submitted configuration settings (without system magic quotes)
406 * @param array $err array of error messages
408 function validate_form($form, &$err) {
409 //override if needed
413 * Processes and stores configuration data for this authentication plugin.
415 * @param object object with submitted configuration settings (without system magic quotes)
417 function process_config($config) {
418 //override if needed
419 return true;
423 * Hook for overriding behaviour of login page.
424 * This method is called from login/index.php page for all enabled auth plugins.
426 * @global object
427 * @global object
429 function loginpage_hook() {
430 global $frm; // can be used to override submitted login form
431 global $user; // can be used to replace authenticate_user_login()
433 //override if needed
437 * Post authentication hook.
438 * This method is called from authenticate_user_login() for all enabled auth plugins.
440 * @param object $user user object, later used for $USER
441 * @param string $username (with system magic quotes)
442 * @param string $password plain text password (with system magic quotes)
444 function user_authenticated_hook(&$user, $username, $password) {
445 //override if needed
449 * Pre logout hook.
450 * This method is called from require_logout() for all enabled auth plugins,
452 * @global object
454 function prelogout_hook() {
455 global $USER; // use $USER->auth to find the plugin used for login
457 //override if needed
461 * Hook for overriding behaviour of logout page.
462 * This method is called from login/logout.php page for all enabled auth plugins.
464 * @global object
465 * @global string
467 function logoutpage_hook() {
468 global $USER; // use $USER->auth to find the plugin used for login
469 global $redirect; // can be used to override redirect after logout
471 //override if needed
475 * Hook called before timing out of database session.
476 * This is useful for SSO and MNET.
478 * @param object $user
479 * @param string $sid session id
480 * @param int $timecreated start of session
481 * @param int $timemodified user last seen
482 * @return bool true means do not timeout session yet
484 function ignore_timeout_hook($user, $sid, $timecreated, $timemodified) {
485 return false;
489 * Return the properly translated human-friendly title of this auth plugin
491 * @todo Document this function
493 function get_title() {
494 return get_string('pluginname', "auth_{$this->authtype}");
498 * Get the auth description (from core or own auth lang files)
500 * @return string The description
502 function get_description() {
503 $authdescription = get_string("auth_{$this->authtype}description", "auth_{$this->authtype}");
504 return $authdescription;
508 * Returns whether or not the captcha element is enabled, and the admin settings fulfil its requirements.
510 * @abstract Implement in child classes
511 * @return bool
513 function is_captcha_enabled() {
514 return false;
518 * Returns whether or not this authentication plugin can be manually set
519 * for users, for example, when bulk uploading users.
521 * This should be overriden by authentication plugins where setting the
522 * authentication method manually is allowed.
524 * @return bool
525 * @since Moodle 2.6
527 function can_be_manually_set() {
528 // Override if needed.
529 return false;
533 * Returns a list of potential IdPs that this authentication plugin supports.
534 * This is used to provide links on the login page.
536 * @param string $wantsurl the relative url fragment the user wants to get to. You can use this to compose a returnurl, for example
538 * @return array like:
539 * array(
540 * array(
541 * 'url' => 'http://someurl',
542 * 'icon' => new pix_icon(...),
543 * 'name' => get_string('somename', 'auth_yourplugin'),
544 * ),
547 function loginpage_idp_list($wantsurl) {
548 return array();
552 * Return custom user profile fields.
554 * @return array list of custom fields.
556 public function get_custom_user_profile_fields() {
557 global $DB;
558 // If already retrieved then return.
559 if (!is_null($this->customfields)) {
560 return $this->customfields;
563 $this->customfields = array();
564 if ($proffields = $DB->get_records('user_info_field')) {
565 foreach ($proffields as $proffield) {
566 $this->customfields[] = 'profile_field_'.$proffield->shortname;
569 unset($proffields);
571 return $this->customfields;
576 * Verify if user is locked out.
578 * @param stdClass $user
579 * @return bool true if user locked out
581 function login_is_lockedout($user) {
582 global $CFG;
584 if ($user->mnethostid != $CFG->mnet_localhost_id) {
585 return false;
587 if (isguestuser($user)) {
588 return false;
591 if (empty($CFG->lockoutthreshold)) {
592 // Lockout not enabled.
593 return false;
596 if (get_user_preferences('login_lockout_ignored', 0, $user)) {
597 // This preference may be used for accounts that must not be locked out.
598 return false;
601 $locked = get_user_preferences('login_lockout', 0, $user);
602 if (!$locked) {
603 return false;
606 if (empty($CFG->lockoutduration)) {
607 // Locked out forever.
608 return true;
611 if (time() - $locked < $CFG->lockoutduration) {
612 return true;
615 login_unlock_account($user);
617 return false;
621 * To be called after valid user login.
622 * @param stdClass $user
624 function login_attempt_valid($user) {
625 global $CFG;
627 // Note: user_loggedin event is triggered in complete_user_login().
629 if ($user->mnethostid != $CFG->mnet_localhost_id) {
630 return;
632 if (isguestuser($user)) {
633 return;
636 // Always unlock here, there might be some race conditions or leftovers when switching threshold.
637 login_unlock_account($user);
641 * To be called after failed user login.
642 * @param stdClass $user
644 function login_attempt_failed($user) {
645 global $CFG;
647 if ($user->mnethostid != $CFG->mnet_localhost_id) {
648 return;
650 if (isguestuser($user)) {
651 return;
654 $count = get_user_preferences('login_failed_count', 0, $user);
655 $last = get_user_preferences('login_failed_last', 0, $user);
656 $sincescuccess = get_user_preferences('login_failed_count_since_success', $count, $user);
657 $sincescuccess = $sincescuccess + 1;
658 set_user_preference('login_failed_count_since_success', $sincescuccess, $user);
660 if (empty($CFG->lockoutthreshold)) {
661 // No threshold means no lockout.
662 // Always unlock here, there might be some race conditions or leftovers when switching threshold.
663 login_unlock_account($user);
664 return;
667 if (!empty($CFG->lockoutwindow) and time() - $last > $CFG->lockoutwindow) {
668 $count = 0;
671 $count = $count+1;
673 set_user_preference('login_failed_count', $count, $user);
674 set_user_preference('login_failed_last', time(), $user);
676 if ($count >= $CFG->lockoutthreshold) {
677 login_lock_account($user);
682 * Lockout user and send notification email.
684 * @param stdClass $user
686 function login_lock_account($user) {
687 global $CFG;
689 if ($user->mnethostid != $CFG->mnet_localhost_id) {
690 return;
692 if (isguestuser($user)) {
693 return;
696 if (get_user_preferences('login_lockout_ignored', 0, $user)) {
697 // This user can not be locked out.
698 return;
701 $alreadylockedout = get_user_preferences('login_lockout', 0, $user);
703 set_user_preference('login_lockout', time(), $user);
705 if ($alreadylockedout == 0) {
706 $secret = random_string(15);
707 set_user_preference('login_lockout_secret', $secret, $user);
709 $oldforcelang = force_current_language($user->lang);
711 $site = get_site();
712 $supportuser = core_user::get_support_user();
714 $data = new stdClass();
715 $data->firstname = $user->firstname;
716 $data->lastname = $user->lastname;
717 $data->username = $user->username;
718 $data->sitename = format_string($site->fullname);
719 $data->link = $CFG->wwwroot.'/login/unlock_account.php?u='.$user->id.'&s='.$secret;
720 $data->admin = generate_email_signoff();
722 $message = get_string('lockoutemailbody', 'admin', $data);
723 $subject = get_string('lockoutemailsubject', 'admin', format_string($site->fullname));
725 if ($message) {
726 // Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
727 email_to_user($user, $supportuser, $subject, $message);
730 force_current_language($oldforcelang);
735 * Unlock user account and reset timers.
737 * @param stdClass $user
739 function login_unlock_account($user) {
740 unset_user_preference('login_lockout', $user);
741 unset_user_preference('login_failed_count', $user);
742 unset_user_preference('login_failed_last', $user);
744 // Note: do not clear the lockout secret because user might click on the link repeatedly.