diff --git a/application/Espo/Controllers/User.php b/application/Espo/Controllers/User.php index bd01f7b091..2becbf5e26 100644 --- a/application/Espo/Controllers/User.php +++ b/application/Espo/Controllers/User.php @@ -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'); - } } diff --git a/application/Espo/Core/Authentication/Logins/Hmac.php b/application/Espo/Core/Authentication/Logins/Hmac.php index 3607268f9e..d89d1bb020 100644 --- a/application/Espo/Core/Authentication/Logins/Hmac.php +++ b/application/Espo/Core/Authentication/Logins/Hmac.php @@ -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) { diff --git a/application/Espo/Services/User.php b/application/Espo/Services/User.php index b0bc58a14f..dffd3c5af7 100644 --- a/application/Espo/Services/User.php +++ b/application/Espo/Services/User.php @@ -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 */ 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(); diff --git a/application/Espo/Tools/UserSecurity/ApiService.php b/application/Espo/Tools/UserSecurity/ApiService.php new file mode 100644 index 0000000000..8badcdb933 --- /dev/null +++ b/application/Espo/Tools/UserSecurity/ApiService.php @@ -0,0 +1,97 @@ +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; + } +}