From b40720204321fe5dbaf4098792215737236655c8 Mon Sep 17 00:00:00 2001 From: Ashwin Date Date: Sat, 13 Apr 2019 15:04:59 +0530 Subject: [PATCH] Release 2.4.0 (#98) Issue #95 feat: Allow User Impersonation If a user is not allowed to use impersonation, throw an error instead of falling back to the token user. --- .../system/tjtokenlogin/tjtokenlogin.php | 19 ++- code/site/language/en-GB/en-GB.com_api.ini | 5 +- code/site/libraries/authentication.php | 116 ++++++++++++++++++ code/site/libraries/authentication/key.php | 24 ++-- 4 files changed, 149 insertions(+), 15 deletions(-) diff --git a/code/plugins/system/tjtokenlogin/tjtokenlogin.php b/code/plugins/system/tjtokenlogin/tjtokenlogin.php index 1e37822..39ff3a1 100644 --- a/code/plugins/system/tjtokenlogin/tjtokenlogin.php +++ b/code/plugins/system/tjtokenlogin/tjtokenlogin.php @@ -9,10 +9,21 @@ defined('_JEXEC') or die('Unauthorized Access'); -require_once JPATH_SITE . '/components/com_api/vendors/php-jwt/src/JWT.php'; -require_once JPATH_SITE . '/components/com_api/vendors/php-jwt/src/BeforeValidException.php'; -require_once JPATH_SITE . '/components/com_api/vendors/php-jwt/src/ExpiredException.php'; -require_once JPATH_SITE . '/components/com_api/vendors/php-jwt/src/SignatureInvalidException.php'; +jimport('joomla.filesystem.file'); + +$jwtBasePath = JPATH_SITE . '/components/com_api/vendors/php-jwt/src'; +$jwtFilePath = $jwtBasePath . '/JWT.php'; + +if (!JFile::exists($jwtFilePath)) +{ + return; +} + +JLoader::import('JWT', $jwtBasePath); +JLoader::import('DomainException', $jwtBasePath); +JLoader::import('InvalidArgumentException', $jwtBasePath); +JLoader::import('UnexpectedValueException', $jwtBasePath); +JLoader::import('DateTime', $jwtBasePath); use Firebase\JWT\JWT; use Firebase\JWT\DomainException; diff --git a/code/site/language/en-GB/en-GB.com_api.ini b/code/site/language/en-GB/en-GB.com_api.ini index bd42068..e68650d 100644 --- a/code/site/language/en-GB/en-GB.com_api.ini +++ b/code/site/language/en-GB/en-GB.com_api.ini @@ -49,6 +49,7 @@ COM_API_ACCESS_SPECIAL="Special" COM_API_SUCCESS="Success" COM_API_UNEXPECTED_ERROR="Unexpected error ocurred" COM_API_KEY_CREATE_UNAUTORIZED="You are not authorized to create API keys, please contact your administrator." - -;vishal - for j3.2 COM_API_METHOD_NALLOW="This method not allowed" + +; Since __DEPLOY_VERSION__ +COM_API_INVALID_USER_TO_IMPERSONATE="Invalid user to impersonate" diff --git a/code/site/libraries/authentication.php b/code/site/libraries/authentication.php index 828f9ab..b72b28b 100644 --- a/code/site/libraries/authentication.php +++ b/code/site/libraries/authentication.php @@ -273,4 +273,120 @@ private static function getAuthorizationHeader() return $headers; } + + /** + * Find if the user is trying impersonate other user + * + * @return int|string|NULL User id or Email id or null + * + * @since __DEPLOY_VERSION__ + */ + public static function getImpersonateHeader() + { + $jinput = JFactory::getApplication()->input; + $xImpersonate = $jinput->server->get('X-Impersonate', '', 'STRING'); + $httpXImpersonate = $jinput->server->get('HTTP_X_IMPERSONATE', '', 'STRING'); + + if (!empty($xImpersonate)) + { + return $xImpersonate; + } + elseif (!empty($httpXImpersonate)) + { + return $httpXImpersonate; + } + } + + /** + * Find if the user is trying impersonate other user + * + * @param int $tokenUserId The userid for which token hash is validated + * + * @return int|boolean User id or Email id or null + * + * @since __DEPLOY_VERSION__ + */ + public static function getUserIdToImpersonate($tokenUserId) + { + // Lets find out if user trying to impersonate other user + $userToImpersonate = self::getImpersonateHeader(); + + // If other is to be impersonated + if (!$userToImpersonate) + { + return false; + } + + // Get user from tokenUserId + $user = JFactory::getUser($tokenUserId); + $isSuperAdmin = $user->authorise('core.admin'); + + // If this user is not super admin user, return false + if (!$isSuperAdmin) + { + ApiError::raiseError(403, "Not authorised to use Impersonation", 'APIUnauthorisedException'); + } + + $searchFor = ''; + $searchForValue = ''; + + if (preg_match('/email:(\S+)/', $userToImpersonate, $matches)) + { + $searchFor = 'email'; + $searchForValue = $matches[1]; + } + elseif (preg_match('/username:(\S+)/', $userToImpersonate, $matches)) + { + $searchFor = 'username'; + $searchForValue = $matches[1]; + } + elseif (is_numeric($userToImpersonate)) + { + $userId = $userToImpersonate; + } + else + { + ApiError::raiseError("400", JText::_('COM_API_INVALID_USER_TO_IMPERSONATE'), 'APIValidationException'); + + return false; + } + + // If username or emailid exists ? + if ($searchFor) + { + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName('#__users')) + ->where($db->quoteName($searchFor) . ' = ' . $db->quote($searchForValue)); + $db->setQuery($query); + + if ($id = $db->loadResult()) + { + return $id; + } + else + { + ApiError::raiseError("400", JText::_('COM_API_INVALID_USER_TO_IMPERSONATE'), 'APIValidationException'); + + return false; + } + } + // If userid exists ? + elseif ($userId) + { + $table = JUser::getTable(); + + if ($table->load($userId)) + { + return $userId; + } + else + { + ApiError::raiseError("400", JText::_('COM_API_INVALID_USER_TO_IMPERSONATE'), 'APIValidationException'); + + return false; + } + } + } } diff --git a/code/site/libraries/authentication/key.php b/code/site/libraries/authentication/key.php index ca4f7e4..37cd788 100755 --- a/code/site/libraries/authentication/key.php +++ b/code/site/libraries/authentication/key.php @@ -4,7 +4,7 @@ * @copyright Copyright (C) 2009-2017 Techjoomla, Tekdi Technologies Pvt. Ltd. All rights reserved. * @license GNU GPLv2 * @link http://techjoomla.com - * Work derived from the original RESTful API by Techjoomla (https://github.com/techjoomla/Joomla-REST-API) + * Work derived from the original RESTful API by Techjoomla (https://github.com/techjoomla/Joomla-REST-API) * and the com_api extension by Brian Edgerton (http://www.edgewebworks.com) */ @@ -18,26 +18,32 @@ */ class ApiAuthenticationKey extends ApiAuthentication { - protected $auth_method = null; + protected $auth_method = null; - protected $domain_checking = null; + protected $domain_checking = null; /** * Authenticate the user using the key in the header or request * - * @return string User id of the user or false + * @return int|boolean User id of the user or false */ public function authenticate() { - $app = JFactory::getApplication(); - $query_token = $app->input->get('key', '', 'STRING'); + $app = JFactory::getApplication(); + $query_token = $app->input->get('key', '', 'STRING'); $header_token = $this->getBearerToken(); - $key = $header_token ? $header_token : $query_token; - - $token = $this->loadTokenByHash($key); + $key = $header_token ? $header_token : $query_token; + $token = $this->loadTokenByHash($key); if (isset($token->state) && $token->state == 1) { + $userId = parent::getUserIdToImpersonate($token->userid); + + if ($userId) + { + return $userId; + } + return $token->userid; }