diff --git a/auth/README b/auth/README index 72944542ee7..ac074c2b234 100644 --- a/auth/README +++ b/auth/README @@ -1,9 +1,9 @@ This directory contains authentication modules. -Each of these modules describes a different way to -check that a user has provided a correct +Each of these modules describes a different way to +check that a user has provided a correct - - username, and + - username, and - password. Even when external forms of authentication are being used, Moodle still @@ -22,18 +22,18 @@ part of the enabled plugin sequence). email - authentication by email (DEFAULT METHOD) - user fills out form with email address - - email sent to user with link + - email sent to user with link - user clicks on link in email to confirm - user account is created - user can log in none - no authentication at all .. very insecure!! - + - user logs in using ANY username and password - if the username doesn't already exist then a new account is created - - when user tries to access a course they + - when user tries to access a course they are forced to set up their account details manual - internal authentication only @@ -81,7 +81,7 @@ nntp - Uses an external NNTP server db - Uses an external database to check username/password - + - user logs in using username and password - these are checked against an external database - if correct, user is logged in @@ -203,14 +203,14 @@ AUTHENTICATION Basic fuctions to authenticate users with external db. -Mandatory: +Mandatory: auth_plugin_foo() Constructor. At the least, it populates config member variable with settings from the Moodle database. It makes sense to put other startup code here. - user_login($username, $password) + user_login($username, $password) Authenticate username, password with userdatabase. @@ -225,7 +225,7 @@ Optional: Query other userinformation from database. Returns: - Userinformation in array ( name => value, .... + Userinformation in array ( name => value, .... or false in case of error @@ -251,9 +251,9 @@ USER CREATION Functions that enable usercreation, activation and deactivation from moodle to external database - - - user_exists ($username) + + + user_exists ($username) Checks if given username exist on external db @@ -261,7 +261,7 @@ from moodle to external database true if given usernname exist or false - user_create ($userobject,$plainpass) + user_create ($userobject,$plainpass) Creates new user to external db. User should be created in inactive stage until confirmed by email. @@ -270,7 +270,7 @@ from moodle to external database True on success otherwise false - user_activate ($username) + user_activate ($username) activate new user after email-address is confirmed @@ -297,11 +297,3 @@ USER INFORMATION AND SYNCRONIZATION All usernames in array or false on error. - get_users($filter='*') - - Get ALL USEROBJECTS FROM EXTERNAL DB. - - Returns: - Array of all users as objects from external db - - diff --git a/auth/README2 b/auth/README2 index 40ba27490d0..2934800fa14 100644 --- a/auth/README2 +++ b/auth/README2 @@ -11,9 +11,6 @@ get_auth_plugin() that does the work for you: $ldapauth = get_auth_plugin('ldap'); -If an auth is not specified, get_auth_plugin() will return you the auth plugin -defined in the $CFG->auth variable. - Auth plugin classes are pretty basic. They contain the same functions that were previously in each plugin's lib.php file, but refactored to become class methods, and tweaked to reference the plugin's instantiated config to get at the @@ -63,6 +60,7 @@ user_login($username, $password) This is the primary method that is used by the authenticate_user_login() function in moodlelib.php. This method should return a boolean indicating whether or not the username and password authenticate successfully. + Both parameter must have magic quotes applied. is_internal() Returns true if this authentication plugin is "internal" (which means that @@ -79,9 +77,10 @@ change_password_url() Other Methods ----------------- -get_userinfo() +get_userinfo($username) This method should return an array of fields from the authentication source - for the given username. + for the given username. Username parameter must have magic quotes applied. + The returned array does not have magic quotes applied. Upgrading from Moodle 1.7 ----------------------------- diff --git a/auth/cas/README-CAS b/auth/cas/README-CAS index 64bfdfcb17f..8b133052b15 100644 --- a/auth/cas/README-CAS +++ b/auth/cas/README-CAS @@ -2,6 +2,6 @@ CAS-module README Please read comments from lib.php for auth/cas module The auth/cas module is using part of the /auth/ldap module. The /auth/ldap directory should exist. -The auth/cas use the PHPCAS project from http://esup-phpcas.sourceforge.net +The auth/cas use the PHPCAS project from http://esup-phpcas.sourceforge.net diff --git a/auth/cas/auth.php b/auth/cas/auth.php index 55b5b99e7b1..af55197908f 100644 --- a/auth/cas/auth.php +++ b/auth/cas/auth.php @@ -11,8 +11,9 @@ * 2006-08-28 File created. */ -// This page cannot be called directly -if (!isset($CFG)) exit; +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page +} /** * CAS authentication plugin. @@ -38,21 +39,21 @@ class auth_plugin_cas { * * @param string $username The username * @param string $password The password - * @returns bool Authentication success or failure. + * @return bool Authentication success or failure. */ function user_login ($username, $password) { if (! function_exists('ldap_connect')) { print_error('auth_casnotinstalled','mnet'); return false; } - + global $CFG; // don't allow blank usernames or passwords if (!$username or !$password) { return false; } - + // CAS specific if ($CFG->auth == "cas" and !empty($this->config->enabled)) { if ($this->config->create_user == '0') { @@ -72,7 +73,7 @@ class auth_plugin_cas { if ($ldap_connection) { $ldap_user_dn = auth_ldap_find_userdn($ldap_connection, $username); - + // if ldap_user_dn is empty, user does not exist if (!$ldap_user_dn) { ldap_close($ldap_connection); @@ -205,7 +206,7 @@ class auth_plugin_cas { /** * Returns true if this authentication plugin is 'internal'. * - * @returns bool + * @return bool */ function is_internal() { return false; @@ -215,7 +216,7 @@ class auth_plugin_cas { * Returns true if this authentication plugin can change the user's * password. * - * @returns bool + * @return bool */ function can_change_password() { return false; @@ -229,7 +230,7 @@ class auth_plugin_cas { * * @param array $page An object containing all the data for this page. */ - function config_form($config, $err) { + function config_form($config, $err, $user_fields) { include 'config.html'; } @@ -237,7 +238,7 @@ class auth_plugin_cas { * Returns the URL for changing the user's pw, or false if the default can * be used. * - * @returns bool + * @return bool */ function change_password_url() { return $this->config->changepasswordurl; @@ -288,7 +289,7 @@ class auth_plugin_cas { set_config('changepasswordurl', $config->changepasswordurl, 'auth/cas'); // save LDAP settings - // TODO: Do we want the CAS LDAP settings to be separate from the LDAP settings? + // TODO: settings must be separated now that we have multiauth! $ldapauth = get_auth_plugin('ldap'); $ldapauth->process_config($config); diff --git a/auth/cas/auth_ldap_sync_users.php b/auth/cas/auth_ldap_sync_users.php index 2e7316151cf..e4caec4b45d 100644 --- a/auth/cas/auth_ldap_sync_users.php +++ b/auth/cas/auth_ldap_sync_users.php @@ -2,31 +2,33 @@ /** auth_ldap_sync_users.php * Modified for cas Module * - * This script is meant to be called from a cronjob to sync moodle with the LDAP + * This script is meant to be called from a cronjob to sync moodle with the LDAP * backend in those setups where the LDAP backend acts as 'master'. - * + * * Recommended cron entry: * # 5 minutes past 4am * 5 4 * * * /usr/bin/php -c /etc/php4/cli/php.ini /var/www/moodle/auth/ldap/auth_ldap_sync_users.php - * - * Notes: + * + * Notes: * - If you have a large number of users, you may want to raise the memory limits * by passing -d momory_limit=256M * - For debugging & better logging, you are encouraged to use in the command line: * -d log_errors=1 -d error_reporting=E_ALL -d display_errors=0 -d html_errors=0 - * + * * Performance notes: * We have optimized it as best as we could for Postgres and mySQL, with 27K students - * we have seen this take 10 minutes. - * + * we have seen this take 10 minutes. + * */ -if (!empty($_SERVER['GATEWAY_INTERFACE'])) { - error_log("should not be called from apache!"); +if (isset($_SERVER['REMOTE_ADDR'])) { + error_log("should not be called from web server!"); exit; } +$nomoodlecookie = true; // cookie not needed + require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); // global moodle config file. require_once($CFG->dirroot.'/course/lib.php'); @@ -34,7 +36,12 @@ require_once($CFG->dirroot.'/lib/blocklib.php'); require_once($CFG->dirroot.'/mod/resource/lib.php'); require_once($CFG->dirroot.'/mod/forum/lib.php'); require_once($CFG->dirroot.'/lib/moodlelib.php'); -$CFG->debug=10; + +if (!is_enabled_auth('cas')) { + echo "Plugin not enabled!"; + die; +} + $casauth = get_auth_plugin('cas'); $casauth->sync_users(1000, true); diff --git a/auth/cas/config.html b/auth/cas/config.html index 22250ff1a20..d666ce1283e 100644 --- a/auth/cas/config.html +++ b/auth/cas/config.html @@ -52,7 +52,7 @@ unset($options); $options[1] = get_string('yes'); choose_from_menu ($options, 'use_cas', $config->use_cas, get_string('no'), '', ''); - + ?>
:
- ()
+ ()
| - + | |||
| + | - + sybasequoting, ''); ?> | ||
| + | - + debugauthdb, ''); ?> | + + | |
+ + |
+|||
| + | + removeuser, ''); + ?> + | ++ + | +|
| - diff --git a/auth/fc/fcFPP.php b/auth/fc/fcFPP.php index 1e6351bef42..57a2ef1848c 100644 --- a/auth/fc/fcFPP.php +++ b/auth/fc/fcFPP.php @@ -22,21 +22,21 @@ */ class fcFPP -{ +{ var $_hostname; // hostname of FirstClass server we are connection to var $_port; // port on which fpp is running var $_conn = 0; // socket we are connecting on var $_debug = FALSE; // set to true to see some debug info - + // class constructor function fcFPP($host="localhost", $port="3333") { $this->_hostname = $host; $this->_port = $port; $this->_user = ""; - $this->_pwd = ""; + $this->_pwd = ""; } - + // open a connection to the FirstClass server function open() { @@ -53,10 +53,10 @@ class fcFPP print_error('auth_fcconnfail','auth', array($errno, $errstr)); return false; } - + // We are connected if ($this->_debug) echo "connected!"; - + // Read connection message. $line = fgets ($conn); //+0 $line = fgets ($conn); //new line @@ -69,7 +69,7 @@ class fcFPP // close any open connections function close() - { + { // get the current connection $conn = &$this->_conn; @@ -84,8 +84,8 @@ class fcFPP } return; } - - + + // Authenticate to the FirstClass server function login($userid, $passwd) { @@ -98,37 +98,37 @@ class fcFPP $line = fgets ($this->_conn); //new line $line = fgets ($this->_conn); //+0 $line = fgets ($this->_conn); //new line - + # Send password fputs($this->_conn,"$passwd\r\n"); $line = fgets ($this->_conn); //new line $line = fgets ($this->_conn); //+0 $line = fgets ($this->_conn); //+0 or message - + if ($this->_debug) echo $line; - + if (preg_match ("/^\+0/", $line)) { //+0, user with subadmin privileges $this->_user = $userid; - $this->_pwd = $passwd; - return TRUE; + $this->_pwd = $passwd; + return TRUE; } elseif (strpos($line, 'You are not allowed')) { // Denied access but a valid user and password // "Sorry. You are not allowed to login with the FPP interface" return TRUE; } else { //Invalid user or password return FALSE; } - + } return FALSE; } - // Get the list of groups the user is a member of + // Get the list of groups the user is a member of function getGroups($userid) { - + $groups = array(); - - // we must be logged in as a user with subadmin privileges + + // we must be logged in as a user with subadmin privileges if ($this->_conn AND $this->_user) { # Send BA-command to get groups fputs($this->_conn,"GET USER '" . $userid . "' 4 -1\r"); @@ -143,29 +143,29 @@ class fcFPP } if ($this->_debug) echo "getGroups:" . implode(",",$groups); } - + return $groups; } // Check if the user is member of any of the groups. // Return the list of groups the user is member of. function isMemberOf($userid, $groups) { - + $usergroups = array_map("strtolower",$this->getGroups($userid)); $groups = array_map("strtolower",$groups); - + $result = array_intersect($groups,$usergroups); - + if ($this->_debug) echo "isMemberOf:" . implode(",",$result); - + return $result; } - + function getUserInfo($userid, $field) { - + $userinfo = ""; - + if ($this->_conn AND $this->_user) { # Send BA-command to get data fputs($this->_conn,"GET USER '" . $userid . "' " . $field . "\r"); @@ -180,17 +180,17 @@ class fcFPP } if ($this->_debug) echo "getUserInfo:" . $userinfo; } - + return str_replace('\r',' ',trim($userinfo,'"')); } function getResume($userid) { - + $resume = ""; $pattern = "/\[.+:.+\..+\]/"; // Remove references to pictures in resumes - + if ($this->_conn AND $this->_user) { # Send BA-command to get data fputs($this->_conn,"GET RESUME '" . $userid . "' 6\r"); @@ -203,17 +203,17 @@ class fcFPP $resume .= preg_replace($pattern,"",str_replace('\r',"\n",trim($line,'6 '))); $line = trim(fgets ($this->_conn)); //print $line; - + } if ($this->_debug) echo "getResume:" . $resume; } - + return $resume; } - - + + } - + ?> diff --git a/auth/imap/auth.php b/auth/imap/auth.php index 0e91e8249a8..448c3ad13f6 100644 --- a/auth/imap/auth.php +++ b/auth/imap/auth.php @@ -12,8 +12,9 @@ * 2006-08-31 File created. */ -// This page cannot be called directly -if (!isset($CFG)) exit; +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page +} /** * IMAP authentication plugin. @@ -38,14 +39,14 @@ class auth_plugin_imap { * * @param string $username The username * @param string $password The password - * @returns bool Authentication success or failure. + * @return bool Authentication success or failure. */ function user_login ($username, $password) { if (! function_exists('imap_open')) { print_error('auth_imapnotinstalled','mnet'); return false; } - + global $CFG; $hosts = split(';', $this->config->host); // Could be multiple hosts @@ -56,22 +57,22 @@ class auth_plugin_imap { case 'imapssl': $host = '{'.$host.":{$this->config->port}/imap/ssl}"; break; - + case 'imapcert': $host = '{'.$host.":{$this->config->port}/imap/ssl/novalidate-cert}"; break; - + case 'imaptls': $host = '{'.$host.":{$this->config->port}/imap/tls}"; break; - + default: $host = '{'.$host.":{$this->config->port}/imap}"; } error_reporting(0); $connection = imap_open($host, $username, $password, OP_HALFOPEN); - error_reporting($CFG->debug); + error_reporting($CFG->debug); if ($connection) { imap_close($connection); @@ -85,7 +86,7 @@ class auth_plugin_imap { /** * Returns true if this authentication plugin is 'internal'. * - * @returns bool + * @return bool */ function is_internal() { return false; @@ -95,23 +96,23 @@ class auth_plugin_imap { * Returns true if this authentication plugin can change the user's * password. * - * @returns bool + * @return bool */ function can_change_password() { return false; } - + /** * Returns the URL for changing the user's pw, or false if the default can * be used. * - * @returns bool + * @return bool */ function change_password_url() { return $CFG->changepasswordurl; // TODO: will this be global? //return $this->config->changepasswordurl; } - + /** * Prints a form for configuring this authentication plugin. * @@ -120,7 +121,7 @@ class auth_plugin_imap { * * @param array $page An object containing all the data for this page. */ - function config_form($config, $err) { + function config_form($config, $err, $user_fields) { include "config.html"; } diff --git a/auth/imap/config.html b/auth/imap/config.html index 658107675ef..e2b2311fd96 100644 --- a/auth/imap/config.html +++ b/auth/imap/config.html @@ -85,9 +85,8 @@ if (!isset($config->changepasswordurl)) { | - diff --git a/auth/ldap/README-LDAP b/auth/ldap/README-LDAP index 698294d63e6..11efdf50d41 100644 --- a/auth/ldap/README-LDAP +++ b/auth/ldap/README-LDAP @@ -1,3 +1,3 @@ LDAP-module README -Please read comments from lib.php +Please read comments from lib.php diff --git a/auth/ldap/auth.php b/auth/ldap/auth.php index 88d95da9382..daf3c7ce066 100644 --- a/auth/ldap/auth.php +++ b/auth/ldap/auth.php @@ -12,12 +12,8 @@ * 2006-08-28 File created. */ -// This page cannot be called directly -if (!isset($CFG)) exit; - -// LDAP functions are reused by other auth libs -if (!defined('AUTH_LDAP_NAME')) { - define('AUTH_LDAP_NAME', 'ldap'); +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page } /** @@ -31,19 +27,40 @@ class auth_plugin_ldap { var $config; /** - * Constructor. + * Constructor with initialisation. */ function auth_plugin_ldap() { $this->config = get_config('auth/ldap'); + if (empty($this->config->ldapencoding)) { + $this->config->ldapencoding = 'utf-8'; + } + if (empty($this->config->user_type)) { + $this->config->user_type = 'default'; + } + + $default = $this->ldap_getdefaults(); + + //use defaults if values not given + foreach ($default as $key => $value) { + // watch out - 0, false are correct values too + if (!isset($this->config->{$key}) or $this->config->{$key} == '') { + $this->config->{$key} = $value[$this->config->user_type]; + } + } + //hack prefix to objectclass + if ('objectClass=' != substr($this->config->objectclass, 0, 12)) { + $this->config->objectclass = 'objectClass='.$this->config->objectclass; + } } /** * Returns true if the username and password work and false if they are * wrong or don't exist. * - * @param string $username The username - * @param string $password The password - * @returns bool Authentication success or failure. + * @param string $username The username (with system magic quotes) + * @param string $password The password (with system magic quotes) + * + * @return bool Authentication success or failure. */ function user_login($username, $password) { if (! function_exists('ldap_bind')) { @@ -51,22 +68,19 @@ class auth_plugin_ldap { return false; } - global $CFG; - if (!$username or !$password) { // Don't allow blank usernames or passwords return false; } - - // CAS-supplied auth tokens override LDAP auth - if ($CFG->auth == "cas" and !empty($CFG->cas_enabled)) { - return cas_ldap_auth_user_login($username, $password); - } + + $textlib = textlib_get_instance(); + $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); + $extpassword = $textlib->convert(stripslashes($password), 'utf-8', $this->config->ldapencoding); $ldapconnection = $this->ldap_connect(); if ($ldapconnection) { - $ldap_user_dn = $this->ldap_find_userdn($ldapconnection, $username); - + $ldap_user_dn = $this->ldap_find_userdn($ldapconnection, $extusername); + //if ldap_user_dn is empty, user does not exist if (!$ldap_user_dn) { ldap_close($ldapconnection); @@ -74,7 +88,7 @@ class auth_plugin_ldap { } // Try to bind with current username and password - $ldap_login = @ldap_bind($ldapconnection, $ldap_user_dn, stripslashes($password)); + $ldap_login = @ldap_bind($ldapconnection, $ldap_user_dn, $extpassword); ldap_close($ldapconnection); if ($ldap_login) { return true; @@ -94,18 +108,20 @@ class auth_plugin_ldap { * Function should return all information available. If you are saving * this information to moodle user-table you should honor syncronization flags * - * @param string $username username - * @return array + * @param string $username username (with system magic quotes) + * + * @return mixed array with no magic quotes or false on error */ function get_userinfo($username) { - global $CFG; + $textlib = textlib_get_instance(); + $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); + $ldapconnection = $this->ldap_connect(); - $config = (array)$CFG; $attrmap = $this->ldap_attributes(); - + $result = array(); $search_attribs = array(); - + foreach ($attrmap as $key=>$values) { if (!is_array($values)) { $values = array($values); @@ -113,66 +129,64 @@ class auth_plugin_ldap { foreach ($values as $value) { if (!in_array($value, $search_attribs)) { array_push($search_attribs, $value); - } + } } } - $user_dn = $this->ldap_find_userdn($ldapconnection, $username); + $user_dn = $this->ldap_find_userdn($ldapconnection, $extusername); if (empty($this->config->objectclass)) { // Can't send empty filter $this->config->objectclass="objectClass=*"; } - - $user_info_result = ldap_read($ldapconnection, $user_dn, $this->config->objectclass, $search_attribs); - if ($user_info_result) { - $user_entry = $this->ldap_get_entries($ldapconnection, $user_info_result); - foreach ($attrmap as $key=>$values) { - if (!is_array($values)) { - $values = array($values); + if (!$user_info_result = ldap_read($ldapconnection, $user_dn, $this->config->objectclass, $search_attribs)) { + return false; // error! + } + $user_entry = $this->ldap_get_entries($ldapconnection, $user_info_result); + if (empty($user_entry)) { + return false; // entry not found + } + + foreach ($attrmap as $key=>$values) { + if (!is_array($values)) { + $values = array($values); + } + $ldapval = NULL; + foreach ($values as $value) { + if (!array_key_exists($value, $user_entry[0])) { + continue; // wrong data mapping! } - $ldapval = NULL; - foreach ($values as $value) { - if (is_array($user_entry[0][strtolower($value)])) { - if (!empty($CFG->unicodedb)) { - $newval = addslashes(stripslashes($user_entry[0][strtolower($value)][0])); - } - else { - $newval = addslashes(stripslashes(utf8_decode($user_entry[0][strtolower($value)][0]))); - } - } - else { - if (!empty($CFG->unicodedb)) { - $newval = addslashes(stripslashes($user_entry[0][strtolower($value)])); - } - else { - $newval = addslashes(stripslashes(utf8_decode($user_entry[0][strtolower($value)]))); - } - } - if (!empty($newval)) { // favour ldap entries that are set - $ldapval = $newval; - } + if (is_array($user_entry[0][$value])) { + $newval = $textlib->convert($user_entry[0][$value][0], $this->config->ldapencoding, 'utf-8'); + } else { + $newval = $textlib->convert($user_entry[0][$value], $this->config->ldapencoding, 'utf-8'); } - if (!is_null($ldapval)) { - $result[$key] = $ldapval; + if (!empty($newval)) { // favour ldap entries that are set + $ldapval = $newval; } } + if (!is_null($ldapval)) { + $result[$key] = $ldapval; + } } @ldap_close($ldapconnection); - return $result; } /** * reads userinformation from ldap and return it in an object * - * @param string $username username - * @return array + * @param string $username username (with system magic quotes) + * @return mixed object or false on error */ function get_userinfo_asobj($username) { - $user_array = truncate_userinfo($this->get_userinfo($username)); - $user = new object; + $user_array = $this->get_userinfo($username); + if ($user_array == false) { + return false; //error or not found + } + $user_array = truncate_userinfo($user_array); + $user = new object(); foreach ($user_array as $key=>$value) { $user->{$key} = $value; } @@ -184,163 +198,75 @@ class auth_plugin_ldap { * * get_userlist returns all usernames from external database * - * @return array + * @return array */ function get_userlist() { - global $CFG; - $this->ldap_init(); return $this->ldap_get_userlist("({$this->config->user_attribute}=*)"); } /** * checks if user exists on external db + * + * @param string $username (with system magic quotes) */ function user_exists($username) { - global $CFG; - $this->ldap_init(); - //returns true if given usernname exist on ldap - $users = $this->ldap_get_userlist("({$this->config->user_attribute}=$username)"); - return count($users); + + $textlib = textlib_get_instance(); + $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); + + //returns true if given username exist on ldap + $users = $this->ldap_get_userlist("({$this->config->user_attribute}=".$this->filter_addslashes($extusername).")"); + return count($users); } /** - * creates new user on external database - * - * user_create() creates new user on external database + * Creates a new user on external database. * By using information in userobject * Use user_exists to prevent dublicate usernames * - * @param mixed $userobject Moodle userobject - * @param mixed $plainpass Plaintext password + * @param mixed $userobject Moodle userobject (with system magic quotes) + * @param mixed $plainpass Plaintext password (with system magic quotes) */ function user_create($userobject, $plainpass) { - global $CFG; + $textlib = textlib_get_instance(); + $extusername = $textlib->convert(stripslashes($userobject->username), 'utf-8', $this->config->ldapencoding); + $extpassword = $textlib->convert(stripslashes($plainpass), 'utf-8', $this->config->ldapencoding); + $ldapconnection = $this->ldap_connect(); $attrmap = $this->ldap_attributes(); - + $newuser = array(); - + foreach ($attrmap as $key => $values) { if (!is_array($values)) { $values = array($values); } foreach ($values as $value) { if (!empty($userobject->$key) ) { - if (!empty($CFG->unicodedb)) { - $newuser[$value] = $userobject->$key; - } - else { - $newuser[$value] = utf8_encode($userobject->$key); - } + $newuser[$value] = $textlib->convert(stripslashes($userobject->$key), 'utf-8', $this->config->ldapencoding); } } } - + //Following sets all mandatory and other forced attribute values //User should be creted as login disabled untill email confirmation is processed - //Feel free to add your user type and send patches to paca@sci.fi to add them + //Feel free to add your user type and send patches to paca@sci.fi to add them //Moodle distribution switch ($this->config->user_type) { case 'edir': - $newuser['objectClass']= array("inetOrgPerson","organizationalPerson","person","top"); - $newuser['uniqueId']= $userobject->username; - $newuser['logindisabled']="TRUE"; - $newuser['userpassword']=$plainpass; + $newuser['objectClass'] = array("inetOrgPerson","organizationalPerson","person","top"); + $newuser['uniqueId'] = $extusername; + $newuser['logindisabled'] = "TRUE"; + $newuser['userpassword'] = $extpassword; break; default: print_error('auth_ldap_unsupportedusertype','auth',$this->config->user_type); } - $uadd = $this->ldap_add($ldapconnection, "{$this->config->user_attribute}={$userobject->username},{$this->config->create_context}", $newuser); + $uadd = $this->ldap_add($ldapconnection, $this->config->user_attribute.'="'.$this->ldap_addslashes($userobject->username).','.$this->config->create_context.'"', $newuser); ldap_close($ldapconnection); return $uadd; - - } - /** - * - * get_users() returns userobjects from external database - * - * Function returns users from external databe as Moodle userobjects - * If filter is not present it should return ALL users in external database - * - * @param mixed $filter substring of username - * @returns array of userobjects - */ - function get_users($filter = '*', $dontlistcreated = false) { - global $CFG; - - $ldapconnection = $this->ldap_connect(); - $fresult = array(); - - if ($filter=="*") { - $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))"; - } - - $contexts = explode(";",$this->config->contexts); - - if (!empty($this->config->create_context) and empty($dontlistcreated)) { - array_push($contexts, $this->config->create_context); - } - - $attrmap = $this->ldap_attributes(); - - $search_attribs = array(); - - foreach ($attrmap as $key=>$values) { - if (!is_array($values)) { - $values = array($values); - } - foreach ($values as $value) { - if (!in_array($value, $search_attribs)) { - array_push($search_attribs, $value); - } - } - } - - - foreach ($contexts as $context) { - - $context = trim($context); - if (empty($context)) { - continue; - } - - if ($this->config->search_sub) { - //use ldap_search to find first user from subtree - $ldap_result = ldap_search($ldapconnection, $context, - $filter, - $search_attribs); - } - else { - //search only in this context - $ldap_result = ldap_list($ldapconnection, $context, - $filter, - $search_attribs); - } - - $users = $this->ldap_get_entries($ldapconnection, $ldap_result); - - //add found users to list - foreach ($users as $ldapuser=>$attribs) { - $user = new object(); - foreach ($attrmap as $key=>$value) { - if (isset($users[$ldapuser][$value][0])) { - $user->$key=$users[$ldapuser][$value][0]; - } - } - //quick way to get around binarystrings - $user->guid=bin2hex($user->guid); - //add authentication source stamp - $user->auth = AUTH_LDAP_NAME; - //add MNET host id - $user->mnethostid = $CFG->mnet_localhost_id; - $fresult[$user->username]=$user; - - } - } - - return $fresult; } /** @@ -353,32 +279,33 @@ class auth_plugin_ldap { * @return integer */ function password_expire($username) { - global $CFG ; $result = false; - + + $textlib = textlib_get_instance(); + $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); + $ldapconnection = $this->ldap_connect(); - $user_dn = $this->ldap_find_userdn($ldapconnection, $username); + $user_dn = $this->ldap_find_userdn($ldapconnection, $extusername); $search_attribs = array($this->config->expireattr); $sr = ldap_read($ldapconnection, $user_dn, 'objectclass=*', $search_attribs); if ($sr) { - $info=$this->ldap_get_entries($ldapconnection, $sr); - if ( empty($info[0][strtolower($this->config->expireattr)][0])) { + $info = $this->ldap_get_entries($ldapconnection, $sr); + if (empty ($info) or empty($info[0][$this->config->expireattr][0])) { //error_log("ldap: no expiration value".$info[0][$this->config->expireattr]); // no expiration attribute, password does not expire $result = 0; } else { $now = time(); - $expiretime = $this->ldap_expirationtime2unix($info[0][strtolower($this->config->expireattr)][0]); + $expiretime = $this->ldap_expirationtime2unix($info[0][$this->config->expireattr][0]); if ($expiretime > $now) { $result = ceil(($expiretime - $now) / DAYSECS); } else { $result = floor(($expiretime - $now) / DAYSECS); - } + } } - } - else { + } else { error_log("ldap: password_expire did't find expiration time."); } @@ -389,41 +316,36 @@ class auth_plugin_ldap { /** * syncronizes user fron external db to moodle user table * - * Sync shouid be done by using idnumber attribute, not username. - * You need to pass firstsync parameter to function to fill in - * idnumbers if they dont exists in moodle user table. - * - * Syncing users removes (disables) users that dont exists anymore in external db. - * Creates new users and updates coursecreator status of users. - * - * @param mixed $firstsync Optional: set to true to fill idnumber fields if not filled yet + * Sync is now using username attribute. + * + * Syncing users removes or suspends users that dont exists anymore in external db. + * Creates new users and updates coursecreator status of users. + * + * @param int $bulk_insert_records will insert $bulkinsert_records per insert statement + * valid only with $unsafe. increase to a couple thousand for + * blinding fast inserts -- but test it: you may hit mysqld's + * max_allowed_packet limit. + * @param bool $do_updates will do pull in data updates from ldap if relevant */ - function sync_users ($bulk_insert_records = 1000, $do_updates = 1) { - //Syncronizes userdb with ldap - //This will add, rename - /// OPTIONAL PARAMETERS - /// $bulk_insert_records = 1 // will insert $bulkinsert_records per insert statement - /// valid only with $unsafe. increase to a couple thousand for - /// blinding fast inserts -- but test it: you may hit mysqld's - /// max_allowed_packet limit. - /// $do_updates = 1 // will do pull in data updates from ldap if relevant - + function sync_users ($bulk_insert_records = 1000, $do_updates = true) { global $CFG; + $textlib = textlib_get_instance(); + $droptablesql = array(); /// sql commands to drop the table (because session scope could be a problem for /// some persistent drivers like ODBTP (mssql) or if this function is invoked /// from within a PHP application using persistent connections - // configure a temp table - print "Configuring temp table\n"; + // configure a temp table + print "Configuring temp table\n"; switch (strtolower($CFG->dbfamily)) { case 'mysql': $temptable = $CFG->prefix . 'extuser'; $droptablesql[] = 'DROP TEMPORARY TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later echo "Creating temp table $temptable\n"; - execute_sql('CREATE TEMPORARY TABLE ' . $temptable . ' (idnumber VARCHAR(64), PRIMARY KEY (idnumber)) TYPE=MyISAM', false); + execute_sql('CREATE TEMPORARY TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username)) TYPE=MyISAM', false); break; case 'postgres': $temptable = $CFG->prefix . 'extuser'; @@ -431,7 +353,7 @@ class auth_plugin_ldap { execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later echo "Creating temp table $temptable\n"; $bulk_insert_records = 1; // no support for multiple sets of values - execute_sql('CREATE TEMPORARY TABLE '. $temptable . ' (idnumber VARCHAR(64), PRIMARY KEY (idnumber))', false); + execute_sql('CREATE TEMPORARY TABLE '. $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))', false); break; case 'mssql': $temptable = '#'.$CFG->prefix . 'extuser'; /// MSSQL temp tables begin with # @@ -439,7 +361,7 @@ class auth_plugin_ldap { execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later echo "Creating temp table $temptable\n"; $bulk_insert_records = 1; // no support for multiple sets of values - execute_sql('CREATE TABLE ' . $temptable . ' (idnumber VARCHAR(64), PRIMARY KEY (idnumber))', false); + execute_sql('CREATE TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))', false); break; case 'oracle': $temptable = $CFG->prefix . 'extuser'; @@ -448,17 +370,17 @@ class auth_plugin_ldap { execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later echo "Creating temp table $temptable\n"; $bulk_insert_records = 1; // no support for multiple sets of values - execute_sql('CREATE GLOBAL TEMPORARY TABLE '.$temptable.' (idnumber VARCHAR(64), PRIMARY KEY (idnumber)) ON COMMIT PRESERVE ROWS', false); + execute_sql('CREATE GLOBAL TEMPORARY TABLE '.$temptable.' (username VARCHAR(64), PRIMARY KEY (username)) ON COMMIT PRESERVE ROWS', false); break; } - print "connecting to ldap\n"; + print "Connecting to ldap...\n"; $ldapconnection = $this->ldap_connect(); if (!$ldapconnection) { @ldap_close($ldapconnection); - notify(get_string('auth_ldap_noconnect','auth',$this->config->host_url)); - return false; + print get_string('auth_ldap_noconnect','auth',$this->config->host_url); + exit; } //// @@ -472,13 +394,12 @@ class auth_plugin_ldap { $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))"; $contexts = explode(";",$this->config->contexts); - + if (!empty($this->config->create_context)) { array_push($contexts, $this->config->create_context); } $fresult = array(); - $count = 0; foreach ($contexts as $context) { $context = trim($context); if (empty($context)) { @@ -490,8 +411,7 @@ class auth_plugin_ldap { $ldap_result = ldap_search($ldapconnection, $context, $filter, array($this->config->user_attribute)); - } - else { + } else { //search only in this context $ldap_result = ldap_list($ldapconnection, $context, $filter, @@ -500,88 +420,122 @@ class auth_plugin_ldap { if ($entry = ldap_first_entry($ldapconnection, $ldap_result)) { do { - $value = ldap_get_values_len($ldapconnection, $entry,$this->config->user_attribute); - $value = $value[0]; - $count++; + $value = ldap_get_values_len($ldapconnection, $entry, $this->config->user_attribute); + $value = $textlib->convert($value[0], $this->config->ldapencoding, 'utf-8'); array_push($fresult, $value); if (count($fresult) >= $bulk_insert_records) { $this->ldap_bulk_insert($fresult, $temptable); - //print var_dump($fresult); - $fresult=array(); - } - } - while ($entry = ldap_next_entry($ldapconnection, $entry)); + $fresult = array(); + } + } while ($entry = ldap_next_entry($ldapconnection, $entry)); } + unset($ldap_result); // free mem // insert any remaining users and release mem if (count($fresult)) { $this->ldap_bulk_insert($fresult, $temptable); - $fresult=array(); + $fresult = array(); } commit_sql(); } - // free mem - $ldap_results = 0; /// preserve our user database /// if the temp table is empty, it probably means that something went wrong, exit /// so as to avoid mass deletion of users; which is hard to undo - $count = get_record_sql('SELECT COUNT(idnumber) AS count, 1 FROM ' . $temptable); + $count = get_record_sql('SELECT COUNT(username) AS count, 1 FROM ' . $temptable); $count = $count->{'count'}; if ($count < 1) { print "Did not get any users from LDAP -- error? -- exiting\n"; exit; } else { - print "Got $count records from LDAP\n"; + print "Got $count records from LDAP\n\n"; } - //// - //// User removal - //// + +/// User removal // find users in DB that aren't in ldap -- to be removed! - // this is still not as scalable - $sql = 'SELECT u.id, u.username - FROM ' . $CFG->prefix .'user u LEFT JOIN ' . $temptable . ' e - ON u.idnumber = e.idnumber - WHERE u.auth=\'' . AUTH_LDAP_NAME . '\' AND u.deleted=\'0\' AND e.idnumber IS NULL'; - //print($sql); - $remove_users = get_records_sql($sql); + // this is still not as scalable (but how often do we mass delete?) + if (!empty($this->config->removeuser)) { + $sql = "SELECT u.id, u.username, u.email + FROM {$CFG->prefix}user u + LEFT JOIN $temptable e ON u.username = e.username + WHERE u.auth='ldap' + AND u.deleted=0 + AND e.username IS NULL"; + $remove_users = get_records_sql($sql); - if (!empty($remove_users)) { - print "User entries to remove: ". count($remove_users) . "\n"; + if (!empty($remove_users)) { + print "User entries to remove: ". count($remove_users) . "\n"; - begin_sql(); - foreach ($remove_users as $user) { - //following is copy pasted from admin/user.php - //maybe this should moved to function in lib/datalib.php - $updateuser = new stdClass(); - $updateuser->id = $user->id; - $updateuser->deleted = '1'; - //$updateuser->username = "$user->username".time(); // Remember it just in case - //$updateuser->email = ''; // Clear this field to free it up - $updateuser->timemodified = time(); - if (update_record("user", $updateuser)) { - // unenrol_student($user->id); // From all courses - // remove_teacher($user->id); // From all courses - // remove_admin($user->id); - delete_records('role_assignments', 'userid', $user->id); // unassign all roles - notify(get_string('deletedactivity', '', fullname($user, true)) ); + begin_sql(); + foreach ($remove_users as $user) { + if ($this->config->removeuser == 2) { + //following is copy pasted from admin/user.php + //maybe this should moved to function in lib/datalib.php + $updateuser = new object(); + $updateuser->id = $user->id; + $updateuser->deleted = 1; + $updateuser->username = addslashes("$user->email.".time()); // Remember it just in case + $updateuser->email = ''; // Clear this field to free it up + $updateuser->idnumber = ''; // Clear this field to free it up + $updateuser->timemodified = time(); + if (update_record('user', $updateuser)) { + delete_records('role_assignments', 'userid', $user->id); // unassign all roles + //copy pasted part ends + echo "\t"; print_string('auth_dbdeleteuser', 'auth', array($user->username, $user->id)); echo "\n"; + } else { + echo "\t"; print_string('auth_dbdeleteusererror', 'auth', $user->username); echo "\n"; + } + } else if ($this->config->removeuser == 1) { + $updateuser = new object(); + $updateuser->id = $user->id; + $updateuser->auth = 'nologin'; + if (update_record('user', $updateuser)) { + echo "\t"; print_string('auth_dbsuspenduser', 'auth', array($user->username, $user->id)); echo "\n"; + } else { + echo "\t"; print_string('auth_dbsuspendusererror', 'auth', $user->username); echo "\n"; + } + } } - else { - notify(get_string('deletednot', '', fullname($user, true))); - } - //copy pasted part ends - } - commit_sql(); - } else { - print "No user entries to be removed\n"; + commit_sql(); + } else { + print "No user entries to be removed\n"; + } + unset($remove_users); // free mem! } - $remove_users = 0; // free mem! - //// - //// User Updates - //// (time-consuming, optional) - //// +/// Revive suspended users + if (!empty($this->config->removeuser) and $this->config->removeuser == 1) { + $sql = "SELECT u.id, u.username + FROM $temptable e, {$CFG->prefix}user u + WHERE e.username=u.username + AND u.auth='nologin'"; + $revive_users = get_records_sql($sql); + + if (!empty($revive_users)) { + print "User entries to be revived: ". count($revive_users) . "\n"; + + begin_sql(); + foreach ($revive_users as $user) { + $updateuser = new object(); + $updateuser->id = $user->id; + $updateuser->auth = 'ldap'; + if (update_record('user', $updateuser)) { + echo "\t"; print_string('auth_dbreviveser', 'auth', array($user->username, $user->id)); echo "\n"; + } else { + echo "\t"; print_string('auth_dbreviveusererror', 'auth', $user->username); echo "\n"; + } + } + commit_sql(); + } else { + print "No user entries to be revived\n"; + } + + unset($revive_users); + } + + +/// User Updates - time-consuming (optional) if ($do_updates) { // narrow down what fields we need to update $all_keys = array_keys(get_object_vars($this->config)); @@ -589,124 +543,118 @@ class auth_plugin_ldap { foreach ($all_keys as $key) { if (preg_match('/^field_updatelocal_(.+)$/',$key, $match)) { // if we have a field to update it from - // and it must be updated 'onlogin' we + // and it must be updated 'onlogin' we // update it on cron if ( !empty($this->config->{'field_map_'.$match[1]}) - and $this->config->{$match[0]} === 'onlogin') { + and $this->config->{$match[0]} === 'onlogin') { array_push($updatekeys, $match[1]); // the actual key name } } } // print_r($all_keys); print_r($updatekeys); unset($all_keys); unset($key); - + } else { print "No updates to be done\n"; } - if ( $do_updates and !(empty($updatekeys)) ) { // run updates only if relevant - $users = get_records_sql('SELECT u.username, u.id FROM ' . $CFG->prefix . 'user u WHERE u.deleted=0 and u.auth=\'' . AUTH_LDAP_NAME . '\'' ); + if ( $do_updates and !empty($updatekeys) ) { // run updates only if relevant + $users = get_records_sql("SELECT u.username, u.id + FROM {$CFG->prefix}user u + WHERE u.deleted=0 AND u.auth='ldap'"); if (!empty($users)) { print "User entries to update: ". count($users). "\n"; + $sitecontext = get_context_instance(CONTEXT_SYSTEM); - - if ($creatorroles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { - $creatorrole = array_shift($creatorroles); // We can only use one, let's use the first one - - begin_sql(); - $xcount = 0; - $maxxcount = 100; - - foreach ($users as $user) { - echo "updating user $user->username \n"; - $this->update_user_record($user->username, $updatekeys); - - // update course creators - if (!empty($this->config->creators) and !empty($this->config->memberattribute) ) { - if ($this->iscreator($user->username)) { // Following calls will not create duplicates - role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap'); - $xcount++; - } else { - role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id); - $xcount++; - } - } - - if ($xcount++ > $maxxcount) { - commit_sql(); - begin_sql(); - $xcount = 0; - } - } - commit_sql(); - unset($users); // free mem + if (!empty($this->config->creators) and !empty($this->config->memberattribute) + and $roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { + $creatorrole = array_shift($roles); // We can only use one, let's use the first one + } else { + $creatorrole = false; } + + begin_sql(); + $xcount = 0; + $maxxcount = 100; + + foreach ($users as $user) { + echo "\t"; print_string('auth_dbupdatinguser', 'auth', array($user->username, $user->id)); + if (!$this->update_user_record(addslashes($user->username), $updatekeys)) { + echo " - ".get_string('skipped'); + } + echo "\n"; + $xcount++; + + // update course creators if needed + if ($creatorrole !== false) { + if ($this->iscreator($user->username)) { + role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap'); + } else { + role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id); + } + } + + if ($xcount++ > $maxxcount) { + commit_sql(); + begin_sql(); + $xcount = 0; + } + } + commit_sql(); + unset($users); // free mem } } else { // end do updates print "No updates to be done\n"; } - - //// - //// User Additions - //// + +/// User Additions // find users missing in DB that are in LDAP // note that get_records_sql wants at least 2 fields returned, // and gives me a nifty object I don't want. - $sql = 'SELECT e.idnumber,1 - FROM ' . $temptable . ' e LEFT JOIN ' . $CFG->prefix .'user u - ON e.idnumber = u.idnumber - WHERE u.id IS NULL OR (u.id IS NOT NULL AND u.deleted=1)'; - $add_users = get_records_sql($sql); // get rid of the fat - + // note: we do not care about deleted accounts anymore, this feature was replaced by suspending to nologin auth plugin + $sql = "SELECT e.username, e.username + FROM $temptable e LEFT JOIN {$CFG->prefix}user u ON e.username = u.username + WHERE u.id IS NULL"; + $add_users = get_records_sql($sql); // get rid of the fat + if (!empty($add_users)) { print "User entries to add: ". count($add_users). "\n"; - if ($roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { + $sitecontext = get_context_instance(CONTEXT_SYSTEM); + if (!empty($this->config->creators) and !empty($this->config->memberattribute) + and $roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { $creatorrole = array_shift($roles); // We can only use one, let's use the first one + } else { + $creatorrole = false; } begin_sql(); foreach ($add_users as $user) { - $user = $this->get_userinfo_asobj($user->idnumber); - //print $user->username . "\n"; - + $user = $this->get_userinfo_asobj(addslashes($user->username)); + // prep a few params $user->modified = time(); $user->confirmed = 1; - $user->auth = AUTH_LDAP_NAME; + $user->auth = 'ldap'; $user->mnethostid = $CFG->mnet_localhost_id; - - // insert it - $old_debug=$CFG->debug; - $CFG->debug=10; - - // maybe the user has been deleted before - if ($old_user = get_record('user', 'idnumber', $user->idnumber, 'deleted', 1, 'mnethostid', $CFG->mnet_localhost_id)) { - $user->id = $old_user->id; - set_field('user', 'deleted', 0, 'id', $user->id); - echo "Revived user $user->username with idnumber $user->idnumber id $user->id\n"; + if (empty($user->lang)) { + $user->lang = $CFG->lang; } - elseif ($id = insert_record('user',$user)) { // it is truly a new user - echo "inserted user $user->username with idnumber $user->idnumber id $id\n"; - $user->id = $id; - } - else { - echo "error inserting user $user->username with idnumber $user->idnumber \n"; - } - $CFG->debug = $old_debug; - $userobj = $this->update_user_record($user->username); - if (isset($this->config->forcechangepassword) and $this->config->forcechangepassword) { - set_user_preference('auth_forcepasswordchange', 1, $userobj->id); - } - - // update course creators - if (isset($creatorrole->id) and !empty($this->config->creators) and !empty($this->config->memberattribute)) { - if ($this->iscreator($user->username)) { - if (user_has_role_assignment($user->id, $creatorrole->id, $sitecontext->id)) { - role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id); - } else { - role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap'); - } + + $user = addslashes_recursive($user); + + if ($id = insert_record('user',$user)) { + echo "\t"; print_string('auth_dbinsertuser', 'auth', array(stripslashes($user->username), $id)); echo "\n"; + $userobj = $this->update_user_record($user->username); + if (!empty($this->config->forcechangepassword)) { + set_user_preference('auth_forcepasswordchange', 1, $userobj->id); } + } else { + echo "\t"; print_string('auth_dbinsertusererror', 'auth', $user->username); echo "\n"; + } + + // add course creators if needed + if ($creatorrole !== false and $this->iscreator(stripslashes($user->username))) { + role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap'); } } commit_sql(); @@ -717,168 +665,182 @@ class auth_plugin_ldap { return true; } - /** - * Update a local user record from an external source. - * This is a lighter version of the one in moodlelib -- won't do + /** + * Update a local user record from an external source. + * This is a lighter version of the one in moodlelib -- won't do * expensive ops such as enrolment. * - * If you don't pass $updatekeys, there is a performance hit and - * values removed from LDAP won't be removed from moodle. + * If you don't pass $updatekeys, there is a performance hit and + * values removed from LDAP won't be removed from moodle. + * + * @param string $username username (with system magic quotes) */ function update_user_record($username, $updatekeys = false) { - global $CFG; //just in case check text case $username = trim(moodle_strtolower($username)); - + // get the current user record $user = get_record('user', 'username', $username, 'mnethostid', $CFG->mnet_localhost_id); if (empty($user)) { // trouble - error_log("Cannot update non-existent user: $username"); + error_log("Cannot update non-existent user: ".stripslashes($username)); + print_error('auth_dbusernotexist','auth',$username); die; } // Protect the userid from being overwritten $userid = $user->id; - if (function_exists('auth_get_userinfo')) { - if ($newinfo = auth_get_userinfo($username)) { - $newinfo = truncate_userinfo($newinfo); - - if (empty($updatekeys)) { // all keys? this does not support removing values - $updatekeys = array_keys($newinfo); + if ($newinfo = $this->get_userinfo($username)) { + $newinfo = truncate_userinfo($newinfo); + + if (empty($updatekeys)) { // all keys? this does not support removing values + $updatekeys = array_keys($newinfo); + } + + foreach ($updatekeys as $key) { + if (isset($newinfo[$key])) { + $value = $newinfo[$key]; + } else { + $value = ''; } - - foreach ($updatekeys as $key) { - if (isset($newinfo[$key])) { - $value = addslashes(stripslashes($newinfo[$key])); - } - else { - $value = ''; - } - if (!empty($this->config->{'field_updatelocal_' . $key})) { - if ($user->{$key} != $value) { // only update if it's changed - set_field('user', $key, $value, 'id', $userid); - } + + if (!empty($this->config->{'field_updatelocal_' . $key})) { + if ($user->{$key} != $value) { // only update if it's changed + set_field('user', $key, addslashes($value), 'id', $userid); } } } + } else { + return false; } - return get_record_select("user", "id = '$userid' AND deleted <> '1'"); + return get_record_select('user', "id = $userid AND deleted = 0"); } - - // bulk insert in SQL's temp table - // $users is an array of usernames + /** + * Bulk insert in SQL's temp table + * @param array $users is an array of usernames + */ function ldap_bulk_insert($users, $temptable) { // bulk insert -- superfast with $bulk_insert_records - $sql = 'INSERT INTO ' . $temptable . ' (idnumber) VALUES '; + $sql = 'INSERT INTO ' . $temptable . ' (username) VALUES '; // make those values safe - array_map('addslashes', $users); + $users = addslashes_recursive($users); // join and quote the whole lot - $sql = $sql . '(\'' . join('\'),(\'', $users) . '\')'; - print "+ " . count($users) . " users\n"; - execute_sql($sql, false); - + $sql = $sql . "('" . implode("'),('", $users) . "')"; + print "\t+ " . count($users) . " users\n"; + execute_sql($sql, false); } - /* - * user_activate activates user in external db. - * + /** * Activates (enables) user in external db so user can login to external db * - * @param mixed $username username + * @param mixed $username username (with system magic quotes) * @return boolen result */ function user_activate($username) { - - global $CFG; - + $textlib = textlib_get_instance(); + $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); + $ldapconnection = $this->ldap_connect(); - $userdn = $this->ldap_find_userdn($ldapconnection, $username); + $userdn = $this->ldap_find_userdn($ldapconnection, $extusername); switch ($this->config->user_type) { case 'edir': $newinfo['loginDisabled']="FALSE"; break; default: - error ('auth: ldap user_activate() does not support selected usertype:"'.$this->config->user_type.'" (..yet)'); - } + error ('auth: ldap user_activate() does not support selected usertype:"'.$this->config->user_type.'" (..yet)'); + } $result = ldap_modify($ldapconnection, $userdn, $newinfo); ldap_close($ldapconnection); return $result; } - /* - * user_disables disables user in external db. - * + /** * Disables user in external db so user can't login to external db * * @param mixed $username username * @return boolean result */ - function user_disable($username) { - global $CFG; +/* function user_disable($username) { + $textlib = textlib_get_instance(); + $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); $ldapconnection = $this->ldap_connect(); - $userdn = $this->ldap_find_userdn($ldapconnection, $username); + $userdn = $this->ldap_find_userdn($ldapconnection, $extusername); switch ($this->config->user_type) { case 'edir': $newinfo['loginDisabled']="TRUE"; break; default: - error ('auth: ldap user_disable() does not support selected usertype (..yet)'); - } + error ('auth: ldap user_disable() does not support selected usertype (..yet)'); + } $result = ldap_modify($ldapconnection, $userdn, $newinfo); ldap_close($ldapconnection); return $result; - } + }*/ - /* + /** * Returns true if user should be coursecreator. * - * @param mixed $username username + * @param mixed $username username (with system magic quotes) * @return boolean result */ function iscreator($username = false) { - ///if user is member of creator group return true - global $USER, $CFG; - $this->ldap_init(); - if (! $username) { + global $USER; + + if (empty($this->config->creators) or empty($this->config->memberattribute)) { + return false; + } + + if ($username === false) { $username = $USER->username; + } else { + $username = stripslashes($username); } - if ((! $this->config->creators) or (! $this->config->memberattribute)) { - return null; - } - return $this->ldap_isgroupmember($username, $this->config->creators); + + $textlib = textlib_get_instance(); + $extusername = $textlib->convert($username, 'utf-8', $this->config->ldapencoding); + + return $this->ldap_isgroupmember($extusername, $this->config->creators); } - /* - * user_update saves userinformation from moodle to external db - * + /** * Called when the user record is updated. - * Modifies user in external database. It takes olduser (before changes) and newuser (after changes) + * Modifies user in external database. It takes olduser (before changes) and newuser (after changes) * conpares information saved modified information to external db. * - * @param mixed $olduser Userobject before modifications - * @param mixed $newuser Userobject new modified userobject + * @param mixed $olduser Userobject before modifications (without system magic quotes) + * @param mixed $newuser Userobject new modified userobject (without system magic quotes) * @return boolean result * */ function user_update($olduser, $newuser) { - global $USER, $CFG; + global $USER; + + if (isset($olduser->username) and isset($newuser->username) and $olduser->username != $newuser->username) { + error_log("ERROR:User renaming not allowed in LDAP"); + return false; + } + + if (isset($olduser->auth) and $olduser->auth == 'ldap') { + return true; // just change auth and skip update + } + + $textlib = textlib_get_instance(); + $extoldusername = $textlib->convert($olduser->username, 'utf-8', $this->config->ldapencoding); $ldapconnection = $this->ldap_connect(); - - $result = array(); + $search_attribs = array(); - $attrmap = $this->ldap_attributes(); + $attrmap = $this->ldap_attributes(); foreach ($attrmap as $key => $values) { if (!is_array($values)) { $values = array($values); @@ -887,10 +849,10 @@ class auth_plugin_ldap { if (!in_array($value, $search_attribs)) { array_push($search_attribs, $value); } - } + } } - $user_dn = $this->ldap_find_userdn($ldapconnection, $olduser->username); + $user_dn = $this->ldap_find_userdn($ldapconnection, $extoldusername); $user_info_result = ldap_read($ldapconnection, $user_dn, $this->config->objectclass, $search_attribs); @@ -898,22 +860,24 @@ class auth_plugin_ldap { if ($user_info_result) { $user_entry = $this->ldap_get_entries($ldapconnection, $user_info_result); - if (count($user_entry) > 1) { + if (empty($user_entry)) { + return false; // old user not found! + } else if (count($user_entry) > 1) { trigger_error("ldap: Strange! More than one user record found in ldap. Only using the first one."); + return false; } $user_entry = $user_entry[0]; //error_log(var_export($user_entry) . 'fpp' ); - - foreach ($attrmap as $key => $ldapkeys) { + foreach ($attrmap as $key => $ldapkeys) { // only process if the moodle field ($key) has changed and we // are set to update LDAP with it - if ($olduser->$key !== $newuser->$key and - !empty($this->config->{'field_updateremote_'. $key})) { - - // for ldap values that could be in more than one - // ldap key, we will do our best to match + if (isset($olduser->$key) and isset($newuser->$key) + and $olduser->$key !== $newuser->$key + and !empty($this->config->{'field_updateremote_'. $key})) { + // for ldap values that could be in more than one + // ldap key, we will do our best to match // where they came from $ambiguous = true; $changed = false; @@ -923,72 +887,77 @@ class auth_plugin_ldap { if (count($ldapkeys) < 2) { $ambiguous = false; } - + + $nuvalue = $textlib->convert($newuser->$key, 'utf-8', $this->config->ldapencoding); + $ouvalue = $textlib->convert($olduser->$key, 'utf-8', $this->config->ldapencoding); + foreach ($ldapkeys as $ldapkey) { - $ldapkey = strtolower($ldapkey); + $ldapkey = $ldapkey; $ldapvalue = $user_entry[$ldapkey][0]; if (!$ambiguous) { // skip update if the values already match - if ( !($newuser->$key === $ldapvalue) ) { - ldap_modify($ldapconnection, $user_dn, array($ldapkey => $newuser->$key)); + if ($nuvalue !== $ldapvalue) { + //this might fail due to schema validation + if (@ldap_modify($ldapconnection, $user_dn, array($ldapkey => $nuvalue))) { + continue; + } else { + error_log('Error updating LDAP record. Error code: ' + . ldap_errno($ldapconnection) . '; Error string : ' + . ldap_err2str(ldap_errno($ldapconnection)) + . "\nKey ($key) - old moodle value: '$ouvalue' new value: '$nuvalue'"); + continue; + } } - else { - error_log("Skip updating field $key for entry $user_dn: it seems to be already same on LDAP. - old moodle value: '{$olduser->$key}' - new value: '{$newuser->$key}' - current value in ldap entry: '{$ldapvalue}'"); - } - } - else { + } else { // ambiguous // value empty before in Moodle (and LDAP) - use 1st ldap candidate field // no need to guess - if (empty($olduser->$key)) { // value empty before - use 1st ldap candidate - if (ldap_modify($ldapconnection, $user_dn, array($ldapkey => $newuser->$key))) { + if ($ouvalue === '') { // value empty before - use 1st ldap candidate + //this might fail due to schema validation + if (@ldap_modify($ldapconnection, $user_dn, array($ldapkey => $nuvalue))) { $changed = true; - last; - } - else { - error ('Error updating LDAP record. Error code: ' - . ldap_errno($ldapconnection) . '; Error string : ' - . ldap_err2str(ldap_errno($ldapconnection))); + continue; + } else { + error_log('Error updating LDAP record. Error code: ' + . ldap_errno($ldapconnection) . '; Error string : ' + . ldap_err2str(ldap_errno($ldapconnection)) + . "\nKey ($key) - old moodle value: '$ouvalue' new value: '$nuvalue'"); + continue; } } - // we found which ldap key to update! - if (!empty($ldapvalue) and $olduser->$key === $ldapvalue ) { - // error_log("Matched: ". $olduser->$key . " === " . $ldapvalue); - if (ldap_modify($ldapconnection, $user_dn, array($ldapkey => $newuser->$key))) { + // we found which ldap key to update! + if ($ouvalue !== '' and $ouvalue === $ldapvalue ) { + //this might fail due to schema validation + if (@ldap_modify($ldapconnection, $user_dn, array($ldapkey => $nuvalue))) { $changed = true; - last; - } - else { - error ('Error updating LDAP record. Error code: ' + continue; + } else { + error_log('Error updating LDAP record. Error code: ' . ldap_errno($ldapconnection) . '; Error string : ' - . ldap_err2str(ldap_errno($ldapconnection))); + . ldap_err2str(ldap_errno($ldapconnection)) + . "\nKey ($key) - old moodle value: '$ouvalue' new value: '$nuvalue'"); + continue; } } } } - + if ($ambiguous and !$changed) { - error_log("Failed to update LDAP with ambiguous field $key". - " old moodle value: '" . $olduser->$key . - "' new value '" . $newuser->$key ); + error_log("Failed to update LDAP with ambiguous field $key". + " old moodle value: '" . $ouvalue . + "' new value '" . $nuvalue ); } } } - - - } - else { + } else { error_log("ERROR:No user found in LDAP"); @ldap_close($ldapconnection); return false; } @ldap_close($ldapconnection); - + return true; } @@ -999,8 +968,8 @@ class auth_plugin_ldap { * called when the user password is updated. * changes userpassword in external db * - * @param object $user User table object - * @param mixed $newpassword Plaintext password + * @param object $user User table object (with system magic quotes) + * @param string $newpassword Plaintext password (with system magic quotes) * @return boolean result * */ @@ -1009,23 +978,27 @@ class auth_plugin_ldap { /// or that you've otherwise checked the user's credentials /// IMPORTANT: $newpassword must be cleartext, not crypted/md5'ed - global $CFG, $USER; + global $USER; $result = false; $username = $user->username; - + + $textlib = textlib_get_instance(); + $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); + $extpassword = $textlib->convert(stripslashes($newpassword), 'utf-8', $this->config->ldapencoding); + $ldapconnection = $this->ldap_connect(); - $user_dn = $this->ldap_find_userdn($ldapconnection, $username); - + $user_dn = $this->ldap_find_userdn($ldapconnection, $extusername); + if (!$user_dn) { - error_log('LDAP Error in user_update_password(). No DN for: ' . $username); + error_log('LDAP Error in user_update_password(). No DN for: ' . stripslashes($user->username)); return false; } switch ($this->config->user_type) { case 'edir': //Change password - $result = ldap_modify($ldapconnection, $user_dn, array('userPassword' => $newpassword)); + $result = ldap_modify($ldapconnection, $user_dn, array('userPassword' => $extpassword)); if (!$result) { error_log('LDAP Error in user_update_password(). Error code: ' . ldap_errno($ldapconnection) . '; Error string : ' @@ -1040,16 +1013,16 @@ class auth_plugin_ldap { if (!empty($info[0][$this->config->expireattr][0])) { //Set expiration time only if passwordExpirationInterval is defined if (!empty($info[0]['passwordExpirationInterval'][0])) { - $expirationtime = time() + $info[0]['passwordExpirationInterval'][0]; + $expirationtime = time() + $info[0]['passwordExpirationInterval'][0]; $ldapexpirationtime = $this->ldap_unix2expirationtime($expirationtime); $newattrs['passwordExpirationTime'] = $ldapexpirationtime; - } + } //set gracelogin count if (!empty($info[0]['loginGraceLimit'][0])) { - $newattrs['loginGraceRemaining']= $info[0]['loginGraceLimit'][0]; + $newattrs['loginGraceRemaining']= $info[0]['loginGraceLimit'][0]; } - + //Store attribute changes to ldap $result = ldap_modify($ldapconnection, $user_dn, $newattrs); if (!$result) { @@ -1063,19 +1036,19 @@ class auth_plugin_ldap { error_log('LDAP Error in user_update_password() when reading password expiration time. Error code: ' . ldap_errno($ldapconnection) . '; Error string : ' . ldap_err2str(ldap_errno($ldapconnection))); - } + } break; - + default: $usedconnection = &$ldapconnection; // send ldap the password in cleartext, it will md5 it itself - $result = ldap_modify($ldapconnection, $user_dn, array('userPassword' => $newpassword)); + $result = ldap_modify($ldapconnection, $user_dn, array('userPassword' => $extpassword)); if (!$result) { - error_log('LDAP Error in user_update_password(). Error code: ' + error_log('LDAP Error in user_update_password(). Error code: ' . ldap_errno($ldapconnection) . '; Error string : ' . ldap_err2str(ldap_errno($ldapconnection))); } - + } @ldap_close($ldapconnection); @@ -1090,23 +1063,20 @@ class auth_plugin_ldap { * * @return array of predefined usertypes */ - function ldap_suppported_usertypes() { - // returns array of supported usertypes (schemas) - // If you like to add our own please name and describe it here - // And then add case clauses in relevant places in functions - // iauth_ldap_init, auth_user_create, auth_check_expire, auth_check_grace + $types = array(); $types['edir']='Novell Edirectory'; $types['rfc2307']='posixAccount (rfc2307)'; $types['rfc2307bis']='posixAccount (rfc2307bis)'; $types['samba']='sambaSamAccount (v.3.0.7)'; - $types['ad']='MS ActiveDirectory'; + $types['ad']='MS ActiveDirectory'; + $types['default']=get_string('default'); return $types; - } + } + - /** - * initializes needed variables for ldap-module + * Initializes needed variables for ldap-module * * Uses names defined in ldap_supported_usertypes. * $default is first defined as: @@ -1121,8 +1091,8 @@ class auth_plugin_ldap { function ldap_getdefaults() { $default['objectclass'] = array( 'edir' => 'User', - 'rfc2703' => 'posixAccount', - 'rfc2703bis' => 'posixAccount', + 'rfc2307' => 'posixAccount', + 'rfc2307bis' => 'posixAccount', 'samba' => 'sambaSamAccount', 'ad' => 'user', 'default' => '*' @@ -1140,7 +1110,7 @@ class auth_plugin_ldap { 'rfc2307' => 'member', 'rfc2307bis' => 'member', 'samba' => 'member', - 'ad' => 'member', + 'ad' => 'member', 'default' => 'member' ); $default['memberattribute_isdn'] = array( @@ -1159,7 +1129,7 @@ class auth_plugin_ldap { 'ad' => '', //No support yet 'default' => '' ); - return $default; + return $default; } /** @@ -1169,84 +1139,40 @@ class auth_plugin_ldap { * @return array */ function ldap_getbinaryfields () { - global $CFG; $binaryfields = array ( 'edir' => array('guid'), - 'rfc2703' => array(), - 'rfc2703bis' => array(), + 'rfc2307' => array(), + 'rfc2307bis' => array(), 'samba' => array(), 'ad' => array(), - 'default' => '*' + 'default' => array() ); if (!empty($this->config->user_type)) { - return $binaryfields[$this->config->user_type]; + return $binaryfields[$this->config->user_type]; } else { return $binaryfields['default']; - } + } } function ldap_isbinary ($field) { - if (!isset($field)) { - return null ; - } - return array_search($field, $this->ldap_getbinaryfields()); - } - - /** - * set $CFG-values for ldap_module - * - * Get default configuration values with ldap_getdefaults() - * and by using this information $CFG-> values are set - * If $CFG->value is alredy set current value is honored. - * - * - */ - function ldap_init () { - global $CFG; - - $default = $this->ldap_getdefaults(); - - // TODO: do we need set_config calls here? - - foreach ($default as $key => $value) { - //set defaults if overriding fields not set - if (empty($this->config->{$key})) { - if (!empty($this->config->user_type) and !empty($default[$key][$this->config->user_type])) { - $this->config->{$key} = $default[$key][$this->config->user_type]; - } - else { - //use default value if user_type not set - if (!empty($default[$key]['default'])) { - $this->config->{$key} = $default[$key]['default']; - } - else { - unset($this->config->{$key}); - } - } - } - } - //hack prefix to objectclass - if ('objectClass=' != substr($this->config->objectclass, 0, 12)) { - $this->config->objectclass = 'objectClass='.$this->config->objectclass; + if (empty($field)) { + return false; } - - //all chages go in $CFG , no need to return value + return array_search($field, $this->ldap_getbinaryfields()); } /** * take expirationtime and return it as unixseconds - * + * * takes expriration timestamp as readed from ldap * returns it as unix seconds - * depends on $config->user_type variable + * depends on $this->config->user_type variable * * @param mixed time Time stamp readed from ldap as it is. * @return timestamp */ function ldap_expirationtime2unix ($time) { - - global $CFG; $result = false; switch ($this->config->user_type) { case 'edir': @@ -1256,12 +1182,12 @@ class auth_plugin_ldap { $hr=substr($time,8,2); $min=substr($time,10,2); $sec=substr($time,12,2); - $result = mktime($hr,$min,$sec,$mo,$dt,$yr); + $result = mktime($hr,$min,$sec,$mo,$dt,$yr); break; case 'posix': $result = $time * DAYSECS; //The shadowExpire contains the number of DAYS between 01/01/1970 and the actual expiration date break; - default: + default: print_error('auth_ldap_usertypeundefined', 'auth'); } return $result; @@ -1273,23 +1199,22 @@ class auth_plugin_ldap { * @param integer unix time stamp */ function ldap_unix2expirationtime($time) { - global $CFG; $result = false; switch ($this->config->user_type) { case 'edir': - $result=date('YmdHis', $time).'Z'; + $result=date('YmdHis', $time).'Z'; break; case 'posix': $result = $time ; //Already in correct format break; - default: + default: print_error('auth_ldap_usertypeundefined2', 'auth'); - } + } return $result; } - /* + /** * checks if user belong to specific group(s) * * Returns true if user belongs group in grupdns string. @@ -1298,14 +1223,13 @@ class auth_plugin_ldap { * @param mixed $groupdns string of group dn separated by ; * */ - function ldap_isgroupmember($username='', $groupdns='') { + function ldap_isgroupmember($extusername='', $groupdns='') { // Takes username and groupdn(s) , separated by ; // Returns true if user is member of any given groups - global $CFG ; $result = false; $ldapconnection = $this->ldap_connect(); - + if (empty($username) or empty($groupdns)) { return $result; } @@ -1318,17 +1242,17 @@ class auth_plugin_ldap { } $groups = explode(";",$groupdns); - + foreach ($groups as $group) { $group = trim($group); if (empty($group)) { continue; } //echo "Checking group $group for member $username\n"; - $search = @ldap_read($ldapconnection, $group, '('.$this->config->memberattribute.'='.$username.')', array($this->config->memberattribute)); + $search = @ldap_read($ldapconnection, $group, '('.$this->config->memberattribute.'='.$this->filter_addslashes($username).')', array($this->config->memberattribute)); if (!empty($search) and ldap_count_entries($ldapconnection, $search)) {$info = $this->ldap_get_entries($ldapconnection, $search); - + if (count($info) > 0 ) { // user is member of group $result = true; @@ -1350,12 +1274,6 @@ class auth_plugin_ldap { * @return connection result */ function ldap_connect($binddn='',$bindpwd='') { - /// connects and binds to ldap-server - /// Returns connection result - - global $CFG; - $this->ldap_init(); - //Select bind password, With empty values use //ldap_bind_* variables or anonymous bind if ldap_bind_* are empty if ($binddn == '' and $bindpwd == '') { @@ -1366,9 +1284,9 @@ class auth_plugin_ldap { $bindpwd = $this->config->bind_pw; } } - + $urls = explode(";",$this->config->host_url); - + foreach ($urls as $server) { $server = trim($server); if (empty($server)) { @@ -1377,21 +1295,21 @@ class auth_plugin_ldap { $connresult = ldap_connect($server); //ldap_connect returns ALWAYS true - + if (!empty($this->config->version)) { ldap_set_option($connresult, LDAP_OPT_PROTOCOL_VERSION, $this->config->version); } if (!empty($binddn)) { //bind with search-user - //$debuginfo .= 'Using bind user'.$binddn.'and password:'.$bindpwd; + //$debuginfo .= 'Using bind user'.$binddn.'and password:'.$bindpwd; $bindresult=ldap_bind($connresult, $binddn,$bindpwd); } else { - //bind anonymously + //bind anonymously $bindresult=@ldap_bind($connresult); - } - + } + if (!empty($this->config->opt_deref)) { ldap_set_option($connresult, LDAP_OPT_DEREF, $this->config->opt_deref); } @@ -1399,7 +1317,7 @@ class auth_plugin_ldap { if ($bindresult) { return $connresult; } - + $debuginfo .= " | ||||
| : | +- + | - + | |||
| : | +version, ''); - if (isset($err['version'])) formerr($err['version']); + if (isset($err['version'])) formerr($err['version']); ?> | - + | |||
| + | + + + | ++ | |||
@@ -99,36 +116,31 @@ if (!function_exists('ldap_connect')) { // Is php4-ldap really there? | |||||
| : | +- preventpassindb, ''); - ?> + preventpassindb, ''); ?> | - + | |||
| : | +- + | - + | |||
| : | +- + | - + | |||
| : | +ldap_suppported_usertypes(), 'user_type', $config->user_type, ''); ?> | - + | |||
| : | +- + | - + | |||
| : | +-search_sub, ''); -?> - + search_sub, ''); ?> | - + | |||
| : | +opt_deref, LDAP_DEREF_NEVER); - if (isset($err['opt_deref'])) formerr($err['opt_deref']); + choose_from_menu($opt_deref, 'opt_deref', $config->opt_deref, LDAP_DEREF_NEVER, ''); + if (isset($err['opt_deref'])) formerr($err['opt_deref']); ?> | - + | |||
| : | +- + | - + | |||
| : | +- + | - + | |||
| : | +- + | - + | |||
| : | +
-
- - + forcechangepassword, ''); ?> |
- + | |||
| : | +
-
- - + stdchangepassword, ''); ?> |
- - + + | |||
| : | +- + | ||||
| : | +expiration, ''); - if (isset($err['expiration'])) formerr($err['expiration']); + if (isset($err['expiration'])) formerr($err['expiration']); ?> | - + | |||
| : | +- - expiration_warning?>" /> + | - + | |||
| : | +- - expireattr?>" /> + | - + | |||
| : | +- gracelogins, ''); - if (isset($err['expiration'])) formerr($err['expiration']); - ?> + gracelogins, ''); ?> | - + | |||
| : | +- - graceattr?>" /> + | - + | |||
| : | +- auth_user_create, ''); - if (isset($err['auth_user_create'])) { - formerr($err['auth_user_create']); - } - - ?> + auth_user_create, ''); ?> | @@ -379,12 +362,12 @@ if (!function_exists('ldap_connect')) { // Is php4-ldap really there? | |||
| : | +- + | - + | |||
| : | +- + | - + |
+ + |
+
+
+||
| + | + removeuser, ''); + ?> + | ++ + | +|||
| : | - | ||||
| : | changepasswordurl)) { if (isset($err["port"])) { formerr($err["port"]); } - + ?> | @@ -66,9 +66,8 @@ if (!isset($config->changepasswordurl)) { | - diff --git a/auth/nologin/auth.php b/auth/nologin/auth.php new file mode 100644 index 00000000000..1ff8341094b --- /dev/null +++ b/auth/nologin/auth.php @@ -0,0 +1,96 @@ + diff --git a/auth/none/auth.php b/auth/none/auth.php index 00d7976a721..57c2b2a2f46 100644 --- a/auth/none/auth.php +++ b/auth/none/auth.php @@ -12,8 +12,9 @@ * 2006-08-31 File created. */ -// This page cannot be called directly -if (!isset($CFG)) exit; +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page +} /** * Plugin for no authentication. @@ -41,7 +42,7 @@ class auth_plugin_none { * * @param string $username The username * @param string $password The password - * @returns bool Authentication success or failure. + * @return bool Authentication success or failure. */ function user_login ($username, $password) { global $CFG; @@ -69,7 +70,7 @@ class auth_plugin_none { /** * Returns true if this authentication plugin is 'internal'. * - * @returns bool + * @return bool */ function is_internal() { return true; @@ -79,22 +80,22 @@ class auth_plugin_none { * Returns true if this authentication plugin can change the user's * password. * - * @returns bool + * @return bool */ function can_change_password() { return true; } - + /** * Returns the URL for changing the user's pw, or false if the default can * be used. * - * @returns bool + * @return bool */ function change_password_url() { return false; } - + /** * Prints a form for configuring this authentication plugin. * @@ -103,7 +104,7 @@ class auth_plugin_none { * * @param array $page An object containing all the data for this page. */ - function config_form($config, $err) { + function config_form($config, $err, $user_fields) { include "config.html"; } diff --git a/auth/none/config.html b/auth/none/config.html index f8e7d036203..cdc7ff7962f 100644 --- a/auth/none/config.html +++ b/auth/none/config.html @@ -2,9 +2,8 @@ | ||
| @@ -103,9 +103,8 @@ if (!isset($config->changepasswordurl)) { | - diff --git a/auth/radius/auth.php b/auth/radius/auth.php index c173eaeb242..1f30f0f1b4f 100644 --- a/auth/radius/auth.php +++ b/auth/radius/auth.php @@ -13,8 +13,9 @@ * 2006-08-31 File created. */ -// This page cannot be called directly -if (!isset($CFG)) exit; +if (!defined('MOODLE_INTERNAL')) { + die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page +} /** * RADIUS authentication plugin. @@ -39,26 +40,26 @@ class auth_plugin_radius { * * @param string $username The username * @param string $password The password - * @returns bool Authentication success or failure. + * @return bool Authentication success or failure. */ function user_login ($username, $password) { require_once 'Auth/RADIUS.php'; - + // Added by Clive on 7th May for test purposes // printf("Username: $username | @@ -59,7 +59,7 @@ if (!isset($config->changepasswordurl)) { |
--
- To restrict access to Moodle, replace the access rule 'require valid-user'
+ To restrict access to Moodle, replace the access rule 'require valid-user'
with something that fits your needs, e.g. 'require affiliation student'.
- For IIS you have protect the auth/shibboleth directory directly in the
+ For IIS you have protect the auth/shibboleth directory directly in the
RequestMap of the Shibboleth configuration file (shibboleth.xml). See
https://authdev.it.ohio-state.edu/twiki/bin/view/Shibboleth/xmlaccesscontrol?topic=XMLAccessControl
-2. As Moodle admin, go to the 'Administrations >> Users >> Authentication
+2. As Moodle admin, go to the 'Administrations >> Users >> Authentication
Options' and select the 'Shibboleth' authentication method from the pop-up.
-
-3. Fill in the fields of the form. The fields 'Username', 'First name',
- 'Surname', etc should contain the name of the environment variables of the
- Shibboleth attributes that you want to map onto the corresponding Moodle
- variable (e.g. 'HTTP_SHIB_PERSON_SURNAME' for the person's last name, refer
+
+3. Fill in the fields of the form. The fields 'Username', 'First name',
+ 'Surname', etc should contain the name of the environment variables of the
+ Shibboleth attributes that you want to map onto the corresponding Moodle
+ variable (e.g. 'HTTP_SHIB_PERSON_SURNAME' for the person's last name, refer
the Shibboleth documentation or the documentation of your Shibboleth
federation for information on which attributes are available).
- Especially the 'Username' field is of great importance because
+ Especially the 'Username' field is of great importance because
this attribute is used for the Moodle authentication of Shibboleth users.
-
+
#############################################################################
Shibboleth Attributes needed by Moodle:
For Moodle to work properly Shibboleth should at least provide the attributes
@@ -60,10 +60,10 @@ Moodle Configuration with Dual login
lengths for each field in the user profile.
#############################################################################
-4. The large text field 'Instructions' must contain a link to the
- moodle/auth/shibboleth/index.php file which is protected by
- Shibboleth (see step 1) and causes the Shibboleth login procedure to start.
- You could also use HTML code in that field, e.g. to create your own
+4. The large text field 'Instructions' must contain a link to the
+ moodle/auth/shibboleth/index.php file which is protected by
+ Shibboleth (see step 1) and causes the Shibboleth login procedure to start.
+ You could also use HTML code in that field, e.g. to create your own
Shibboleth login button.
5. Save the changes for the Shibboleth authentication method.
@@ -73,44 +73,44 @@ Moodle Configuration with Shibboleth only login
If you want Shibboleth as your only authentication method, configure Moodle as
described in the dual login section above and do the following steps:
-4.a On the Moodle Shibboleth settings page, set the 'Alternate Login URL' to
+4.a On the Moodle Shibboleth settings page, set the 'Alternate Login URL' to
the URL of the file 'moodle/auth/shibboleth/index.php'
This will enforce Shibboleth login.
How the Shibboleth authentication works
--------------------------------------------------------------------------------
-To get Shibboleth authenticated in Moodle a user basically must access the
-Shibboleth-protected page /auth/shibboleth/index.php. If Shibboleth is the only
-authentication method (see 4.a), this happens automatically when a user wants to
-login in Moodle. Otherwise, the user has to click on the link on the login page
+To get Shibboleth authenticated in Moodle a user basically must access the
+Shibboleth-protected page /auth/shibboleth/index.php. If Shibboleth is the only
+authentication method (see 4.a), this happens automatically when a user wants to
+login in Moodle. Otherwise, the user has to click on the link on the login page
you provided in step 4.
Moodle basically checks whether the Shibboleth attribute that you mapped
-as the username is present. This attribute should only be present if a user is
+as the username is present. This attribute should only be present if a user is
Shibboleth authenticated.
If the user's Moodle account has not existed yet, it gets automatically created.
To prevent that every Shibboleth user can access your Moodle site you have to
-adapt the 'require valid-user' line in your webserver's config (see step 1) to
+adapt the 'require valid-user' line in your webserver's config (see step 1) to
allow only specific users. If you defined some authorization rules in step 1,
-these are checked by Shibboleth itself. Only users who met these rules
+these are checked by Shibboleth itself. Only users who met these rules
actually can access /auth/shibboleth/index.php and get logged in.
-You can use Shibboleth AND another authentication method (it was tested with
-manual login). So, if there are a few users that don't have a Shibboleth
-login, you could create manual accounts for them and they could use the manual
-login. For other authentication methods you first have to configure them and
-then set Shibboleth as your authentication method. Users can log in only via one
+You can use Shibboleth AND another authentication method (it was tested with
+manual login). So, if there are a few users that don't have a Shibboleth
+login, you could create manual accounts for them and they could use the manual
+login. For other authentication methods you first have to configure them and
+then set Shibboleth as your authentication method. Users can log in only via one
authentication method unless they have two accounts in Moodle.
Shibboleth dual login with custom login page
--------------------------------------------------------------------------------
-Of course you can create a dual login page that better fits your needs. For this
-to work, you have to set up the two authentication methods (e.g. 'Manual' and
-'Shibboleth') and specify an alternate login link to your own dual login page.
+Of course you can create a dual login page that better fits your needs. For this
+to work, you have to set up the two authentication methods (e.g. 'Manual' and
+'Shibboleth') and specify an alternate login link to your own dual login page.
On that page you basically need a link to the Shibboleth-protected page
-('/auth/shibboleth/index.php') for the Shibboleth login and a
+('/auth/shibboleth/index.php') for the Shibboleth login and a
form that sends 'username' and 'password' to moodle/login/index.php.
Consult the Moodle documentation for further instructions and requirements.
@@ -119,21 +119,21 @@ How to customize the way the Shibboleth user data is used in Moodle
Among the Shibboleth settings in Moodle there is a field that should contain a
path to a php file that can be used as data manipulation hook.
You can use this if you want to further process the way your Shibboleth
-attributes are used in Moodle.
+attributes are used in Moodle.
-Example 1: Your Shibboleth federation uses an attribute that specifies the
+Example 1: Your Shibboleth federation uses an attribute that specifies the
user's preferred language, but the content of this attribute is not
compatible with the Moodle data representation, e.g. the Shibboleth
- attribute contains 'German' but Moodle needs a two letter value like
+ attribute contains 'German' but Moodle needs a two letter value like
'de'.
Example 2: The country, city and street are provided in one Shibboleth attribute
and you want these values to be used in the Moodle user profile. So
You have to parse the corresponding attribute to fill the user fields.
-If you want to use this hook you have to be a skilled PHP programmer. It is
-strongly recommended that you take a look at the file
-moodle/auth/shibboleth/auth.php, especially the function 'get_userinfo'
-where this file is included.
+If you want to use this hook you have to be a skilled PHP programmer. It is
+strongly recommended that you take a look at the file
+moodle/auth/shibboleth/auth.php, especially the function 'get_userinfo'
+where this file is included.
The context of the file is the same as within this login function. So you
can directly edit the object $result.
@@ -146,16 +146,16 @@ Example file:
if ($_SERVER[$pluginconfig->field_map_address] != '')
{
// $address contains something like 'SWITCH$Limmatquai 138$CH-8021 Zurich'
- // We want to split this up to get:
+ // We want to split this up to get:
// institution, street, zipcode, city and country
$address = $_SERVER[$pluginconfig->field_map_address];
list($institution, $street, $zip_city) = split('\$', $address);
ereg(' (.+)',$zip_city, $regs);
$city = $regs[1];
-
+
ereg('(.+)-',$zip_city, $regs);
$country = $regs[1];
-
+
$result["address"] = $street;
$result["city"] = $city;
$result["country"] = $country;
@@ -165,5 +165,5 @@ Example file:
--
--------------------------------------------------------------------------------
-In case of problems and questions with Shibboleth authentication, contact
+In case of problems and questions with Shibboleth authentication, contact
Lukas Haemmerle | : |
-
+
|
| : |
-
- convert_data?>">
+ convert_data and $config->convert_data != '' and !is_readable($config->convert_data)) {
echo ' | '; @@ -74,9 +74,8 @@
| |