Commit 874d5ae9 authored by Richard Mansfield's avatar Richard Mansfield
Browse files
parents d356510d c85bca90
......@@ -37,6 +37,7 @@ if ($install) {
if (!get_config('installed')) {
try {
// Install the default institution
// @todo Transaction!!!
$institution = new StdClass;
$institution->name = 'mahara';
$institution->displayname = 'No Institution';
......
......@@ -185,7 +185,6 @@ function auth_setup () {
// they can fix this little problem :)
if (!get_config('installed')) {
$SESSION->logout();
log_debug('system not installed, letting user through');
return;
}
......@@ -289,7 +288,7 @@ function auth_check_password_change() {
if (
($url = get_config_plugin('auth', $authtype, 'changepasswordurl'))
|| (method_exists($authclass, 'change_password'))) {
log_debug('user DOES need to change their password');
log_debug('user needs to change their password');
if ($url) {
redirect($url);
exit;
......@@ -297,28 +296,34 @@ function auth_check_password_change() {
require_once('form.php');
$form = array(
'name' => 'change_password',
'method' => 'post',
'elements' => array(
'password1' => array(
'type' => 'password',
'title' => 'New Password:',
'description' => 'Your new password',
'rules' => array(
'required' => true
)
),
'password2' => array(
'type' => 'password',
'title' => 'Confirm Password:',
'description' => 'Your new password again',
'rules' => array(
'required' => true
'name' => 'change_password',
'method' => 'post',
'elements' => array(
'passwords' => array(
'type' => 'fieldset',
'legend' => get_string('newpassword'),
'elements' => array(
'password1' => array(
'type' => 'password',
'title' => get_string('newpassword') . ':',
'description' => get_string('yournewpassword'),
'rules' => array(
'required' => true
)
),
'password2' => array(
'type' => 'password',
'title' => get_string('confirmpassword') . ':',
'description' => get_string('yournewpasswordagain'),
'rules' => array(
'required' => true
)
)
)
),
'submit' => array(
'type' => 'submit',
'value' => 'Change Password'
'type' => 'submit',
'value' => get_string('changepassword')
)
)
);
......@@ -333,22 +338,7 @@ function auth_check_password_change() {
/**
* Validates the form for changing the password for a user.
*
* This only applies to the internal authentication plugin.
*
* @todo As far as I can tell, the change password and registration forms will
* only be used for internal authentication. And so, by proxy, will the
* username/password valid methods for the Auth class. [THIS IS TRUE]
*
*
* I think this means they can be removed from the Auth class, and instead just
* be part of AuthInternal since they don't need to be specified for other types.
* [THIS IS ALSO TRUE]
*
* Furthermore, I think that the change_password stuff (as well as suspended
* and expired) are also quite possibly related to internal only. This will
* require a lot of thought about how to best structure it.
*
* Change password will only be if a URL for it exists, or a function exists
* Change password will only be if a URL for it exists, or a function exists.
*
* @param Form $form The form to check
* @param array $values The values to check
......@@ -363,30 +353,14 @@ function change_password_validate(Form $form, $values) {
$authlang = 'auth.' . $authtype;
safe_require('auth', $authtype, 'lib.php', 'require_once');
// Check that the password is in valid form
if (!$form->get_error('password1')
&& !call_static_method($authclass, 'is_password_valid', $values['password1'])) {
$form->set_error('password1', get_string('passwordinvalidform', $authlang));
}
// The password must not be too easy :)
$suckypasswords = array(
'mahara', 'password', $USER->username
);
if (!$form->get_error('password1') && in_array($values['password1'], $suckypasswords)) {
$form->set_error('password1', get_string('passwordtooeasy'));
}
// @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
if (!$form->get_error('password1')
&& call_static_method($authclass, 'authenticate_user_account', $USER->username, $values['password1'], $USER->institution)) {
$form->set_error('password1', get_string('passwordnotchanged'));
}
// The passwords must match
if (!$form->get_error('password1') && !$form->get_error('password2') && $values['password1'] != $values['password2']) {
$form->set_error('password2', get_string('passwordsdonotmatch'));
}
}
/**
......@@ -416,7 +390,8 @@ function change_password_submit($values) {
exit;
}
throw new Exception('You are trying to change your password, but the attempt failed');
throw new Exception('Attempt by "' . $SESSION->get('username') . '@'
. $SESSION->get('institution') . 'to change their password failed');
}
/**
......@@ -437,11 +412,11 @@ function change_password_submit($values) {
function auth_draw_login_page($message=null, Form $form=null) {
global $USER, $SESSION;
if ($form != null) {
$loginform = $form->build();
$loginform = get_login_form_js($form->build());
}
else {
require_once('form.php');
$loginform = form(auth_get_login_form());
$loginform = get_login_form_js(form(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
......@@ -458,7 +433,6 @@ function auth_draw_login_page($message=null, Form $form=null) {
}
$smarty = smarty();
$smarty->assign('login_form', $loginform);
$smarty->assign('INLINEJAVASCRIPT', 'addLoadEvent(function () { $(\'login_username\').focus(); });');
$smarty->display('login.tpl');
exit;
}
......@@ -501,9 +475,6 @@ function auth_get_login_form() {
'type' => 'submit',
'value' => get_string('login')
),
'register' => array(
'value' => '<tr><td colspan="2"><a href="' . get_config('wwwroot') . 'register.php">' . get_string('register') . '</a></td></tr>'
)
);
// The login page is completely transient, and it is smart because it
......@@ -549,6 +520,36 @@ function auth_get_login_form() {
return $form;
}
/**
* Returns javascript to assist with the rendering of the login forms. The
* javascript is used to detect whether cookies are enabled, and not show the
* login form if they are not.
*
* @param string $form A rendered login form
* @return string The form with extra javascript added for cookie detection
* @private
*/
function get_login_form_js($form) {
$form = str_replace('/', '\/', str_replace("'", "\'", (str_replace(array("\n", "\t"), '', $form))));
$strcookiesnotenabled = get_string('cookiesnotenabled');
$strjavascriptnotenabled = get_string('javascriptnotenabled');
$cookiename = get_config('cookieprefix') . 'ctest';
return <<<EOF
<script type="text/javascript">
var loginbox = $('loginbox');
document.cookie = '$cookiename=1;expires=0';
if (document.cookie) {
loginbox.innerHTML = '$form';
}
else {
appendChildNodes(loginbox, P(null, $strcookiesnotenabled));
}
</script>
<noscript>
<p>$strjavascriptnotenabled</p>
</noscript>
EOF;
}
/**
* Called when the login form is submittd. Validates the user and password, and
......@@ -561,6 +562,15 @@ function login_submit($values) {
global $SESSION, $USER;
log_debug('auth details supplied, attempting to log user in');
// Check if the cookie set to test cookies is actually set
if (!get_cookie('ctest')) {
set_cookie('ctest', '', time() - 3600);
log_debug('cookie for detecting cookies not set');
redirect(get_config('wwwroot'));
}
set_cookie('ctest', '', time() - 3600);
$username = $values['login_username'];
$password = $values['login_password'];
$institution = (isset($values['login_institution'])) ? $values['login_institution'] : 'mahara';
......@@ -601,8 +611,8 @@ function login_submit($values) {
}
// Check if the user's account has expired
log_debug('Checking to see if the user has expired');
if ($USER->expiry > 0 && time() > $USER->expiry) {
log_debug('the user account has expired');
// Trash the $USER object, used for checking if the user is logged in.
// Smarty uses it and puts login-only stuff in the output otherwise...
$USER = null;
......@@ -613,8 +623,8 @@ function login_submit($values) {
// Note: only the internal authentication method can say if a user is suspended for now.
// There are problems with how searching excluding suspended users will work that would
// need to be resolved before this could be implemented for all methods
log_debug('Checking to see if the user is suspended');
if ($suspend = get_record('usr_suspension', 'usr', $USER->id)) {
log_debug('the user account has been suspended');
$USER = null;
die_info(get_string('accountsuspended', 'mahara', $suspend->ctime, $suspend->reason));
}
......@@ -662,6 +672,7 @@ function auth_validate(Form $form, $values) {
*/
function auth_submit($values) {
global $SESSION, $db;
// @todo use db_begin/db_commit
$db->StartTrans();
foreach ($values as $key => $value) {
......
<?php
/**
* This program is part of Mahara
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* @package mahara
* @subpackage core
* @author Nigel McNie <nigel@catalyst.net.nz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
* @copyright (C) 2006,2007 Catalyst IT Ltd http://catalyst.net.nz
*
*/
define('INTERNAL', 1);
define('PUBLIC', 1);
require('init.php');
if (!session_id()) {
session_start();
}
if (!empty($_SESSION['pwchangerequested'])) {
unset($_SESSION['pwchangerequested']);
die_info(get_string('pwchangerequestsent'));
}
if (isset($_GET['key'])) {
if (!$pwrequest = get_record('usr_password_request', 'key', $_GET['key'])) {
die_info(get_string('nosuchpasswordrequest'));
}
$form = array(
'name' => 'forgotpasschange',
'method' => 'post',
'action' => '',
'autofocus' => true,
'elements' => array(
'password1' => array(
'type' => 'password',
'title' => get_string('password'),
'rules' => array(
'required' => true
)
),
'password2' => array(
'type' => 'password',
'title' => get_string('confirmpassword'),
'rules' => array(
'required' => true
)
),
'user' => array(
'type' => 'hidden',
'value' => $pwrequest->usr
),
'submit' => array(
'type' => 'submit',
'value' => get_string('submit')
)
)
);
$smarty = smarty();
$smarty->assign('forgotpasschange_form', form($form));
$smarty->display('forgotpass.tpl');
exit;
}
$form = array(
'name' => 'forgotpass',
'method' => 'post',
'action' => '',
'autofocus' => true,
'elements' => array(
'email' => array(
'type' => 'text',
'title' => get_string('emailaddress'),
'description' => get_string('emailaddressdescription'),
'rules' => array(
'required' => true,
'email' => true
)
),
'submit' => array(
'type' => 'submit',
'value' => get_string('submit')
)
)
);
function forgotpass_validate(Form $form, $values) {
// The e-mail address cannot already be in the system
if (!$form->get_error('email') && !($user = get_record('usr', 'email', $values['email']))) {
$form->set_error('email', get_string('emailaddressinvalid'));
}
$authtype = auth_get_authtype_for_institution($user->institution);
safe_require('auth', $authtype, 'lib.php', 'require_once');
$authclass = 'Auth' . ucfirst($authtype);
if (!method_exists($authclass, 'change_password')) {
die_info(get_string('youwannabutyoucantchangepassword'));
}
}
function forgotpass_submit($values) {
global $SESSION;
try {
if (!$user = get_record('usr', 'email', $values['email'])) {
die_info(get_string('emailaddressinvalid'));
}
$pwrequest = new StdClass;
$pwrequest->usr = $user->id;
$pwrequest->expiry = db_format_timestamp(time() + 86400);
$pwrequest->key = get_random_key();
email_user($user, null,
get_string('forgotpassemailsubject'),
get_string('forgotpassemailmessagetext', 'mahara', $pwrequest->key, $pwrequest->key),
get_string('forgotpassemailmessagehtml', 'mahara', $pwrequest->key, $pwrequest->key, $pwrequest->key, $pwrequest->key));
insert_record('usr_password_request', $pwrequest);
}
catch (SQLException $e) {
die_info(get_string('forgotpasswordemailsendunsuccessful'));
}
catch (EmailException $e) {
die_info(get_string('forgotpasswordemailsendunsuccessful'));
}
// Add a marker in the session to say that the user has registered
$_SESSION['pwchangerequested'] = true;
redirect(get_config('wwwroot') . 'forgotpass.php');
}
function forgotpasschange_validate(Form $form, $values) {
if (!$user = get_record('usr', 'id', $values['user'])) {
throw new Exception('Request to change the password for a user who does not exist');
}
password_validate($form, $values, $user);
}
// TODO:
// password_validate to maharalib, use it in places specified, test with a drop/create run
// support autofocus => (true|'id'), remove stuff doing autofocus from where it is, focus error fields
// commit stuff
function forgotpasschange_submit($values) {
global $SESSION;
if (!$user = get_record('usr', 'id', $values['user'])) {
throw new Exception('Request to change the password for a user who does not exist');
}
$authtype = auth_get_authtype_for_institution($user->institution);
$authclass = 'Auth' . ucfirst($authtype);
safe_require('auth', $authtype, 'lib.php', 'require_once');
log_debug($values);
if ($password = call_static_method($authclass, 'change_password', $user->username, $values['password1'])) {
$userrec = new StdClass;
$userrec->password = $password;
// @todo at the time of writing, update_record didn't support a null $where clause, even though
// it's the default. That should be fixed, so this is easier
$where = new StdClass;
$where->id = $values['user'];
update_record('usr', $userrec, $where);
// Remove the password request(s) for the user
delete_records('usr_password_request', 'usr', $values['user']);
$SESSION->login($user);
$SESSION->add_ok_msg(get_string('passwordchangedok'));
redirect(get_config('wwwroot'));
exit;
}
throw new Exception('User "' . $user->username . '@' . $user->institution
. ' tried to change their password, but the attempt failed');
}
$smarty = smarty();
$smarty->assign('forgotpass_form', form($form));
$smarty->display('forgotpass.tpl');
?>
......@@ -39,12 +39,13 @@ if (!get_config('installed')) {
// this, we can guarantee whether the user is logged in or not for this page.
if (!$SESSION->is_logged_in()) {
require_once('form.php');
$form = array(
$loginform = get_login_form_js(form(array(
'name' => 'login',
'method' => 'post',
'action' => '',
'renderer' => 'div',
'submit' => false,
'autofocus' => 'login_password', // only for testing for now
'elements' => array(
'login' => array(
'type' => 'fieldset',
......@@ -77,11 +78,11 @@ if (!$SESSION->is_logged_in()) {
'value' => get_string('login')
),
'register' => array(
'value' => '<div><a href="' . get_config('wwwroot') . 'register.php">' . get_string('register') . '</a></div>'
'value' => '<div><a href="' . get_config('wwwroot') . 'register.php">' . get_string('register') . '</a> '
. '| <a href="' . get_config('wwwroot') . 'forgotpass.php">' . get_string('forgotpassword') . '</a></div>'
)
)
);
$login_form = form($form);
)));
$pagename = 'loggedouthome';
}
else {
......@@ -90,8 +91,7 @@ else {
$smarty = smarty();
if (!$SESSION->is_logged_in()) {
$smarty->assign('login_form', $login_form);
$smarty->assign('INLINEJAVASCRIPT', 'addLoadEvent(function () { $(\'login_username\').focus(); });');
$smarty->assign('login_form', $loginform);
}
$smarty->assign('page_content', get_site_page_content($pagename));
$smarty->assign('site_menu', site_menu());
......
......@@ -39,7 +39,7 @@ else {
set_include_path('.' . PATH_SEPARATOR . $CFG->libroot);
// Set up error handling
require 'errors.php';
require('errors.php');
if (!is_readable($CFG->docroot . 'config.php')) {
// @todo Later, this will redirect to the installer script. For now, we
......@@ -137,6 +137,8 @@ if (!get_config('theme')) {
$CFG->themeurl = get_config('wwwroot') . 'theme/' . get_config('theme') . '/static/';
header('Content-type: text/html; charset=UTF-8');
// Only do authentication once we know the page theme, so that the login form
// can have the correct theming.
require('auth/lib.php');
......
......@@ -50,3 +50,15 @@ function processingStart(msg) {
function processingStop() {
$('loading_box').style.display = 'none';
}
// Autofocus the first element with a class of 'autofocus' on page load
addLoadEvent(function() {
getFirstElementByTagAndClassName(null, 'autofocus', document.body).focus();
});
// @todo remove this when we migrate to mochikit 1.4
if (typeof(getFirstElementByTagAndClassName) == 'undefined') {
function getFirstElementByTagAndClassName(tag, className, parentElement) {
return getElementsByTagAndClassName(tag, className, parentElement)[0];
}
}
......@@ -40,6 +40,7 @@ $string['sitecontentnotfound'] = '%s text not available';
// auth
$string['accountexpired'] = 'Sorry, your account has expired';
$string['accountsuspended'] = 'Your account has been suspeneded as of %s. The reason for your suspension is:<blockquote>%s</blockquote>';
$string['confirmpassword'] = 'Confirm password';
$string['loggedoutok'] = 'You have been logged out successfully';
$string['login'] = 'Log In';
$string['loginfailed'] = 'You have not provided the correct credentials to log in. Please check your username and password are correct.';
......@@ -53,7 +54,7 @@ $string['username'] = 'Username';
$string['usernamedesc'] = 'Your username';
$string['usernamehelp'] = 'The username you have been given to access this system.';
// registration
// Registration
$string['registeredemailsubject'] = 'You have registered at Mahara';
$string['registeredemailmessagetext'] = 'Congratulations!
......@@ -69,6 +70,43 @@ to complete the signup process:</p>
$string['registeredok'] = '<p>You have successfully registered. Please check your e-mail account for instructions on how to activate your account</p>';
$string['registrationnosuchkey'] = 'Sorry, there does not seem to be a registration with this key. Perhaps you waited longer than 24 hours to complete your registration? Otherwise, it might be our fault.';
// Forgot password
$string['pwchangerequestsent'] = 'You should receive an e-mail shortly with a link you can use to change the password for your account';
$string['forgotpassemailsubject'] = 'Change password request for Mahara';
$string['forgotpassemailmessagetext'] = 'Dear $fullname,
A request to reset your password has been received for your $sitename account.
Please follow the link below to continue the reset process.
' . get_config('wwwroot') . 'forgotpass.php?key=%s
If you did not request a password reset, please ignore this email.
If you have any questsions regarding the above, please feel free to contact
us.
' . get_config('wwwroot') . 'contact.php
Regards, $sitename Site Administrator
' . get_config('wwwroot') . 'forgotpass.php?key=%s';
$string['forgotpassemailmessagehtml'] = '<p>Dear $fullname,</p>
<p>A request to reset your password has been received for your $sitename account.</p>
<p>Please follow the link below to continue the reset process.</p>
<p><a href="' . get_config('wwwroot') . 'forgotpass.php?key=%s">' . get_config('wwwroot') . 'forgotpass.php?key=%s</a></p>
<p>If you did not request a password reset, please ignore this email.</p>
<p>If you have any questsions regarding the above, please feel free to <a href="' . get_config('wwwroot') . 'contact.php">contact us</a>.</p>
<p>Regards, $sitename Site Administrator</p>
<p><a href="' . get_config('wwwroot') . 'forgotpass.php?key=%s">' . get_config('wwwroot') . 'forgotpass.php?key=%s</a></p>';
// Admin menu editor
$string['adminfile'] = 'Admin file';
$string['externallink'] = 'External link';
......
......@@ -448,8 +448,8 @@
<FIELD NAME="firstname" TYPE="text" NOTNULL="true"/>
<FIELD NAME="lastname" TYPE="text" NOTNULL="true"/>
<FIELD NAME="email" TYPE="text" NOTNULL="true"/>
<FIELD NAME="regkey" TYPE="char" LENGTH="16" NOTNULL="true"/>
<FIELD NAME="timeregistered" TYPE="datetime" NOTNULL="true"/>
<FIELD NAME="key" TYPE="char" LENGTH="16" NOTNULL="true"/>
<FIELD NAME="expiry" TYPE="datetime" NOTNULL="true"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
......@@ -460,7 +460,7 @@
<FIELDS>
<FIELD NAME="usr" TYPE="int" LENGTH="10" NOTNULL="true" />
<FIELD NAME="expiry" TYPE="datetime" NOTNULL="true" />
<FIELD NAME="code" TYPE="char" LENGTH="20" NOTNULL="true" />
<FIELD NAME="key" TYPE="char" LENGTH="20" NOTNULL="true" />
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="usr,expiry" />
......
......@@ -450,4 +450,9 @@ class SQLException extends Exception {}
*/
class ParameterException extends Exception {}
/**
* An exception generated when e-mail can't be sent
*/
class EmailException extends Exception {}
?>