MDL-15098 dml auth conversion

This commit is contained in:
skodak 2008-06-07 15:41:25 +00:00
parent 21a7e260fc
commit df884cd852
5 changed files with 178 additions and 235 deletions

View File

@ -1,4 +1,5 @@
<?php
/**
* @author Martin Dougiamas
* @authro Jerome GUTIERREZ
@ -43,7 +44,7 @@ class auth_plugin_cas extends auth_plugin_base {
//hack prefix to objectclass
if (empty($this->config->objectclass)) { // Can't send empty filter
$this->config->objectclass='objectClass=*';
} else if (strpos($this->config->objectclass, 'objectClass=') !== 0) {
} else if (stripos($this->config->objectclass, 'objectClass=') !== 0) {
$this->config->objectclass = 'objectClass='.$this->config->objectclass;
}
}
@ -361,10 +362,13 @@ if ( !is_object($PHPCAS_CLIENT) ) {
function get_userinfo($username) {
$textlib = textlib_get_instance();
$extusername = $textlib->convert($username, 'utf-8', $this->config->ldapencoding);
$ldapconnection = $this->ldap_connect();
$attrmap = $this->ldap_attributes();
$result = array();
$search_attribs = array();
foreach ($attrmap as $key=>$values) {
if (!is_array($values)) {
$values = array($values);
@ -388,7 +392,7 @@ if ( !is_object($PHPCAS_CLIENT) ) {
$values = array($values);
}
$ldapval = NULL;
foreach ($values as $value) {
foreach ($values as $value) {
if ($value == 'dn') {
$result[$key] = $user_dn;
}
@ -562,11 +566,11 @@ if ( !is_object($PHPCAS_CLIENT) ) {
/**
* checks if user exists on external db
*
* @param string $username (with system magic quotes)
* @param string $username
*/
function user_exists($username) {
$textlib = textlib_get_instance();
$extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
$extusername = $textlib->convert($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);
@ -579,81 +583,55 @@ if ( !is_object($PHPCAS_CLIENT) ) {
* 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 = true) {
global $CFG;
function sync_users ($do_updates = true) {
global $CFG, $DB;
$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
$dbman = $DB->get_manager();
/// TODO: move this to sql generators
error('fix temporary table code in CAS');
/// Define table user to be created
$table = new xmldb_table('tmp_extuser');
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
$table->add_field('username', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, null, null);
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
$table->add_index('username', XMLDB_INDEX_UNIQUE, array('mnethostid', 'username'));
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 . ' (username VARCHAR(64), PRIMARY KEY (username)) TYPE=MyISAM', false);
break;
case 'postgres':
$temptable = $CFG->prefix . 'extuser';
$droptablesql[] = 'DROP 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";
$bulk_insert_records = 1; // no support for multiple sets of values
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 #
$droptablesql[] = 'DROP 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";
$bulk_insert_records = 1; // no support for multiple sets of values
execute_sql('CREATE TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))', false);
break;
case 'oracle':
$temptable = $CFG->prefix . 'extuser';
$droptablesql[] = 'TRUNCATE TABLE ' . $temptable; // oracle requires truncate before being able to drop a temp table
$droptablesql[] = 'DROP 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";
$bulk_insert_records = 1; // no support for multiple sets of values
execute_sql('CREATE GLOBAL TEMPORARY TABLE '.$temptable.' (username VARCHAR(64), PRIMARY KEY (username)) ON COMMIT PRESERVE ROWS', false);
break;
echo "Creating temp table $temptable\n";
if (!$dbman->create_temp_table($table)) {
print "Failed to create temporary users table - aborting\n";
exit;
}
print "Connecting to ldap...\n";
$ldapconnection = $this->ldap_connect();
if (!$ldapconnection) {
@ldap_close($ldapconnection);
print get_string('auth_ldap_noconnect','auth',$this->config->host_url);
exit;
}
////
//// get user's list from ldap to sql in a scalable fashion
////
// prepare some data we'll need
$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();
foreach ($contexts as $context) {
$context = trim($context);
if (empty($context)) {
continue;
}
begin_sql();
if ($this->config->search_sub) {
//use ldap_search to find first user from subtree
$ldap_result = ldap_search($ldapconnection, $context,
@ -665,49 +643,44 @@ error('fix temporary table code in CAS');
$filter,
array($this->config->user_attribute));
}
if ($entry = ldap_first_entry($ldapconnection, $ldap_result)) {
do {
$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);
$fresult = array();
}
$this->ldap_bulk_insert($value);
} 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();
}
commit_sql();
}
/// 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(username) AS count, 1 FROM ' . $temptable);
$count = $count->{'count'};
$count = $DB->count_records_sql('SELECT COUNT(username) AS count, 1 FROM {tmp_extuser}');
if ($count < 1) {
print "Did not get any users from LDAP -- error? -- exiting\n";
exit;
} else {
print "Got $count records from LDAP\n\n";
}
/// User removal
// find users in DB that aren't in ldap -- to be removed!
// 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, u.auth
FROM {$CFG->prefix}user u
LEFT JOIN $temptable e ON u.username = e.username
WHERE u.auth='cas'
AND u.deleted=0
AND e.username IS NULL";
$remove_users = get_records_sql($sql);
$sql = "SELECT u.id, u.username, u.email, u.auth
FROM {user} u
LEFT JOIN {tmp_extuser} e ON (u.username = e.username AND u.mnethostid = ?)
WHERE u.auth='cas'
AND u.deleted=0
AND e.username IS NULL";
$remove_users = $DB->get_records_sql($sql, array($CFG->mnet_localhost_id));
if (!empty($remove_users)) {
print "User entries to remove: ". count($remove_users) . "\n";
foreach ($remove_users as $user) {
if ($this->config->removeuser == AUTH_REMOVEUSER_FULLDELETE) {
if (delete_user($user)) {
@ -719,7 +692,7 @@ error('fix temporary table code in CAS');
$updateuser = new object();
$updateuser->id = $user->id;
$updateuser->auth = 'nologin';
if (update_record('user', $updateuser)) {
if ($DB->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";
@ -731,32 +704,36 @@ error('fix temporary table code in CAS');
}
unset($remove_users); // free mem!
}
/// Revive suspended users
if (!empty($this->config->removeuser) and $this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) {
$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);
FROM {user} u
JOIN {tmp_extuser} e ON (u.username = e.username AND u.mnethostid = ?)
WHERE u.auth='nologin' AND u.deleted=0";
$revive_users = $DB->get_records_sql($sql, array($CFG->mnet_localhost_id));
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 = 'cas';
if (update_record('user', $updateuser)) {
$updateuser->auth = 'ldap';
if ($DB->pdate_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
@ -775,15 +752,17 @@ error('fix temporary table code in CAS');
}
// 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='cas'");
$users = $DB->get_records_sql("SELECT u.username, u.id
FROM {user} u
WHERE u.deleted=0 AND u.auth='cas' AND u.mnethostid = ?", array($CFG->mnet_localhost_id));
if (!empty($users)) {
print "User entries to update: ". count($users). "\n";
$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)) {
@ -791,9 +770,11 @@ error('fix temporary table code in CAS');
} else {
$creatorrole = false;
}
begin_sql();
$DB->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($user->username, $updatekeys)) {
@ -801,6 +782,7 @@ error('fix temporary table code in CAS');
}
echo "\n";
$xcount++;
// update course creators if needed
if ($creatorrole !== false) {
if ($this->iscreator($user->username)) {
@ -809,13 +791,14 @@ error('fix temporary table code in CAS');
role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id, 'cas');
}
}
if ($xcount++ > $maxxcount) {
commit_sql();
begin_sql();
$DB->commit_sql();
$DB->begin_sql();
$xcount = 0;
}
}
commit_sql();
$DB->commit_sql();
unset($users); // free mem
}
} else { // end do updates
@ -823,15 +806,18 @@ error('fix temporary table code in CAS');
}
/// 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.
// 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
// mnetid not used here in join because we can not add users with the same username
$sql = "SELECT e.id, e.username
FROM {user} u
LEFT JOIN {tmp_extuser} e ON u.username = e.username
WHERE u.id IS NULL";
$add_users = $DB->get_records_sql($sql); // get rid of the fat
if (!empty($add_users)) {
print "User entries to add: ". count($add_users). "\n";
$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)) {
@ -839,9 +825,11 @@ error('fix temporary table code in CAS');
} else {
$creatorrole = false;
}
begin_sql();
$DB->begin_sql();
foreach ($add_users as $user) {
$user = $this->get_userinfo_asobj(addslashes($user->username));
$user = $this->get_userinfo_asobj($user->username);
// prep a few params
$user->modified = time();
$user->confirmed = 1;
@ -850,9 +838,9 @@ error('fix temporary table code in CAS');
if (empty($user->lang)) {
$user->lang = $CFG->lang;
}
$user = addslashes_recursive($user);
if ($id = insert_record('user',$user)) {
echo "\t"; print_string('auth_dbinsertuser', 'auth', array(stripslashes($user->username), $id)); echo "\n";
if ($id = $DB->insert_record('user', $user)) {
echo "\t"; print_string('auth_dbinsertuser', 'auth', array($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);
@ -860,18 +848,23 @@ error('fix temporary table code in CAS');
} 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))) {
if ($creatorrole !== false and $this->iscreator($user->username)) {
role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'cas');
}
}
commit_sql();
$DB->commit_sql();
unset($add_users); // free mem
} else {
print "No users to be added\n";
}
$dbman->drop_temp_table($table);
return true;
}
/**
* Update a local user record from an external source.
* This is a lighter version of the one in moodlelib -- won't do
@ -883,30 +876,36 @@ error('fix temporary table code in CAS');
* @param string $username username
*/
function update_user_record($username, $updatekeys = false) {
global $CFG, $DB;
global $CFG;
//just in case check text case
$username = trim(moodle_strtolower($username));
// get the current user record
$user = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id));
if (empty($user)) { // trouble
error_log("Cannot update non-existent user: ".stripslashes($username));
print_error('auth_dbusernotexist','auth',$username);
error_log("Cannot update non-existent user: ".$username);
print_error('auth_dbusernotexist','auth','',$username);
die;
}
// Protect the userid from being overwritten
$userid = $user->id;
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 = '';
}
if (!empty($this->config->{'field_updatelocal_' . $key})) {
if ($user->{$key} != $value) { // only update if it's changed
$DB->set_field('user', $key, $value, array('id'=>$userid));
@ -920,17 +919,13 @@ error('fix temporary table code in CAS');
}
/**
* 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 . ' (username) VALUES ';
// make those values safe
$users = addslashes_recursive($users);
// join and quote the whole lot
$sql = $sql . "('" . implode("'),('", $users) . "')";
print "\t+ " . count($users) . " users\n";
execute_sql($sql, false);
function ldap_bulk_insert($username) {
global $DB;
$username = moodle_strtolower($username); // usernames are __always__ lowercase.
$DB->insert_record_raw('tmp_extuser', array('username'=>$username), false, true);
print ".";
}
/**
* Returns true if user should be coursecreator.

View File

@ -43,6 +43,6 @@ if (!is_enabled_auth('cas')) {
}
$casauth = get_auth_plugin('cas');
$casauth->sync_users(1000, true);
$casauth->sync_users(true);
?>

View File

@ -342,7 +342,7 @@ class auth_plugin_db extends auth_plugin_base {
if (!empty($add_users)) {
print_string('auth_dbuserstoadd','auth',count($add_users)); echo "\n";
begin_sql();
$DB->begin_sql();
foreach($add_users as $user) {
$username = $user;
$user = $this->get_userinfo_asobj($user);
@ -357,7 +357,6 @@ class auth_plugin_db extends auth_plugin_base {
$user->lang = $CFG->lang;
}
$user = addslashes_object($user);
// maybe the user has been deleted before
if ($old_user = $DB->get_record('user', array('username'=>$user->username, 'deleted'=>1, 'mnethostid'=>$user->mnethostid))) {
$user->id = $old_user->id;
@ -374,7 +373,7 @@ class auth_plugin_db extends auth_plugin_base {
echo "\t"; print_string('auth_dbinsertusererror', 'auth', $user->username); echo "\n";
}
}
commit_sql();
$DB->commit_sql();
unset($add_users); // free mem
}
return true;

View File

@ -254,12 +254,12 @@ class auth_plugin_ldap extends auth_plugin_base {
/**
* checks if user exists on external db
*
* @param string $username (with system magic quotes)
* @param string $username
*/
function user_exists($username) {
$textlib = textlib_get_instance();
$extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
$extusername = $textlib->convert($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).")");
@ -271,13 +271,13 @@ class auth_plugin_ldap extends auth_plugin_base {
* By using information in userobject
* Use user_exists to prevent dublicate usernames
*
* @param mixed $userobject Moodle userobject (with system magic quotes)
* @param mixed $plainpass Plaintext password (with system magic quotes)
* @param mixed $userobject Moodle userobject
* @param mixed $plainpass Plaintext password
*/
function user_create($userobject, $plainpass) {
$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);
$extusername = $textlib->convert($userobject->username, 'utf-8', $this->config->ldapencoding);
$extpassword = $textlib->convert($plainpass, 'utf-8', $this->config->ldapencoding);
switch ($this->config->passtype) {
case 'md5':
@ -302,7 +302,7 @@ class auth_plugin_ldap extends auth_plugin_base {
}
foreach ($values as $value) {
if (!empty($userobject->$key) ) {
$newuser[$value] = $textlib->convert(stripslashes($userobject->$key), 'utf-8', $this->config->ldapencoding);
$newuser[$value] = $textlib->convert($userobject->$key, 'utf-8', $this->config->ldapencoding);
}
}
}
@ -437,6 +437,8 @@ class auth_plugin_ldap extends auth_plugin_base {
* @param string $confirmsecret
*/
function user_confirm($username, $confirmsecret) {
global $DB;
$user = get_complete_user_data('username', $username);
if (!empty($user)) {
@ -450,10 +452,10 @@ class auth_plugin_ldap extends auth_plugin_base {
if (!$this->user_activate($username)) {
return AUTH_CONFIRM_FAIL;
}
if (!set_field("user", "confirmed", 1, "id", $user->id)) {
if (!$DB->set_field("user", "confirmed", 1, array("id"=>$user->id))) {
return AUTH_CONFIRM_FAIL;
}
if (!set_field("user", "firstaccess", time(), "id", $user->id)) {
if (!$DB->set_field("user", "firstaccess", time(), array("id"=>$user->id))) {
return AUTH_CONFIRM_FAIL;
}
return AUTH_CONFIRM_OK;
@ -469,14 +471,14 @@ class auth_plugin_ldap extends auth_plugin_base {
* If userpassword does not expire it should return 0. If password is already expired
* it should return negative value.
*
* @param mixed $username username (with system magic quotes)
* @param mixed $username username
* @return integer
*/
function password_expire($username) {
$result = 0;
$textlib = textlib_get_instance();
$extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
$extusername = $textlib->convert($username, 'utf-8', $this->config->ldapencoding);
$ldapconnection = $this->ldap_connect();
$user_dn = $this->ldap_find_userdn($ldapconnection, $extusername);
@ -512,57 +514,23 @@ class auth_plugin_ldap extends auth_plugin_base {
* 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 = true) {
global $CFG;
function sync_users($do_updates=true) {
global $CFG, $DB;
$textlib = textlib_get_instance();
$dbman = $DB->get_manager();
$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
$temptable = $CFG->prefix . 'extuser';
$createtemptablesql = '';
/// Define table user to be created
$table = new xmldb_table('tmp_extuser');
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
$table->add_field('username', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, null, null);
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
$table->add_index('username', XMLDB_INDEX_UNIQUE, array('mnethostid', 'username'));
// configure a temp table
print "Configuring temp table\n";
error('fix temporary table code in CAS'); // use sql generator
switch (strtolower($CFG->dbfamily)) {
case 'mysql':
$droptablesql[] = 'DROP TEMPORARY TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem)
$createtemptablesql = 'CREATE TEMPORARY TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username)) TYPE=MyISAM';
break;
case 'postgres':
$droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem)
$bulk_insert_records = 1; // no support for multiple sets of values
$createtemptablesql = 'CREATE TEMPORARY TABLE '. $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))';
break;
case 'mssql':
$temptable = '#'. $temptable; /// MSSQL temp tables begin with #
$droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem)
$bulk_insert_records = 1; // no support for multiple sets of values
$createtemptablesql = 'CREATE TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))';
break;
case 'oracle':
$droptablesql[] = 'TRUNCATE TABLE ' . $temptable; // oracle requires truncate before being able to drop a temp table
$droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem)
$bulk_insert_records = 1; // no support for multiple sets of values
$createtemptablesql = 'CREATE GLOBAL TEMPORARY TABLE '.$temptable.' (username VARCHAR(64), PRIMARY KEY (username)) ON COMMIT PRESERVE ROWS';
break;
}
/// TODO: remove these ugly hacks
error('fix temporary table code in CAS');
execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later
echo "Creating temp table $temptable\n";
if(! execute_sql($createtemptablesql, false) ){
if (!$dbman->create_temp_table($table)) {
print "Failed to create temporary users table - aborting\n";
exit;
}
@ -594,7 +562,6 @@ error('fix temporary table code in CAS');
if (empty($context)) {
continue;
}
begin_sql();
if ($this->config->search_sub) {
//use ldap_search to find first user from subtree
$ldap_result = ldap_search($ldapconnection, $context,
@ -611,29 +578,16 @@ error('fix temporary table code in CAS');
do {
$value = ldap_get_values_len($ldapconnection, $entry, $this->config->user_attribute);
$value = $textlib->convert($value[0], $this->config->ldapencoding, 'utf-8');
// usernames are __always__ lowercase.
array_push($fresult, moodle_strtolower($value));
if (count($fresult) >= $bulk_insert_records) {
$this->ldap_bulk_insert($fresult, $temptable);
$fresult = array();
}
$this->ldap_bulk_insert($value);
} 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();
}
commit_sql();
}
/// 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(username) AS count, 1 FROM ' . $temptable);
$count = $count->{'count'};
$count = $DB->count_records_sql('SELECT COUNT(username) AS count, 1 FROM {tmp_extuser}');
if ($count < 1) {
print "Did not get any users from LDAP -- error? -- exiting\n";
exit;
@ -647,12 +601,12 @@ error('fix temporary table code in CAS');
// 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, u.auth
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);
FROM {user} u
LEFT JOIN {tmp_extuser} e ON (u.username = e.username AND u.mnethostid = ?)
WHERE u.auth='ldap'
AND u.deleted=0
AND e.username IS NULL";
$remove_users = $DB->get_records_sql($sql, array($CFG->mnet_localhost_id));
if (!empty($remove_users)) {
print "User entries to remove: ". count($remove_users) . "\n";
@ -668,7 +622,7 @@ error('fix temporary table code in CAS');
$updateuser = new object();
$updateuser->id = $user->id;
$updateuser->auth = 'nologin';
if (update_record('user', $updateuser)) {
if ($DB->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";
@ -684,26 +638,24 @@ error('fix temporary table code in CAS');
/// Revive suspended users
if (!empty($this->config->removeuser) and $this->config->removeuser == AUTH_REMOVEUSER_SUSPEND) {
$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);
FROM {user} u
JOIN {tmp_extuser} e ON (u.username = e.username AND u.mnethostid = ?)
WHERE u.auth='nologin' AND u.deleted=0";
$revive_users = $DB->get_records_sql($sql, array($CFG->mnet_localhost_id));
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)) {
if ($DB->pdate_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";
}
@ -735,9 +687,9 @@ error('fix temporary table code in CAS');
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='ldap'");
$users = $DB->get_records_sql("SELECT u.username, u.id
FROM {user} u
WHERE u.deleted=0 AND u.auth='ldap' AND u.mnethostid = ?", array($CFG->mnet_localhost_id));
if (!empty($users)) {
print "User entries to update: ". count($users). "\n";
@ -749,7 +701,7 @@ error('fix temporary table code in CAS');
$creatorrole = false;
}
begin_sql();
$DB->begin_sql();
$xcount = 0;
$maxxcount = 100;
@ -771,12 +723,12 @@ error('fix temporary table code in CAS');
}
if ($xcount++ > $maxxcount) {
commit_sql();
begin_sql();
$DB->commit_sql();
$DB->begin_sql();
$xcount = 0;
}
}
commit_sql();
$DB->commit_sql();
unset($users); // free mem
}
} else { // end do updates
@ -785,13 +737,14 @@ error('fix temporary table code in CAS');
/// 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.
// 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
// mnetid not used here in join because we can not add users with the same username
$sql = "SELECT e.id, e.username
FROM {user} u
LEFT JOIN {tmp_extuser} e ON u.username = e.username
WHERE u.id IS NULL";
$add_users = $DB->get_records_sql($sql); // get rid of the fat
if (!empty($add_users)) {
print "User entries to add: ". count($add_users). "\n";
@ -804,9 +757,9 @@ error('fix temporary table code in CAS');
$creatorrole = false;
}
begin_sql();
$DB->begin_sql();
foreach ($add_users as $user) {
$user = $this->get_userinfo_asobj(addslashes($user->username));
$user = $this->get_userinfo_asobj($user->username);
// prep a few params
$user->modified = time();
@ -817,10 +770,8 @@ error('fix temporary table code in CAS');
$user->lang = $CFG->lang;
}
$user = addslashes_recursive($user);
if ($id = insert_record('user',$user)) {
echo "\t"; print_string('auth_dbinsertuser', 'auth', array(stripslashes($user->username), $id)); echo "\n";
if ($id = $DB->insert_record('user', $user)) {
echo "\t"; print_string('auth_dbinsertuser', 'auth', array($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);
@ -830,15 +781,18 @@ error('fix temporary table code in CAS');
}
// add course creators if needed
if ($creatorrole !== false and $this->iscreator(stripslashes($user->username))) {
if ($creatorrole !== false and $this->iscreator($user->username)) {
role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap');
}
}
commit_sql();
$DB->commit_sql();
unset($add_users); // free mem
} else {
print "No users to be added\n";
}
$dbman->drop_temp_table($table);
return true;
}
@ -897,30 +851,25 @@ error('fix temporary table code in CAS');
/**
* Bulk insert in SQL's temp table
* @param array $users is an array of usernames
*/
function ldap_bulk_insert($users, $temptable) {
function ldap_bulk_insert($username) {
global $DB;
// bulk insert -- superfast with $bulk_insert_records
$sql = 'INSERT INTO ' . $temptable . ' (username) VALUES ';
// make those values safe
$users = addslashes_recursive($users);
// join and quote the whole lot
$sql = $sql . "('" . implode("'),('", $users) . "')";
print "\t+ " . count($users) . " users\n";
execute_sql($sql, false);
$username = moodle_strtolower($username); // usernames are __always__ lowercase.
$DB->insert_record_raw('tmp_extuser', array('username'=>$username), false, true);
print ".";
}
/**
* Activates (enables) user in external db so user can login to external db
*
* @param mixed $username username (with system magic quotes)
* @param mixed $username
* @return boolen result
*/
function user_activate($username) {
$textlib = textlib_get_instance();
$extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
$extusername = $textlib->convert($username, 'utf-8', $this->config->ldapencoding);
$ldapconnection = $this->ldap_connect();
@ -955,7 +904,7 @@ error('fix temporary table code in CAS');
*/
/* function user_disable($username) {
$textlib = textlib_get_instance();
$extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding);
$extusername = $textlib->convert($username, 'utf-8', $this->config->ldapencoding);
$ldapconnection = $this->ldap_connect();

View File

@ -41,6 +41,6 @@ if (!is_enabled_auth('ldap')) {
}
$ldapauth = get_auth_plugin('ldap');
$ldapauth->sync_users(1000, true);
$ldapauth->sync_users(true);
?>