Commit 210a98b4 authored by Robert Lyon's avatar Robert Lyon
Browse files

Bug 1640308: Adding an auth_instance "active" column



To allow us to easily turn of a 'bad' auth when it is trying to
connect to a third party server but that server is not reachable.

Currently it makes logging in slow as it needs to timeout on that auth
instance before trying the next one.

behatnotneeded

Change-Id: Ieeaeeaeb1bc0aa61ed3faad8f3bf751edd9c1023
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent 17ef60df
......@@ -298,7 +298,10 @@ function adduser_submit(Pieform $form, $values) {
$user->quota = $values['quota'];
}
$authinstance = get_record('auth_instance', 'id', $values['authinstance']);
$authinstance = get_record('auth_instance', 'id', $values['authinstance'], 'active', 1);
if (!$authinstance) {
throw new InvalidArgumentException("trying to add user to inactive auth instance " . $values['authinstance']);
}
$remoteauth = false;
if ($authinstance->authname != 'internal') {
$remoteauth = true;
......
......@@ -60,6 +60,7 @@ if ($institution && $plugin) {
$authinstance->instancename = $plugin;
$authinstance->institution = $institution;
$authinstance->authname = $plugin;
$authinstance->active = 1;
$authinstance->id = insert_record('auth_instance', $authinstance, 'id', true);
json_reply(false, array('id' => $authinstance->id, 'name' => ucfirst($authinstance->authname), 'authname' => $authinstance->authname));
exit;
......
......@@ -173,7 +173,10 @@ function import_next_user($filename, $username, $authinstance) {
log_debug('adding user ' . $username . ' from ' . $filename);
$authobj = get_record('auth_instance', 'id', $authinstance);
$authobj = get_record('auth_instance', 'id', $authinstance, 'active', 1);
if (!$authobj) {
throw new InvalidArgumentException("trying to add user to inactive auth instance {$authinstance}");
}
$institution = new Institution($authobj->institution);
$date = time();
......
......@@ -76,7 +76,7 @@ if ($institution || $add) {
$authinstanceids
);
if ($badusers) {
$defaultauth = record_exists('auth_instance', 'institution', 'mahara', 'authname', 'internal');
$defaultauth = record_exists('auth_instance', 'institution', 'mahara', 'authname', 'internal', 'active', 1);
if ($values['i'] == 'mahara' || !$defaultauth) {
$form->set_error(
'submit',
......@@ -133,7 +133,7 @@ if ($institution || $add) {
execute_sql("
UPDATE {usr}
SET authinstance = (
SELECT MIN(id) FROM {auth_instance} WHERE institution = 'mahara' AND authname = 'internal'
SELECT MIN(id) FROM {auth_instance} WHERE institution = 'mahara' AND authname = 'internal' AND active = 1
)
WHERE authinstance IN (" . join(',', array_fill(0, count($authinstanceids), '?')) . ')',
$authinstanceids
......@@ -915,6 +915,7 @@ function institution_submit(Pieform $form, $values) {
$authinstance = (object)array(
'instancename' => 'internal',
'priority' => 0,
'active' => 1,
'institution' => $newinstitution->name,
'authname' => 'internal',
);
......
......@@ -54,7 +54,7 @@ if (count($authinstances) > 0) {
}
}
if ($USER->get('admin')) {
$definst = get_field('auth_instance', 'id', 'institution', 'mahara');
$definst = get_field('auth_instance', 'id', 'institution', 'mahara', 'active', 1);
$default = $definst ? $definst : key($options);
}
else {
......@@ -184,7 +184,7 @@ function uploadcsv_validate(Pieform $form, $values) {
require_once('csvfile.php');
$authinstance = (int) $values['authinstance'];
$institution = get_field('auth_instance', 'institution', 'id', $authinstance);
$institution = get_field('auth_instance', 'institution', 'id', $authinstance, 'active', 1);
if (!$USER->can_edit_institution($institution)) {
$form->set_error('authinstance', get_string('notadminforinstitution', 'admin'));
return;
......@@ -461,7 +461,10 @@ function uploadcsv_submit(Pieform $form, $values) {
$formatkeylookup = array_flip($FORMAT);
$authinstance = (int) $values['authinstance'];
$authrecord = get_record('auth_instance', 'id', $authinstance);
$authrecord = get_record('auth_instance', 'id', $authinstance, 'active', 1);
if (!$authrecord) {
throw new InvalidArgumentException("trying to add user to inactive auth instance {$authinstance}");
}
$authobj = AuthFactory::create($authinstance);
$institution = new Institution($authobj->institution);
......
......@@ -124,6 +124,7 @@ HTML
$todb = new stdClass();
$todb->instancename = 'internal';
$todb->authname = 'internal';
$todb->active = 1;
$todb->institution = $authinst->institution;
$todb->priority = $authinst->priority;
$internal = insert_record('auth_instance', $todb, 'id', true);
......
......@@ -121,7 +121,7 @@ class AuthImap extends Auth {
*/
class PluginAuthImap extends PluginAuth {
private static $default_config = array('host'=>'', 'port'=>'143', 'protocol'=>'/imap', 'domainname'=>'', 'changepasswordurl'=>'', 'weautocreateusers'=>'');
private static $default_config = array('host'=>'', 'port'=>'143', 'protocol'=>'/imap', 'domainname'=>'', 'changepasswordurl'=>'', 'weautocreateusers'=>'', 'active' => 1);
public static function has_config() {
return false;
......@@ -163,6 +163,7 @@ class PluginAuthImap extends PluginAuth {
self::$default_config[$key] = $current_config[$key];
}
}
self::$default_config['active'] = $default->active;
} else {
$default = new stdClass();
$default->instancename = '';
......@@ -177,6 +178,12 @@ class PluginAuthImap extends PluginAuth {
'defaultvalue' => $default->instancename
);
$elements['active'] = array(
'type' => 'switchbox',
'title' => get_string('active', 'auth'),
'defaultvalue' => (int) self::$default_config['active'],
);
$elements['instance'] = array(
'type' => 'hidden',
'value' => $instance
......@@ -279,6 +286,7 @@ class PluginAuthImap extends PluginAuth {
$authinstance->instancename = $values['instancename'];
$authinstance->institution = $values['institution'];
$authinstance->authname = $values['authname'];
$authinstance->active = $values['active'];
if ($values['create']) {
$values['instance'] = insert_record('auth_instance', $authinstance, 'id', true);
......
......@@ -1601,6 +1601,7 @@ class PluginAuthLdap extends PluginAuth {
'syncgroupsbyuserfield' => false,
'syncgroupsuserattribute' => '',
'syncgroupsusergroupnames' => '',
'active' => 1
);
public static function get_cron() {
......@@ -1623,13 +1624,15 @@ class PluginAuthLdap extends PluginAuth {
return;
}
foreach ($auths as $auth) {
/* @var $authobj AuthLdap */
$authobj = AuthFactory::create($auth->id);
// Each instance will decide for itself whether it should sync users and/or groups
// User sync needs to be called before group sync in order for new users to wind
// up in the correct groups
$authobj->sync_users();
$authobj->sync_groups();
if ($auth->active == '1') {
/* @var $authobj AuthLdap */
$authobj = AuthFactory::create($auth->id);
// Each instance will decide for itself whether it should sync users and/or groups
// User sync needs to be called before group sync in order for new users to wind
// up in the correct groups
$authobj->sync_users();
$authobj->sync_groups();
}
}
}
......@@ -1682,6 +1685,7 @@ class PluginAuthLdap extends PluginAuth {
self::$default_config[$key] = $current_config[$key];
}
}
self::$default_config['active'] = $default->active;
} else {
$default = new stdClass();
$default->instancename = '';
......@@ -1711,6 +1715,11 @@ class PluginAuthLdap extends PluginAuth {
'type' => 'hidden',
'value' => 'ldap',
),
'active' => array(
'type' => 'switchbox',
'title' => get_string('active', 'auth'),
'defaultvalue' => (int) self::$default_config['active'],
),
'host_url' => array(
'type' => 'text',
'title' => get_string('hosturl', 'auth.ldap'),
......
......@@ -72,6 +72,7 @@ abstract class Auth {
protected $instancename;
protected $priority;
protected $authname;
protected $active;
protected $config;
protected $has_instance_config;
protected $type;
......@@ -109,6 +110,7 @@ abstract class Auth {
$this->institution = $instance->institution;
$this->instancename = $instance->instancename;
$this->priority = $instance->priority;
$this->active = $instance->active;
$this->authname = $instance->authname;
// Return now if the plugin type doesn't require any config
......@@ -534,7 +536,8 @@ function auth_get_auth_instances() {
inst.name,
inst.displayname,
i.instancename,
i.authname
i.authname,
i.active
FROM
{institution} inst,
{auth_instance} i
......@@ -570,7 +573,8 @@ function auth_get_auth_instances_for_institutions($institutions) {
inst.name,
inst.displayname,
i.instancename,
i.authname
i.authname,
i.active
FROM
{institution} inst,
{auth_instance} i
......@@ -611,6 +615,7 @@ function auth_get_auth_instances_for_institution($institution=null) {
i.instancename,
i.priority,
i.authname,
i.active,
a.requires_config,
a.requires_parent
FROM
......@@ -643,6 +648,7 @@ function auth_get_auth_instances_for_wwwroot($wwwroot) {
$query = " SELECT
ai.id,
ai.authname,
ai.active,
i.id as institutionid,
i.displayname,
i.suspended
......@@ -1378,8 +1384,12 @@ function auth_get_enabled_auth_plugins() {
{auth_installed} inst ON inst.name = ai.authname
WHERE
i.suspended = 0 AND
inst.active = 1
ORDER BY authname';
inst.active = 1';
if (get_config('version') >= '2016111000') {
// we added a new column auth_instance.active so check for $version to avoid error messages on upgrade
$sql .= ' AND ai.active = 1';
}
$sql .= ' ORDER BY authname';
$authplugins = get_column_sql($sql);
$usableplugins = array();
......@@ -1483,7 +1493,7 @@ function login_submit(Pieform $form, $values) {
$authinstances = get_records_sql_array("
SELECT a.id, a.instancename, a.priority, a.authname, a.institution, i.suspended, i.displayname
FROM {institution} i JOIN {auth_instance} a ON a.institution = i.name
WHERE a.authname != 'internal'
WHERE a.authname != 'internal' AND a.active = 1
ORDER BY a.institution, a.priority, a.instancename", array());
if ($authinstances == false) {
......@@ -1677,12 +1687,13 @@ function ensure_user_account_is_active($user=null) {
// make sure their authinstance is not set to the suspended/expired institution
// otherwise they will not be able to login (administer via site).
$authinstance = get_record_sql('
SELECT i.suspended, CASE WHEN i.expiry < NOW() THEN 1 ELSE 0 END AS expired, i.displayname
SELECT i.suspended, CASE WHEN i.expiry < NOW() THEN 1 ELSE 0 END AS expired, i.displayname, a.active
FROM {institution} i JOIN {auth_instance} a ON a.institution = i.name
WHERE a.id = ?', array($user->authinstance));
if ($authinstance->suspended || $authinstance->expired) {
if ($authinstance->suspended || $authinstance->expired || !$authinstance->active) {
$sitename = get_config('sitename');
$state = ($authinstance->suspended) ? 'suspended' : 'expired';
$state = ($authinstane->active) ? $state : 'inactive';
throw new AccessTotallyDeniedException(get_string('accesstotallydenied_institution' . $state, 'mahara', $authinstance->displayname, $sitename));
return false;
}
......@@ -2119,6 +2130,7 @@ function auth_generate_registration_form($formname, $authname='internal', $goto)
{auth_instance} ai
WHERE
ai.authname = ? AND
ai.active = 1 AND
ai.institution = i.name AND
i.registerallowed = 1';
$institutions = get_records_sql_array($sql, array($authname));
......@@ -2401,7 +2413,7 @@ function auth_register_submit(Pieform $form, $values) {
// @todo the expiry date should be configurable
if ($confirm = (get_config('requireregistrationconfirm') || get_field('institution', 'registerconfirm', 'name', $values['institution']))) {
if (isset($values['authtype']) && $values['authtype'] != 'internal') {
$authinstance = get_record('auth_instance', 'institution', $values['institution'], 'authname', $values['authtype'] ? $values['authtype'] : 'internal');
$authinstance = get_record('auth_instance', 'institution', $values['institution'], 'authname', $values['authtype'] ? $values['authtype'] : 'internal', 'active', 1);
$auth = AuthFactory::create($authinstance->id);
$confirm = !$auth->weautocreateusers;
}
......
......@@ -17,7 +17,8 @@
<FIELD NAME="instancename" TYPE="char" LENGTH="255" NOTNULL="true" />
<FIELD NAME="priority" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" />
<FIELD NAME="institution" TYPE="char" LENGTH="255" NOTNULL="true" />
<FIELD NAME="authname" TYPE="char" LENGTH="255" NOTNULL="true" />
<FIELD NAME="authname" TYPE="char" LENGTH="255" NOTNULL="true" />
<FIELD NAME="active" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" />
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
......
......@@ -263,7 +263,7 @@ function auth_saml_find_authinstance($saml_attributes) {
$institutions = array();
// find all the possible institutions/auth instances of type saml
$instances = recordset_to_array(get_recordset_sql("SELECT * FROM {auth_instance_config} aic, {auth_instance} ai WHERE ai.id = aic.instance AND ai.authname = 'saml' AND aic.field = 'institutionattribute'"));
$instances = recordset_to_array(get_recordset_sql("SELECT * FROM {auth_instance_config} aic, {auth_instance} ai WHERE ai.id = aic.instance AND ai.authname = 'saml' AND ai.active = 1 AND aic.field = 'institutionattribute'"));
foreach ($instances as $row) {
$institutions[]= $row->instance . ':' . $row->institution . ':' . $row->value;
if (isset($saml_attributes[$row->value])) {
......@@ -551,10 +551,10 @@ function login_test_all_user_authinstance($username, $password) {
// internal, or ldap - definitely NOT none, saml, or xmlrpc
$instances = array();
// all other candidtate auth_instances
// all other candidate auth_instances
$sql = 'SELECT ai.* from {auth_instance} ai INNER JOIN {auth_remote_user} aru
ON ai.id = aru.authinstance
WHERE ai.authname NOT IN(\'saml\', \'xmlrpc\', \'none\') AND aru.localusr = ?';
WHERE ai.active = 1 AND ai.authname NOT IN(\'saml\', \'xmlrpc\', \'none\') AND aru.localusr = ?';
$authinstances = get_records_sql_array($sql, array($user->id));
foreach ($authinstances as $authinstance) {
$instances[]= $authinstance->id;
......@@ -562,7 +562,7 @@ function login_test_all_user_authinstance($username, $password) {
// determine the internal authinstance ID associated with the base 'mahara'
// 'no institution' - use this is a default fallback login attempt
$authinstance = get_record('auth_instance', 'institution', 'mahara', 'authname', 'internal');
$authinstance = get_record('auth_instance', 'institution', 'mahara', 'authname', 'internal', 'active', 1);
$instances[]= $authinstance->id;
// test each auth_instance candidate associated with this user
......
......@@ -287,6 +287,7 @@ class PluginAuthSaml extends PluginAuth {
'institutionregex' => 0,
'remoteuser' => 1,
'loginlink' => 0,
'active' => 1
);
public static function can_be_disabled() {
......@@ -516,18 +517,20 @@ class PluginAuthSaml extends PluginAuth {
if ($current_config == false) {
$current_config = array();
}
foreach (self::$default_config as $key => $value) {
if (array_key_exists($key, $current_config)) {
self::$default_config[$key] = $current_config[$key];
}
}
if(empty(self::$default_config['institutionvalue'])) {
if (empty(self::$default_config['institutionvalue'])) {
self::$default_config['institutionvalue'] = $institution;
}
} else {
self::$default_config['active'] = $default->active;
}
else {
$default = new stdClass();
$default->instancename = '';
$default->active = 1;
}
// lookup the institution metadata
......@@ -577,6 +580,11 @@ class PluginAuthSaml extends PluginAuth {
'type' => 'hidden',
'value' => 'saml',
),
'active' => array(
'type' => 'switchbox',
'title' => get_string('active', 'auth'),
'defaultvalue' => (int) self::$default_config['active'],
),
'institutionidp' => array(
'type' => 'textarea',
'title' => $idp_title,
......@@ -767,6 +775,7 @@ class PluginAuthSaml extends PluginAuth {
$authinstance->institution = $values['institution'];
$authinstance->authname = $values['authname'];
$authinstance->active = (int) $values['active'];
$authinstance->instancename = $values['authname'];
if ($values['create']) {
......
......@@ -587,7 +587,8 @@ class PluginAuthXmlrpc extends PluginAuth {
'theyssoin' => 0,
'weimportcontent' => 0,
'parent' => null,
'authloginmsg' => ''
'authloginmsg' => '',
'active' => 1
);
public static function has_config() {
......@@ -667,18 +668,21 @@ class PluginAuthXmlrpc extends PluginAuth {
$peer->findByWwwroot($current_config[$key]);
self::$default_config['wwwroot_orig'] = $current_config[$key];
}
} elseif (property_exists($default, $key)) {
}
else if (property_exists($default, $key)) {
self::$default_config[$key] = $default->{$key};
}
}
} else {
}
else {
$max_priority = get_field('auth_instance', 'MAX(priority)', 'institution', $institution);
self::$default_config['priority'] = ++$max_priority;
}
if (empty($peer->application->name)) {
self::$default_config['appname'] = key(current($applicationset));
} else {
}
else {
self::$default_config['appname'] = $peer->application->name;
}
......@@ -692,6 +696,12 @@ class PluginAuthXmlrpc extends PluginAuth {
'help' => true
);
$elements['actve'] = array(
'type' => 'switchbox',
'title' => get_string('active', 'auth'),
'defaultvalue' => (int) self::$default_config['active'],
);
$elements['instance'] = array(
'type' => 'hidden',
'value' => $instance
......@@ -939,6 +949,7 @@ class PluginAuthXmlrpc extends PluginAuth {
$authinstance->instancename = $values['instancename'];
$authinstance->institution = $values['institution'];
$authinstance->authname = $values['authname'];
$authinstance->active = $values['active'];
if ($values['create']) {
$values['instance'] = insert_record('auth_instance', $authinstance, 'id', true);
......
......@@ -108,14 +108,14 @@ function forgotpass_validate(Pieform $form, $values) {
if (!$form->get_error('emailusername')) {
// Check if the user who associates to username or email address is using the external authentication
if (record_exists_sql('SELECT u.authinstance
FROM {usr} u INNER JOIN {auth_instance} ai ON (u.authinstance = ai.id)
FROM {usr} u INNER JOIN {auth_instance} ai ON (u.authinstance = ai.id AND ai.active = 1)
WHERE (LOWER(u.email) = ? OR LOWER(u.username) = ?)
AND ((ai.authname != \'internal\') AND (ai.authname != \'none\'))', array_fill(0, 2, strtolower($values['emailusername'])))) {
$form->set_error('emailusername', get_string('forgotpassuserusingexternalauthentication', 'mahara', get_config('wwwroot') . 'contact.php'));
}
else {
if (!($authinstance = get_field_sql('SELECT u.authinstance
FROM {usr} u INNER JOIN {auth_instance} ai ON (u.authinstance = ai.id)
FROM {usr} u INNER JOIN {auth_instance} ai ON (u.authinstance = ai.id AND ai.active = 1)
WHERE (LOWER(u.email) = ? OR LOWER(u.username) = ?)
AND ai.authname = \'internal\'', array_fill(0, 2, strtolower($values['emailusername']))))) {
$form->set_error('emailusername', get_string('forgotpassnosuchemailaddressorusername'));
......@@ -138,7 +138,7 @@ function forgotpass_submit(Pieform $form, $values) {
try {
if (!($user = get_record_sql('SELECT u.* FROM {usr} u
INNER JOIN {auth_instance} ai ON (u.authinstance = ai.id)
INNER JOIN {auth_instance} ai ON (u.authinstance = ai.id AND ai.active = 1)
WHERE (LOWER(u.email) = ? OR LOWER(u.username) = ?)
AND ai.authname = \'internal\'', array_fill(0, 2, strtolower($values['emailusername']))))) {
die_info(get_string('forgotpassnosuchemailaddressorusername'));
......
......@@ -43,6 +43,7 @@ $string['authloginmsg2'] = "When you have not chosen a parent authority, enter a
$string['application'] = 'Application';
$string['cantretrievekey'] = 'An error occurred while retrieving the public key from the remote server.<br>Please ensure that the Application and WWW root fields are correct and that networking is enabled on the remote host.';
$string['ssodirection'] = 'SSO direction';
$string['active'] = 'Active';
$string['errorcertificateinvalidwwwroot'] = 'This certificate claims to be for %s, but you are trying to use it for %s.';
$string['errorcouldnotgeneratenewsslkey'] = 'Could not generate a new SSL key. Are you sure that both openssl and the PHP module for openssl are installed on this machine?';
......
......@@ -247,6 +247,8 @@ $string['accesstotallydenied_institutionsuspended'] = 'Your institution %s has b
Please contact your institution for help.';
$string['accesstotallydenied_institutionexpired'] = 'Your institution %s has expired. Until it is unexpired, you will not be able to log in to %s.
Please contact your institution for help.';
$string['accesstotallydenied_institutioninactive'] = 'Your institution %s authenticcation method is inactive. Until it is made active, you will not be able to log in to %s.
Please contact your institution for help.';
$string['accessforbiddentoadminsection'] = 'You are forbidden from accessing the administration section.';
$string['accountdeleted'] = 'Sorry, your account has been deleted. You can <a href="%scontact.php">contact the site administrator</a>.';
$string['accountexpired'] = 'Sorry, your account has expired. You can <a href="%scontact.php">contact the site administrator</a> to have it reactivated.';
......
......@@ -4861,5 +4861,13 @@ function xmldb_core_upgrade($oldversion=0) {
bump_cache_version();
}
if ($oldversion < 2017012600) {
log_debug('Add "active" column to "auth_instance" table');
$table = new XMLDBTable('auth_instance');
$field = new XMLDBField('active');
$field->setAttributes(XMLDB_TYPE_INTEGER, 1, null, XMLDB_NOTNULL, null, null, null, 1);
add_field($table, $field);
}
return $status;
}
......@@ -579,7 +579,7 @@ class Institution {
// we can't find that, some other no institution auth.
$authinstances = get_records_select_assoc(
'auth_instance',
"institution IN ('mahara', ?)",
"institution IN ('mahara', ?) AND active = 1",
array($this->name),
"institution = 'mahara' DESC, authname = 'internal' DESC"
);
......
......@@ -245,7 +245,7 @@ EOD;
* @return int new user id.
*/
protected function create_test_user($userdata = null, $institution = null) {
$authinstance = get_record('auth_instance', 'institution', 'mahara');
$authinstance = get_record('auth_instance', 'institution', 'mahara', 'active', 1);
$testdata = array(
'username' => 'test' . count($this->testusers),
'email' => 'test' . count($this->testusers) . '@localhost',
......
......@@ -743,6 +743,7 @@ function core_install_lastcoredata_defaults() {
$auth_instance->priority='1';
$auth_instance->institution = 'mahara';
$auth_instance->authname = 'internal';
$auth_instance->active = 1;
$auth_instance->id = insert_record('auth_instance', $auth_instance, 'id', true);
// Insert the root user
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment