diff --git a/src/language/en-GB/en-GB.plg_api_users.ini b/src/language/en-GB/en-GB.plg_api_users.ini index 1e75e9c..17739ba 100755 --- a/src/language/en-GB/en-GB.plg_api_users.ini +++ b/src/language/en-GB/en-GB.plg_api_users.ini @@ -1,3 +1,11 @@ +; @package API +; @subpackage plg_api_users +; +; @author Techjoomla +; @copyright Copyright (C) 2009 - 2019 Techjoomla, Tekdi Technologies Pvt. Ltd. All rights reserved. +; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL +; Note All ini files need to be saved as UTF-8 + PLG_API_USERS="API - Users" PLG_API_USERS_DESCRIPTION="This plugin exposes users to the Joomla! API. Supports creation, listing and login for users." PLG_API_USERS_BAD_REQUEST_MESSAGE="Bad request" diff --git a/src/users.php b/src/users.php index bd8e736..7de517b 100644 --- a/src/users.php +++ b/src/users.php @@ -1,29 +1,43 @@ - * @link http://www.techjoomla.com -*/ + * @package API + * @subpackage plg_api_users + * + * @author Techjoomla + * @copyright Copyright (C) 2009 - 2019 Techjoomla, Tekdi Technologies Pvt. Ltd. All rights reserved. + * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL + */ -defined('_JEXEC') or die( 'Restricted access' ); +// No direct access. +defined('_JEXEC') or die('Restricted access'); jimport('joomla.plugin.plugin'); -class plgAPIUsers extends ApiPlugin +/** + * Users plgAPI class + * + * @since 1.0.0 + */ +class PlgAPIUsers extends ApiPlugin { + /** + * Constructor + * + * @param string &$subject subject + * @param string $config config + */ public function __construct(&$subject, $config = array()) { parent::__construct($subject, $config = array()); - ApiResource::addIncludePath(dirname(__FILE__).'/users'); - - /*load language file for plugin frontend*/ - $lang = JFactory::getLanguage(); - $lang->load('plg_api_users', JPATH_ADMINISTRATOR,'',true); - + ApiResource::addIncludePath(dirname(__FILE__) . '/users'); + + // Load language file for plugin frontend + $lang = JFactory::getLanguage(); + $lang->load('plg_api_users', JPATH_ADMINISTRATOR, '', true); + // Set the login resource to be public - $this->setResourceAccess('login', 'public','get'); + $this->setResourceAccess('login', 'public', 'get'); $this->setResourceAccess('users', 'public', 'post'); $this->setResourceAccess('config', 'public', 'get'); $this->setResourceAccess('user', 'public', 'post'); diff --git a/src/users/impersonatelogin.php b/src/users/impersonatelogin.php new file mode 100644 index 0000000..87018fd --- /dev/null +++ b/src/users/impersonatelogin.php @@ -0,0 +1,261 @@ + + * @copyright Copyright (C) 2009 - 2022 Techjoomla, Tekdi Technologies Pvt. Ltd. All rights reserved. + * @license GNU GPLv2 + */ + +// No direct access. +defined('_JEXEC') or die('Restricted access'); + +require_once JPATH_SITE . '/components/com_api/vendors/php-jwt/src/JWT.php'; +use Firebase\JWT\JWT; + +use Joomla\CMS\Factory; +use Joomla\CMS\User\UserHelper; +use Joomla\CMS\Language\Text; +use Joomla\CMS\Table\Table; +use Joomla\CMS\Session\Session; +use Joomla\CMS\Component\ComponentHelper; + +JModelLegacy::addIncludePath(JPATH_SITE . 'components/com_api/models'); +require_once JPATH_SITE . '/components/com_api/libraries/authentication/user.php'; +require_once JPATH_SITE . '/components/com_api/libraries/authentication/login.php'; +require_once JPATH_ADMINISTRATOR . '/components/com_api/models/key.php'; +require_once JPATH_ADMINISTRATOR . '/components/com_api/models/keys.php'; + +/** + * Impersonate Login API resource class + * + * @package API + * @since 1.6.0 + */ +class UsersApiResourceImpersonateLogin extends ApiResource +{ + /** + * Get method + * + * @return object + */ + public function get() + { + $this->plugin->setResponse(Text::_('PLG_API_USERS_GET_METHOD_NOT_ALLOWED_MESSAGE')); + } + + /** + * Post method + * + * @return object + */ + public function post() + { + $this->plugin->setResponse($this->keygen()); + } + + /** + * Generate key method + * + * @return object|boolean + */ + public function keygen() + { + // Init variables + $obj = new stdclass; + $jinput = Factory::getApplication()->input; + $xImpersonate = $jinput->server->get('X-Impersonate', '', 'STRING'); + $httpXImpersonate = $jinput->server->get('HTTP_X_IMPERSONATE', '', 'STRING'); + + if (!empty($xImpersonate)) + { + $userToImpersonate = $xImpersonate; + } + elseif (!empty($httpXImpersonate)) + { + $userToImpersonate = $httpXImpersonate; + } + + if (preg_match('/email:(\S+)/', $userToImpersonate, $matches)) + { + $userId = $this->getUserByEmail($matches[1]); + } + elseif (preg_match('/username:(\S+)/', $userToImpersonate, $matches)) + { + $userId = UserHelper::getUserId($matches[1]); + } + elseif (is_numeric($userToImpersonate)) + { + $userId = $userToImpersonate; + } + else + { + ApiError::raiseError("403", Text::_('PLG_API_USERS_BAD_REQUEST_MESSAGE')); + + return false; + } + + if ($userId && $email) + { + $model = FD::model('Users'); + $userId = $model->getUserId('email', $userId); + } + + if (!$userId) + { + ApiError::raiseError("403", Text::_('PLG_API_USERS_BAD_REQUEST_MESSAGE')); + + return; + } + + // Init vars + $keyModel = new ApiModelKey; + $keysModel = new ApiModelKeys; + $key = null; + + // Get login user hash + // $keyModel->setState('user_id', $user->id); + + // $keyModel->setState('user_id', $id); + // $log_hash = $keyModel->getList(); + $keysModel->setState('user_id', $userId); + $log_hash = $keysModel->getItems(); + + $log_hash = (!empty($log_hash)) ? $log_hash[count($log_hash) - count($log_hash)] : $log_hash; + + if (!empty($log_hash)) + { + $key = $log_hash->hash; + } + elseif ($key == null || empty($key)) + { + // Create new key for user + $data = array ( + 'userid' => $userId, + 'domain' => '' , + 'state' => 1, + 'id' => '', + 'task' => 'save', + 'c' => 'key', + 'ret' => 'index.php?option=com_api&view=keys', + 'option' => 'com_api', + Session::getFormToken() => 1 + ); + + $result = $keyModel->save($data); + + // $key = $result->hash; + + if (!$result) + { + return false; + } + + // Load api key table + Table::addIncludePath(JPATH_ROOT . '/administrator/components/com_api/tables'); + $table = Table::getInstance('Key', 'ApiTable'); + $table->load(array('userid' => $userId)); + $key = $table->hash; + + // Add new key in easysocial table + $easyblog = JPATH_ROOT . '/administrator/components/com_easyblog/easyblog.php'; + + if (file_exists($easyblog) && ComponentHelper::isEnabled('com_easysocial', true)) + { + $this->updateEauth($user, $key); + } + } + + if (!empty($key)) + { + $obj->auth = $key; + $obj->code = '200'; + + // $obj->id = $user->id; + // $obj->id = $id; + + // Set user details for response + $obj->id = $userId; + $obj->name = Factory::getUser($userId)->name; + $obj->username = Factory::getUser($userId)->username; + $obj->email = Factory::getUser($userId)->email; + + // Generate claim for jwt + $data = [ + "id" => trim($userId), + + /*"iat" => '', + "exp" => '', + "aud" => '', + "sub" => ''"*/ + ]; + + // Using HS256 algo to generate JWT + $jwt = JWT::encode($data, trim($key), 'HS256'); + + if (isset($jwt) && $jwt != '') + { + $obj->jwt = $jwt; + } + else + { + $obj->jwt = false; + } + } + else + { + $obj->code = 403; + $obj->message = Text::_('PLG_API_USERS_BAD_REQUEST_MESSAGE'); + } + + return ($obj); + } + + /** + * Method to update Easyblog auth keys + * + * @param mixed $user User object + * @param mixed $key Key + * + * @return integer + * + * @since 1.6 + */ + public function updateEauth ($user = null, $key = null) + { + require_once JPATH_ADMINISTRATOR . '/components/com_easysocial/includes/foundry.php'; + + $keysModel = FD::model('Users'); + $id = $keysModel->getUserId('username', $user->username); + $user = FD::user($id); + + $user->alias = $user->username; + $user->auth = $key; + $user->store(); + + return $id; + } + + /** + * Function to fetch user id by email + * + * @param string $email User email + * + * @return integer User Id. + * + * @since 1.0 + */ + private function getUserByEmail($email) + { + $db = Factory::getDbo(); + $query = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName('#__users')) + ->where($db->quoteName('email') . ' = ' . $db->quote($email)); + $db->setQuery($query); + $user = $db->loadResult(); + + return $user; + } +} diff --git a/src/users/login.php b/src/users/login.php index ba2b5b8..7d4b9be 100644 --- a/src/users/login.php +++ b/src/users/login.php @@ -12,16 +12,8 @@ defined('_JEXEC') or die('Restricted access'); require_once JPATH_SITE . '/components/com_api/vendors/php-jwt/src/JWT.php'; - use Firebase\JWT\JWT; -jimport('joomla.plugin.plugin'); -jimport('joomla.html.html'); -jimport('joomla.application.component.controller'); -jimport('joomla.application.component.model'); -jimport('joomla.user.helper'); -jimport('joomla.user.user'); -jimport('joomla.application.component.helper'); JModelLegacy::addIncludePath(JPATH_SITE . 'components/com_api/models'); require_once JPATH_SITE . '/components/com_api/libraries/authentication/user.php'; @@ -64,34 +56,55 @@ public function post() */ public function keygen() { - // Init variable - $obj = new stdclass; - $umodel = new JUser; - $user = $umodel->getInstance(); - + // Init variables + $obj = new stdclass; $app = JFactory::getApplication(); - $username = $app->input->get('username', 0, 'STRING'); + $username = $app->input->get('username', '', 'STRING'); + $password = $app->input->get('password', '', 'STRING'); + + // Authenticate User + jimport('joomla.user.authentication'); + + $authenticate = JAuthentication::getInstance(); + $response = $authenticate->authenticate(array( 'username' => $username, 'password' => $password )); + + if ($response->status != JAuthentication::STATUS_SUCCESS) + { + ApiError::raiseError("403", JText::_('JLIB_LOGIN_AUTHENTICATE')); + } $user = JFactory::getUser(); - $id = JUserHelper::getUserId($username); - if ($id == null) + if ($username) + { + $umodel = new JUser; + $user = $umodel->getInstance(); + + $userId = JUserHelper::getUserId($username); + + if ($userId == null) + { + $keysModel = FD::model('Users'); + $userId = $keysModel->getUserId('email', $username); + } + } + else { - $model = FD::model('Users'); - $id = $model->getUserId('email', $username); + $userId = $user->id; } - $kmodel = new ApiModelKey; - $model = new ApiModelKeys; - $key = null; + // Init vars + $keyModel = new ApiModelKey; + $keysModel = new ApiModelKeys; + $key = null; // Get login user hash - // $kmodel->setState('user_id', $user->id); + // $keyModel->setState('user_id', $user->id); - // $kmodel->setState('user_id', $id); - // $log_hash = $kmodel->getList(); - $model->setState('user_id', $id); - $log_hash = $model->getItems(); + // $keyModel->setState('user_id', $id); + // $log_hash = $keyModel->getList(); + $keysModel->setState('user_id', $userId); + $log_hash = $keysModel->getItems(); $log_hash = (!empty($log_hash)) ? $log_hash[count($log_hash) - count($log_hash)] : $log_hash; @@ -103,7 +116,7 @@ public function keygen() { // Create new key for user $data = array ( - 'userid' => $user->id, + 'userid' => $userId, 'domain' => '' , 'state' => 1, 'id' => '', @@ -114,7 +127,7 @@ public function keygen() JSession::getFormToken() => 1 ); - $result = $kmodel->save($data); + $result = $keyModel->save($data); // $key = $result->hash; @@ -126,7 +139,7 @@ public function keygen() // Load api key table JTable::addIncludePath(JPATH_ROOT . '/administrator/components/com_api/tables'); $table = JTable::getInstance('Key', 'ApiTable'); - $table->load(array('userid' => $user->id)); + $table->load(array('userid' => $userId)); $key = $table->hash; // Add new key in easysocial table @@ -144,12 +157,18 @@ public function keygen() $obj->code = '200'; // $obj->id = $user->id; + // $obj->id = $id; - $obj->id = $id; + // Set user details for response + $obj->id = $userId; + $obj->name = JFactory::getUser($userId)->name; + $obj->username = JFactory::getUser($userId)->username; + $obj->email = JFactory::getUser($userId)->email; // Generate claim for jwt $data = [ - "id" => trim($id), + "id" => trim($userId), + /*"iat" => '', "exp" => '', "aud" => '', @@ -191,9 +210,10 @@ public function updateEauth ($user = null, $key = null) { require_once JPATH_ADMINISTRATOR . '/components/com_easysocial/includes/foundry.php'; - $model = FD::model('Users'); - $id = $model->getUserId('username', $user->username); - $user = FD::user($id); + $keysModel = FD::model('Users'); + $id = $keysModel->getUserId('username', $user->username); + $user = FD::user($id); + $user->alias = $user->username; $user->auth = $key; $user->store(); diff --git a/src/users/user.php b/src/users/user.php index bee8825..50bacf7 100644 --- a/src/users/user.php +++ b/src/users/user.php @@ -1,13 +1,15 @@ + * @copyright Copyright (C) 2009 - 2019 Techjoomla, Tekdi Technologies Pvt. Ltd. All rights reserved. + * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL */ // No direct access. -defined('_JEXEC') or die(); +defined('_JEXEC') or die('Restricted access'); /** * User Api. diff --git a/src/users/users.php b/src/users/users.php index 93d8a22..a4f4104 100644 --- a/src/users/users.php +++ b/src/users/users.php @@ -1,13 +1,15 @@ + * @copyright Copyright (C) 2009 - 2019 Techjoomla, Tekdi Technologies Pvt. Ltd. All rights reserved. + * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL */ + // No direct access. -defined('_JEXEC') or die; +defined('_JEXEC') or die('Restricted access'); jimport('joomla.user.user'); jimport('joomla.plugin.plugin');