Commit f782dbf9 authored by Nigel McNie's avatar Nigel McNie

Lets authentication plugins trigger the creation of users if the plugin can authenticate them.

If an authentication plugin thinks that a user should be able to log in, and furthermore thinks that it is able/allowed to automatically create user accounts, then it is now able to do just that. The authentication API now has a new method - can_auto_create_users() - to define whether each authentication instance feels it can/should be able to do this.

If the instance thinks it can, it needs to export some information through the get_user_info method in order to populate the user account. Although this may change shortly to be optional, with the users instead being forced to enter any information that is required that they haven't otherwise filled out.
parent db407597
......@@ -100,6 +100,13 @@ class AuthImap extends Auth {
return false; // No match
}
/**
* Imap doesn't export enough information to be able to auto-create users
*/
public function can_auto_create_users() {
return false;
}
}
/**
......@@ -277,4 +284,4 @@ class PluginAuthImap extends PluginAuth {
}
}
?>
\ No newline at end of file
?>
......@@ -61,6 +61,14 @@ class AuthInternal extends Auth {
return $this->validate_password($password, $user->password, $user->salt);
}
/**
* Internal authentication never auto-creates users - users instead
* register through register.php
*/
public function can_auto_create_users() {
return false;
}
/**
* For internal authentication, passwords can contain a range of letters,
* numbers and symbols. There is a minimum limit of six characters allowed
......@@ -201,4 +209,4 @@ class PluginAuthInternal extends PluginAuth {
}
}
?>
\ No newline at end of file
?>
......@@ -208,9 +208,31 @@ abstract class Auth {
throw new AuthUnknownUserException("\"$username\" is not known to Auth");
}
/**
* Returns whether the authentication instance can automatically create a
* user record.
*
* Auto creating users means that the authentication plugin can say that
* users who don't exist yet in Mahara's usr table are allowed, and Mahara
* should create a user account for them. Example: the first time a user logs
* in, when authenticating against an ldap store or similar).
*
* However, if a plugin says a user can be authenticated, then it must
* implement the get_user_info() method which will be called to find out
* information about the user so a record in the usr table _can_ be created
* for the new user.
*
* Authentication methods must implement this method. Some may choose to
* implement it by returning an instance config value that the admin user
* can set.
*
* @return bool
*/
public abstract function can_auto_create_users();
/**
* Given a username, returns a hash of information about a user from the
* external data source, e.g. Moodle or Drupal.
* external data source.
*
* @param string $username The username to look up information for
* @return array The information for the user
......@@ -962,7 +984,6 @@ function login_submit(Pieform $form, $values) {
$oldlastlogin = 0;
try {
//var_dump(array($username, $password, $institution, $_SESSION));
$authenticated = $USER->login($username, $password);
if (empty($authenticated)) {
......@@ -971,13 +992,17 @@ function login_submit(Pieform $form, $values) {
}
catch (AuthUnknownUserException $e) {
// If the user doesn't exist, check for institutions that
// want to create users automatically.
try {
// If the user doesn't exist, check for institutions that
// want to create users automatically.
// Reset the LiveUser object, since we are attempting to create a
// new user
session_destroy();
$USER = new LiveUser();
$authinstances = get_records_sql_array('
SELECT a.id, a.instancename, a.priority, a.authname, a.institution
FROM {institution} i JOIN {auth_instance} a ON a.institution = i.name
WHERE i.updateuserinfoonlogin = 1
ORDER BY a.institution, a.priority, a.instancename', null);
if ($authinstances == false) {
......@@ -986,57 +1011,72 @@ function login_submit(Pieform $form, $values) {
$USER->username = $username;
foreach ($authinstances as $authinstance) {
reset($authinstances);
while ((list(, $authinstance) = each($authinstances)) && false == $authenticated) {
$auth = AuthFactory::create($authinstance->id);
if (!$auth->can_auto_create_users()) {
continue;
}
if ($auth->authenticate_user_account($USER, $password)) {
$authenticated = true;
} else {
continue;
}
while (list(, $authinstance) = each($authinstances) && false == $authenticated) {
// TODO: Test this code with an auth plugin that provides a
// get_user_info method
$auth = AuthFactory::create($authinstance->id);
if ($auth->authenticate_user_account($USER, $password)) {
$authenticated = true;
} else {
continue;
}
// Check now to see if the institution has its maximum quota of users
require_once('institution.php');
$institution = new Institution($authinstance->institution);
if ($institution->isFull()) {
throw new AuthUnknownUserException('Institution has too many users');
}
$USER->authinstance = $authinstance->id;
$userdata = $auth->get_user_info();
if (
empty($userdata) ||
empty($userdata->firstname) ||
empty($userdata->lastname) ||
empty($userdata->email)
) {
throw new AuthUnknownUserException("\"$username\" is not known");
} else {
// We have the data - create the user
$USER->expiry = db_format_timestamp(time() + 86400);
$USER->lastlogin = db_format_timestamp(time());
$USER->firstname = $userdata->firstname;
$USER->lastname = $userdata->lastname;
$USER->email = $userdata->email;
try {
db_begin();
$USER->commit();
if ($authinstance->institution !== 'mahara') {
$USER->join_institution($authinstance->institution);
}
handle_event('createuser', $USER);
db_commit();
}
catch (Exception $e) {
db_rollback();
throw $e;
$USER->authinstance = $authinstance->id;
$userdata = $auth->get_user_info($username);
if (
empty($userdata) ||
empty($userdata->firstname) ||
empty($userdata->lastname) ||
empty($userdata->email)
) {
throw new AuthUnknownUserException("\"$username\" is not known");
} else {
// We have the data - create the user
$USER->lastlogin = db_format_timestamp(time());
$USER->firstname = $userdata->firstname;
$USER->lastname = $userdata->lastname;
$USER->email = $userdata->email;
try {
db_begin();
$USER->commit();
set_profile_field($USER->id, 'firstname', $USER->firstname);
set_profile_field($USER->id, 'lastname', $USER->lastname);
set_profile_field($USER->id, 'email', $USER->email);
if ($authinstance->institution !== 'mahara') {
$USER->join_institution($authinstance->institution);
}
handle_event('createuser', $USER->to_stdclass());
db_commit();
$USER->reanimate($USER->id, $authinstance->id);
}
catch (Exception $e) {
db_rollback();
throw $e;
}
}
}
if (!$authenticated) {
$SESSION->add_error_msg(get_string('loginfailed'));
return;
}
}
catch (AuthUnknownUserException $e) {
$SESSION->add_error_msg(get_string('loginfailed'));
return;
}
}
......
......@@ -347,22 +347,13 @@ class AuthXmlrpc extends Auth {
}
/**
* Given a user that we know about, return an array of information about them
*
* Used when a user who was otherwise unknown authenticates successfully,
* or if getting userinfo on each login is enabled for this auth method.
*
* Does not need to be implemented for the internal authentication method,
* because all users are already known about.
* In practice, I don't think this method needs to return an accurate
* answer for this, because XMLRPC authentication doesn't use the standard
* authentication mechanisms, instead relying on land.php to handle
* everything.
*/
public function get_user_info($username) {
$this->must_be_ready();
$userdata = parent::get_user_info_cached($username);
/**
* Here, we will sift through the data returned by the XMLRPC server
* and update any userdata properties that have changed
*/
public function can_auto_create_users() {
return (bool)$this->config['weautocreateusers'];
}
/**
......
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