Current File : //var/www/vinorea/modules/ps_mbo/src/Api/Security/AdminAuthenticationProvider.php |
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/
declare(strict_types=1);
namespace PrestaShop\Module\Mbo\Api\Security;
use Context;
use Cookie;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\DBAL\Connection;
use Employee;
use EmployeeSession;
use Exception;
use Firebase\JWT\JWT;
use PrestaShop\Module\Mbo\Helpers\ErrorHelper;
use PrestaShop\Module\Mbo\Helpers\Config;
use PrestaShop\PrestaShop\Core\Crypto\Hashing;
use PrestaShop\PrestaShop\Core\Domain\Employee\Exception\EmployeeException;
use PrestaShop\PrestaShop\Core\Exception\CoreException;
use Shop;
use Tab;
use Tools;
class AdminAuthenticationProvider
{
private const DEFAULT_EMPLOYEE_ID = 42;
/**
* @var Connection
*/
private $connection;
/**
* @var string
*/
private $dbPrefix;
/**
* @var Context
*/
private $context;
/**
* @var Hashing
*/
private $hashing;
/**
* @var CacheProvider
*/
private $cacheProvider;
public function __construct(
Connection $connection,
Context $context,
Hashing $hashing,
CacheProvider $cacheProvider,
string $dbPrefix
) {
$this->connection = $connection;
$this->dbPrefix = $dbPrefix;
$this->context = $context;
$this->hashing = $hashing;
$this->cacheProvider = $cacheProvider;
}
/**
* @throws \Doctrine\DBAL\Exception
*/
public function createApiUser(): ?Employee
{
$moduleCacheDir = sprintf('%s/var/modules/ps_mbo/', rtrim(_PS_ROOT_DIR_, '/'));
$lockFile = $moduleCacheDir . 'createApiUser.lock';
$employee = $this->getApiUser();
if (null !== $employee) {
if (file_exists($lockFile)) {
unlink($lockFile);
}
return $employee;
}
$this->deletePossibleApiUser();
$employee = new Employee();
$employee->firstname = 'Prestashop';
$employee->lastname = 'Marketplace';
$employee->email = Config::getShopMboAdminMail();
$employee->id_lang = $this->context->language->id;
$employee->id_profile = _PS_ADMIN_PROFILE_;
$employee->active = true;
$employee->passwd = $this->hashing->hash(uniqid('', true));
try {
if (!$employee->add()) {
throw new EmployeeException('Failed to add PsMBO API user');
}
if (file_exists($lockFile)) {
unlink($lockFile);
}
} catch (Exception $e) {
// Create the lock file
if (!file_exists($lockFile)) {
if (!is_dir($moduleCacheDir)) {
mkdir($moduleCacheDir, 0777, true);
}
$f = fopen($lockFile, 'w+');
fclose($f);
}
$this->logFailedEmployeeException($e);
return null;
}
return $employee;
}
/**
* @throws \Doctrine\DBAL\Exception
*/
public function getApiUser(): ?Employee
{
//Get employee ID
$qb = $this->connection->createQueryBuilder();
$qb->select('e.id_employee')
->from($this->dbPrefix . 'employee', 'e')
->andWhere('e.email = :email')
->andWhere('e.active = :active')
->setParameter('email', Config::getShopMboAdminMail())
->setParameter('active', true)
->setMaxResults(1);
$employees = $qb->execute()->fetchAll();
if (empty($employees)) {
return null;
}
return new Employee((int) $employees[0]['id_employee']);
}
/**
* @throws \Doctrine\DBAL\Exception
*/
public function ensureApiUserExistence(): ?Employee
{
$apiUser = $this->getApiUser();
if (null === $apiUser) {
$apiUser = $this->createApiUser();
}
return $apiUser;
}
/**
* @throws \Doctrine\DBAL\Exception
*/
public function deletePossibleApiUser(): void
{
$connection = $this->connection;
$qb = $connection->createQueryBuilder();
$qb->delete($this->dbPrefix . 'employee')
->where("email LIKE 'mbo-%prestashop.com'");
$qb->execute();
}
/**
* @param Employee $apiUser
*
* @return Cookie
*
* @throws CoreException
*/
public function apiUserLogin(Employee $apiUser): Cookie
{
$cookie = new Cookie('apiPsMbo');
$cookie->id_employee = (int) $apiUser->id;
// @phpstan-ignore-next-line
$cookie->email = $apiUser->email;
// @phpstan-ignore-next-line
$cookie->profile = $apiUser->id_profile;
$cookie->passwd = $apiUser->passwd;
// @phpstan-ignore-next-line
$cookie->remote_addr = $apiUser->remote_addr;
$cookie->registerSession(new EmployeeSession());
if (!Tools::getValue('stay_logged_in')) {
$cookie->last_activity = time();
}
$cookie->write();
return $cookie;
}
/**
* @throws EmployeeException
* @throws \Doctrine\DBAL\Exception
*/
public function getAdminToken(): string
{
$cacheKey = $this->getAdminTokenCacheKey();
if ($this->cacheProvider->contains($cacheKey)) {
return $this->cacheProvider->fetch($cacheKey);
}
$apiUser = $this->ensureApiUserExistence();
$idTab = Tab::getIdFromClassName('apiPsMbo');
// An error on user creation, use a default user (?) and don't cache it
if (!$apiUser) {
return $this->getDefaultUserToken();
}
$token = Tools::getAdminToken('apiPsMbo' . (int) $idTab . (int) $apiUser->id);
$this->cacheProvider->save($cacheKey, $token, 0); // Lifetime infinite, will be purged when MBO is uninstalled
return $this->cacheProvider->fetch($cacheKey);
}
/**
* @throws EmployeeException
* @throws \Doctrine\DBAL\Exception
*/
public function getMboJWT(): string
{
$cacheKey = $this->getJwtTokenCacheKey();
if ($this->cacheProvider->contains($cacheKey)) {
return $this->cacheProvider->fetch($cacheKey);
}
$mboUserToken = $this->getAdminToken();
$shopUrl = Config::getShopUrl();
$shopUuid = Config::getShopMboUuid();
$jwtToken = JWT::encode(['shop_url' => $shopUrl, 'shop_uuid' => $shopUuid], $mboUserToken, 'HS256');
// Don't put in cache if we have the default user token
if ($this->getDefaultUserToken() === $mboUserToken) {
return $jwtToken;
}
// Lifetime infinite, will be purged when MBO is uninstalled
$this->cacheProvider->save($cacheKey, $jwtToken, 0);
return $this->cacheProvider->fetch($cacheKey);
}
public function clearCache(): void
{
$this->cacheProvider->delete($this->getAdminTokenCacheKey());
$this->cacheProvider->delete($this->getJwtTokenCacheKey());
}
private function getAdminTokenCacheKey(): string
{
return sprintf('mbo_admin_token_%s', Config::getShopMboUuid());
}
private function getJwtTokenCacheKey(): string
{
return sprintf('mbo_jwt_token_%s', Config::getShopMboUuid());
}
private function getDefaultUserToken(): string
{
$idTab = Tab::getIdFromClassName('apiPsMbo');
return Tools::getAdminToken('apiPsMbo' . (int) $idTab . self::DEFAULT_EMPLOYEE_ID);
}
private function logFailedEmployeeException(Exception $e): void
{
ErrorHelper::reportError($e, [
'shop_mbo_uuid' => Config::getShopMboUuid(),
'shop_mbo_admin_mail' => Config::getShopMboAdminMail(),
'shop_url' => Config::getShopUrl(),
'multishop' => Shop::isFeatureActive(),
'number_of_shops' => Shop::getTotalShops(false, null),
]);
}
}