MDL-46138 post integratino phpdoc fixes
[moodle.git] / lib / authlib.php
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.
14 //
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
20  *
21  * 2006-08-28  File created, AUTH return values defined.
22  *
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
27  */
29 defined('MOODLE_INTERNAL') || die();
31 /**
32  * Returned when the login was successful.
33  */
34 define('AUTH_OK',     0);
36 /**
37  * Returned when the login was unsuccessful.
38  */
39 define('AUTH_FAIL',   1);
41 /**
42  * Returned when the login was denied (a reason for AUTH_FAIL).
43  */
44 define('AUTH_DENIED', 2);
46 /**
47  * Returned when some error occurred (a reason for AUTH_FAIL).
48  */
49 define('AUTH_ERROR',  4);
51 /**
52  * Authentication - error codes for user confirm
53  */
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.
82  *
83  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
84  * @package moodlecore
85  */
86 class auth_plugin_base {
88     /**
89      * The configuration details for the plugin.
90      * @var object
91      */
92     var $config;
94     /**
95      * Authentication plugin type - the same as db field.
96      * @var string
97      */
98     var $authtype;
99     /*
100      * The fields we can lock and update from/to external authentication backends
101      * @var array
102      */
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     );
120     /**
121      * Moodle custom fields to sync with.
122      * @var array()
123      */
124     var $customfields = null;
126     /**
127      * This is the primary method that is used by the authenticate_user_login()
128      * function in moodlelib.php.
129      *
130      * This method should return a boolean indicating
131      * whether or not the username and password authenticate successfully.
132      *
133      * Returns true if the username and password work and false if they are
134      * wrong or don't exist.
135      *
136      * @param string $username The username (with system magic quotes)
137      * @param string $password The password (with system magic quotes)
138      *
139      * @return bool Authentication success or failure.
140      */
141     function user_login($username, $password) {
142         print_error('mustbeoveride', 'debug', '', 'user_login()' );
143     }
145     /**
146      * Returns true if this authentication plugin can change the users'
147      * password.
148      *
149      * @return bool
150      */
151     function can_change_password() {
152         //override if needed
153         return false;
154     }
156     /**
157      * Returns the URL for changing the users' passwords, or empty if the default
158      * URL can be used.
159      *
160      * This method is used if can_change_password() returns true.
161      * This method is called only when user is logged in, it may use global $USER.
162      * If you are using a plugin config variable in this method, please make sure it is set before using it,
163      * as this method can be called even if the plugin is disabled, in which case the config values won't be set.
164      *
165      * @return moodle_url url of the profile page or null if standard used
166      */
167     function change_password_url() {
168         //override if needed
169         return null;
170     }
172     /**
173      * Returns true if this authentication plugin can edit the users'
174      * profile.
175      *
176      * @return bool
177      */
178     function can_edit_profile() {
179         //override if needed
180         return true;
181     }
183     /**
184      * Returns the URL for editing the users' profile, or empty if the default
185      * URL can be used.
186      *
187      * This method is used if can_edit_profile() returns true.
188      * This method is called only when user is logged in, it may use global $USER.
189      *
190      * @return moodle_url url of the profile page or null if standard used
191      */
192     function edit_profile_url() {
193         //override if needed
194         return null;
195     }
197     /**
198      * Returns true if this authentication plugin is "internal".
199      *
200      * Internal plugins use password hashes from Moodle user table for authentication.
201      *
202      * @return bool
203      */
204     function is_internal() {
205         //override if needed
206         return true;
207     }
209     /**
210      * Indicates if password hashes should be stored in local moodle database.
211      * @return bool true means md5 password hash stored in user table, false means flag 'not_cached' stored there instead
212      */
213     function prevent_local_passwords() {
214         return !$this->is_internal();
215     }
217     /**
218      * Indicates if moodle should automatically update internal user
219      * records with data from external sources using the information
220      * from get_userinfo() method.
221      *
222      * @return bool true means automatically copy data from ext to user table
223      */
224     function is_synchronised_with_external() {
225         return !$this->is_internal();
226     }
228     /**
229      * Updates the user's password.
230      *
231      * In previous versions of Moodle, the function
232      * auth_user_update_password accepted a username as the first parameter. The
233      * revised function expects a user object.
234      *
235      * @param  object  $user        User table object
236      * @param  string  $newpassword Plaintext password
237      *
238      * @return bool                  True on success
239      */
240     function user_update_password($user, $newpassword) {
241         //override if needed
242         return true;
243     }
245     /**
246      * Called when the user record is updated.
247      * Modifies user in external database. It takes olduser (before changes) and newuser (after changes)
248      * compares information saved modified information to external db.
249      *
250      * @param mixed $olduser     Userobject before modifications    (without system magic quotes)
251      * @param mixed $newuser     Userobject new modified userobject (without system magic quotes)
252      * @return boolean true if updated or update ignored; false if error
253      *
254      */
255     function user_update($olduser, $newuser) {
256         //override if needed
257         return true;
258     }
260     /**
261      * User delete requested - internal user record is mared as deleted already, username not present anymore.
262      *
263      * Do any action in external database.
264      *
265      * @param object $user       Userobject before delete    (without system magic quotes)
266      * @return void
267      */
268     function user_delete($olduser) {
269         //override if needed
270         return;
271     }
273     /**
274      * Returns true if plugin allows resetting of internal password.
275      *
276      * @return bool
277      */
278     function can_reset_password() {
279         //override if needed
280         return false;
281     }
283     /**
284      * Returns true if plugin allows resetting of internal password.
285      *
286      * @return bool
287      */
288     function can_signup() {
289         //override if needed
290         return false;
291     }
293     /**
294      * Sign up a new user ready for confirmation.
295      * Password is passed in plaintext.
296      *
297      * @param object $user new user object
298      * @param boolean $notify print notice with link and terminate
299      */
300     function user_signup($user, $notify=true) {
301         //override when can signup
302         print_error('mustbeoveride', 'debug', '', 'user_signup()' );
303     }
305     /**
306      * Return a form to capture user details for account creation.
307      * This is used in /login/signup.php.
308      * @return moodle_form A form which edits a record from the user table.
309      */
310     function signup_form() {
311         global $CFG;
313         require_once($CFG->dirroot.'/login/signup_form.php');
314         return new login_signup_form(null, null, 'post', '', array('autocomplete'=>'on'));
315     }
317     /**
318      * Returns true if plugin allows confirming of new users.
319      *
320      * @return bool
321      */
322     function can_confirm() {
323         //override if needed
324         return false;
325     }
327     /**
328      * Confirm the new user as registered.
329      *
330      * @param string $username
331      * @param string $confirmsecret
332      */
333     function user_confirm($username, $confirmsecret) {
334         //override when can confirm
335         print_error('mustbeoveride', 'debug', '', 'user_confirm()' );
336     }
338     /**
339      * Checks if user exists in external db
340      *
341      * @param string $username (with system magic quotes)
342      * @return bool
343      */
344     function user_exists($username) {
345         //override if needed
346         return false;
347     }
349     /**
350      * return number of days to user password expires
351      *
352      * If userpassword does not expire it should return 0. If password is already expired
353      * it should return negative value.
354      *
355      * @param mixed $username username (with system magic quotes)
356      * @return integer
357      */
358     function password_expire($username) {
359         return 0;
360     }
361     /**
362      * Sync roles for this user - usually creator
363      *
364      * @param $user object user object (without system magic quotes)
365      */
366     function sync_roles($user) {
367         //override if needed
368     }
370     /**
371      * Read user information from external database and returns it as array().
372      * Function should return all information available. If you are saving
373      * this information to moodle user-table you should honour synchronisation flags
374      *
375      * @param string $username username
376      *
377      * @return mixed array with no magic quotes or false on error
378      */
379     function get_userinfo($username) {
380         //override if needed
381         return array();
382     }
384     /**
385      * Prints a form for configuring this authentication plugin.
386      *
387      * This function is called from admin/auth.php, and outputs a full page with
388      * a form for configuring this plugin.
389      *
390      * @param object $config
391      * @param object $err
392      * @param array $user_fields
393      */
394     function config_form($config, $err, $user_fields) {
395         //override if needed
396     }
398     /**
399      * A chance to validate form data, and last chance to
400      * do stuff before it is inserted in config_plugin
401      * @param object object with submitted configuration settings (without system magic quotes)
402      * @param array $err array of error messages
403      */
404      function validate_form($form, &$err) {
405         //override if needed
406     }
408     /**
409      * Processes and stores configuration data for this authentication plugin.
410      *
411      * @param object object with submitted configuration settings (without system magic quotes)
412      */
413     function process_config($config) {
414         //override if needed
415         return true;
416     }
418     /**
419      * Hook for overriding behaviour of login page.
420      * This method is called from login/index.php page for all enabled auth plugins.
421      *
422      * @global object
423      * @global object
424      */
425     function loginpage_hook() {
426         global $frm;  // can be used to override submitted login form
427         global $user; // can be used to replace authenticate_user_login()
429         //override if needed
430     }
432     /**
433      * Post authentication hook.
434      * This method is called from authenticate_user_login() for all enabled auth plugins.
435      *
436      * @param object $user user object, later used for $USER
437      * @param string $username (with system magic quotes)
438      * @param string $password plain text password (with system magic quotes)
439      */
440     function user_authenticated_hook(&$user, $username, $password) {
441         //override if needed
442     }
444     /**
445      * Pre logout hook.
446      * This method is called from require_logout() for all enabled auth plugins,
447      *
448      * @global object
449      */
450     function prelogout_hook() {
451         global $USER; // use $USER->auth to find the plugin used for login
453         //override if needed
454     }
456     /**
457      * Hook for overriding behaviour of logout page.
458      * This method is called from login/logout.php page for all enabled auth plugins.
459      *
460      * @global object
461      * @global string
462      */
463     function logoutpage_hook() {
464         global $USER;     // use $USER->auth to find the plugin used for login
465         global $redirect; // can be used to override redirect after logout
467         //override if needed
468     }
470     /**
471      * Hook called before timing out of database session.
472      * This is useful for SSO and MNET.
473      *
474      * @param object $user
475      * @param string $sid session id
476      * @param int $timecreated start of session
477      * @param int $timemodified user last seen
478      * @return bool true means do not timeout session yet
479      */
480     function ignore_timeout_hook($user, $sid, $timecreated, $timemodified) {
481         return false;
482     }
484     /**
485      * Return the properly translated human-friendly title of this auth plugin
486      *
487      * @todo Document this function
488      */
489     function get_title() {
490         return get_string('pluginname', "auth_{$this->authtype}");
491     }
493     /**
494      * Get the auth description (from core or own auth lang files)
495      *
496      * @return string The description
497      */
498     function get_description() {
499         $authdescription = get_string("auth_{$this->authtype}description", "auth_{$this->authtype}");
500         return $authdescription;
501     }
503     /**
504      * Returns whether or not the captcha element is enabled, and the admin settings fulfil its requirements.
505      *
506      * @abstract Implement in child classes
507      * @return bool
508      */
509     function is_captcha_enabled() {
510         return false;
511     }
513     /**
514      * Returns whether or not this authentication plugin can be manually set
515      * for users, for example, when bulk uploading users.
516      *
517      * This should be overriden by authentication plugins where setting the
518      * authentication method manually is allowed.
519      *
520      * @return bool
521      * @since Moodle 2.6
522      */
523     function can_be_manually_set() {
524         // Override if needed.
525         return false;
526     }
528     /**
529      * Returns a list of potential IdPs that this authentication plugin supports.
530      * This is used to provide links on the login page.
531      *
532      * @param string $wantsurl the relative url fragment the user wants to get to.  You can use this to compose a returnurl, for example
533      *
534      * @return array like:
535      *              array(
536      *                  array(
537      *                      'url' => 'http://someurl',
538      *                      'icon' => new pix_icon(...),
539      *                      'name' => get_string('somename', 'auth_yourplugin'),
540      *                 ),
541      *             )
542      */
543     function loginpage_idp_list($wantsurl) {
544         return array();
545     }
547     /**
548      * Return custom user profile fields.
549      *
550      * @return array list of custom fields.
551      */
552     public function get_custom_user_profile_fields() {
553         global $DB;
554         // If already retrieved then return.
555         if (!is_null($this->customfields)) {
556             return $this->customfields;
557         }
559         $this->customfields = array();
560         if ($proffields = $DB->get_records('user_info_field')) {
561             foreach ($proffields as $proffield) {
562                 $this->customfields[] = 'profile_field_'.$proffield->shortname;
563             }
564         }
565         unset($proffields);
567         return $this->customfields;
568     }
570     /**
571      * Post logout hook.
572      *
573      * This method is used after moodle logout by auth classes to execute server logout.
574      *
575      * @param stdClass $user clone of USER object before the user session was terminated
576      */
577     public function postlogout_hook($user) {
578     }
581 /**
582  * Verify if user is locked out.
583  *
584  * @param stdClass $user
585  * @return bool true if user locked out
586  */
587 function login_is_lockedout($user) {
588     global $CFG;
590     if ($user->mnethostid != $CFG->mnet_localhost_id) {
591         return false;
592     }
593     if (isguestuser($user)) {
594         return false;
595     }
597     if (empty($CFG->lockoutthreshold)) {
598         // Lockout not enabled.
599         return false;
600     }
602     if (get_user_preferences('login_lockout_ignored', 0, $user)) {
603         // This preference may be used for accounts that must not be locked out.
604         return false;
605     }
607     $locked = get_user_preferences('login_lockout', 0, $user);
608     if (!$locked) {
609         return false;
610     }
612     if (empty($CFG->lockoutduration)) {
613         // Locked out forever.
614         return true;
615     }
617     if (time() - $locked < $CFG->lockoutduration) {
618         return true;
619     }
621     login_unlock_account($user);
623     return false;
626 /**
627  * To be called after valid user login.
628  * @param stdClass $user
629  */
630 function login_attempt_valid($user) {
631     global $CFG;
633     // Note: user_loggedin event is triggered in complete_user_login().
635     if ($user->mnethostid != $CFG->mnet_localhost_id) {
636         return;
637     }
638     if (isguestuser($user)) {
639         return;
640     }
642     // Always unlock here, there might be some race conditions or leftovers when switching threshold.
643     login_unlock_account($user);
646 /**
647  * To be called after failed user login.
648  * @param stdClass $user
649  */
650 function login_attempt_failed($user) {
651     global $CFG;
653     if ($user->mnethostid != $CFG->mnet_localhost_id) {
654         return;
655     }
656     if (isguestuser($user)) {
657         return;
658     }
660     $count = get_user_preferences('login_failed_count', 0, $user);
661     $last = get_user_preferences('login_failed_last', 0, $user);
662     $sincescuccess = get_user_preferences('login_failed_count_since_success', $count, $user);
663     $sincescuccess = $sincescuccess + 1;
664     set_user_preference('login_failed_count_since_success', $sincescuccess, $user);
666     if (empty($CFG->lockoutthreshold)) {
667         // No threshold means no lockout.
668         // Always unlock here, there might be some race conditions or leftovers when switching threshold.
669         login_unlock_account($user);
670         return;
671     }
673     if (!empty($CFG->lockoutwindow) and time() - $last > $CFG->lockoutwindow) {
674         $count = 0;
675     }
677     $count = $count+1;
679     set_user_preference('login_failed_count', $count, $user);
680     set_user_preference('login_failed_last', time(), $user);
682     if ($count >= $CFG->lockoutthreshold) {
683         login_lock_account($user);
684     }
687 /**
688  * Lockout user and send notification email.
689  *
690  * @param stdClass $user
691  */
692 function login_lock_account($user) {
693     global $CFG;
695     if ($user->mnethostid != $CFG->mnet_localhost_id) {
696         return;
697     }
698     if (isguestuser($user)) {
699         return;
700     }
702     if (get_user_preferences('login_lockout_ignored', 0, $user)) {
703         // This user can not be locked out.
704         return;
705     }
707     $alreadylockedout = get_user_preferences('login_lockout', 0, $user);
709     set_user_preference('login_lockout', time(), $user);
711     if ($alreadylockedout == 0) {
712         $secret = random_string(15);
713         set_user_preference('login_lockout_secret', $secret, $user);
715         $oldforcelang = force_current_language($user->lang);
717         $site = get_site();
718         $supportuser = core_user::get_support_user();
720         $data = new stdClass();
721         $data->firstname = $user->firstname;
722         $data->lastname  = $user->lastname;
723         $data->username  = $user->username;
724         $data->sitename  = format_string($site->fullname);
725         $data->link      = $CFG->wwwroot.'/login/unlock_account.php?u='.$user->id.'&s='.$secret;
726         $data->admin     = generate_email_signoff();
728         $message = get_string('lockoutemailbody', 'admin', $data);
729         $subject = get_string('lockoutemailsubject', 'admin', format_string($site->fullname));
731         if ($message) {
732             // Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
733             email_to_user($user, $supportuser, $subject, $message);
734         }
736         force_current_language($oldforcelang);
737     }
740 /**
741  * Unlock user account and reset timers.
742  *
743  * @param stdClass $user
744  */
745 function login_unlock_account($user) {
746     unset_user_preference('login_lockout', $user);
747     unset_user_preference('login_failed_count', $user);
748     unset_user_preference('login_failed_last', $user);
750     // Note: do not clear the lockout secret because user might click on the link repeatedly.