From 865adaa99f65f137beafa8d2b6e18f1b37c2fc80 Mon Sep 17 00:00:00 2001 From: SteveD Date: Sun, 9 Jun 2013 20:53:44 +0100 Subject: [PATCH] Issue #343 partial fix - needs JS sorting properly, but should now be possible to log in using CHAP. CHAP didn't work at all for admin login. Also need to change challenge value on every page reload without losing track. --- class2.php | 14 ++++++----- e107_admin/auth.php | 40 ++++++++++++++++++++++++------- e107_admin/header.php | 17 ++++++++++++- e107_handlers/session_handler.php | 30 +++++++++++++++++------ e107_web/js/chap_script.js | 3 ++- 5 files changed, 80 insertions(+), 24 deletions(-) diff --git a/class2.php b/class2.php index fc1c4406d..683a7e8d3 100644 --- a/class2.php +++ b/class2.php @@ -578,17 +578,14 @@ if(isset($pref['lan_global_list'])) -$sql->db_Mark_Time('Start: CHAPT challenge'); +$sql->db_Mark_Time('Start: CHAP challenge'); e107::getSession() - ->challenge() // Create a unique challenge string for CHAP login + ->challenge() // Make sure there is a unique challenge string for CHAP login ->check(); // Token protection - - - // // N: misc setups: online user tracking, cache // @@ -613,7 +610,9 @@ if(isset($pref['notify']) && $pref['notify'] == true) // O: Start user session // $sql -> db_Mark_Time('Start: Init session'); -init_session(); +init_session(); // Set up a lot of the user-related constants + + //DEPRECATED but necessary. BC Fix. function getip() @@ -929,6 +928,8 @@ if (isset($_POST['userlogin']) || isset($_POST['userlogin_x'])) // $usr = new userlogin($_POST['username'], $_POST['userpass'], $_POST['autologin'], varset($_POST['hashchallenge'],'')); } + + // $_SESSION['ubrowser'] check not needed anymore - see session handler // e_QUERY not defined in single entry mod if (($_SERVER['QUERY_STRING'] == 'logout')/* || (($pref['user_tracking'] == 'session') && isset($_SESSION['ubrowser']) && ($_SESSION['ubrowser'] != $ubrowser))*/) @@ -961,6 +962,7 @@ if (($_SERVER['QUERY_STRING'] == 'logout')/* || (($pref['user_tracking'] == 'ses { session_destroy(); $_SESSION[e_COOKIE]=''; + // @TODO: Need to destroy the session cookie as well (not done by session_destroy() } cookie(e_COOKIE, '', (time() - 2592000)); diff --git a/e107_admin/auth.php b/e107_admin/auth.php index ed10305ee..79cda598f 100644 --- a/e107_admin/auth.php +++ b/e107_admin/auth.php @@ -252,8 +252,9 @@ class auth */ public function authform() // NOTE: this should NOT be a template of the admin-template, however themes may style it using css. { - global $use_imagecode,$sec_img,$pref; + global $use_imagecode,$sec_img; + $pref = e107::getPref(); $frm = e107::getForm(); $incChap = (vartrue($pref['password_CHAP'], 0)) ? " onsubmit='hashLoginPassword(this)'" : ""; @@ -319,18 +320,16 @@ class auth */ public function authcheck($authname, $authpass, $authresponse = '') { - - global $pref; - + $pref = e107::getPref(); $tp = e107::getParser(); $sql_auth = e107::getDb('sql_auth'); $user_info = e107::getUserSession(); - $reason = ''; + $reason = ''; $authname = $tp->toDB(preg_replace("/\sOR\s|\=|\#/", "", trim($authname))); $authpass = trim($authpass); - if (($authpass == '') || ($authname == '')) + if ((($authpass == '') && ($authresponse == '')) || ($authname == '')) $reason = 'np'; if (strlen($authname) > varset($pref['loginname_maxlength'], 30)) $reason = 'lu'; @@ -351,18 +350,41 @@ class auth $reason = 'iu'; } } + if (!$reason && ($row['user_id'])) // Can validate password { $session = e107::getSession(); - if (($authresponse && $session->is('challenge')) && ($authresponse != $session->get('challenge'))) + if (($authresponse && $session->is('prevchallenge')) && ($authresponse != $session->get('prevchallenge'))) { // Verify using CHAP (can't handle login by email address - only loginname - although with this code it does still work if the password is stored unsalted) - if (($pass_result = $user_info->CheckCHAP($session->get('challenge'), $authresponse, $authname, $row['user_password'])) !== PASSWORD_INVALID) + /* + $title = 'Login via admin'; + $extra_text = 'C: '.$session->get('challenge').' PC: '.$session->get('prevchallenge').' PPC: '.$session->get('prevprevchallenge').' R:'.$authresponse.' P:'.$row['user_password']; + $text = 'CHAP: '.$username.' ('.$extra_text.')'; + $title = e107::getParser()->toDB($title); + $text = e107::getParser()->toDB($text); + e107::getAdminLog()->e_log_event(4, __FILE__."|".__FUNCTION__."@".__LINE__, "LOGIN", $title, $text, FALSE, LOG_TO_ROLLING); + + $logfp = fopen(e_LOG.'authlog.txt', 'a+'); fwrite($logfp, $title.': '.$text."\n"); fclose($logfp); + */ + + if (($pass_result = $user_info->CheckCHAP($session->get('prevchallenge'), $authresponse, $authname, $row['user_password'])) !== PASSWORD_INVALID) { - return $$row; + return $row; } } else { // Plaintext password + /* + $title = 'Login via admin'; + $extra_text = 'C: '.$session->get('challenge').' PC: '.$session->get('prevchallenge').' PPC: '.$session->get('prevprevchallenge').' R:'.$authresponse.' P:'.$row['user_password']; + $text = 'STD: '.$username.' ('.$extra_text.')'; + $title = e107::getParser()->toDB($title); + $text = e107::getParser()->toDB($text); + e107::getAdminLog()->e_log_event(4, __FILE__."|".__FUNCTION__."@".__LINE__, "LOGIN", $title, $text, FALSE, LOG_TO_ROLLING); + +// $logfp = fopen(e_LOG.'authlog.txt', 'a+'); fwrite($logfp, $title.': '.$text."\n"); fclose($logfp); + */ + if (($pass_result = $user_info->CheckPassword($authpass, $authname, $row['user_password'])) !== PASSWORD_INVALID) { return $row; diff --git a/e107_admin/header.php b/e107_admin/header.php index bf649ffc4..797a10cd8 100644 --- a/e107_admin/header.php +++ b/e107_admin/header.php @@ -352,6 +352,18 @@ if (vartrue($pref['e_header_list']) && is_array($pref['e_header_list'])) } unset($e_headers); +if (!USER && ($pref['user_tracking'] == "session") && varset($pref['password_CHAP'],0)) +{ + if ($pref['password_CHAP'] == 2) + { + // *** Add in the code to swap the display tags +// $js_body_onload[] = "expandit('loginmenuchap','nologinmenuchap');"; + $js_body_onload[] = "expandit('loginmenuchap');"; + $js_body_onload[] = "expandit('nologinmenuchap');"; + } + echo "\n"; + $js_body_onload[] = "getChallenge();"; +} //XXX - do we still need it? Now we have better way of doing this - admin tools (see below) @@ -401,7 +413,10 @@ echo "\n\n"; // // I: Calculate JS onload() functions for the BODY tag [user mode only] // -$body_onload = ""; +// XXX DEPRECATED $body_onload and related functionality +if (defined('THEME_ONLOAD')) $js_body_onload[] = THEME_ONLOAD; +$body_onload=''; +if (count($js_body_onload)) $body_onload = " onload=\"".implode(" ",$js_body_onload)."\""; // // J: Send end of and start of diff --git a/e107_handlers/session_handler.php b/e107_handlers/session_handler.php index 5e8201bd6..2d2b73c8a 100644 --- a/e107_handlers/session_handler.php +++ b/e107_handlers/session_handler.php @@ -64,7 +64,7 @@ if (!defined('e107_INIT')) class e_session { /** - * No protection, label 'Looking for troubles' + * No protection, label 'Looking for trouble' * @var integer */ const SECURITY_LEVEL_NONE = 0; @@ -887,18 +887,34 @@ class e_core_session extends e_session } /** - * Creates (once per session) unique challenge string for CHAP login + * Make sure there is unique challenge string for CHAP login * @see class2.php * @return e_core_session + + @TODO: Remove debug code */ public function challenge() { - if (!$this->is('challenge')) - { - // Create a unique challenge string for CHAP login - // FIXME - session id will be regenerated if e_SECURITY_LEVEL is 'paranoid|insane' - $this->set('challenge', sha1(time().$this->getSessionId())); + if (!$this->is('challenge')) // TODO: Eliminate need for this + { + $this->set('challenge', sha1(time().rand().$this->getSessionId())); // New challenge for next time } + if ($this->is('challenge')) + { + $this->set('prevprevchallenge', $this->get('prevchallenge')); // Purely for debug + $this->set('prevchallenge', $this->get('challenge')); // Need to check user login against this + } + else + { + $this->set('prevchallenge', ''); // Dummy value + $this->set('prevprevchallenge', ''); // Dummy value + } + //$this->set('challenge', sha1(time().rand().$this->getSessionId())); // Temporarily disabled + // FIXME - session id will be regenerated if e_SECURITY_LEVEL is 'paranoid|insane' - generate (might be OK as long as values retained) + + //$extra_text = 'C: '.$this->get('challenge').' PC: '.$this->get('prevchallenge').' PPC: '.$this->get('prevprevchallenge'); + //$logfp = fopen(e_LOG.'authlog.txt', 'a+'); fwrite($logfp, strftime('%H:%M:%S').' CHAP start: '.$extra_text."\n"); fclose($logfp); + // could go, see _validate() $ubrowser = md5('E107'.$_SERVER['HTTP_USER_AGENT']); if (!$this->is('ubrowser')) diff --git a/e107_web/js/chap_script.js b/e107_web/js/chap_script.js index 3b1085631..1530f13b7 100644 --- a/e107_web/js/chap_script.js +++ b/e107_web/js/chap_script.js @@ -19,10 +19,11 @@ function getChallenge() // Passed current form function hashLoginPassword(doForm) { - getChallenge(); + //getChallenge(); if (typeof(hex_md5) == "undefined") return; if (typeof(challenge) == "undefined") return; + //alert('P: '+ doForm.userpass.value + ' U: ' + doForm.username.value + ' C: ' + challenge); doForm.hashchallenge.value = hex_md5(hex_md5(hex_md5(doForm.userpass.value) + doForm.username.value) + challenge); doForm.userpass.value = ""; // Don't send plaintext password back return true;