This commit is contained in:
Yuri Kuznetsov
2022-10-18 21:32:21 +03:00
parent 1f88b60cca
commit 531992adff
4 changed files with 131 additions and 80 deletions

View File

@@ -33,12 +33,10 @@ use Espo\Core\Exceptions\Error;
use Espo\Core\Exceptions\NotFound;
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\BadRequest;
use Espo\Services\User as Service;
use Espo\Core\Api\Request;
use Espo\Core\Controllers\Record;
use Espo\Core\Mail\Exceptions\SendingError;
use Espo\Tools\UserSecurity\ApiService;
use Espo\Tools\UserSecurity\Password\RecoveryService;
use Espo\Core\Select\SearchParams;
use Espo\Core\Select\Where\Item as WhereItem;
@@ -163,12 +161,12 @@ class User extends Record
throw new Forbidden();
}
return $this->getUserService()
->generateNewApiKeyForEntity($data->id)
return $this->injectableFactory
->create(ApiService::class)
->generateNewApiKey($data->id)
->getValueMap();
}
/**
* @throws BadRequest
* @throws Forbidden
@@ -257,10 +255,4 @@ class User extends Record
{
return $this->injectableFactory->create(PasswordService::class);
}
private function getUserService(): Service
{
/** @var Service */
return $this->getServiceFactory()->create('User');
}
}

View File

@@ -29,23 +29,22 @@
namespace Espo\Core\Authentication\Logins;
use Espo\Core\{
Api\Request,
Utils\ApiKey,
Authentication\Login,
Authentication\Login\Data,
Authentication\Result,
Authentication\Helper\UserFinder,
Authentication\Result\FailReason,
};
use Espo\Core\Api\Request;
use Espo\Core\Authentication\Helper\UserFinder;
use Espo\Core\Authentication\Login;
use Espo\Core\Authentication\Login\Data;
use Espo\Core\Authentication\Result;
use Espo\Core\Authentication\Result\FailReason;
use Espo\Core\Utils\ApiKey;
use RuntimeException;
class Hmac implements Login
{
private $userFinder;
public const NAME = 'Hmac';
private $apiKeyUtil;
private UserFinder $userFinder;
private ApiKey $apiKeyUtil;
public function __construct(UserFinder $userFinder, ApiKey $apiKeyUtil)
{

View File

@@ -30,6 +30,7 @@
namespace Espo\Services;
use Espo\Core\ApplicationUser;
use Espo\Core\Authentication\Logins\Hmac;
use Espo\Core\Mail\Exceptions\SendingError;
use Espo\Entities\Team as TeamEntity;
use Espo\Entities\User as UserEntity;
@@ -39,7 +40,6 @@ use Espo\Core\Di;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Exceptions\Error;
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\NotFound;
use Espo\Core\Record\CreateParams;
use Espo\Core\Record\DeleteParams;
use Espo\Core\Record\UpdateParams;
@@ -54,7 +54,7 @@ use stdClass;
use Exception;
/**
* @extends Record<\Espo\Entities\User>
* @extends Record<UserEntity>
*/
class User extends Record implements
@@ -62,26 +62,27 @@ class User extends Record implements
{
use Di\DataManagerSetter;
private const AUTHENTICATION_METHOD_HMAC = 'Hmac';
/**
* @var string[]
*/
/** @var string[] */
protected $mandatorySelectAttributeList = [
'isActive',
'userName',
'type',
];
/**
* @var string[]
*/
protected $validateSkipFieldList = ['name', "firstName", "lastName"];
/** @var string[] */
protected $validateSkipFieldList = [
'name',
'firstName',
'lastName',
];
/**
* @var string[]
*/
protected $allowedUserTypeList = ['regular', 'admin', 'portal', 'api'];
/** @var string[] */
private $allowedUserTypeList = [
UserEntity::TYPE_REGULAR,
UserEntity::TYPE_ADMIN,
UserEntity::TYPE_PORTAL,
UserEntity::TYPE_API,
];
/**
* @throws Forbidden
@@ -236,7 +237,7 @@ class User extends Record implements
if ($entity->isApi()) {
if ($this->user->isAdmin()) {
if ($entity->getAuthMethod() === self::AUTHENTICATION_METHOD_HMAC) {
if ($entity->getAuthMethod() === Hmac::NAME) {
$secretKey = $this->getSecretKeyForUserId($entity->getId());
$entity->set('secretKey', $secretKey);
}
@@ -254,44 +255,6 @@ class User extends Record implements
return $apiKeyUtil->getSecretKeyForUserId($id);
}
/**
* @throws Forbidden
* @throws NotFound
*/
public function generateNewApiKeyForEntity(string $id): Entity
{
/** @var ?UserEntity $entity */
$entity = $this->getEntity($id);
if (!$entity) {
throw new NotFound();
}
if (!$this->user->isAdmin()) {
throw new Forbidden();
}
if (!$entity->isApi()) {
throw new Forbidden();
}
$apiKey = Util::generateApiKey();
$entity->set('apiKey', $apiKey);
if ($entity->getAuthMethod() === self::AUTHENTICATION_METHOD_HMAC) {
$secretKey = Util::generateSecretKey();
$entity->set('secretKey', $secretKey);
}
$this->entityManager->saveEntity($entity);
$this->prepareEntityForOutput($entity);
return $entity;
}
protected function getInternalUserCount(): int
{
return $this->entityManager
@@ -309,7 +272,7 @@ class User extends Record implements
protected function getPortalUserCount(): int
{
return $this->entityManager
->getRDBRepository(UserEntity::ENTITY_TYPE)
->getRDBRepositoryByClass(UserEntity::class)
->where([
'isActive' => true,
'type' => UserEntity::TYPE_PORTAL,
@@ -356,7 +319,7 @@ class User extends Record implements
$entity->set('apiKey', $apiKey);
if ($entity->getAuthMethod() === self::AUTHENTICATION_METHOD_HMAC) {
if ($entity->getAuthMethod() === Hmac::NAME) {
$secretKey = Util::generateSecretKey();
$entity->set('secretKey', $secretKey);
@@ -435,7 +398,7 @@ class User extends Record implements
if ($entity->isApi()) {
if (
$entity->isAttributeChanged('authMethod') &&
$entity->getAuthMethod() === self::AUTHENTICATION_METHOD_HMAC
$entity->getAuthMethod() === Hmac::NAME
) {
$secretKey = Util::generateSecretKey();

View File

@@ -0,0 +1,97 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2022 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM 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 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\UserSecurity;
use Espo\Core\Authentication\Logins\Hmac;
use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\NotFound;
use Espo\Core\Record\ServiceContainer;
use Espo\Core\Utils\Util;
use Espo\Entities\User;
use Espo\Entities\User as UserEntity;
use Espo\ORM\Entity;
use Espo\ORM\EntityManager;
class ApiService
{
private ServiceContainer $serviceContainer;
private UserEntity $user;
private EntityManager $entityManager;
public function __construct(
ServiceContainer $serviceContainer,
User $user,
EntityManager $entityManager
) {
$this->serviceContainer = $serviceContainer;
$this->user = $user;
$this->entityManager = $entityManager;
}
/**
* @throws Forbidden
* @throws NotFound
*/
public function generateNewApiKey(string $id): Entity
{
if (!$this->user->isAdmin()) {
throw new Forbidden();
}
$service = $this->serviceContainer->get(User::ENTITY_TYPE);
/** @var ?UserEntity $entity */
$entity = $service->getEntity($id);
if (!$entity) {
throw new NotFound();
}
if (!$entity->isApi()) {
throw new Forbidden();
}
$apiKey = Util::generateApiKey();
$entity->set('apiKey', $apiKey);
if ($entity->getAuthMethod() === Hmac::NAME) {
$secretKey = Util::generateSecretKey();
$entity->set('secretKey', $secretKey);
}
$this->entityManager->saveEntity($entity);
$service->prepareEntityForOutput($entity);
return $entity;
}
}