Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
934404c
Convert token api auth plugin to services
laoneo May 15, 2022
3e44d0f
cs
laoneo May 15, 2022
5b66d47
final
laoneo May 16, 2022
ebd9cb1
Update plugins/api-authentication/token/services/provider.php
laoneo May 17, 2022
994cb74
Inject filter
laoneo May 18, 2022
1562e71
Use the model to load the plugin params
laoneo May 18, 2022
1f18983
Update plugins/api-authentication/token/services/provider.php
laoneo May 18, 2022
b6fefae
Update plugins/api-authentication/token/services/provider.php
laoneo May 18, 2022
633c2ce
Merge branch '4.2-dev' into j4/plugins/api-auth/token
laoneo May 18, 2022
d64feca
Update plugins/api-authentication/token/services/provider.php
laoneo May 20, 2022
6e92ad1
Update plugins/api-authentication/token/src/Extension/Token.php
laoneo May 20, 2022
e96989b
Update plugins/api-authentication/token/token.xml
laoneo May 20, 2022
57f1a18
Merge branch '4.2-dev' into j4/plugins/api-auth/token
laoneo May 20, 2022
4c75189
Update plugins/api-authentication/token/src/Extension/Token.php
laoneo May 20, 2022
2566887
Update plugins/api-authentication/token/src/Extension/Token.php
laoneo May 20, 2022
5d1c029
Update plugins/api-authentication/token/src/Extension/Token.php
laoneo May 20, 2022
2d498a9
Update administrator/components/com_plugins/src/Model/PluginModel.php
laoneo May 20, 2022
88ff0d5
Update administrator/components/com_plugins/src/Model/PluginModel.php
laoneo May 20, 2022
aa76f6c
Update plugins/api-authentication/token/src/Extension/Token.php
laoneo May 20, 2022
693d585
Merge branch '4.2-dev' into j4/plugins/api-auth/token
laoneo May 20, 2022
0e62c34
Merge branch '4.2-dev' into j4/plugins/api-auth/token
roland-d May 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions administrator/components/com_plugins/src/Model/PluginModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,20 @@ public function getItem($pk = null)
{
$pk = (!empty($pk)) ? $pk : (int) $this->getState('plugin.id');

if (!isset($this->_cache[$pk]))
$cacheId = $pk;

if (is_array($cacheId))
{
$cacheId = serialize($cacheId);
}

if (!isset($this->_cache[$cacheId]))
{
// Get a row instance.
$table = $this->getTable();

// Attempt to load the row.
$return = $table->load(array('extension_id' => $pk, 'type' => 'plugin'));
$return = $table->load(is_array($pk) ? $pk : array('extension_id' => $pk, 'type' => 'plugin'));

// Check for a table object error.
if ($return === false)
Expand All @@ -177,26 +184,26 @@ public function getItem($pk = null)

// Convert to the \Joomla\CMS\Object\CMSObject before adding other data.
$properties = $table->getProperties(1);
$this->_cache[$pk] = ArrayHelper::toObject($properties, CMSObject::class);
$this->_cache[$cacheId] = ArrayHelper::toObject($properties, CMSObject::class);

// Convert the params field to an array.
$registry = new Registry($table->params);
$this->_cache[$pk]->params = $registry->toArray();
$this->_cache[$cacheId]->params = $registry->toArray();

// Get the plugin XML.
$path = Path::clean(JPATH_PLUGINS . '/' . $table->folder . '/' . $table->element . '/' . $table->element . '.xml');

if (file_exists($path))
{
$this->_cache[$pk]->xml = simplexml_load_file($path);
$this->_cache[$cacheId]->xml = simplexml_load_file($path);
}
else
{
$this->_cache[$pk]->xml = null;
$this->_cache[$cacheId]->xml = null;
}
}

return $this->_cache[$pk];
return $this->_cache[$cacheId];
}

/**
Expand Down
51 changes: 51 additions & 0 deletions plugins/api-authentication/token/services/provider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage Apiauthentication.token
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

defined('_JEXEC') or die;

use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Filter\InputFilter;
use Joomla\Plugin\APIAuthentication\Token\Extension\Token;

return new class implements ServiceProviderInterface
{
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since __DEPLOY_VERSION__
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container)
{
$plugin = new Token(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('api-authentication', 'token'),
$container->get(UserFactoryInterface::class),
new InputFilter
);
$plugin->setDatabase($container->get(DatabaseInterface::class));

return $plugin;
}
);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,30 @@
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/

namespace Joomla\Plugin\APIAuthentication\Token\Extension;

defined('_JEXEC') or die;

use Joomla\CMS\Application\ApiApplication;
use Joomla\CMS\Authentication\Authentication;
use Joomla\CMS\Crypt\Crypt;
use Joomla\CMS\Factory;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\Database\DatabaseInterface;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Component\Plugins\Administrator\Model\PluginModel;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Database\ParameterType;
use Joomla\Registry\Registry;
use Joomla\Event\DispatcherInterface;
use Joomla\Filter\InputFilter;

/**
* Joomla Token Authentication plugin
*
* @since 4.0.0
*/
class PlgApiAuthenticationToken extends CMSPlugin
final class Token extends CMSPlugin
{
use DatabaseAwareTrait;

/**
* The application object
*
Expand All @@ -36,14 +39,6 @@ class PlgApiAuthenticationToken extends CMSPlugin
*/
protected $app;

/**
* The application object
*
* @var DatabaseInterface
* @since 4.0.0
*/
protected $db;

/**
* The prefix of the user profile keys, without the dot.
*
Expand All @@ -60,6 +55,41 @@ class PlgApiAuthenticationToken extends CMSPlugin
*/
private $allowedAlgos = ['sha256', 'sha512'];

/**
* The user factory
*
* @var UserFactoryInterface
*
* @since __DEPLOY_VERSION__
*/
private $userFactory;

/**
* The input filter
*
* @var InputFilter
*
* @since __DEPLOY_VERSION__
*/
private $filter;

/**
* Constructor.
*
* @param DispatcherInterface $dispatcher The dispatcher
* @param array $config An optional associative array of configuration settings
* @param UserFactoryInterface $userFactory The user factory
*
* @since __DEPLOY_VERSION__
*/
public function __construct(DispatcherInterface $dispatcher, array $config, UserFactoryInterface $userFactory, InputFilter $filter)
{
parent::__construct($dispatcher, $config);

$this->userFactory = $userFactory;
$this->filter = $filter;
}

/**
* This method should handle any authentication and report back to the subject
*
Expand All @@ -76,7 +106,7 @@ public function onUserAuthenticate($credentials, $options, &$response): void
// Default response is authentication failure.
$response->type = 'Token';
$response->status = Authentication::STATUS_FAILURE;
$response->error_message = Text::_('JGLOBAL_AUTH_FAIL');
$response->error_message = $this->app->getLanguage()->_('JGLOBAL_AUTH_FAIL');

/**
* First look for an HTTP Authorization header with the following format:
Expand All @@ -95,17 +125,15 @@ public function onUserAuthenticate($credentials, $options, &$response): void

if (array_key_exists('authorization', $apacheHeaders))
{
$filter = \Joomla\CMS\Filter\InputFilter::getInstance();
$authHeader = $filter->clean($apacheHeaders['authorization'], 'STRING');
$authHeader = $this->filter->clean($apacheHeaders['authorization'], 'STRING');
}
}

if (substr($authHeader, 0, 7) == 'Bearer ')
{
$parts = explode(' ', $authHeader, 2);
$tokenString = trim($parts[1]);
$filter = InputFilter::getInstance();
$tokenString = $filter->clean($tokenString, 'BASE64');
$tokenString = $this->filter->clean($tokenString, 'BASE64');
}

if (empty($tokenString))
Expand Down Expand Up @@ -157,7 +185,7 @@ public function onUserAuthenticate($credentials, $options, &$response): void
{
$siteSecret = $this->app->get('secret');
}
catch (Exception $e)
catch (\Exception $e)
{
return;
}
Expand Down Expand Up @@ -217,7 +245,7 @@ public function onUserAuthenticate($credentials, $options, &$response): void
}

// Get the actual user record
$user = Factory::getUser($userId);
$user = $this->userFactory->loadUserById($userId);

// Disallow login for blocked, inactive or password reset required users
if ($user->block || !empty(trim($user->activation)) || $user->requireReset)
Expand Down Expand Up @@ -249,20 +277,20 @@ private function getTokenSeedForUser(int $userId): ?string
{
try
{
$db = $this->db;
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->qn('profile_value'))
->from($db->qn('#__user_profiles'))
->where($db->qn('profile_key') . ' = :profileKey')
->where($db->qn('user_id') . ' = :userId');
->select($db->quoteName('profile_value'))
->from($db->quoteName('#__user_profiles'))
->where($db->quoteName('profile_key') . ' = :profileKey')
->where($db->quoteName('user_id') . ' = :userId');

$profileKey = $this->profileKeyPrefix . '.token';
$query->bind(':profileKey', $profileKey, ParameterType::STRING);
$query->bind(':userId', $userId, ParameterType::INTEGER);

return $db->setQuery($query)->loadResult();
}
catch (Exception $e)
catch (\Exception $e)
{
return null;
}
Expand All @@ -281,12 +309,12 @@ private function isTokenEnabledForUser(int $userId): bool
{
try
{
$db = $this->db;
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->qn('profile_value'))
->from($db->qn('#__user_profiles'))
->where($db->qn('profile_key') . ' = :profileKey')
->where($db->qn('user_id') . ' = :userId');
->select($db->quoteName('profile_value'))
->from($db->quoteName('#__user_profiles'))
->where($db->quoteName('profile_key') . ' = :profileKey')
->where($db->quoteName('user_id') . ' = :userId');

$profileKey = $this->profileKeyPrefix . '.enabled';
$query->bind(':profileKey', $profileKey, ParameterType::STRING);
Expand All @@ -296,7 +324,7 @@ private function isTokenEnabledForUser(int $userId): bool

return $value == 1;
}
catch (Exception $e)
catch (\Exception $e)
{
return false;
}
Expand All @@ -313,30 +341,19 @@ private function isTokenEnabledForUser(int $userId): bool
* @return mixed
* @since 4.0.0
*/
private function getPluginParameter(string $folder, string $plugin, string $param,
$default = null
)
private function getPluginParameter(string $folder, string $plugin, string $param, $default = null)
{
if (!PluginHelper::isEnabled($folder, $plugin))
{
return $default;
}

$pluginObject = PluginHelper::getPlugin($folder, $plugin);
/** @var PluginModel $model */
$model = $this->app->bootComponent('plugins')->getMVCFactory()->createModel('Plugin', 'Administrator', ['ignore_request' => true]);

if (empty($pluginObject))
{
return $default;
}
$pluginObject = $model->getItem(['folder' => $folder, 'element' => $plugin]);

if (!is_object($pluginObject) || !isset($pluginObject->params))
if (!is_object($pluginObject) || !$pluginObject->enabled || !array_key_exists($param, $pluginObject->params))
{
return $default;
}

$params = new Registry($pluginObject->params);

return $params->get($param, $default);
return $pluginObject->params[$param];
}

/**
Expand All @@ -347,9 +364,7 @@ private function getPluginParameter(string $folder, string $plugin, string $para
*/
private function getAllowedUserGroups(): array
{
$userGroups = $this->getPluginParameter('user', 'token',
'allowedUserGroups', [8]
);
$userGroups = $this->getPluginParameter('user', 'token', 'allowedUserGroups', [8]);

if (empty($userGroups))
{
Expand All @@ -376,7 +391,7 @@ private function isInAllowedUserGroup($userId)
{
$allowedUserGroups = $this->getAllowedUserGroups();

$user = Factory::getUser($userId);
$user = $this->userFactory->loadUserById($userId);

if ($user->id != $userId)
{
Expand Down
4 changes: 3 additions & 1 deletion plugins/api-authentication/token/token.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
<authorUrl>www.joomla.org</authorUrl>
<version>4.0.0</version>
<description>PLG_API-AUTHENTICATION_TOKEN_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\APIAuthentication\Token</namespace>
<files>
<filename plugin="token">token.php</filename>
<folder plugin="token">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_api-authentication_token.ini</language>
Expand Down