From 918d5fd469c24fc62f53ceced6f405d3f0913fcf Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Oct 2018 09:39:04 -0400 Subject: [PATCH 1/3] move utility functions for doing get/post requests into functions.php from actions.php --- web/includes/actions.php | 45 ------------------------------------- web/includes/functions.php | 46 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/web/includes/actions.php b/web/includes/actions.php index de0861fe0..9e0b15bca 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -18,51 +18,6 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -// PP - POST request handler for PHP which does not need extensions -// credit: http://wezfurlong.org/blog/2006/nov/http-post-from-php-without-curl/ - - -function do_request($method, $url, $data=array(), $optional_headers = null) { - global $php_errormsg; - - $params = array('http' => array( - 'method' => $method, - 'content' => $data - )); - if ( $optional_headers !== null ) { - $params['http']['header'] = $optional_headers; - } - $ctx = stream_context_create($params); - $fp = @fopen($url, 'rb', false, $ctx); - if ( !$fp ) { - throw new Exception("Problem with $url, $php_errormsg"); - } - $response = @stream_get_contents($fp); - if ( $response === false ) { - throw new Exception("Problem reading data from $url, $php_errormsg"); - } - return $response; -} - -function do_post_request($url, $data, $optional_headers = null) { - $params = array('http' => array( - 'method' => 'POST', - 'content' => $data - )); - if ( $optional_headers !== null ) { - $params['http']['header'] = $optional_headers; - } - $ctx = stream_context_create($params); - $fp = @fopen($url, 'rb', false, $ctx); - if ( !$fp ) { - throw new Exception("Problem with $url, $php_errormsg"); - } - $response = @stream_get_contents($fp); - if ( $response === false ) { - throw new Exception("Problem reading data from $url, $php_errormsg"); - } - return $response; -} function getAffectedIds( $name ) { $names = $name.'s'; diff --git a/web/includes/functions.php b/web/includes/functions.php index e610ad8dd..d5b12d495 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2272,4 +2272,50 @@ function unparse_url($parsed_url, $substitutions = array() ) { $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : ''; return "$scheme$user$pass$host$port$path$query$fragment"; } + +// PP - POST request handler for PHP which does not need extensions +// credit: http://wezfurlong.org/blog/2006/nov/http-post-from-php-without-curl/ + + +function do_request($method, $url, $data=array(), $optional_headers = null) { + global $php_errormsg; + + $params = array('http' => array( + 'method' => $method, + 'content' => $data + )); + if ( $optional_headers !== null ) { + $params['http']['header'] = $optional_headers; + } + $ctx = stream_context_create($params); + $fp = @fopen($url, 'rb', false, $ctx); + if ( !$fp ) { + throw new Exception("Problem with $url, $php_errormsg"); + } + $response = @stream_get_contents($fp); + if ( $response === false ) { + throw new Exception("Problem reading data from $url, $php_errormsg"); + } + return $response; +} + +function do_post_request($url, $data, $optional_headers = null) { + $params = array('http' => array( + 'method' => 'POST', + 'content' => $data + )); + if ( $optional_headers !== null ) { + $params['http']['header'] = $optional_headers; + } + $ctx = stream_context_create($params); + $fp = @fopen($url, 'rb', false, $ctx); + if ( !$fp ) { + throw new Exception("Problem with $url, $php_errormsg"); + } + $response = @stream_get_contents($fp); + if ( $response === false ) { + throw new Exception("Problem reading data from $url, $php_errormsg"); + } + return $response; +} ?> From a3d0cb42ea5124db961709d25f5f769e92967026 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Oct 2018 10:05:50 -0400 Subject: [PATCH 2/3] Move GOOGLE RECAPCHA to includes/auth.php, clean login actions. --- web/includes/actions.php | 53 ++++++------------------------------ web/includes/auth.php | 59 ++++++++++++++++++++++++++++++++++++++-- web/index.php | 19 ++----------- 3 files changed, 68 insertions(+), 63 deletions(-) diff --git a/web/includes/actions.php b/web/includes/actions.php index 9e0b15bca..ecde1b80c 100644 --- a/web/includes/actions.php +++ b/web/includes/actions.php @@ -43,52 +43,17 @@ if ( empty($action) ) { return; } if ( $action == 'login' && isset($_REQUEST['username']) && ( ZM_AUTH_TYPE == 'remote' || isset($_REQUEST['password']) ) ) { - // if true, a popup will display after login - // PP - lets validate reCaptcha if it exists - if ( defined('ZM_OPT_USE_GOOG_RECAPTCHA') - && defined('ZM_OPT_GOOG_RECAPTCHA_SECRETKEY') - && defined('ZM_OPT_GOOG_RECAPTCHA_SITEKEY') - && ZM_OPT_USE_GOOG_RECAPTCHA && ZM_OPT_GOOG_RECAPTCHA_SECRETKEY - && ZM_OPT_GOOG_RECAPTCHA_SITEKEY ) - { - $url = 'https://www.google.com/recaptcha/api/siteverify'; - $fields = array ( - 'secret' => ZM_OPT_GOOG_RECAPTCHA_SECRETKEY, - 'response' => $_REQUEST['g-recaptcha-response'], - 'remoteip' => $_SERVER['REMOTE_ADDR'] - ); - $res = do_post_request($url, http_build_query($fields)); - $responseData = json_decode($res,true); - // PP - credit: https://github.com/google/recaptcha/blob/master/src/ReCaptcha/Response.php - // if recaptcha resulted in error, we might have to deny login - if ( isset($responseData['success']) && $responseData['success'] == false ) { - // PP - before we deny auth, let's make sure the error was not 'invalid secret' - // because that means the user did not configure the secret key correctly - // in this case, we prefer to let him login in and display a message to correct - // the key. Unfortunately, there is no way to check for invalid site key in code - // as it produces the same error as when you don't answer a recaptcha - if ( isset($responseData['error-codes']) && is_array($responseData['error-codes']) ) { - if ( !in_array('invalid-input-secret',$responseData['error-codes']) ) { - Error('reCaptcha authentication failed'); - userLogout(); - $view = 'login'; - $refreshParent = true; - return; - } else { - //Let them login but show an error - echo ''; - Error('Invalid recaptcha secret detected'); - } - } - } // end if success==false - } // end if using reCaptcha - $username = validStr($_REQUEST['username']); - $password = isset($_REQUEST['password'])?validStr($_REQUEST['password']):''; - userLogin($username, $password); $refreshParent = true; - $view = 'console'; - $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=console'; + // User login is automatically performed in includes/auth.php So we don't need to perform a login here, + // just handle redirects. This is the action that comes from the login view, so the logical thing to + // do on successful auth is redirect to console, otherwise loop back to login. + if ( !$user ) { + $view = 'login'; + } else { + $view = 'console'; + $redirect = ZM_BASE_URL.$_SERVER['PHP_SELF'].'?view=console'; + } } else if ( $action == 'logout' ) { userLogout(); $refreshParent = true; diff --git a/web/includes/auth.php b/web/includes/auth.php index 9cf8d37c1..0f7e79b36 100644 --- a/web/includes/auth.php +++ b/web/includes/auth.php @@ -18,9 +18,50 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // -function userLogin($username, $password='', $passwordHashed=false) { +function userLogin($username='', $password='', $passwordHashed=false) { global $user; + if ( !$username and isset($_REQUEST['username']) ) + $username = $_REQUEST['username']; + if ( !$password and isset($_REQUEST['password']) ) + $password = $_REQUEST['password']; + + // if true, a popup will display after login + // PP - lets validate reCaptcha if it exists + if ( defined('ZM_OPT_USE_GOOG_RECAPTCHA') + && defined('ZM_OPT_GOOG_RECAPTCHA_SECRETKEY') + && defined('ZM_OPT_GOOG_RECAPTCHA_SITEKEY') + && ZM_OPT_USE_GOOG_RECAPTCHA + && ZM_OPT_GOOG_RECAPTCHA_SECRETKEY + && ZM_OPT_GOOG_RECAPTCHA_SITEKEY ) + { + $url = 'https://www.google.com/recaptcha/api/siteverify'; + $fields = array ( + 'secret' => ZM_OPT_GOOG_RECAPTCHA_SECRETKEY, + 'response' => $_REQUEST['g-recaptcha-response'], + 'remoteip' => $_SERVER['REMOTE_ADDR'] + ); + $res = do_post_request($url, http_build_query($fields)); + $responseData = json_decode($res,true); + // PP - credit: https://github.com/google/recaptcha/blob/master/src/ReCaptcha/Response.php + // if recaptcha resulted in error, we might have to deny login + if ( isset($responseData['success']) && $responseData['success'] == false ) { + // PP - before we deny auth, let's make sure the error was not 'invalid secret' + // because that means the user did not configure the secret key correctly + // in this case, we prefer to let him login in and display a message to correct + // the key. Unfortunately, there is no way to check for invalid site key in code + // as it produces the same error as when you don't answer a recaptcha + if ( isset($responseData['error-codes']) && is_array($responseData['error-codes']) ) { + if ( !in_array('invalid-input-secret',$responseData['error-codes']) ) { + Error('reCaptcha authentication failed'); + return null; + } else { + Error('Invalid recaptcha secret detected'); + } + } + } // end if success==false + } // end if using reCaptcha + $sql = 'SELECT * FROM Users WHERE Enabled=1'; $sql_values = NULL; if ( ZM_AUTH_TYPE == 'builtin' ) { @@ -36,7 +77,6 @@ function userLogin($username, $password='', $passwordHashed=false) { } $close_session = 0; if ( !is_session_started() ) { - Logger::Debug("Starting session in userLogin"); session_start(); $close_session = 1; } @@ -70,7 +110,6 @@ function userLogout() { session_start(); unset($_SESSION['user']); unset($user); - session_destroy(); } @@ -179,4 +218,18 @@ function is_session_started() { return FALSE; } +if ( ZM_OPT_USE_AUTH ) { + if ( ZM_AUTH_HASH_LOGINS && empty($user) && ! empty($_REQUEST['auth']) ) { + if ( $authUser = getAuthUser($_REQUEST['auth']) ) { + userLogin($authUser['Username'], $authUser['Password'], true); + } + } + else if ( isset($_REQUEST['username']) and isset($_REQUEST['password']) ) { + userLogin($_REQUEST['username'], $_REQUEST['password'], false); + } + if ( !empty($user) ) { + // generate it once here, while session is open. Value will be cached in session and return when called later on + generateAuthHash(ZM_AUTH_HASH_IPS); + } +} ?> diff --git a/web/index.php b/web/index.php index addddce06..f25b9eb15 100644 --- a/web/index.php +++ b/web/index.php @@ -156,7 +156,6 @@ session_write_close(); require_once('includes/lang.php'); require_once('includes/functions.php'); -require_once('includes/auth.php'); # Running is global but only do the daemonCheck if it is actually needed $running = null; @@ -182,20 +181,8 @@ if ( isset($_REQUEST['request']) ) foreach ( getSkinIncludes('skin.php') as $includeFile ) require_once $includeFile; -if ( ZM_OPT_USE_AUTH ) { - if ( ZM_AUTH_HASH_LOGINS && empty($user) && ! empty($_REQUEST['auth']) ) { - if ( $authUser = getAuthUser($_REQUEST['auth']) ) { - userLogin($authUser['Username'], $authUser['Password'], true); - } - } - else if ( isset($_REQUEST['username']) and isset($_REQUEST['password']) ) { - userLogin($_REQUEST['username'], $_REQUEST['password'], false); - } - if ( !empty($user) ) { - // generate it once here, while session is open. Value will be cached in session and return when called later on - generateAuthHash(ZM_AUTH_HASH_IPS); - } -} +# User Login will be performed in auth.php +require_once('includes/auth.php'); if ( isset($_REQUEST['action']) ) { $action = detaintPath($_REQUEST['action']); @@ -229,7 +216,7 @@ if ( ZM_OPT_USE_AUTH and !isset($user) ) { Logger::Debug('Redirecting to login'); $view = 'login'; $request = null; -} else if ( ZM_SHOW_PRIVACY && ($action != 'privacy') && ($view !='options') && (!$request) && canEdit('System') ) { +} else if ( ZM_SHOW_PRIVACY && ($action != 'privacy') && ($view != 'options') && (!$request) && canEdit('System') ) { Logger::Debug('Redirecting to privacy'); $view = 'privacy'; $request = null; From cbc26e0cec44acfbb8f12c16434013624f314fd9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Oct 2018 10:07:40 -0400 Subject: [PATCH 3/3] cleanup trailing whitespace --- web/includes/auth.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/includes/auth.php b/web/includes/auth.php index 0f7e79b36..13f259572 100644 --- a/web/includes/auth.php +++ b/web/includes/auth.php @@ -2,21 +2,21 @@ // // ZoneMinder auth library, $Date$, $Revision$ // Copyright (C) 2001-2008 Philip Coombes -// +// // 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. -// +// function userLogin($username='', $password='', $passwordHashed=false) { global $user; @@ -28,11 +28,11 @@ function userLogin($username='', $password='', $passwordHashed=false) { // if true, a popup will display after login // PP - lets validate reCaptcha if it exists - if ( defined('ZM_OPT_USE_GOOG_RECAPTCHA') - && defined('ZM_OPT_GOOG_RECAPTCHA_SECRETKEY') + if ( defined('ZM_OPT_USE_GOOG_RECAPTCHA') + && defined('ZM_OPT_GOOG_RECAPTCHA_SECRETKEY') && defined('ZM_OPT_GOOG_RECAPTCHA_SITEKEY') && ZM_OPT_USE_GOOG_RECAPTCHA - && ZM_OPT_GOOG_RECAPTCHA_SECRETKEY + && ZM_OPT_GOOG_RECAPTCHA_SECRETKEY && ZM_OPT_GOOG_RECAPTCHA_SITEKEY ) { $url = 'https://www.google.com/recaptcha/api/siteverify'; @@ -223,7 +223,7 @@ if ( ZM_OPT_USE_AUTH ) { if ( $authUser = getAuthUser($_REQUEST['auth']) ) { userLogin($authUser['Username'], $authUser['Password'], true); } - } + } else if ( isset($_REQUEST['username']) and isset($_REQUEST['password']) ) { userLogin($_REQUEST['username'], $_REQUEST['password'], false); }