$this->get_sitename() . ': Authentication problem'));
}
}
/**
* We tried to call a method on an auth plugin that hasn't been init'ed
* successfully
*/
class UninitialisedAuthException extends SystemException {}
/**
* We tried creating automatically creating an account for a user but
* it failed for a reason that the user might want to know about
* (e.g. they used an email address that's already used on the site)
*/
class AccountAutoCreationException extends AuthInstanceException {
public function strings() {
return array_merge(parent::strings(),
array('message' => 'The automatic creation of your user account failed.'
. "\nDetails if any, follow:"));
}
}
/**
* Base authentication class. Provides a common interface with which
* authentication can be carried out for system users.
*
* @todo for authentication:
* - inactivity: each institution has inactivity timeout times, this needs
* to be supported
* - this means the lastlogin field needs to be updated on the usr table
* - warnings are handled by cron
*/
abstract class Auth {
protected $instanceid;
protected $institution;
protected $instancename;
protected $priority;
protected $authname;
protected $config;
protected $has_instance_config;
protected $type;
protected $ready;
/**
* Given an id, create the auth object and retrieve the config settings
* If an instance ID is provided, get all the *instance* config settings
*
* @param int $id The unique ID of the auth instance
* @return bool Whether the create was successful
*/
public function __construct($id = null) {
$this->ready = false;
}
/**
* Instantiate the plugin by pulling the config data for an instance from
* the database
*
* @param int $id The unique ID of the auth instance
* @return bool Whether the create was successful
*/
public function init($id) {
if (!is_numeric($id) || intval($id) != $id) {
throw new UserNotFoundException();
}
$instance = get_record('auth_instance', 'id', $id);
if (empty($instance)) {
throw new UserNotFoundException();
}
$this->instanceid = $id;
$this->institution = $instance->institution;
$this->instancename = $instance->instancename;
$this->priority = $instance->priority;
$this->authname = $instance->authname;
// Return now if the plugin type doesn't require any config
// (e.g. internal)
if ($this->has_instance_config == false) {
return true;
}
$records = get_records_array('auth_instance_config', 'instance', $this->instanceid);
if ($records == false) {
return false;
}
foreach($records as $record) {
$this->config[$record->field] = $record->value;
}
return true;
}
/**
* The __get overloader is invoked when the requested member is private or
* protected, or just doesn't exist.
*
* @param string $name The name of the value to fetch
* @return mixed The value
*/
public function __get($name) {
$approved_members = array('instanceid', 'institution', 'instancename', 'priority', 'authname', 'type');
if (in_array($name, $approved_members)) {
return $this->{$name};
}
if (isset($this->config[$name])) {
return $this->config[$name];
}
return null;
}
/**
* The __set overloader is invoked when the specified member is private or
* protected, or just doesn't exist.
*
* @param string $name The name of the value to set
* @param mixed $value The value to assign
* @return void
*/
public function __set($name, $value) {
/*
if (property_exists($this, $name)) {
$this->{$name} = $value;
return;
}
*/
throw new SystemException('It\'s forbidden to set values on Auth objects');
}
/**
* Check that the plugin has been initialised before we try to use it.
*
* @throws UninitialisedAuthException
* @return bool
*/
protected function must_be_ready() {
if ($this->ready == false) {
throw new UninitialisedAuthException('This Auth plugin has not been initialised');
}
return true;
}
/**
* Fetch the URL that users can visit to change their passwords. This might
* be a Moodle installation, for example.
*
* @return mixed URL to change password or false if there is none
*/
public function changepasswordurl() {
$this->must_be_ready();
if (empty($this->config['changepasswordurl'])) {
return false;
}
return $this->config['changepasswordurl'];
}
/**
* Given a username and password, attempts to log the user in.
*
* @param object $user An object with username member (at least)
* @param string $password The password to use for the attempt
* @return bool Whether the authentication was successful
* @throws AuthUnknownUserException If the user is unknown to the
* authentication method
*/
public function authenticate_user_account($user, $password) {
$this->must_be_ready();
return false;
}
/**
* Given a username, returns whether the user exists in the usr table
*
* @param string $username The username to attempt to identify
* @return bool Whether the username exists
*/
public function user_exists($username) {
$this->must_be_ready();
if (record_exists_select('usr', 'LOWER(username) = ?', array(strtolower($username)))) {
return true;
}
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();
/**
* If this plugin allows new user's to self-register, this function will be
* called to check whether it is okay to display a captcha method on the new
* user self-registration form.
*/
public static function can_use_registration_captcha() {
return true;
}
/**
* Given a username, returns a hash of information about a user from the
* external data source.
*
* @param string $username The username to look up information for
* @return array The information for the user
* @throws AuthUnknownUserException If the user is unknown to the
* authentication method
*/
public function get_user_info($username) {
return false;
}
/**
* Given a password, returns whether it is in a valid format for this
* authentication method.
*
* This only needs to be defined by subclasses if:
* - They implement the change_password method, which means that the
* system can use the passwordchange flag on the usr
* table to control whether the user's password needs changing.
* - The password that a user can set must be in a certain format.
*
* The default behaviour is to assume that the password is in a valid form,
* so make sure to implement this method if this is not the case!
*
* This method is defined to be empty, so that authentication methods do
* not have to specify a format if they do not need to.
*
* @param string $password The password to check
* @return bool Whether the username is in valid form.
*/
public function is_password_valid($password) {
return true;
}
/**
* Called when a user is being logged in, after the main authentication routines.
*
* You can use $USER->login() to perform any additional tasks, for example
* to set a cookie that another application can read, or pull some data
* from somewhere.
*
* This method has no parameters and needs no return value
*/
public function login() {
}
/**
* Called when a user is being logged out, either by clicking a logout
* link, their session timing out or some other method where their session
* is explicitly being ended with no more processing to take place on this
* page load.
*
* You can use $USER->logout() to log a user out but continue page
* processing if necessary. register.php is an example of such a place
* where this happens.
*
* If you define this hook, you can call $USER->logout() in it if you need
* to before redirecting. Otherwise, it will be called for you once your
* hook has run.
*
* If you do not explicitly redirect yourself, once this hook is finished
* the user will be redirected to the homepage with a message saying they
* have been logged out successfully.
*
* This method has no parameters and needs no return value
*/
public function logout() {
}
/**
* Indicates whether this auth instance is parent to another auth instance
* @return boolean (For backwards-compatibility reasons, it actually returns $this or null)
*/
public function is_parent_authority() {
if (count_records('auth_instance_config', 'field', 'parent', 'value', $this->instanceid)) {
return $this;
}
else {
return null;
}
}
/**
* Returns the ID of this instance's parent authority; or FALSE if it has no parent authority
* @return int|false
*/
public function get_parent_authority() {
return get_field('auth_instance_config', 'value', 'instance', $this->id, 'field', 'parent');
}
/**
* Indicates whether or not this auth instance uses the remote username. Most auth instances
* will only use it if they are the parent to another auth instance.
*/
public function needs_remote_username() {
return (boolean) $this->is_parent_authority();
}
}
/******************************************************************************/
// End of Auth base-class
/******************************************************************************/
/**
* Handles authentication by setting up a session for a user if they are logged
* in.
*
* This function combined with the Session class is smart - if the user is not
* logged in then they do not get a session, which prevents simple curl hits
* or search engine crawls to a page from getting sessions they won't use.
*
* Once the user has a session, they keep it even if the log out, so it can
* be reused. The session does expire, but the expiry time is typically a week
* or more.
*
* If the user is not authenticated for this page, then this function will
* exit, printing the login page. Therefore, after including init.php, you can
* be sure that the user is logged in, or has a valid guest key. However, no
* testing is done to make sure the user has the required permissions to see
* the page.
*
*/
function auth_setup () {
global $SESSION, $USER;
// If the system is not installed, let the user through in the hope that
// they can fix this little problem :)
if (!get_config('installed')) {
$USER->logout();
return;
}
// Lock the site until core upgrades are done
require(get_config('libroot') . 'version.php');
$siteclosed = $config->version > get_config('version');
$disablelogin = $config->disablelogin;
if (!$siteclosed && get_config('forcelocalupgrades')) {
require(get_config('docroot') . 'local/version.php');
$siteclosed = $config->version > get_config('localversion');
}
$cfgsiteclosed = get_config('siteclosed');
if ($siteclosed && !$cfgsiteclosed || !$siteclosed && $cfgsiteclosed) {
// If the admin closed the site manually, open it automatically
// when an upgrade is successful.
if ($cfgsiteclosed && get_config('siteclosedbyadmin')) {
set_config('siteclosedbyadmin', false);
}
set_config('siteclosed', $siteclosed);
set_config('disablelogin', $disablelogin);
}
// Check the time that the session is set to log out. If the user does
// not have a session, this time will be 0.
$sessionlogouttime = $USER->get('logout_time');
// Need to doublecheck that the User's sessionid still has a match the usr_session table
// It can disappear if the current user has hacked the real user's account and the real user has
// reset the password clearing the session from usr_session.
$sessionexists = get_record('usr_session', 'usr', $USER->id, 'session', $USER->get('sessionid'));
$parentuser = $USER->get('parentuser');
if (($sessionlogouttime && isset($_GET['logout'])) || ($sessionexists === false && $USER->get('sessionid') != '' && empty($parentuser))) {
// Call the authinstance' logout hook
$authinstance = $SESSION->get('authinstance');
if ($authinstance) {
$authobj = AuthFactory::create($authinstance);
$authobj->logout();
}
else {
log_debug("Strange: user " . $USER->get('username') . " had no authinstance set in their session");
}
if (function_exists('local_logout')) {
local_logout();
}
$USER->logout();
$SESSION->add_ok_msg(get_string('loggedoutok'));
redirect();
}
if ($sessionlogouttime > time()) {
// The session is still active, so continue it.
// Make sure that if a user's admin status has changed, they're kicked
// out of the admin section
if (in_admin_section()) {
// Reload site admin/staff permissions
$realuser = get_record('usr', 'id', $USER->id, null, null, null, null, 'admin,staff');
if (!$USER->get('admin') && $realuser->admin) {
// The user has been made into an admin
$USER->admin = 1;
}
else if ($USER->get('admin') && !$realuser->admin) {
// The user's admin rights have been taken away
$USER->admin = 0;
}
if (!$USER->get('staff') && $realuser->staff) {
$USER->staff = 1;
}
else if ($USER->get('staff') && !$realuser->staff) {
$USER->staff = 0;
}
// Reload institutional admin/staff permissions
$USER->reset_institutions();
auth_check_admin_section();
}
$USER->renew();
auth_check_required_fields();
}
else if ($sessionlogouttime > 0) {
// The session timed out
$authinstance = $SESSION->get('authinstance');
if ($authinstance) {
$authobj = AuthFactory::create($authinstance);
$mnetuser = 0;
if ($SESSION->get('mnetuser') && $authobj->parent) {
// We wish to remember that the user is an MNET user - even though
// they're using the local login form
$mnetuser = $USER->get('id');
}
$authobj->logout();
$USER->logout();
if ($mnetuser != 0) {
$SESSION->set('mnetuser', $mnetuser);
$SESSION->set('authinstance', $authinstance);
}
}
else {
log_debug("Strange: user " . $USER->get('username') . " had no authinstance set in their session");
}
if (defined('JSON')) {
json_reply('global', get_string('sessiontimedoutreload'), 1);
}
if (defined('IFRAME')) {
header('Content-type: text/html');
print_auth_frame();
exit;
}
// If the page the user is viewing is public, inform them that they can
// log in again
if (defined('PUBLIC')) {
// @todo this links to ?login - later it should do magic to make
// sure that whatever GET string is made it includes the old data
// correctly
$loginurl = $_SERVER['REQUEST_URI'];
$loginurl .= (false === strpos($loginurl, '?')) ? '?' : '&';
$loginurl .= 'login';
$SESSION->add_info_msg(get_string('sessiontimedoutpublic', 'mahara', hsc($loginurl)), false);
return;
}
auth_draw_login_page(get_string('sessiontimedout'));
}
else {
// There is no session, so we check to see if one needs to be started.
// Build login form. If the form is submitted it will be handled here,
// and set $USER for us (this will happen when users hit a page and
// specify login data immediately
require_once('pieforms/pieform.php');
$form = new Pieform(auth_get_login_form());
if ($USER->is_logged_in()) {
return;
}
// Check if the page is public or the site is configured to be public.
if (defined('PUBLIC') && !isset($_GET['login'])) {
if ($lang = param_alphanumext('lang', null)) {
$SESSION->set('lang', $lang);
}
return;
}
// No session and a json request
if (defined('JSON')) {
json_reply('global', get_string('nosessionreload'), 1);
}
auth_draw_login_page(null, $form);
exit;
}
}
/**
*
* Returns all auth instances
*
* @return array Array of auth instance records
*/
function auth_get_auth_instances() {
static $cache = array();
if (count($cache) > 0) {
return $cache;
}
$sql ='
SELECT DISTINCT
i.id,
inst.name,
inst.displayname,
i.instancename,
i.authname
FROM
{institution} inst,
{auth_instance} i
WHERE
i.institution = inst.name
ORDER BY
inst.displayname,
i.instancename';
$cache = get_records_sql_array($sql, array());
if (empty($cache)) {
return array();
}
return $cache;
}
/**
*
* Given a list of institutions, returns all auth instances associated with them
*
* @return array Array of auth instance records
*/
function auth_get_auth_instances_for_institutions($institutions) {
if (empty($institutions)) {
return array();
}
$sql ='
SELECT DISTINCT
i.id,
inst.name,
inst.displayname,
i.instancename,
i.authname
FROM
{institution} inst,
{auth_instance} i
WHERE
i.institution = inst.name AND
inst.name IN (' . join(',', array_map('db_quote',$institutions)) . ')
ORDER BY
inst.displayname,
i.instancename';
return get_records_sql_array($sql, array());
}
/**
* Given an institution, returns the authentication methods used by it, sorted
* by priority.
*
* @param string $institution Name of the institution
* @return array Array of auth instance records
*/
function auth_get_auth_instances_for_institution($institution=null) {
static $cache = array();
if (null == $institution) {
return array();
}
if (!isset($cache[$institution])) {
// Get auth instances in order of priority
// DO NOT CHANGE THE SORT ORDER OF THIS RESULT SET
// YEAH EINSTEIN - THAT MEANS YOU!!!
// TODO: work out why this won't accept a placeholder - had to use db_quote
$sql ='
SELECT DISTINCT
i.id,
i.instancename,
i.priority,
i.authname,
a.requires_config,
a.requires_parent
FROM
{auth_instance} i,
{auth_installed} a
WHERE
a.name = i.authname AND
i.institution = '. db_quote($institution).'
ORDER BY
i.priority,
i.instancename';
$cache[$institution] = get_records_sql_array($sql, array());
if (empty($cache[$institution])) {
return false;
}
}
return $cache[$institution];
}
/**
* Given a wwwroot, find any auth instances that can come from that host
*
* @param string wwwroot of the host that is connecting to us
* @return array array of record objects
*/
function auth_get_auth_instances_for_wwwroot($wwwroot) {
// TODO: we just need ai.id and ai.authname... rewrite query, or
// just drop this function
$query = " SELECT
ai.*,
aic.*,
i.*
FROM
{auth_instance} ai,
{auth_instance_config} aic,
{institution} i
WHERE
aic.field = 'wwwroot' AND
aic.value = ? AND
aic.instance = ai.id AND
i.name = ai.institution";
return get_records_sql_array($query, array('value' => $wwwroot));
}
/**
* Given an institution, get all the auth types EXCEPT those that are already
* enabled AND do not require configuration.
*
* @param string $institution Name of the institution
* @return array Array of auth instance records
*/
function auth_get_available_auth_types($institution=null) {
if (!is_null($institution) && (!is_string($institution) || strlen($institution) > 255)) {
return array();
}
// TODO: work out why this won't accept a placeholder - had to use db_quote
$sql ='
SELECT DISTINCT
a.name,
a.requires_config
FROM
{auth_installed} a
LEFT JOIN
{auth_instance} i
ON
a.name = i.authname AND
i.institution = '. db_quote($institution).'
WHERE
(a.requires_config = 1 OR
i.id IS NULL) AND
a.active = 1
ORDER BY
a.name';
if (is_null($institution)) {
$result = get_records_array('auth_installed', '','','name','name, requires_config');
} else {
$result = get_records_sql_array($sql, array());
}
if (empty($result)) {
return array();
}
foreach ($result as &$row) {
$row->title = get_string('title', 'auth.' . $row->name);
safe_require('auth', $row->name);
if ($row->is_usable = call_static_method('PluginAuth' . $row->name, 'is_usable')) {
$row->description = get_string('description', 'auth.' . $row->name);
}
else {
$row->description = get_string('notusable', 'auth.' . $row->name);
}
}
usort($result, create_function('$a, $b', 'if ($a->is_usable != $b->is_usable) return $b->is_usable; return strnatcasecmp($a->title, $b->title);'));
return $result;
}
/**
* Checks that all the required fields are set, and handles setting them if required.
*
* Checks whether the current user needs to change their password, and handles
* the password changing if it's required.
*/
function auth_check_required_fields() {
global $USER, $SESSION;
if (defined('NOCHECKREQUIREDFIELDS')) {
return;
}
$changepassword = true;
$elements = array();
if (
!$USER->get('passwordchange') // User doesn't need to change their password
|| ($USER->get('parentuser') && $USER->get('loginanyway')) // User is masquerading and wants to log in anyway
|| defined('NOCHECKPASSWORDCHANGE') // The page wants to skip this hassle
) {
$changepassword = false;
}
// Check if the user wants to log in anyway
if ($USER->get('passwordchange') && $USER->get('parentuser') && isset($_GET['loginanyway'])) {
$USER->loginanyway = true;
$changepassword = false;
}
if ($changepassword) {
$authobj = AuthFactory::create($USER->authinstance);
if ($authobj->changepasswordurl) {
redirect($authobj->changepasswordurl);
exit;
}
if (method_exists($authobj, 'change_password')) {
if ($SESSION->get('resetusername')) {
$elements['username'] = array(
'type' => 'text',
'defaultvalue' => $USER->get('username'),
'title' => get_string('changeusername', 'account'),
'description' => get_string('changeusernamedesc', 'account', hsc(get_config('sitename'))),
);
}
$elements['password1'] = array(
'type' => 'password',
'title' => get_string('newpassword') . ':',
'description' => get_string('yournewpassword'),
'rules' => array(
'required' => true
)
);
$elements['password2'] = array(
'type' => 'password',
'title' => get_string('confirmpassword') . ':',
'description' => get_string('yournewpasswordagain'),
'rules' => array(
'required' => true,
),
);
$elements['email'] = array(
'type' => 'text',
'title' => get_string('principalemailaddress', 'artefact.internal'),
'ignore' => (trim($USER->get('email')) != '' && !preg_match('/@example\.org$/', $USER->get('email'))),
'rules' => array(
'required' => true,
'email' => true,
),
);
}
}
else if (defined('JSON')) {
// Don't need to check this for json requests
return;
}
safe_require('artefact', 'internal');
require_once('pieforms/pieform.php');
$alwaysmandatoryfields = array_keys(ArtefactTypeProfile::get_always_mandatory_fields());
foreach(ArtefactTypeProfile::get_mandatory_fields() as $field => $type) {
// Always mandatory fields are stored in the usr table, so are part of
// the user session object. We can save a query by grabbing them from
// the session.
if (in_array($field, $alwaysmandatoryfields) && $USER->get($field) != null) {
continue;
}
// Not cached? Get value the standard way.
if (get_profile_field($USER->get('id'), $field) != null) {
continue;
}
if ($field == 'email') {
if (isset($elements['email'])) {
continue;
}
// Use a text field for their first e-mail address, not the
// emaillist element
$type = 'text';
}
$elements[$field] = array(
'type' => $type,
'title' => get_string($field, 'artefact.internal'),
'rules' => array('required' => true)
);
// @todo ruthlessly stolen from artefact/internal/index.php, could be merged
if ($type == 'wysiwyg') {
$elements[$field]['rows'] = 10;
$elements[$field]['cols'] = 60;
}
if ($type == 'textarea') {
$elements[$field]['rows'] = 4;
$elements[$field]['cols'] = 60;
}
if ($field == 'country') {
$elements[$field]['options'] = getoptions_country();
$elements[$field]['defaultvalue'] = get_config('country');
}
if ($field == 'email') {
// Check if a validation email has been sent
if (record_exists('artefact_internal_profile_email', 'owner', $USER->get('id'))) {
$elements['email']['type'] = 'html';
$elements['email']['value'] = get_string('validationprimaryemailsent', 'auth');
$elements['email']['disabled'] = true;
$elements['email']['rules'] = array('required' => false);
}
else {
$elements[$field]['rules']['email'] = true;
$elements[$field]['description'] = get_string('primaryemaildescription', 'auth');
}
}
}
if (empty($elements)) { // No mandatory fields that aren't set
return;
}
if ((count($elements) == 1) && isset($elements['email']) && ($elements['email']['type'] == 'html')) {
// Display a message if there is only 1 required field and this field is email whose validation has been sent
$elements['submit'] = array(
'type' => 'submit',
'value' => get_string('continue', 'admin')
);
$form = pieform(array(
'name' => 'requiredfields',
'method' => 'post',
'action' => get_config('wwwroot') . '?logout',
'elements' => $elements
));
}
else {
$elements['submit'] = array(
'type' => 'submit',
'value' => get_string('submit')
);
$form = pieform(array(
'name' => 'requiredfields',
'method' => 'post',
'action' => '',
'elements' => $elements
));
}
$smarty = smarty();
if ($USER->get('parentuser')) {
$smarty->assign('loginasoverridepasswordchange',
get_string('loginasoverridepasswordchange', 'admin',
'', ''));
}
$smarty->assign('changepassword', $changepassword);
$smarty->assign('changeusername', $SESSION->get('resetusername'));
$smarty->assign('form', $form);
$smarty->display('requiredfields.tpl');
exit;
}
function requiredfields_validate(Pieform $form, $values) {
global $USER;
if (isset($values['password1'])) {
// Get the authentication type for the user, and
// use the information to validate the password
$authobj = AuthFactory::create($USER->authinstance);
// @todo this could be done by a custom form rule... 'password' => $user
password_validate($form, $values, $USER);
// The password cannot be the same as the old one
try {
if (!$form->get_error('password1')
&& $authobj->authenticate_user_account($USER, $values['password1'])) {
$form->set_error('password1', get_string('passwordnotchanged'));
}
}
// propagate error up as the collective error AuthUnknownUserException
catch (AuthInstanceException $e) {
$form->set_error('password1', $e->getMessage());
}
if ($authobj->authname == 'internal' && isset($values['username']) && $values['username'] != $USER->get('username')) {
if (!AuthInternal::is_username_valid($values['username'])) {
$form->set_error('username', get_string('usernameinvalidform', 'auth.internal'));
}
if (!$form->get_error('username') && record_exists_select('usr', 'LOWER(username) = ?', strtolower($values['username']))) {
$form->set_error('username', get_string('usernamealreadytaken', 'auth.internal'));
}
}
}
// Check if email has been taken
if (isset($values['email']) && record_exists('artefact_internal_profile_email', 'email', $values['email'])) {
$form->set_error('email', get_string('unvalidatedemailalreadytaken', 'artefact.internal'));
}
}
function requiredfields_submit(Pieform $form, $values) {
global $USER, $SESSION;
if (isset($values['password1'])) {
$authobj = AuthFactory::create($USER->authinstance);
// This method should exist, because if it did not then the change
// password form would not have been shown.
if ($password = $authobj->change_password($USER, $values['password1'])) {
$SESSION->add_ok_msg(get_string('passwordsaved'));
}
else {
throw new SystemException('Attempt by "' . $USER->get('username') . '@'
. $USER->get('institution') . 'to change their password failed');
}
}
if (isset($values['username'])) {
$SESSION->set('resetusername', false);
if ($values['username'] != $USER->get('username')) {
$USER->username = $values['username'];
$USER->commit();
$otherfield = true;
}
}
foreach ($values as $field => $value) {
if (in_array($field, array('submit', 'sesskey', 'password1', 'password2', 'username'))) {
continue;
}
if ($field == 'email') {
$email = $values['email'];
// Need to update the admin email on installation
if ($USER->get('admin')) {
$oldemail = get_field('usr', 'email', 'id', $USER->get('id'));
if ($oldemail == 'admin@example.org') {
// we are dealing with the dummy email that is set on install
update_record('usr', array('email' => $email), array('id' => $USER->get('id')));
update_record('artefact_internal_profile_email', array('email' => $email), array('owner' => $USER->get('id')));
}
}
// Check if a validation email has been sent, if not send one
if (!record_exists('artefact_internal_profile_email', 'owner', $USER->get('id'))) {
$key = get_random_key();
$key_url = get_config('wwwroot') . 'artefact/internal/validate.php?email=' . rawurlencode($email) . '&key=' . $key;
$key_url_decline = $key_url . '&decline=1';
try {
$sitename = get_config('sitename');
email_user(
(object)array(
'id' => $USER->get('id'),
'username' => $USER->get('username'),
'firstname' => $USER->get('firstname'),
'lastname' => $USER->get('lastname'),
'preferredname' => $USER->get('preferredname'),
'admin' => $USER->get('admin'),
'staff' => $USER->get('staff'),
'email' => $email,
),
null,
get_string('emailvalidation_subject', 'artefact.internal'),
get_string('emailvalidation_body1', 'artefact.internal', $USER->get('firstname'), $email, $sitename, $key_url, $sitename, $key_url_decline)
);
}
catch (EmailException $e) {
$SESSION->add_error_msg($email);
}
insert_record(
'artefact_internal_profile_email',
(object) array(
'owner' => $USER->get('id'),
'email' => $email,
'verified' => 0,
'principal' => 1,
'key' => $key,
'expiry' => db_format_timestamp(time() + 86400),
)
);
$SESSION->add_ok_msg(get_string('validationemailsent', 'artefact.internal'));
}
}
else {
set_profile_field($USER->get('id'), $field, $value);
$otherfield = true;
}
}
if (isset($otherfield)) {
$SESSION->add_ok_msg(get_string('requiredfieldsset', 'auth'));
}
// Update the title of user's first blog if first and/or last name have been changed
$updatedfields = array_keys($values);
if (in_array('firstname', $updatedfields) || in_array('lastname', $updatedfields)) {
safe_require('artefact', 'blog');
$userblogs = get_records_select_array('artefact', 'artefacttype = \'blog\' AND owner = ?', array($USER->get('id')));
if ($userblogs && count($userblogs) == 1) {
$defaultblog = new ArtefactTypeBlog($userblogs[0]->id);
$defaultblog->set('title', get_string('defaultblogtitle', 'artefact.blog', display_name($USER, null, true)));
$defaultblog->commit();
}
}
redirect();
}
/**
* Creates and displays the transient login page.
*
* This login page remembers all GET/POST data and passes it on. This way,
* users can have their sessions time out, and then can log in again without
* losing any of their data.
*
* As this function builds and validates a login form, it is possible that
* calling this may validate a user to be logged in.
*
* @param Pieform $form If specified, just build this form to get the HTML
* required. Otherwise, this function will build and
* validate the form itself.
* @access private
*/
function auth_draw_login_page($message=null, Pieform $form=null) {
global $USER, $SESSION;
if ($form != null) {
$loginform = get_login_form_js($form->build());
}
else {
require_once('pieforms/pieform.php');
$loginform = get_login_form_js(pieform(auth_get_login_form()));
/*
* If $USER is set, the form was submitted even before being built.
* This happens when a user's session times out and they resend post
* data. The request should just continue if so.
*/
if ($USER->is_logged_in()) {
return;
}
}
$externallogin = get_config('externallogin');
if ($externallogin) {
$externallogin = preg_replace('/{shorturlencoded}/', urlencode(get_relative_script_path()), $externallogin);
$externallogin = preg_replace('/{wwwroot}/', get_config('wwwroot'), $externallogin);
redirect($externallogin);
}
if ($message) {
$SESSION->add_info_msg($message);
}
$smarty = smarty(array(), array(), array(), array('pagehelp' => false, 'sidebars' => false));
$smarty->assign('login_form', $loginform);
$smarty->assign('PAGEHEADING', get_string('loginto', 'mahara', get_config('sitename')));
$smarty->assign('LOGINPAGE', true);
$smarty->display('login.tpl');
exit;
}
/**
* Returns the definition of the login form, for display on the transient login page.
*
* @return array The login form definition array.
* @access private
*/
function auth_get_login_form() {
$elements = auth_get_login_form_elements();
$elements['login']['elements']['login_submitted'] = array(
'type' => 'hidden',
'value' => 1
);
// Change login redirection for clean urls
$url = get_relative_script_path();
$getstart = strrpos($url, '?');
if ($getstart !== false) {
$getpart = substr($url, $getstart + 1);
$url = substr($url, 0, $getstart);
}
if (!file_exists(get_config('docroot') . $url)) {
// clean url, treat get string differently
$get = array();
if (isset($getpart)) {
$getarr = explode('&', $getpart);
if ($getarr) {
foreach ($getarr as $data) {
$arr = explode('=', $data);
$get[$arr[0]] = isset($arr[1]) ? $arr[1] : null;
}
}
}
}
else {
$get = $_GET;
}
// The login page is completely transient, and it is smart because it
// remembers the GET and POST data sent to it and resends that on
// afterwards.
$action = '';
if ($get) {
if (isset($get['logout'])) {
// You can log the user out on any particular page by appending
// ?logout to the URL. In this case, we don't want the "action"
// of the url to include that, or be blank, else the next time
// the user logs in they will be logged out again.
$action = hsc(substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?')));
}
else {
$action .= '?';
foreach ($get as $key => $value) {
if ($key != 'login') {
$action .= hsc($key) . '=' . hsc($value) . '&';
}
}
$action = substr($action, 0, -1);
}
}
if ($_POST) {
foreach ($_POST as $key => $value) {
if (!isset($elements[$key]) && !isset($elements['login']['elements'][$key])) {
$elements[$key] = array(
'type' => 'hidden',
'value' => $value
);
}
}
}
$form = array(
'name' => 'login',
'renderer' => 'div',
'method' => 'post',
'action' => $action,
'plugintype' => 'auth',
'pluginname' => 'internal',
'elements' => $elements,
'dieaftersubmit' => false,
'iscancellable' => false
);
return $form;
}
/**
* Returns the definition of the login form elements.
*
* @return array The login form elements array.
* @access private
*/
function auth_get_login_form_elements() {
// See if user can register
if (count_records('institution', 'registerallowed', 1, 'suspended', 0)) {
$registerlink = '' . get_string('register') . '
';
}
else {
$registerlink = '';
}
$elements = array(
'login_username' => array(
'type' => 'text',
'title' => get_string('username') . ':',
'description' => get_string('usernamedescription'),
'defaultvalue' => (isset($_POST['login_username'])) ? $_POST['login_username'] : '',
'rules' => array(
'required' => true
)
),
'login_password' => array(
'type' => 'password',
'title' => get_string('password') . ':',
'description' => get_string('passworddescription'),
'defaultvalue' => '',
'rules' => array(
'required' => true
)
),
'submit' => array(
'type' => 'submit',
'value' => get_string('login')
),
'register' => array(
'type' => 'markup',
'value' => '