* SELECT session.*, usr.* FROM session JOIN usr ON ( user_no )
*
*/
if ( function_exists('local_session_sql') ) {
$sql = local_session_sql();
}
else {
$sql = "SELECT session.*, usr.* FROM session JOIN usr USING ( user_no )";
}
$sql .= " WHERE session.session_id = ? AND session.session_key = ? ORDER BY session.session_start DESC LIMIT 2";
$qry = new AwlQuery($sql, $session_id, $session_key);
if ( $qry->Exec('Session') && 1 == $qry->rows() ) {
$this->AssignSessionDetails( $qry->Fetch() );
$qry = new AwlQuery('UPDATE session SET session_end = current_timestamp WHERE session_id=?', $session_id);
$qry->Exec('Session');
}
else {
// Kill the existing cookie, which appears to be bogus
setcookie('sid', '', 0,'/');
$this->cause = 'ERR: Other than one session record matches. ' . $qry->rows();
$this->Log( "WARN: Login $this->cause" );
}
}
/**
* DEPRECATED Utility function to log stuff with printf expansion.
*
* This function could be expanded to log something identifying the session, but
* somewhat strangely this has not yet been done.
*
* @param string $whatever A log string
* @param mixed $whatever... Further parameters to be replaced into the log string a la printf
* @deprecated
*/
function Log( $whatever )
{
global $c;
deprecated('Session::Log');
$argc = func_num_args();
$format = func_get_arg(0);
if ( $argc == 1 || ($argc == 2 && func_get_arg(1) == "0" ) ) {
error_log( "$c->sysabbr: $format" );
}
else {
$args = array();
for( $i=1; $i < $argc; $i++ ) {
$args[] = func_get_arg($i);
}
error_log( "$c->sysabbr: " . vsprintf($format,$args) );
}
}
/**
* DEPRECATED Utility function to log debug stuff with printf expansion, and the ability to
* enable it selectively.
*
* The enabling is done by setting a variable "$debuggroups[$group] = 1"
*
* @param string $group The name of an arbitrary debug group.
* @param string $whatever A log string
* @param mixed $whatever... Further parameters to be replaced into the log string a la printf
* @deprecated
*/
function Dbg( $whatever )
{
global $debuggroups, $c;
deprecated('Session::Dbg');
$argc = func_num_args();
$dgroup = func_get_arg(0);
if ( ! (isset($debuggroups[$dgroup]) && $debuggroups[$dgroup]) ) return;
$format = func_get_arg(1);
if ( $argc == 2 || ($argc == 3 && func_get_arg(2) == "0" ) ) {
error_log( "$c->sysabbr: DBG: $dgroup: $format" );
}
else {
$args = array();
for( $i=2; $i < $argc; $i++ ) {
$args[] = func_get_arg($i);
}
error_log( "$c->sysabbr: DBG: $dgroup: " . vsprintf($format,$args) );
}
}
/**
* Checks whether a user is allowed to do something.
*
* The check is performed to see if the user has that role.
*
* @param string $whatever The role we want to know if the user has.
* @return boolean Whether or not the user has the specified role.
*/
function AllowedTo ( $whatever ) {
return ( $this->logged_in && isset($this->roles[$whatever]) && $this->roles[$whatever] );
}
/**
* Internal function used to get the user's roles from the database.
*/
function GetRoles () {
$this->roles = array();
$qry = new AwlQuery( 'SELECT role_name FROM role_member m join roles r ON r.role_no = m.role_no WHERE user_no = ? ', $this->user_no );
if ( $qry->Exec('Session::GetRoles') && $qry->rows() > 0 ) {
while( $role = $qry->Fetch() ) {
$this->roles[$role->role_name] = true;
}
}
}
/**
* Internal function used to assign the session details to a user's new session.
* @param object $u The user+session object we (probably) read from the database.
*/
function AssignSessionDetails( $u ) {
// Assign each field in the selected record to the object
foreach( $u AS $k => $v ) {
$this->{$k} = $v;
}
$date_format = ($this->date_format_type == 'E' ? 'European,ISO' : ($this->date_format_type == 'U' ? 'US,ISO' : 'ISO'));
$qry = new AwlQuery( 'SET DATESTYLE TO '. $date_format );
$qry->Exec();
$this->GetRoles();
$this->logged_in = true;
}
/**
* Attempt to perform a login action.
*
* This will validate the user's username and password. If they are OK then a new
* session id will be created and the user will be cookied with it for subsequent
* pages. A logged in session will be created, and the $_POST array will be cleared
* of the username, password and submit values. submit will also be cleared from
* $_GET and $GLOBALS, just in case.
*
* @param string $username The user's login name, or at least what they entered it as.
* @param string $password The user's password, or at least what they entered it as.
* @param string $authenticated If true, then authentication has already happened and the password is not checked, though the user must still exist.
* @return boolean Whether or not the user correctly guessed a temporary password within the necessary window of opportunity.
*/
function Login( $username, $password, $authenticated = false ) {
global $c;
$rc = false;
dbg_error_log( "Login", " Login: Attempting login for $username" );
if ( isset($usr) ) unset($usr); /** In case someone is running with register_globals on */
/**
* @todo In here we will need to put code to call the auth plugin, in order to
* ensure the 'usr' table has current valid data. At this stage we are just
* thinking it through... like ...
*
*/
if ( !$authenticated && isset($c->authenticate_hook) && isset($c->authenticate_hook['call']) && function_exists($c->authenticate_hook['call']) ) {
/**
* The authenticate hook needs to:
* - Accept a username / password
* - Confirm the username / password are correct
* - Create (or update) a 'usr' record in our database
* - Return the 'usr' record as an object
* - Return === false when authentication fails
* It can expect that:
* - Configuration data will be in $c->authenticate_hook['config'], which might be an array, or whatever is needed.
*/
$usr = call_user_func( $c->authenticate_hook['call'], $username, $password );
if ( $usr === false ) unset($usr); else $authenticated = true;
}
$sql = "SELECT * FROM usr WHERE lower(username) = text(?) AND active";
$qry = new AwlQuery( $sql, strtolower($username) );
if ( isset($usr) || ($qry->Exec('Login',__LINE__,__FILE__) && $qry->rows() == 1 && $usr = $qry->Fetch() ) ) {
$user_no = ( method_exists( $usr, 'user_no' ) ? $usr->user_no() : $usr->user_no );
if ( $authenticated || session_validate_password( $password, $usr->password ) || check_temporary_passwords( $password, $user_no ) ) {
// Now get the next session ID to create one from...
$qry = new AwlQuery( "SELECT nextval('session_session_id_seq')" );
if ( $qry->Exec('Login') && $qry->rows() == 1 ) {
$seq = $qry->Fetch();
$session_id = $seq->nextval;
$session_key = md5( rand(1010101,1999999999) . microtime() ); // just some random shite
dbg_error_log( "Login", " Login: Valid username/password for $username ($user_no)" );
// Set the last_used timestamp to match the previous login.
$qry = new AwlQuery('UPDATE usr SET last_used = (SELECT session_start FROM session WHERE session.user_no = ? ORDER BY session_id DESC LIMIT 1) WHERE user_no = ?;', $usr->user_no, $usr->user_no);
$qry->Exec('Session');
// And create a session
$sql = "INSERT INTO session (session_id, user_no, session_key) VALUES( ?, ?, ? )";
$qry = new AwlQuery( $sql, $session_id, $user_no, $session_key );
if ( $qry->Exec('Login') ) {
// Assign our session ID variable
$sid = "$session_id;$session_key";
// Create a cookie for the sesssion
setcookie('sid',$sid, 0,'/');
// Recognise that we have started a session now too...
$this->__construct($sid);
dbg_error_log( "Login", " Login: New session $session_id started for $username ($user_no)" );
$this->just_logged_in = true;
// Unset all of the submitted values, so we don't accidentally submit an unexpected form.
unset($_POST['username']);
unset($_POST['password']);
unset($_POST['submit']);
unset($_GET['submit']);
unset($GLOBALS['submit']);
if ( function_exists('local_session_sql') ) {
$sql = local_session_sql();
}
else {
$sql = "SELECT session.*, usr.* FROM session JOIN usr USING ( user_no )";
}
$sql .= " WHERE session.session_id = ? AND session.session_key = ? ORDER BY session.session_start DESC LIMIT 2";
$qry = new AwlQuery($sql, $session_id, $session_key);
if ( $qry->Exec('Session') && 1 == $qry->rows() ) {
$this->AssignSessionDetails( $qry->Fetch() );
}
$rc = true;
return $rc;
}
// else ...
$this->cause = 'ERR: Could not create new session.';
}
else {
$this->cause = 'ERR: Could not increment session sequence.';
}
}
else {
$c->messages[] = i18n('Invalid username or password.');
if ( isset($c->dbg['Login']) || isset($c->dbg['ALL']) )
$this->cause = 'WARN: Invalid password.';
else
$this->cause = 'WARN: Invalid username or password.';
}
}
else {
$c->messages[] = i18n('Invalid username or password.');
if ( isset($c->dbg['Login']) || isset($c->dbg['ALL']) )
$this->cause = 'WARN: Invalid username.';
else
$this->cause = 'WARN: Invalid username or password.';
}
$this->Log( "Login failure: $this->cause" );
$this->login_failed = true;
$rc = false;
return $rc;
}
/**
* Renders some HTML for a basic login panel
*
* @return string The HTML to display a login panel.
*/
function RenderLoginPanel() {
$action_target = htmlspecialchars(preg_replace('/\?logout.*$/','',$_SERVER['REQUEST_URI']));
dbg_error_log( "Login", " RenderLoginPanel: action_target='%s'", $action_target );
$userprompt = translate("User Name");
$pwprompt = translate("Password");
$gobutton = htmlspecialchars(translate("GO!"));
$gotitle = htmlspecialchars(translate("Enter your username and password then click here to log in."));
$temppwprompt = translate("If you have forgotten your password then");
$temppwbutton = htmlspecialchars(translate("Help! I've forgotten my password!"));
$temppwtitle = htmlspecialchars(translate("Enter a username, if you know it, and click here, to be e-mailed a temporary password."));
$html = <<For access to the %s you should log on withthe username and password that have been issued to you.
If you would like to request access, please e-mail %s.
"); $page_content = sprintf( $login_html, $c->system_name, $c->admin_email ); $page_content .= $this->RenderLoginPanel(); if ( isset($page_elements) && gettype($page_elements) == 'array' ) { $page_elements[] = $page_content; @include("page-renderer.php"); exit(0); } @include("page-header.php"); echo $page_content; @include("page-footer.php"); } } else { $valid_groups = explode(",", $groups); foreach( $valid_groups AS $k => $v ) { if ( $this->AllowedTo($v) ) return; } $c->messages[] = i18n("You are not authorised to use this function."); if ( isset($page_elements) && gettype($page_elements) == 'array' ) { @include("page-renderer.php"); exit(0); } @include("page-header.php"); @include("page-footer.php"); } exit; } /** * E-mails a temporary password in response to a request from a user. * * This could be called from somewhere within the application that allows * someone to set up a user and invite them. * * This function includes EMail.php to actually send the password. */ function EmailTemporaryPassword( $username, $email_address, $body_template="" ) { global $c; $password_sent = false; $where = ""; $params = array(); if ( isset($username) && $username != "" ) { $where = 'WHERE active AND lower(usr.username) = :lcusername'; $params[':lcusername'] = strtolower($username); } else if ( isset($email_address) && $email_address != "" ) { $where = 'WHERE active AND lower(usr.email) = :lcemail'; $params[':lcemail'] = strtolower($email_address); } if ( $where != '' ) { if ( !isset($body_template) || $body_template == "" ) { $body_template = <<We were unable to reset your password at this time. Please contact $c->admin_email to arrange for an administrator to reset your password.
Thank you.
EOTEXT; } else if ( $password_sent ) { $page_content = <<A temporary password has been e-mailed to you. This password will be valid for 24 hours and you will be required to change your password after logging in.
Click here to return to the login page.
EOTEXT; } else { $page_content = <<