25 require_once(
'AWLUtilities.php');
26 require_once(
'AwlQuery.php');
27 require_once(
'EMail.php');
36 function check_temporary_passwords( $they_sent, $user_no ) {
37 $sql =
'SELECT 1 AS ok FROM tmp_password WHERE user_no = ? AND password = ? AND valid_until > current_timestamp';
38 $qry =
new AwlQuery( $sql, $user_no, $they_sent );
39 if ( $qry->Exec(
'Session::check_temporary_passwords') ) {
40 dbg_error_log(
"Login",
" check_temporary_passwords: Rows = ".$qry->rows());
41 if ( $row = $qry->Fetch() ) {
42 dbg_error_log(
"Login",
" check_temporary_passwords: OK = $row->ok");
44 $sql =
'DELETE FROM tmp_password WHERE user_no = ? ';
45 $qry =
new AwlQuery( $sql, $user_no );
46 $qry->Exec(
'Login',__LINE__,__FILE__);
87 var $username =
'guest';
93 var $fullname =
'Guest';
105 var $logged_in =
false;
113 var $just_logged_in =
false;
119 var $last_session_start;
126 var $last_session_end;
147 global $sid, $sysname;
149 $this->roles = array();
150 $this->logged_in =
false;
151 $this->just_logged_in =
false;
152 $this->login_failed =
false;
155 if ( ! isset($_COOKIE[
'sid']) )
return;
156 $sid = $_COOKIE[
'sid'];
159 list( $session_id, $session_key ) = explode(
';', $sid, 2 );
170 if ( function_exists(
'local_session_sql') ) {
171 $sql = local_session_sql();
174 $sql =
"SELECT session.*, usr.* FROM session JOIN usr USING ( user_no )";
176 $sql .=
" WHERE session.session_id = ? AND (md5(session.session_start::text) = ? OR session.session_key = ?) ORDER BY session.session_start DESC LIMIT 2";
178 $qry =
new AwlQuery($sql, $session_id, $session_key, $session_key);
179 if ( $qry->Exec(
'Session') && 1 == $qry->rows() ) {
181 $qry =
new AwlQuery(
'UPDATE session SET session_end = current_timestamp WHERE session_id=?', $session_id);
182 $qry->Exec(
'Session');
186 setcookie(
'sid',
'', 0,
'/');
187 $this->cause =
'ERR: Other than one session record matches. ' . $qry->rows();
188 $this->
Log(
"WARN: Login $this->cause" );
206 deprecated(
'Session::Log');
208 $argc = func_num_args();
209 $format = func_get_arg(0);
210 if ( $argc == 1 || ($argc == 2 && func_get_arg(1) ==
"0" ) ) {
211 error_log(
"$c->sysabbr: $format" );
215 for( $i=1; $i < $argc; $i++ ) {
216 $args[] = func_get_arg($i);
218 error_log(
"$c->sysabbr: " . vsprintf($format,$args) );
235 global $debuggroups, $c;
236 deprecated(
'Session::Dbg');
238 $argc = func_num_args();
239 $dgroup = func_get_arg(0);
241 if ( ! (isset($debuggroups[$dgroup]) && $debuggroups[$dgroup]) )
return;
243 $format = func_get_arg(1);
244 if ( $argc == 2 || ($argc == 3 && func_get_arg(2) ==
"0" ) ) {
245 error_log(
"$c->sysabbr: DBG: $dgroup: $format" );
249 for( $i=2; $i < $argc; $i++ ) {
250 $args[] = func_get_arg($i);
252 error_log(
"$c->sysabbr: DBG: $dgroup: " . vsprintf($format,$args) );
265 return ( $this->logged_in && isset($this->roles[$whatever]) && $this->roles[$whatever] );
273 $this->roles = array();
274 $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 );
275 if ( $qry->Exec(
'Session::GetRoles') && $qry->rows() > 0 ) {
276 while( $role = $qry->Fetch() ) {
277 $this->roles[$role->role_name] =
true;
289 foreach( $u AS $k => $v ) {
293 $date_format = ($this->date_format_type ==
'E' ?
'European,ISO' : ($this->date_format_type ==
'U' ?
'US,ISO' :
'ISO'));
294 $qry =
new AwlQuery(
'SET DATESTYLE TO '. $date_format );
298 $this->logged_in =
true;
316 function Login( $username, $password, $authenticated =
false ) {
319 dbg_error_log(
"Login",
" Login: Attempting login for $username" );
320 if ( isset($usr) ) unset($usr);
328 if ( !$authenticated && isset($c->authenticate_hook) && isset($c->authenticate_hook[
'call']) && function_exists($c->authenticate_hook[
'call']) ) {
339 $usr = call_user_func( $c->authenticate_hook[
'call'], $username, $password );
340 if ( $usr ===
false ) unset($usr);
else $authenticated =
true;
343 $sql =
"SELECT * FROM usr WHERE lower(username) = text(?) AND active";
344 $qry =
new AwlQuery( $sql, strtolower($username) );
345 if ( isset($usr) || ($qry->Exec(
'Login',__LINE__,__FILE__) && $qry->rows() == 1 && $usr = $qry->Fetch() ) ) {
346 $user_no = ( method_exists( $usr,
'user_no' ) ? $usr->user_no() : $usr->user_no );
347 if ( $authenticated || session_validate_password( $password, $usr->password ) || check_temporary_passwords( $password, $user_no ) ) {
349 $qry =
new AwlQuery(
"SELECT nextval('session_session_id_seq')" );
350 if ( $qry->Exec(
'Login') && $qry->rows() == 1 ) {
351 $seq = $qry->Fetch();
352 $session_id = $seq->nextval;
353 $session_key = md5( rand(1010101,1999999999) . microtime() );
354 dbg_error_log(
"Login",
" Login: Valid username/password for $username ($user_no)" );
357 $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);
358 $qry->Exec(
'Session');
361 $sql =
"INSERT INTO session (session_id, user_no, session_key) VALUES( ?, ?, ? )";
362 $qry =
new AwlQuery( $sql, $session_id, $user_no, $session_key );
363 if ( $qry->Exec(
'Login') ) {
365 $sid =
"$session_id;$session_key";
368 setcookie(
'sid',$sid, 0,
'/');
371 dbg_error_log(
"Login",
" Login: New session $session_id started for $username ($user_no)" );
372 if ( isset($_POST[
'remember']) && intval($_POST[
'remember']) > 0 ) {
373 $cookie = md5( $user_no ) .
";";
374 $cookie .= session_salted_md5($user_no . $usr->username . $usr->password);
375 $GLOBALS[
'lsid'] = $cookie;
376 setcookie(
"lsid", $cookie, time() + (86400 * 3600),
"/" );
378 $this->just_logged_in =
true;
381 unset($_POST[
'username']);
382 unset($_POST[
'password']);
383 unset($_POST[
'submit']);
384 unset($_GET[
'submit']);
385 unset($GLOBALS[
'submit']);
387 if ( function_exists(
'local_session_sql') ) {
388 $sql = local_session_sql();
391 $sql =
"SELECT session.*, usr.* FROM session JOIN usr USING ( user_no )";
393 $sql .=
" WHERE session.session_id = ? AND (md5(session.session_start::text) = ? OR session.session_key = ?) ORDER BY session.session_start DESC LIMIT 2";
395 $qry =
new AwlQuery($sql, $session_id, $session_key, $session_key);
396 if ( $qry->Exec(
'Session') && 1 == $qry->rows() ) {
404 $this->cause =
'ERR: Could not create new session.';
407 $this->cause =
'ERR: Could not increment session sequence.';
411 $c->messages[] = i18n(
'Invalid username or password.');
412 if ( isset($c->dbg[
'Login']) || isset($c->dbg[
'ALL']) )
413 $this->cause =
'WARN: Invalid password.';
415 $this->cause =
'WARN: Invalid username or password.';
419 $c->messages[] = i18n(
'Invalid username or password.');
420 if ( isset($c->dbg[
'Login']) || isset($c->dbg[
'ALL']) )
421 $this->cause =
'WARN: Invalid username.';
423 $this->cause =
'WARN: Invalid username or password.';
426 $this->
Log(
"Login failure: $this->cause" );
427 $this->login_failed =
true;
444 dbg_error_log(
"Login",
" LSIDLogin: Attempting login for $lsid" );
446 list($md5_user_no,$validation_string) = explode(
';', $lsid );
447 $qry =
new AwlQuery(
"SELECT * FROM usr WHERE md5(user_no::text)=? AND active", $md5_user_no );
448 if ( $qry->Exec(
'Login') && $qry->rows() == 1 ) {
449 $usr = $qry->Fetch();
450 list( $x, $salt, $y) = explode(
'*', $validation_string);
451 $my_validation = session_salted_md5($usr->user_no . $usr->username . $usr->password, $salt);
452 if ( $validation_string == $my_validation ) {
454 $qry =
new AwlQuery(
"SELECT nextval('session_session_id_seq')" );
455 if ( $qry->Exec(
'Login') && $qry->rows() == 1 ) {
456 $seq = $qry->Fetch();
457 $session_id = $seq->nextval;
458 $session_key = md5( rand(1010101,1999999999) . microtime() );
459 dbg_error_log(
"Login",
" LSIDLogin: Valid username/password for $usr->username ($usr->user_no)" );
462 $sql =
"INSERT INTO session (session_id, user_no, session_key) VALUES( ?, ?, ? )";
463 $qry =
new AwlQuery( $sql, $session_id, $usr->user_no, $session_key );
464 if ( $qry->Exec(
'Login') ) {
466 $sid =
"$session_id;$session_key";
469 setcookie(
'sid',$sid, 0,
'/');
472 dbg_error_log(
"Login",
" LSIDLogin: New session $session_id started for $usr->username ($usr->user_no)" );
474 $this->just_logged_in =
true;
477 unset($_POST[
'username']);
478 unset($_POST[
'password']);
479 unset($_POST[
'submit']);
480 unset($_GET[
'submit']);
481 unset($GLOBALS[
'submit']);
483 if ( function_exists(
'local_session_sql') ) {
484 $sql = local_session_sql();
487 $sql =
"SELECT session.*, usr.* FROM session JOIN usr USING ( user_no )";
489 $sql .=
" WHERE session.session_id = ? AND (md5(session.session_start::text) = ? OR session.session_key = ?) ORDER BY session.session_start DESC LIMIT 2";
491 $qry =
new AwlQuery($sql, $session_id, $session_key, $session_key);
492 if ( $qry->Exec(
'Session') && 1 == $qry->rows() ) {
500 $this->cause =
'ERR: Could not create new session.';
503 $this->cause =
'ERR: Could not increment session sequence.';
507 dbg_error_log(
"Login",
" LSIDLogin: $validation_string != $my_validation ($salt - $usr->user_no, $usr->username, $usr->password)");
508 $client_messages[] = i18n(
'Invalid username or password.');
509 if ( isset($c->dbg[
'Login']) || isset($c->dbg[
'ALL']) )
510 $this->cause =
'WARN: Invalid password.';
512 $this->cause =
'WARN: Invalid username or password.';
516 $client_messages[] = i18n(
'Invalid username or password.');
517 if ( isset($c->dbg[
'Login']) || isset($c->dbg[
'ALL']) )
518 $this->cause =
'WARN: Invalid username.';
520 $this->cause =
'WARN: Invalid username or password.';
523 dbg_error_log(
"Login",
" LSIDLogin: $this->cause" );
534 $action_target = htmlspecialchars(preg_replace(
'/\?logout.*$/',
'',$_SERVER[
'REQUEST_URI']));
535 dbg_error_log(
"Login",
" RenderLoginPanel: action_target='%s'", $action_target );
536 $userprompt = translate(
"User Name");
537 $pwprompt = translate(
"Password");
538 $rememberprompt = str_replace(
' ',
' ', translate(
"forget me not"));
539 $gobutton = htmlspecialchars(translate(
"GO!"));
540 $gotitle = htmlspecialchars(translate(
"Enter your username and password then click here to log in."));
541 $temppwprompt = translate(
"If you have forgotten your password then");
542 $temppwbutton = htmlspecialchars(translate(
"Help! I've forgotten my password!"));
543 $temppwtitle = htmlspecialchars(translate(
"Enter a username, if you know it, and click here, to be e-mailed a temporary password."));
546 <form action=
"$action_target" method=
"post">
549 <th
class=
"prompt">$userprompt:</th>
551 <input
class=
"text" type=
"text" name=
"username" size=
"12" /></td>
554 <th
class=
"prompt">$pwprompt:</th>
556 <input
class=
"password" type=
"password" name=
"password" size=
"12" />
557 <label>$rememberprompt: <input
class=
"checkbox" type=
"checkbox" name=
"remember" value=
"1" /></label>
561 <th
class=
"prompt"> </th>
563 <input type=
"submit" value=
"$gobutton" title=
"$gotitle" name=
"submit" class=
"submit" />
568 $temppwprompt: <input type=
"submit" value=
"$temppwbutton" title=
"$temppwtitle" name=
"lostpass" class=
"submit" />
588 global $c, $session, $page_elements;
590 if ( $this->logged_in && $groups ==
"" )
return;
591 if ( ! $this->logged_in ) {
593 if ( function_exists(
"local_index_not_logged_in") ) {
594 local_index_not_logged_in();
597 $login_html = translate(
"<h1>Log On Please</h1><p>For access to the %s you should log on withthe username and password that have been issued to you.</p><p>If you would like to request access, please e-mail %s.</p>");
598 $page_content = sprintf( $login_html, $c->system_name, $c->admin_email );
600 if ( isset($page_elements) && gettype($page_elements) ==
'array' ) {
601 $page_elements[] = $page_content;
602 @include(
"page-renderer.php");
605 @include(
"page-header.php");
607 @include(
"page-footer.php");
611 $valid_groups = explode(
",", $groups);
612 foreach( $valid_groups AS $k => $v ) {
615 $c->messages[] = i18n(
"You are not authorised to use this function.");
616 if ( isset($page_elements) && gettype($page_elements) ==
'array' ) {
617 @include(
"page-renderer.php");
620 @include(
"page-header.php");
621 @include(
"page-footer.php");
640 $password_sent =
false;
643 if ( isset($username) && $username !=
"" ) {
644 $where =
'WHERE active AND lower(usr.username) = :lcusername';
645 $params[
':lcusername'] = strtolower($username);
647 else if ( isset($email_address) && $email_address !=
"" ) {
648 $where =
'WHERE active AND lower(usr.email) = :lcemail';
649 $params[
':lcemail'] = strtolower($email_address);
652 if ( $where !=
'' ) {
653 if ( !isset($body_template) || $body_template ==
"" ) {
654 $body_template = <<<EOTEXT
656 @@debugging@@A temporary password has been requested
for @@system_name@@.
658 Temporary Password: @@password@@
660 This has been applied to the following usernames:
663 and will be valid
for 24 hours.
665 If you have any problems, please contact the system administrator.
670 $qry =
new AwlQuery(
'SELECT * FROM usr '.$where, $params );
671 $qry->Exec(
'Session::EmailTemporaryPassword');
672 if ( $qry->rows() > 0 ) {
676 while ( $row = $qry->Fetch() ) {
677 $mail =
new EMail(
"Access to $c->system_name" );
678 $mail->SetFrom($c->admin_email );
681 if ( isset($c->debug_email) ) {
682 $debug_to =
"This e-mail would normally be sent to:\n ";
683 $mail->AddTo(
"Tester <$c->debug_email>" );
687 for ( $i=0; $i < 8; $i++ ) {
688 $tmp_passwd .= substr(
'ABCDEFGHIJKLMNOPQRSTUVWXYZ+#.-=*%@0123456789abcdefghijklmnopqrstuvwxyz', rand(0,69), 1);
691 $q2->QDo(
'INSERT INTO tmp_password (user_no, password) VALUES(?,?)', array($row->user_no, $tmp_passwd));
692 if ( isset($c->debug_email) ) {
693 $debug_to .=
"$row->fullname <$row->email> ";
696 $mail->AddTo(
"$row->fullname <$row->email>" );
698 $usernames .=
" $row->username\n";
700 if ( $mail->To() !=
"" ) {
701 if ( isset($c->debug_email) ) {
702 $debug_to .=
"\n============================================================\n";
706 $qry->Exec(
"Session::SendTemporaryPassword");
707 $body = str_replace(
'@@system_name@@', $c->system_name, $body_template);
708 $body = str_replace(
'@@password@@', $tmp_passwd, $body);
709 $body = str_replace(
'@@usernames@@', $usernames, $body);
710 $body = str_replace(
'@@debugging@@', $debug_to, $body);
711 $mail->SetBody($body);
713 $password_sent =
true;
718 return $password_sent;
730 global $c, $page_elements;
732 $password_sent = $this->
EmailTemporaryPassword( (isset($_POST[
'username'])?$_POST[
'username']:null), (isset($_POST[
'email_address'])?$_POST[
'email_address']:null) );
734 if ( ! $password_sent && ((isset($_POST[
'username']) && $_POST[
'username'] !=
"" )
735 || (isset($_POST[
'email_address']) && $_POST[
'email_address'] !=
"" )) ) {
737 $page_content = <<<EOTEXT
739 <h1>Unable to Reset Password</h1>
740 <p>We were unable to reset your password at
this time. Please contact
741 <a href=
"mailto:$c->admin_email">$c->admin_email</a>
742 to arrange
for an administrator to reset your password.</p>
747 else if ( $password_sent ) {
748 $page_content = <<<EOTEXT
750 <h1>Temporary Password Sent</h1>
751 <p>A temporary password has been e-mailed to you. This password
752 will be valid
for 24 hours and you will be required to change
753 your password after logging in.</p>
754 <p><a href=
".">Click here to
return to the login page.</a></p>
759 $page_content = <<<EOTEXT
761 <h1>Temporary Password</h1>
762 <form action=
"$action_target" method=
"post">
765 <th
class=
"prompt" style=
"white-space: nowrap;">Enter your
User Name:</th>
766 <td
class=
"entry"><input
class=
"text" type=
"text" name=
"username" size=
"12" /></td>
769 <th
class=
"prompt" style=
"white-space: nowrap;">Or your
EMail Address:</th>
770 <td
class=
"entry"><input
class=
"text" type=
"text" name=
"email_address" size=
"50" /></td>
773 <th
class=
"prompt" style=
"white-space: nowrap;">and click on -></th>
775 <input
class=
"submit" type=
"submit" value=
"Send me a temporary password" alt=
"Enter a username, or e-mail address, and click here." name=
"lostpass" />
779 <p>Note: If you have multiple accounts with the same e-mail address, they will <em>all</em>
780 be assigned a
new temporary password, but only the one(s) that you use that temporary password
781 on will have the existing password invalidated.</p>
782 <h2>The temporary password will only be valid
for 24 hours.</h2>
783 <p>You will need to log on and change your password during
this time.</p>
788 if ( isset($page_elements) && gettype($page_elements) ==
'array' ) {
789 $page_elements[] = $page_content;
790 @include(
"page-renderer.php");
793 @include(
"page-header.php");
795 @include(
"page-footer.php");
799 static function _CheckLogout() {
800 if ( isset($_GET[
'logout']) ) {
801 dbg_error_log(
"Login",
":_CheckLogout: Logging out");
802 if ( isset($_COOKIE[
'sid']) ) {
804 list( $session_id, $session_key ) = explode(
';', $_COOKIE[
'sid'], 2 );
805 $sql =
'DELETE FROM session WHERE session_id = ? AND session_key = ?';
806 $qry =
new AwlQuery( $sql, $session_id, $session_key );
807 $qry->Exec(
'Logout',__LINE__,__FILE__);
809 $sql =
"DELETE FROM session WHERE session_end < current_timestamp - interval '16 hours'";
811 $qry->Exec(
'Expire',__LINE__,__FILE__);
813 setcookie(
'sid',
'', 0,
'/');
814 unset($_COOKIE[
'sid']);
815 unset($GLOBALS[
'sid']);
816 unset($_COOKIE[
'lsid']);
817 unset($GLOBALS[
'lsid']);
819 if ( isset($_GET[
'forget']) ) setcookie(
'lsid',
'', 0,
'/');
825 if ( isset($_POST[
'lostpass']) ) {
826 dbg_error_log(
"Login",
":_CheckLogin: User '$_POST[username]' has lost the password." );
829 else if ( isset($_POST[
'username']) && isset($_POST[
'password']) ) {
831 $this->
Login( $_POST[
'username'], $_POST[
'password'] );
832 @dbg_error_log(
"Login",
":_CheckLogin: User %s(%s) - %s (%d) login status is %d", $_POST[
'username'], $this->fullname, $this->user_no, $this->logged_in );
834 else if ( !isset($_COOKIE[
'sid']) && isset($_COOKIE[
'lsid']) && $_COOKIE[
'lsid'] !=
"" ) {
837 dbg_error_log(
"Login",
":_CheckLogin: User $this->username - $this->fullname ($this->user_no) login status is $this->logged_in" );
839 else if ( !isset($_COOKIE[
'sid']) && isset($c->authenticate_hook[
'server_auth_type']) ) {
843 if ( ( is_array($c->authenticate_hook[
'server_auth_type'])
844 && in_array( strtolower($_SERVER[
'AUTH_TYPE']), array_map(
'strtolower', $c->authenticate_hook[
'server_auth_type'])) )
846 ( !is_array($c->authenticate_hook[
'server_auth_type'])
847 && strtolower($c->authenticate_hook[
'server_auth_type']) == strtolower($_SERVER[
'AUTH_TYPE']) )
849 if (isset($_SERVER[
"REMOTE_USER"]))
850 $this->
Login($_SERVER[
'REMOTE_USER'],
"",
true);
852 $this->
Login($_SERVER[
'REDIRECT_REMOTE_USER'],
"",
true);
866 if ( preg_match(
'#^\s*$#', $indate ) ) {
870 if ( preg_match(
'#^\d{1,2}[/-]\d{1,2}[/-]\d{2,4}#', $indate ) ) {
874 $yr = substr($indate,0,4);
875 $mo = substr($indate,5,2);
876 $dy = substr($indate,8,2);
877 switch ( $this->date_format_type ) {
879 $out = sprintf(
"%d/%d/%d", $mo, $dy, $yr );
882 $out = sprintf(
"%d/%d/%d", $dy, $mo, $yr );
885 $out = sprintf(
"%d-%02d-%02d", $yr, $mo, $dy );
888 if ( $type ==
'timestamp' ) {
889 $out .= substr($indate,10,6);
909 $confirmation_hash = session_salted_md5( $this->session_start.$varname.$this->session_key,
"" );
910 if ( $method ==
'GET' ) {
911 $confirm = $varname .
'='. urlencode($confirmation_hash);
914 $confirm = sprintf(
'<input type="hidden" name="%s" value="%s">', $varname, htmlspecialchars($confirmation_hash) );
928 if ( $method ==
'GET' && isset($_GET[$varname])) {
929 $hashwegot = $_GET[$varname];
930 dbg_error_log(
'Session',
':CheckConfirmationHash: We got "%s" from GET', $hashwegot );
932 else if ( isset($_POST[$varname]) ) {
933 $hashwegot = $_POST[$varname];
934 dbg_error_log(
'Session',
':CheckConfirmationHash: We got "%s" from POST', $hashwegot );
940 if ( preg_match(
'{^\*(.+)\*.+$}i', $hashwegot, $regs ) ) {
943 dbg_error_log(
'Session',
':CheckConfirmationHash: Salt "%s"', $salt );
944 $test_against = session_salted_md5( $this->session_start.$varname.$this->session_key, $salt ) ;
945 dbg_error_log(
'Session',
':CheckConfirmationHash: Testing against "%s"', $test_against );
947 return ($hashwegot == $test_against);
961 if ( !isset($session) ) {
962 Session::_CheckLogout();
964 $session->_CheckLogin();
Login( $username, $password, $authenticated=false)
AssignSessionDetails( $u)
EmailTemporaryPassword( $username, $email_address, $body_template="")
LoginRequired( $groups="")
BuildConfirmationHash( $method, $varname)
CheckConfirmationHash( $method, $varname)
FormattedDate( $indate, $type='date')