From 1d2e991be5f4e0220a9ef8caddf5d7a13f2bb256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D?= Date: Sun, 7 Apr 2024 07:44:23 +0200 Subject: [PATCH] chore(tests): UT for UserMasterPass service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rubén D --- .../web/Controllers/ControllerBase.php | 8 +- .../UserSettingsGeneral/SaveController.php | 6 +- lib/SP/Core/Context/SessionContext.php | 12 +- lib/SP/Core/Context/StatelessContext.php | 12 +- lib/SP/Core/Definitions/CoreDefinitions.php | 14 +- .../Account/Ports/AccountAclService.php | 8 +- lib/SP/Domain/Account/Services/Account.php | 14 +- lib/SP/Domain/Account/Services/AccountAcl.php | 27 +- .../Services/Builders/AccountFilter.php | 6 +- lib/SP/Domain/Api/Services/Api.php | 4 +- ...LoginResponse.php => LoginResponseDto.php} | 2 +- .../Auth/Dtos/UserLoginDto.php} | 38 +- lib/SP/Domain/Auth/Ports/LoginService.php | 6 +- lib/SP/Domain/Auth/Services/Login.php | 211 ++--- .../Domain/Core/Context/ContextInterface.php | 9 +- .../Ports/TemporaryMasterPassService.php | 4 +- lib/SP/Domain/User/Dtos/UserDataDto.php | 151 ++++ .../UserMasterPassDto.php} | 48 +- .../User/Ports/UserMasterPassService.php | 65 ++ .../User/Ports/UserPassServiceInterface.php | 87 -- .../User/Services/UserLoginResponse.php | 323 -------- .../Domain/User/Services/UserMasterPass.php | 212 +++++ .../User/Services/UserMasterPassStatus.php | 37 + lib/SP/Domain/User/Services/UserPass.php | 71 ++ .../Domain/User/Services/UserPassService.php | 215 +---- lib/SP/Domain/User/Services/UserService.php | 41 +- .../Infrastructure/User/Repositories/User.php | 3 +- lib/SP/Providers/Auth/AuthInterface.php | 8 +- lib/SP/Providers/Auth/AuthProvider.php | 8 +- .../Providers/Auth/AuthProviderInterface.php | 9 +- lib/SP/Providers/Auth/Browser/BrowserAuth.php | 8 +- .../Providers/Auth/Database/DatabaseAuth.php | 38 +- ...hInterface.php => DatabaseAuthService.php} | 5 +- lib/SP/Providers/Auth/Ldap/LdapAuth.php | 6 +- tests/SPT/Core/LanguageTest.php | 14 +- tests/SPT/Core/UI/ThemeTest.php | 13 +- .../Account/Services/AccountAclTest.php | 71 +- .../Services/AccountFilterUserTest.php | 28 +- .../Domain/Account/Services/AccountTest.php | 204 ++++- .../Domain/Export/Services/XmlExportTest.php | 116 ++- .../Services/NotificationTest.php | 31 +- .../User/Services/UserMasterPassTest.php | 761 ++++++++++++++++++ tests/SPT/Generators/ConfigDataGenerator.php | 2 +- .../User/Repositories/UserTest.php | 19 +- tests/SPT/Providers/Auth/AuthProviderTest.php | 6 +- .../Auth/Browser/BrowserAuthTest.php | 16 +- .../Auth/Database/DatabaseAuthTest.php | 28 +- .../SPT/Providers/Auth/Ldap/LdapAuthTest.php | 10 +- tests/SPT/UnitaryTestCase.php | 31 +- tests/SPT/bootstrap.php | 4 +- 50 files changed, 1994 insertions(+), 1076 deletions(-) rename lib/SP/Domain/Auth/Dtos/{LoginResponse.php => LoginResponseDto.php} (98%) rename lib/SP/{DataModel/UserLoginData.php => Domain/Auth/Dtos/UserLoginDto.php} (56%) create mode 100644 lib/SP/Domain/User/Dtos/UserDataDto.php rename lib/SP/Domain/User/{Services/UserPassResponse.php => Dtos/UserMasterPassDto.php} (54%) create mode 100644 lib/SP/Domain/User/Ports/UserMasterPassService.php delete mode 100644 lib/SP/Domain/User/Ports/UserPassServiceInterface.php delete mode 100644 lib/SP/Domain/User/Services/UserLoginResponse.php create mode 100644 lib/SP/Domain/User/Services/UserMasterPass.php create mode 100644 lib/SP/Domain/User/Services/UserMasterPassStatus.php create mode 100644 lib/SP/Domain/User/Services/UserPass.php rename lib/SP/Providers/Auth/Database/{DatabaseAuthInterface.php => DatabaseAuthService.php} (90%) create mode 100644 tests/SPT/Domain/User/Services/UserMasterPassTest.php diff --git a/app/modules/web/Controllers/ControllerBase.php b/app/modules/web/Controllers/ControllerBase.php index 6de2777d..c44493a6 100644 --- a/app/modules/web/Controllers/ControllerBase.php +++ b/app/modules/web/Controllers/ControllerBase.php @@ -43,7 +43,7 @@ use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Core\PhpExtensionCheckerService; use SP\Domain\Core\UI\ThemeInterface; use SP\Domain\Http\RequestInterface; -use SP\Domain\User\Services\UserLoginResponse; +use SP\Domain\User\Dtos\UserDataDto; use SP\Modules\Web\Controllers\Helpers\LayoutHelper; use SP\Modules\Web\Controllers\Traits\WebControllerTrait; use SP\Mvc\Controller\WebControllerHelper; @@ -71,9 +71,9 @@ abstract class ControllerBase protected ConfigDataInterface $configData; protected RequestInterface $request; protected PhpExtensionCheckerService $extensionChecker; - protected TemplateInterface $view; - protected ?UserLoginResponse $userData = null; - protected ?ProfileData $userProfileData = null; + protected TemplateInterface $view; + protected ?UserDataDto $userData = null; + protected ?ProfileData $userProfileData = null; protected bool $isAjax; protected LayoutHelper $layoutHelper; protected string $actionName; diff --git a/app/modules/web/Controllers/UserSettingsGeneral/SaveController.php b/app/modules/web/Controllers/UserSettingsGeneral/SaveController.php index 281150fb..defa6f91 100644 --- a/app/modules/web/Controllers/UserSettingsGeneral/SaveController.php +++ b/app/modules/web/Controllers/UserSettingsGeneral/SaveController.php @@ -28,9 +28,9 @@ use Exception; use JsonException; use SP\Core\Application; use SP\Core\Events\Event; +use SP\Domain\User\Dtos\UserDataDto; use SP\Domain\User\Models\UserPreferences; use SP\Domain\User\Ports\UserServiceInterface; -use SP\Domain\User\Services\UserLoginResponse; use SP\Domain\User\Services\UserService; use SP\Http\JsonMessage; use SP\Modules\Web\Controllers\SimpleControllerBase; @@ -87,11 +87,11 @@ final class SaveController extends SimpleControllerBase } /** - * @param UserLoginResponse $userData + * @param UserDataDto $userData * * @return UserPreferences */ - private function getUserPreferencesData(UserLoginResponse $userData): UserPreferences + private function getUserPreferencesData(UserDataDto $userData): UserPreferences { $userPreferencesData = clone $userData->getPreferences(); diff --git a/lib/SP/Core/Context/SessionContext.php b/lib/SP/Core/Context/SessionContext.php index 529af0cd..658c22a8 100644 --- a/lib/SP/Core/Context/SessionContext.php +++ b/lib/SP/Core/Context/SessionContext.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -29,7 +29,7 @@ use SP\Domain\Account\Dtos\AccountCacheDto; use SP\Domain\Account\Dtos\AccountSearchFilterDto; use SP\Domain\Core\Context\SessionContextInterface; use SP\Domain\Core\Crypt\VaultInterface; -use SP\Domain\User\Services\UserLoginResponse; +use SP\Domain\User\Dtos\UserDataDto; use function SP\__u; use function SP\getLastCaller; @@ -145,9 +145,9 @@ class SessionContext extends ContextBase implements SessionContextInterface /** * Establece los datos del usuario en la sesión. */ - public function setUserData(?UserLoginResponse $userLoginResponse = null): void + public function setUserData(?UserDataDto $userDataDto = null): void { - $this->setContextKey('userData', $userLoginResponse); + $this->setContextKey('userData', $userDataDto); } /** @@ -193,9 +193,9 @@ class SessionContext extends ContextBase implements SessionContextInterface /** * Devuelve los datos del usuario en la sesión. */ - public function getUserData(): UserLoginResponse + public function getUserData(): UserDataDto { - return $this->getContextKey('userData', new UserLoginResponse()); + return $this->getContextKey('userData', new UserDataDto()); } /** diff --git a/lib/SP/Core/Context/StatelessContext.php b/lib/SP/Core/Context/StatelessContext.php index d961c0fe..fe80c6de 100644 --- a/lib/SP/Core/Context/StatelessContext.php +++ b/lib/SP/Core/Context/StatelessContext.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -25,7 +25,7 @@ namespace SP\Core\Context; use SP\DataModel\ProfileData; -use SP\Domain\User\Services\UserLoginResponse; +use SP\Domain\User\Dtos\UserDataDto; use function SP\processException; @@ -39,9 +39,9 @@ class StatelessContext extends ContextBase /** * Establece los datos del usuario en la sesión. */ - public function setUserData(?UserLoginResponse $userLoginResponse = null): void + public function setUserData(?UserDataDto $userDataDto = null): void { - $this->setContextKey('userData', $userLoginResponse); + $this->setContextKey('userData', $userDataDto); } /** @@ -99,9 +99,9 @@ class StatelessContext extends ContextBase /** * Devuelve los datos del usuario en la sesión. */ - public function getUserData(): UserLoginResponse + public function getUserData(): UserDataDto { - return $this->getContextKey('userData', new UserLoginResponse()); + return $this->getContextKey('userData', new UserDataDto()); } /** diff --git a/lib/SP/Core/Definitions/CoreDefinitions.php b/lib/SP/Core/Definitions/CoreDefinitions.php index 05440bcc..8d1171c2 100644 --- a/lib/SP/Core/Definitions/CoreDefinitions.php +++ b/lib/SP/Core/Definitions/CoreDefinitions.php @@ -96,7 +96,7 @@ use SP\Providers\Auth\AuthTypeEnum; use SP\Providers\Auth\Browser\BrowserAuth; use SP\Providers\Auth\Browser\BrowserAuthInterface; use SP\Providers\Auth\Database\DatabaseAuth; -use SP\Providers\Auth\Database\DatabaseAuthInterface; +use SP\Providers\Auth\Database\DatabaseAuthService; use SP\Providers\Auth\Ldap\LdapActions; use SP\Providers\Auth\Ldap\LdapAuth; use SP\Providers\Auth\Ldap\LdapBase; @@ -166,7 +166,7 @@ final class CoreDefinitions ), ThemeInterface::class => autowire(Theme::class), TemplateInterface::class => autowire(Template::class), - DatabaseAuthInterface::class => autowire(DatabaseAuth::class), + DatabaseAuthService::class => autowire(DatabaseAuth::class), BrowserAuthInterface::class => autowire(BrowserAuth::class), LdapParams::class => factory([LdapParams::class, 'getFrom']), LdapConnectionInterface::class => autowire(LdapConnection::class), @@ -178,11 +178,11 @@ final class CoreDefinitions ), AuthProviderInterface::class => factory( static function ( - AuthProvider $authProvider, - ConfigDataInterface $configData, - LdapAuthService $ldapAuth, - BrowserAuthInterface $browserAuth, - DatabaseAuthInterface $databaseAuth, + AuthProvider $authProvider, + ConfigDataInterface $configData, + LdapAuthService $ldapAuth, + BrowserAuthInterface $browserAuth, + DatabaseAuthService $databaseAuth, ) { if ($configData->isLdapEnabled()) { $authProvider->registerAuth($ldapAuth, AuthTypeEnum::Ldap); diff --git a/lib/SP/Domain/Account/Ports/AccountAclService.php b/lib/SP/Domain/Account/Ports/AccountAclService.php index cbff2b14..7f7af02c 100644 --- a/lib/SP/Domain/Account/Ports/AccountAclService.php +++ b/lib/SP/Domain/Account/Ports/AccountAclService.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -29,7 +29,7 @@ use SP\Domain\Account\Adapters\AccountPermission; use SP\Domain\Account\Dtos\AccountAclDto; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; -use SP\Domain\User\Services\UserLoginResponse; +use SP\Domain\User\Dtos\UserDataDto; /** * Class AccountAclService @@ -41,12 +41,12 @@ interface AccountAclService /** * Sets grants which don't need the account's data * - * @param UserLoginResponse $userData + * @param UserDataDto $userData * @param ProfileData $profileData * * @return bool */ - public static function getShowPermission(UserLoginResponse $userData, ProfileData $profileData): bool; + public static function getShowPermission(UserDataDto $userData, ProfileData $profileData): bool; /** * Obtener la ACL de una cuenta diff --git a/lib/SP/Domain/Account/Services/Account.php b/lib/SP/Domain/Account/Services/Account.php index 8d7db962..56fa1cd4 100644 --- a/lib/SP/Domain/Account/Services/Account.php +++ b/lib/SP/Domain/Account/Services/Account.php @@ -56,7 +56,7 @@ use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\ItemPreset\Ports\ItemPresetInterface; use SP\Domain\ItemPreset\Ports\ItemPresetService; -use SP\Domain\User\Services\UserLoginResponse; +use SP\Domain\User\Dtos\UserDataDto; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Infrastructure\Database\QueryResult; @@ -247,14 +247,14 @@ final class Account extends Service implements AccountService } /** - * @param UserLoginResponse $userData + * @param UserDataDto $userData * @param ProfileData $userProfile * @param AccountModel $account * * @return bool */ protected function userCanChangeOwner( - UserLoginResponse $userData, + UserDataDto $userData, ProfileData $userProfile, AccountModel $account ): bool { @@ -263,14 +263,14 @@ final class Account extends Service implements AccountService } /** - * @param UserLoginResponse $userData + * @param UserDataDto $userData * @param ProfileData $userProfile * @param AccountModel $account * * @return bool */ protected function userCanChangeGroup( - UserLoginResponse $userData, + UserDataDto $userData, ProfileData $userProfile, AccountModel $account ): bool { @@ -335,13 +335,13 @@ final class Account extends Service implements AccountService } /** - * @param UserLoginResponse $userData + * @param UserDataDto $userData * @param AccountCreateDto $accountCreateDto * * @return AccountCreateDto */ private static function buildWithUserData( - UserLoginResponse $userData, + UserDataDto $userData, AccountCreateDto $accountCreateDto ): AccountCreateDto { return $accountCreateDto->withUserGroupId($userData->getUserGroupId())->withUserId($userData->getId()); diff --git a/lib/SP/Domain/Account/Services/AccountAcl.php b/lib/SP/Domain/Account/Services/AccountAcl.php index 71f0c10c..b24df945 100644 --- a/lib/SP/Domain/Account/Services/AccountAcl.php +++ b/lib/SP/Domain/Account/Services/AccountAcl.php @@ -24,7 +24,6 @@ namespace SP\Domain\Account\Services; -use SP\Core\Acl\Acl; use SP\Core\Application; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; @@ -38,8 +37,8 @@ use SP\Domain\Core\Acl\AclInterface; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Storage\Ports\FileCacheService; +use SP\Domain\User\Dtos\UserDataDto; use SP\Domain\User\Ports\UserToUserGroupServiceInterface; -use SP\Domain\User\Services\UserLoginResponse; use SP\Infrastructure\File\FileException; use function SP\processException; @@ -56,25 +55,19 @@ final class AccountAcl extends Service implements AccountAclService */ public const ACL_PATH = CACHE_PATH . DIRECTORY_SEPARATOR . 'accountAcl' . DIRECTORY_SEPARATOR; - private ?AccountAclDto $accountAclDto = null; - private ?AccountPermission $accountAcl = null; - private Acl $acl; - private ?FileCacheService $fileCache; - private UserToUserGroupServiceInterface $userToUserGroupService; - private UserLoginResponse $userData; + private ?AccountAclDto $accountAclDto = null; + private ?AccountPermission $accountAcl = null; + private UserDataDto $userData; public function __construct( - Application $application, - AclInterface $acl, - UserToUserGroupServiceInterface $userGroupService, - ?FileCacheService $fileCache = null + Application $application, + private readonly AclInterface $acl, + private readonly UserToUserGroupServiceInterface $userToUserGroupService, + private readonly ?FileCacheService $fileCache = null ) { parent::__construct($application); - $this->acl = $acl; - $this->userToUserGroupService = $userGroupService; $this->userData = $this->context->getUserData(); - $this->fileCache = $fileCache; } /** @@ -130,12 +123,12 @@ final class AccountAcl extends Service implements AccountAclService /** * Sets grants which don't need the account's data * - * @param UserLoginResponse $userData + * @param UserDataDto $userData * @param ProfileData $profileData * * @return bool */ - public static function getShowPermission(UserLoginResponse $userData, ProfileData $profileData): bool + public static function getShowPermission(UserDataDto $userData, ProfileData $profileData): bool { return $userData->getIsAdminApp() || $userData->getIsAdminAcc() diff --git a/lib/SP/Domain/Account/Services/Builders/AccountFilter.php b/lib/SP/Domain/Account/Services/Builders/AccountFilter.php index 09c71ae5..88d45a47 100644 --- a/lib/SP/Domain/Account/Services/Builders/AccountFilter.php +++ b/lib/SP/Domain/Account/Services/Builders/AccountFilter.php @@ -31,7 +31,7 @@ use SP\Domain\Account\Ports\AccountFilterBuilder; use SP\Domain\Account\Ports\AccountSearchConstants; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Core\Context\ContextInterface; -use SP\Domain\User\Services\UserLoginResponse; +use SP\Domain\User\Dtos\UserDataDto; /** * Class AccountFilterUser @@ -91,14 +91,14 @@ final class AccountFilter implements AccountFilterBuilder } /** - * @param UserLoginResponse $userData + * @param UserDataDto $userData * @param bool $useGlobalSearch * @param ProfileData|null $userProfile * * @return bool */ private function isFilterWithoutGlobalSearch( - UserLoginResponse $userData, + UserDataDto $userData, bool $useGlobalSearch, ?ProfileData $userProfile ): bool { diff --git a/lib/SP/Domain/Api/Services/Api.php b/lib/SP/Domain/Api/Services/Api.php index e950e004..55970c1b 100644 --- a/lib/SP/Domain/Api/Services/Api.php +++ b/lib/SP/Domain/Api/Services/Api.php @@ -46,9 +46,9 @@ use SP\Domain\Core\Exceptions\InvalidClassException; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\Security\Dtos\TrackRequest; use SP\Domain\Security\Ports\TrackService; +use SP\Domain\User\Dtos\UserDataDto; use SP\Domain\User\Ports\UserProfileServiceInterface; use SP\Domain\User\Ports\UserServiceInterface; -use SP\Domain\User\Services\UserService; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Modules\Api\Controllers\Help\HelpInterface; use SP\Util\Filter; @@ -216,7 +216,7 @@ final class Api extends Service implements ApiService */ private function setupUser(): void { - $userLoginResponse = UserService::mapUserLoginResponse( + $userLoginResponse = new UserDataDto( $this->userService->getById($this->authToken->getUserId()) ); $userLoginResponse->getIsDisabled() && $this->accessDenied(); diff --git a/lib/SP/Domain/Auth/Dtos/LoginResponse.php b/lib/SP/Domain/Auth/Dtos/LoginResponseDto.php similarity index 98% rename from lib/SP/Domain/Auth/Dtos/LoginResponse.php rename to lib/SP/Domain/Auth/Dtos/LoginResponseDto.php index dbbb7068..2f7b767d 100644 --- a/lib/SP/Domain/Auth/Dtos/LoginResponse.php +++ b/lib/SP/Domain/Auth/Dtos/LoginResponseDto.php @@ -29,7 +29,7 @@ namespace SP\Domain\Auth\Dtos; * * @package SP\Domain\Auth\Services */ -final class LoginResponse +final class LoginResponseDto { private int $status; private ?string $redirect; diff --git a/lib/SP/DataModel/UserLoginData.php b/lib/SP/Domain/Auth/Dtos/UserLoginDto.php similarity index 56% rename from lib/SP/DataModel/UserLoginData.php rename to lib/SP/Domain/Auth/Dtos/UserLoginDto.php index 08c1e51b..a9d3f1a9 100644 --- a/lib/SP/DataModel/UserLoginData.php +++ b/lib/SP/Domain/Auth/Dtos/UserLoginDto.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -22,20 +22,30 @@ * along with sysPass. If not, see . */ -namespace SP\DataModel; +namespace SP\Domain\Auth\Dtos; -use SP\Domain\User\Services\UserLoginResponse; +use SP\Domain\User\Dtos\UserDataDto; /** - * Class UserLoginData - * - * @package SP\DataModel + * Class UserLoginDto */ -class UserLoginData +class UserLoginDto { - protected ?string $loginUser = null; - protected ?string $loginPass = null; - protected ?UserLoginResponse $userLoginResponse = null; + protected ?string $loginUser = null; + protected ?string $loginPass = null; + protected ?UserDataDto $userDataDto = null; + + /** + * @param string|null $loginUser + * @param string|null $loginPass + * @param UserDataDto|null $userDataDto + */ + public function __construct(?string $loginUser = null, ?string $loginPass = null, ?UserDataDto $userDataDto = null) + { + $this->loginUser = $loginUser; + $this->loginPass = $loginPass; + $this->userDataDto = $userDataDto; + } public function getLoginUser(): ?string { @@ -57,13 +67,13 @@ class UserLoginData $this->loginPass = $loginPass; } - public function getUserLoginResponse(): ?UserLoginResponse + public function getUserDataDto(): ?UserDataDto { - return $this->userLoginResponse; + return $this->userDataDto; } - public function setUserLoginResponse(UserLoginResponse $userLoginResponse = null): void + public function setUserDataDto(UserDataDto $userDataDto = null): void { - $this->userLoginResponse = $userLoginResponse; + $this->userDataDto = $userDataDto; } } diff --git a/lib/SP/Domain/Auth/Ports/LoginService.php b/lib/SP/Domain/Auth/Ports/LoginService.php index c8e92c66..343ad264 100644 --- a/lib/SP/Domain/Auth/Ports/LoginService.php +++ b/lib/SP/Domain/Auth/Ports/LoginService.php @@ -26,7 +26,7 @@ namespace SP\Domain\Auth\Ports; use Defuse\Crypto\Exception\EnvironmentIsBrokenException; use Exception; -use SP\Domain\Auth\Dtos\LoginResponse; +use SP\Domain\Auth\Dtos\LoginResponseDto; use SP\Domain\Auth\Services\AuthException; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; @@ -42,7 +42,7 @@ interface LoginService /** * Ejecutar las acciones de login * - * @return LoginResponse + * @return LoginResponseDto * @throws AuthException * @throws SPException * @throws EnvironmentIsBrokenException @@ -54,7 +54,7 @@ interface LoginService * @uses Login::authLdap() * */ - public function doLogin(): LoginResponse; + public function doLogin(): LoginResponseDto; /** * @param string|null $from diff --git a/lib/SP/Domain/Auth/Services/Login.php b/lib/SP/Domain/Auth/Services/Login.php index 922a8396..ed3ab66d 100644 --- a/lib/SP/Domain/Auth/Services/Login.php +++ b/lib/SP/Domain/Auth/Services/Login.php @@ -24,19 +24,21 @@ namespace SP\Domain\Auth\Services; -use Defuse\Crypto\Exception\CryptoException; use Defuse\Crypto\Exception\EnvironmentIsBrokenException; use Exception; use SP\Core\Application; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; -use SP\DataModel\UserLoginData; -use SP\Domain\Auth\Dtos\LoginResponse; +use SP\DataModel\ProfileData; +use SP\Domain\Auth\Dtos\LoginResponseDto; +use SP\Domain\Auth\Dtos\UserLoginDto; use SP\Domain\Auth\Ports\LdapAuthService; use SP\Domain\Auth\Ports\LoginService; use SP\Domain\Common\Services\Service; +use SP\Domain\Common\Services\ServiceException; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Core\Exceptions\ConstraintException; +use SP\Domain\Core\Exceptions\CryptException; use SP\Domain\Core\Exceptions\InvalidArgumentException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; @@ -45,13 +47,12 @@ use SP\Domain\Crypt\Ports\TemporaryMasterPassService; use SP\Domain\Http\RequestInterface; use SP\Domain\Security\Dtos\TrackRequest; use SP\Domain\Security\Ports\TrackService; -use SP\Domain\User\Models\UserPreferences; +use SP\Domain\User\Ports\UserMasterPassService; use SP\Domain\User\Ports\UserPassRecoverService; -use SP\Domain\User\Ports\UserPassServiceInterface; use SP\Domain\User\Ports\UserProfileServiceInterface; use SP\Domain\User\Ports\UserServiceInterface; use SP\Domain\User\Services\UserLoginRequest; -use SP\Domain\User\Services\UserPassService; +use SP\Domain\User\Services\UserMasterPassStatus; use SP\Http\Uri; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Providers\Auth\AuthProviderInterface; @@ -61,6 +62,7 @@ use SP\Providers\Auth\Ldap\LdapAuthData; use SP\Providers\Auth\Ldap\LdapCodeEnum; use SP\Util\PasswordUtil; +use function SP\__; use function SP\__u; /** @@ -77,7 +79,7 @@ final class Login extends Service implements LoginService private const STATUS_PASS = 0; private const STATUS_NONE = 100; - private UserLoginData $userLoginData; + private UserLoginDto $userLoginData; private ConfigDataInterface $configData; private TrackRequest $trackRequest; private ?string $from = null; @@ -94,13 +96,13 @@ final class Login extends Service implements LoginService private readonly UserServiceInterface $userService, private readonly UserPassRecoverService $userPassRecoverService, private readonly TemporaryMasterPassService $temporaryMasterPassService, - private readonly UserPassServiceInterface $userPassService, + private readonly UserMasterPassService $userMasterPassService, private readonly UserProfileServiceInterface $userProfileService ) { parent::__construct($application); $this->configData = $this->config->getConfigData(); - $this->userLoginData = new UserLoginData(); + $this->userLoginData = new UserLoginDto(); $this->trackRequest = $this->trackService->buildTrackRequest(__CLASS__); $this->authProvider->initialize(); } @@ -108,7 +110,7 @@ final class Login extends Service implements LoginService /** * Ejecutar las acciones de login * - * @return LoginResponse + * @return LoginResponseDto * @throws AuthException * @throws SPException * @throws EnvironmentIsBrokenException @@ -120,7 +122,7 @@ final class Login extends Service implements LoginService * @uses Login::authLdap() * */ - public function doLogin(): LoginResponse + public function doLogin(): LoginResponseDto { $user = $this->request->analyzeString('user'); $pass = $this->request->analyzeEncrypted('pass'); @@ -191,7 +193,7 @@ final class Login extends Service implements LoginService $uri->addParam('r', 'index'); } - return new LoginResponse(self::STATUS_PASS, $uri->getUri()); + return new LoginResponseDto(self::STATUS_PASS, $uri->getUri()); } /** @@ -208,7 +210,8 @@ final class Login extends Service implements LoginService __u('Internal error'), SPException::ERROR, null, - Service::STATUS_INTERNAL_ERROR + Service::STATUS_INTERNAL_ERROR, + $e ); } } @@ -216,15 +219,15 @@ final class Login extends Service implements LoginService /** * Comprobar estado del usuario * - * @return LoginResponse + * @return LoginResponseDto * @throws EnvironmentIsBrokenException * @throws ConstraintException * @throws QueryException * @throws AuthException */ - private function checkUser(): LoginResponse + private function checkUser(): LoginResponseDto { - $userLoginResponse = $this->userLoginData->getUserLoginResponse(); + $userLoginResponse = $this->userLoginData->getUserDataDto(); if ($userLoginResponse !== null) { // Comprobar si el usuario está deshabilitado @@ -263,17 +266,19 @@ final class Login extends Service implements LoginService $uri = new Uri('index.php'); $uri->addParam('r', 'userPassReset/reset/' . $hash); - return new LoginResponse(self::STATUS_PASS_RESET, $uri->getUri()); + return new LoginResponseDto(self::STATUS_PASS_RESET, $uri->getUri()); } } - return new LoginResponse(self::STATUS_NONE); + return new LoginResponseDto(self::STATUS_NONE); } /** * Cargar la clave maestra o solicitarla * * @throws AuthException + * @throws CryptException + * @throws NoSuchItemException * @throws SPException */ private function loadMasterPass(): void @@ -283,76 +288,21 @@ final class Login extends Service implements LoginService try { if ($masterPass) { - if ($this->temporaryMasterPassService->checkTempMasterPass($masterPass)) { - $this->eventDispatcher->notify( - 'login.masterPass.temporary', - new Event($this, EventMessage::factory()->addDescription(__u('Using temporary password'))) - ); - - $masterPass = $this->temporaryMasterPassService->getUsingKey($masterPass); - } - - if ($this->userPassService->updateMasterPassOnLogin( - $masterPass, - $this->userLoginData - )->getStatus() !== UserPassService::MPASS_OK - ) { - $this->eventDispatcher->notify( - 'login.masterPass', - new Event($this, EventMessage::factory()->addDescription(__u('Wrong master password'))) - ); - - $this->addTracking(); - - throw new AuthException( - __u('Wrong master password'), - SPException::INFO, - null, - self::STATUS_INVALID_MASTER_PASS - ); - } - - $this->eventDispatcher->notify( - 'login.masterPass', - new Event($this, EventMessage::factory()->addDescription(__u('Master password updated'))) - ); + $this->checkMasterPass($masterPass); } elseif ($oldPass) { - if ($this->userPassService->updateMasterPassFromOldPass( - $oldPass, - $this->userLoginData - )->getStatus() !== UserPassService::MPASS_OK - ) { - $this->eventDispatcher->notify( - 'login.masterPass', - new Event($this, EventMessage::factory()->addDescription(__u('Wrong master password'))) - ); - - $this->addTracking(); - - throw new AuthException( - __u('Wrong master password'), - SPException::INFO, - null, - self::STATUS_INVALID_MASTER_PASS - ); - } - - $this->eventDispatcher->notify( - 'login.masterPass', - new Event($this, EventMessage::factory()->addDescription(__u('Master password updated'))) - ); + $this->loadMasterPassUsingOld($oldPass); } else { - switch ($this->userPassService->loadUserMPass($this->userLoginData)->getStatus()) { - case UserPassService::MPASS_CHECKOLD: + switch ($this->userMasterPassService->load($this->userLoginData)->getUserMasterPassStatus()) { + case UserMasterPassStatus::CheckOld: throw new AuthException( __u('Your previous password is needed'), SPException::INFO, null, self::STATUS_NEED_OLD_PASS ); - case UserPassService::MPASS_NOTSET: - case UserPassService::MPASS_CHANGED: - case UserPassService::MPASS_WRONG: + case UserMasterPassStatus::NotSet: + case UserMasterPassStatus::Changed: + case UserMasterPassStatus::Invalid: $this->addTracking(); throw new AuthException( @@ -361,9 +311,15 @@ final class Login extends Service implements LoginService null, self::STATUS_INVALID_MASTER_PASS ); + case UserMasterPassStatus::Ok: + $this->eventDispatcher->notify( + 'login.masterPass', + new Event($this, EventMessage::factory()->addDescription(__u('Master password loaded'))) + ); + break; } } - } catch (CryptoException $e) { + } catch (ServiceException $e) { $this->eventDispatcher->notify('exception', new Event($e)); throw new AuthException( @@ -376,6 +332,81 @@ final class Login extends Service implements LoginService } } + /** + * @param string $masterPass + * @return void + * @throws AuthException + * @throws NoSuchItemException + * @throws ServiceException + * @throws CryptException + */ + private function checkMasterPass(string $masterPass): void + { + if ($this->temporaryMasterPassService->checkTempMasterPass($masterPass)) { + $this->eventDispatcher->notify( + 'login.masterPass.temporary', + new Event($this, EventMessage::factory()->addDescription(__u('Using temporary password'))) + ); + + $masterPass = $this->temporaryMasterPassService->getUsingKey($masterPass); + } + + if ($this->userMasterPassService->updateOnLogin($masterPass, $this->userLoginData) + ->getUserMasterPassStatus() !== UserMasterPassStatus::Ok + ) { + $this->eventDispatcher->notify( + 'login.masterPass', + new Event($this, EventMessage::factory()->addDescription(__u('Wrong master password'))) + ); + + $this->addTracking(); + + throw new AuthException( + __u('Wrong master password'), + SPException::INFO, + null, + self::STATUS_INVALID_MASTER_PASS + ); + } + + $this->eventDispatcher->notify( + 'login.masterPass', + new Event($this, EventMessage::factory()->addDescription(__u('Master password updated'))) + ); + } + + /** + * @param string $oldPass + * @return void + * @throws AuthException + * @throws SPException + */ + private function loadMasterPassUsingOld(string $oldPass): void + { + if ($this->userMasterPassService->updateFromOldPass($oldPass, $this->userLoginData) + ->getUserMasterPassStatus() !== UserMasterPassStatus::Ok + ) { + $this->eventDispatcher->notify( + 'login.masterPass', + new Event($this, EventMessage::factory()->addDescription(__u('Wrong master password'))) + ); + + $this->addTracking(); + + throw new AuthException( + __u('Wrong master password'), + SPException::INFO, + null, + self::STATUS_INVALID_MASTER_PASS + ); + } + + $this->eventDispatcher->notify( + 'login.masterPass', + new Event($this, EventMessage::factory()->addDescription(__u('Master password updated'))) + ); + } + /** * Cargar la sesión del usuario * @@ -385,26 +416,24 @@ final class Login extends Service implements LoginService */ private function setUserSession(): void { - $userLoginResponse = $this->userLoginData->getUserLoginResponse(); + $userLoginResponse = $this->userLoginData->getUserDataDto(); // Actualizar el último login del usuario $this->userService->updateLastLoginById($userLoginResponse->getId()); - if ($this->context->getTrasientKey('mpass_updated')) { - $userLoginResponse->setLastUpdateMPass(time()); - } +// if ($this->context->getTrasientKey(UserMasterPass::SESSION_MASTERPASS_UPDATED)) { +// $this->context->setTrasientKey('user_master_pass_last_update', time()); +// } // Cargar las variables de ussuario en la sesión $this->context->setUserData($userLoginResponse); $this->context->setUserProfile( - $this->userProfileService->getById($userLoginResponse->getUserProfileId())->getProfile() + $this->userProfileService + ->getById($userLoginResponse->getUserProfileId()) + ->hydrate(ProfileData::class) ); $this->context->setLocale($userLoginResponse->getPreferences()->getLang()); - if ($this->configData->isDemoEnabled()) { - $userLoginResponse->setPreferences(new UserPreferences()); - } - $this->eventDispatcher->notify( 'login.session.load', new Event($this, EventMessage::factory()->addDetail(__u('User'), $userLoginResponse->getLogin())) @@ -426,7 +455,7 @@ final class Login extends Service implements LoginService */ private function cleanUserData(): void { - $this->userLoginData->setUserLoginResponse(); + $this->userLoginData->setUserDataDto(); } /** diff --git a/lib/SP/Domain/Core/Context/ContextInterface.php b/lib/SP/Domain/Core/Context/ContextInterface.php index 7fac8e91..81c14acf 100644 --- a/lib/SP/Domain/Core/Context/ContextInterface.php +++ b/lib/SP/Domain/Core/Context/ContextInterface.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -27,7 +27,8 @@ namespace SP\Domain\Core\Context; use SP\Core\Context\ContextException; use SP\DataModel\ProfileData; use SP\Domain\Account\Dtos\AccountCacheDto; -use SP\Domain\User\Services\UserLoginResponse; +use SP\Domain\User\Dtos\UserDataDto; +use SP\Domain\User\Services\UserData; /** * Class ContextInterface @@ -58,7 +59,7 @@ interface ContextInterface /** * Establece los datos del usuario en la sesión. */ - public function setUserData(?UserLoginResponse $userLoginResponse = null); + public function setUserData(?UserDataDto $userDataDto = null); /** * Obtiene el objeto de perfil de usuario de la sesión. @@ -78,7 +79,7 @@ interface ContextInterface /** * Devuelve los datos del usuario en la sesión. */ - public function getUserData(): UserLoginResponse; + public function getUserData(): UserDataDto; /** * Establecer el lenguaje de la sesión diff --git a/lib/SP/Domain/Crypt/Ports/TemporaryMasterPassService.php b/lib/SP/Domain/Crypt/Ports/TemporaryMasterPassService.php index 2e2e7e50..31029624 100644 --- a/lib/SP/Domain/Crypt/Ports/TemporaryMasterPassService.php +++ b/lib/SP/Domain/Crypt/Ports/TemporaryMasterPassService.php @@ -24,10 +24,10 @@ namespace SP\Domain\Crypt\Ports; -use Defuse\Crypto\Exception\CryptoException; use PHPMailer\PHPMailer\Exception; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Core\Exceptions\ConstraintException; +use SP\Domain\Core\Exceptions\CryptException; use SP\Domain\Core\Exceptions\QueryException; use SP\Infrastructure\Common\Repositories\NoSuchItemException; @@ -82,7 +82,7 @@ interface TemporaryMasterPassService * @return string con la clave maestra desencriptada * @throws NoSuchItemException * @throws ServiceException - * @throws CryptoException + * @throws CryptException */ public function getUsingKey(string $key): string; } diff --git a/lib/SP/Domain/User/Dtos/UserDataDto.php b/lib/SP/Domain/User/Dtos/UserDataDto.php new file mode 100644 index 00000000..c4b6955d --- /dev/null +++ b/lib/SP/Domain/User/Dtos/UserDataDto.php @@ -0,0 +1,151 @@ +. + */ + +namespace SP\Domain\User\Dtos; + +use SP\Domain\User\Models\User; +use SP\Domain\User\Models\UserPreferences; + +/** + * Class UserLoginResponse + */ +final readonly class UserDataDto +{ + private ?UserPreferences $preferences; + + public function __construct(private ?User $user = null) + { + $this->preferences = $this->user?->hydrate(UserPreferences::class); + } + + public function getLogin(): ?string + { + return $this->user->getLogin(); + } + + public function getSsoLogin(): ?string + { + return $this->user->getSsoLogin(); + } + + public function getName(): ?string + { + return $this->user->getName(); + } + + public function getEmail(): ?string + { + return $this->user->getEmail(); + } + + public function getUserGroupId(): int + { + return (int)$this->user->getUserGroupId(); + } + + public function getUserProfileId(): int + { + return (int)$this->user->getUserProfileId(); + } + + public function getIsAdminApp(): bool + { + return (bool)$this->user->isAdminApp(); + } + + public function getIsAdminAcc(): bool + { + return (bool)$this->user->isAdminAcc(); + } + + public function getIsDisabled(): bool + { + return (bool)$this->user->isDisabled(); + } + + public function getIsChangePass(): bool + { + return (bool)$this->user->isChangePass(); + } + + public function getIsChangedPass(): bool + { + return (bool)$this->user->isChangedPass(); + } + + public function getIsLdap(): bool + { + return (bool)$this->user->isLdap(); + } + + public function getIsMigrate(): bool + { + return (bool)$this->user->isMigrate(); + } + + public function getPreferences(): ?UserPreferences + { + return $this->preferences; + } + + public function getPass(): ?string + { + return $this->user->getPass(); + } + + public function getMPass(): ?string + { + return $this->user->getMPass(); + } + + public function getMKey(): ?string + { + return $this->user->getMKey(); + } + + public function getLastUpdateMPass(): int + { + return $this->user->getLastUpdateMPass(); + } + + public function getHashSalt(): ?string + { + return $this->user->getHashSalt(); + } + + public function getId(): ?int + { + return $this->user->getId(); + } + + public function getUserGroupName(): ?string + { + return $this->user->offsetGet('userGroup.name'); + } + + public function getLastUpdate(): int + { + return (int)strtotime($this->user->getLastUpdate()); + } +} diff --git a/lib/SP/Domain/User/Services/UserPassResponse.php b/lib/SP/Domain/User/Dtos/UserMasterPassDto.php similarity index 54% rename from lib/SP/Domain/User/Services/UserPassResponse.php rename to lib/SP/Domain/User/Dtos/UserMasterPassDto.php index 73bafa58..6f3e5acb 100644 --- a/lib/SP/Domain/User/Services/UserPassResponse.php +++ b/lib/SP/Domain/User/Dtos/UserMasterPassDto.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -22,37 +22,29 @@ * along with sysPass. If not, see . */ -namespace SP\Domain\User\Services; +namespace SP\Domain\User\Dtos; + +use SP\Domain\User\Services\UserMasterPassStatus; /** - * Class UserPassResponse - * - * @package SP\DataModel\Dto + * Class UserMasterPassDto */ -final class UserPassResponse +final readonly class UserMasterPassDto { - private int $status; - private ?string $cryptMasterPass = null; - private ?string $cryptSecuredKey = null; - private ?string $clearMasterPass; - /** * UserPassResponse constructor. */ - public function __construct(int $status, ?string $clearUserMPass = null) - { - $this->status = $status; - $this->clearMasterPass = $clearUserMPass; + public function __construct( + private UserMasterPassStatus $userMasterPassStatus, + private ?string $clearMasterPass = null, + private ?string $cryptMasterPass = null, + private ?string $cryptSecuredKey = null + ) { } - public function getStatus(): int + public function getUserMasterPassStatus(): UserMasterPassStatus { - return $this->status; - } - - public function setStatus(int $status): void - { - $this->status = $status; + return $this->userMasterPassStatus; } public function getCryptMasterPass(): ?string @@ -60,23 +52,13 @@ final class UserPassResponse return $this->cryptMasterPass; } - public function setCryptMasterPass(string $cryptMasterPass): void - { - $this->cryptMasterPass = $cryptMasterPass; - } - public function getCryptSecuredKey(): ?string { return $this->cryptSecuredKey; } - public function setCryptSecuredKey(string $cryptSecuredKey): void - { - $this->cryptSecuredKey = $cryptSecuredKey; - } - public function getClearMasterPass(): ?string { return $this->clearMasterPass; } -} \ No newline at end of file +} diff --git a/lib/SP/Domain/User/Ports/UserMasterPassService.php b/lib/SP/Domain/User/Ports/UserMasterPassService.php new file mode 100644 index 00000000..0500ab3c --- /dev/null +++ b/lib/SP/Domain/User/Ports/UserMasterPassService.php @@ -0,0 +1,65 @@ +. + */ + +namespace SP\Domain\User\Ports; + +use SP\Domain\Auth\Dtos\UserLoginDto; +use SP\Domain\Common\Services\ServiceException; +use SP\Domain\User\Dtos\UserMasterPassDto; + +/** + * Class UserPassService + * + * @package SP\Domain\User\Services + */ +interface UserMasterPassService +{ + /** + * Actualizar la clave maestra con la clave anterior del usuario + * + * @throws ServiceException + */ + public function updateFromOldPass(string $oldUserPass, UserLoginDto $userLoginDto): UserMasterPassDto; + + /** + * Comprueba la clave maestra del usuario. + * + * @throws ServiceException + */ + public function load(UserLoginDto $userLoginDto, ?string $userPass = null): UserMasterPassDto; + + /** + * Actualizar la clave maestra del usuario al realizar login + * + * @throws ServiceException + */ + public function updateOnLogin(string $userMasterPass, UserLoginDto $userLoginDto): UserMasterPassDto; + + /** + * Actualizar la clave maestra del usuario en la BBDD. + * + * @throws ServiceException + */ + public function create(string $masterPass, string $userLogin, string $userPass): UserMasterPassDto; +} diff --git a/lib/SP/Domain/User/Ports/UserPassServiceInterface.php b/lib/SP/Domain/User/Ports/UserPassServiceInterface.php deleted file mode 100644 index e84856f4..00000000 --- a/lib/SP/Domain/User/Ports/UserPassServiceInterface.php +++ /dev/null @@ -1,87 +0,0 @@ -. - */ - -namespace SP\Domain\User\Ports; - -use Defuse\Crypto\Exception\CryptoException; -use SP\DataModel\UserLoginData; -use SP\Domain\Core\Exceptions\ConstraintException; -use SP\Domain\Core\Exceptions\QueryException; -use SP\Domain\Core\Exceptions\SPException; -use SP\Domain\User\Services\UserPassResponse; -use SP\Infrastructure\Common\Repositories\NoSuchItemException; - -/** - * Class UserPassService - * - * @package SP\Domain\User\Services - */ -interface UserPassServiceInterface -{ - /** - * Actualizar la clave maestra con la clave anterior del usuario - * - * @throws SPException - * @throws CryptoException - */ - public function updateMasterPassFromOldPass(string $oldUserPass, UserLoginData $userLoginData): UserPassResponse; - - /** - * Comprueba la clave maestra del usuario. - * - * @throws SPException - */ - public function loadUserMPass(UserLoginData $userLoginData, ?string $userPass = null): UserPassResponse; - - /** - * Obtener una clave de cifrado basada en la clave del usuario y un salt. - * - * @return string con la clave de cifrado - */ - public function makeKeyForUser(string $userLogin, string $userPass): string; - - /** - * Actualizar la clave maestra del usuario al realizar login - * - * @throws SPException - * @throws CryptoException - * @throws SPException - */ - public function updateMasterPassOnLogin(string $userMPass, UserLoginData $userLoginData): UserPassResponse; - - /** - * Actualizar la clave maestra del usuario en la BBDD. - * - * @throws CryptoException - * @throws SPException - */ - public function createMasterPass(string $masterPass, string $userLogin, string $userPass): UserPassResponse; - - /** - * @throws ConstraintException - * @throws QueryException - * @throws NoSuchItemException - */ - public function migrateUserPassById(int $id, string $userPass): void; -} diff --git a/lib/SP/Domain/User/Services/UserLoginResponse.php b/lib/SP/Domain/User/Services/UserLoginResponse.php deleted file mode 100644 index 9c5a126e..00000000 --- a/lib/SP/Domain/User/Services/UserLoginResponse.php +++ /dev/null @@ -1,323 +0,0 @@ -. - */ - -namespace SP\Domain\User\Services; - -use SP\Domain\User\Models\UserPreferences; - -/** - * Class UserLoginResponse - * - * @package SP\Domain\User\Services - */ -final class UserLoginResponse -{ - private ?int $id = null; - private ?string $login = null; - private ?string $ssoLogin = null; - private ?string $name = null; - private ?string $email = null; - private int $userGroupId = 0; - private ?string $userGroupName = null; - private int $userProfileId = 0; - private bool $isAdminApp = false; - private bool $isAdminAcc = false; - private bool $isDisabled = false; - private bool $isChangePass = false; - private bool $isChangedPass = false; - private bool $isLdap = false; - private bool $isMigrate = false; - private ?UserPreferences $preferences = null; - private ?string $pass = null; - private ?string $hashSalt = null; - private ?string $mPass = null; - private ?string $mKey = null; - private int $lastUpdateMPass = 0; - private ?int $lastUpdate = null; - - public function getLogin(): ?string - { - return $this->login; - } - - public function setLogin(string $login): UserLoginResponse - { - $this->login = $login; - - return $this; - } - - public function getSsoLogin(): ?string - { - return $this->ssoLogin; - } - - public function setSsoLogin(?string $ssoLogin): UserLoginResponse - { - $this->ssoLogin = $ssoLogin; - - return $this; - } - - public function getName(): ?string - { - return $this->name; - } - - public function setName(string $name): UserLoginResponse - { - $this->name = $name; - - return $this; - } - - public function getEmail(): ?string - { - return $this->email; - } - - public function setEmail(?string $email): UserLoginResponse - { - $this->email = $email; - - return $this; - } - - public function getUserGroupId(): int - { - return $this->userGroupId; - } - - public function setUserGroupId(int $userGroupId): UserLoginResponse - { - $this->userGroupId = $userGroupId; - - return $this; - } - - public function getUserProfileId(): int - { - return $this->userProfileId; - } - - public function setUserProfileId(int $userProfileId): UserLoginResponse - { - $this->userProfileId = $userProfileId; - - return $this; - } - - public function getIsAdminApp(): bool - { - return $this->isAdminApp; - } - - public function setIsAdminApp(bool $isAdminApp): UserLoginResponse - { - $this->isAdminApp = $isAdminApp; - - return $this; - } - - public function getIsAdminAcc(): bool - { - return $this->isAdminAcc; - } - - public function setIsAdminAcc(bool $isAdminAcc): UserLoginResponse - { - $this->isAdminAcc = $isAdminAcc; - - return $this; - } - - public function getIsDisabled(): bool - { - return $this->isDisabled; - } - - public function setIsDisabled(bool $isDisabled): UserLoginResponse - { - $this->isDisabled = $isDisabled; - - return $this; - } - - public function getIsChangePass(): bool - { - return $this->isChangePass; - } - - public function setIsChangePass(bool $isChangePass): UserLoginResponse - { - $this->isChangePass = $isChangePass; - - return $this; - } - - public function getIsChangedPass(): bool - { - return $this->isChangedPass; - } - - public function setIsChangedPass(bool $isChangedPass): UserLoginResponse - { - $this->isChangedPass = $isChangedPass; - - return $this; - } - - public function getIsLdap(): bool - { - return $this->isLdap; - } - - public function setIsLdap(bool $isLdap): UserLoginResponse - { - $this->isLdap = $isLdap; - - return $this; - } - - public function getIsMigrate(): bool - { - return $this->isMigrate; - } - - public function setIsMigrate(bool $isMigrate): UserLoginResponse - { - $this->isMigrate = $isMigrate; - - return $this; - } - - public function getPreferences(): ?UserPreferences - { - return $this->preferences; - } - - public function setPreferences(UserPreferences $preferences): UserLoginResponse - { - $this->preferences = $preferences; - - return $this; - } - - public function getPass(): ?string - { - return $this->pass; - } - - public function setPass(string $pass): UserLoginResponse - { - $this->pass = $pass; - - return $this; - } - - public function getMPass(): ?string - { - return $this->mPass; - } - - public function setMPass(string $mPass): UserLoginResponse - { - $this->mPass = $mPass; - - return $this; - } - - public function getMKey(): ?string - { - return $this->mKey; - } - - public function setMKey(string $mKey): UserLoginResponse - { - $this->mKey = $mKey; - - return $this; - } - - public function getLastUpdateMPass(): int - { - return $this->lastUpdateMPass; - } - - public function setLastUpdateMPass(int $lastUpdateMPass): UserLoginResponse - { - $this->lastUpdateMPass = $lastUpdateMPass; - - return $this; - } - - public function getHashSalt(): ?string - { - return $this->hashSalt; - } - - public function setHashSalt(string $hashSalt): UserLoginResponse - { - $this->hashSalt = $hashSalt; - - return $this; - } - - public function getId(): ?int - { - return $this->id; - } - - public function setId(int $id): UserLoginResponse - { - $this->id = $id; - - return $this; - } - - public function getUserGroupName(): ?string - { - return $this->userGroupName; - } - - public function setUserGroupName(string $userGroupName): UserLoginResponse - { - $this->userGroupName = $userGroupName; - - return $this; - } - - - public function getLastUpdate(): int - { - return $this->lastUpdate; - } - - public function setLastUpdate(int $lastUpdate): UserLoginResponse - { - $this->lastUpdate = $lastUpdate; - - return $this; - } -} diff --git a/lib/SP/Domain/User/Services/UserMasterPass.php b/lib/SP/Domain/User/Services/UserMasterPass.php new file mode 100644 index 00000000..331e4677 --- /dev/null +++ b/lib/SP/Domain/User/Services/UserMasterPass.php @@ -0,0 +1,212 @@ +. + */ + +namespace SP\Domain\User\Services; + +use Exception; +use SP\Core\Application; +use SP\Core\Crypt\Hash; +use SP\Core\Events\Event; +use SP\Domain\Auth\Dtos\UserLoginDto; +use SP\Domain\Common\Services\Service; +use SP\Domain\Common\Services\ServiceException; +use SP\Domain\Config\Ports\ConfigService; +use SP\Domain\Core\Crypt\CryptInterface; +use SP\Domain\Core\Exceptions\CryptException; +use SP\Domain\User\Dtos\UserMasterPassDto; +use SP\Domain\User\Ports\UserMasterPassService; +use SP\Domain\User\Ports\UserRepository; + +use function SP\__u; + +/** + * Class UserMasterPass + */ +final class UserMasterPass extends Service implements UserMasterPassService +{ +// public const SESSION_MASTERPASS_UPDATED = 'mpass_updated'; + + private const PARAM_MASTER_PWD = 'masterPwd'; + private const PARAM_LASTUPDATEMPASS = 'lastupdatempass'; + + public function __construct( + Application $application, + private readonly UserRepository $userRepository, + private readonly ConfigService $configService, + private readonly CryptInterface $crypt + ) { + parent::__construct($application); + } + + /** + * Update the master pass by using the old user's password + * + * @throws ServiceException + */ + public function updateFromOldPass(string $oldUserPass, UserLoginDto $userLoginDto): UserMasterPassDto + { + $response = $this->load($userLoginDto, $oldUserPass); + + if ($response->getUserMasterPassStatus() === UserMasterPassStatus::Ok) { + return $this->updateOnLogin($response->getClearMasterPass(), $userLoginDto); + } + + return new UserMasterPassDto(UserMasterPassStatus::Invalid); + } + + /** + * Load the user's master pass + * + * @throws ServiceException + */ + public function load(UserLoginDto $userLoginDto, ?string $userPass = null): UserMasterPassDto + { + try { + if (($userDataDto = $userLoginDto->getUserDataDto()) === null + || empty($userDataDto->getMPass()) + || empty($userDataDto->getMKey()) + || empty($systemMasterPassHash = $this->configService->getByParam(self::PARAM_MASTER_PWD)) + ) { + return new UserMasterPassDto(UserMasterPassStatus::NotSet); + } + + if ($userDataDto->getLastUpdateMPass() < + (int)$this->configService->getByParam(self::PARAM_LASTUPDATEMPASS, 0) + ) { + return new UserMasterPassDto(UserMasterPassStatus::Changed); + } + + if ($userPass === null && $userDataDto->getIsChangedPass()) { + return new UserMasterPassDto(UserMasterPassStatus::CheckOld); + } + + + $key = $this->makeKeyForUser($userLoginDto->getLoginUser(), $userPass ?? $userLoginDto->getLoginPass()); + + $userMasterPass = $this->crypt->decrypt($userDataDto->getMPass(), $userDataDto->getMKey(), $key); + + // Comprobamos el hash de la clave del usuario con la guardada + if (Hash::checkHashKey($userMasterPass, $systemMasterPassHash)) { + $this->setMasterKeyInContext($userMasterPass); + + return new UserMasterPassDto( + UserMasterPassStatus::Ok, + $userMasterPass, + $userDataDto->getMPass(), + $userDataDto->getMKey() + ); + } + } catch (CryptException $e) { + $this->eventDispatcher->notify('exception', new Event($e)); + + return new UserMasterPassDto(UserMasterPassStatus::CheckOld); + } catch (Exception $e) { + throw ServiceException::from($e); + } + + return new UserMasterPassDto(UserMasterPassStatus::Invalid); + } + + /** + * Obtener una clave de cifrado basada en la clave del usuario y un salt. + * + * @return string con la clave de cifrado + */ + private function makeKeyForUser(string $userLogin, string $userPass): string + { + return trim($userPass . $userLogin . $this->config->getConfigData()->getPasswordSalt()); + } + + /** + * Update the user's master pass on log in. + * It requires the user's login data to build a secure key to store the master password + * + * @throws ServiceException + */ + public function updateOnLogin(string $userMasterPass, UserLoginDto $userLoginDto): UserMasterPassDto + { + try { + $userData = $userLoginDto->getUserDataDto(); + $systemMasterPassHash = $this->configService->getByParam(self::PARAM_MASTER_PWD); + + if (null === $systemMasterPassHash) { + $systemMasterPassHash = Hash::hashKey($userMasterPass); + + $this->configService->save(self::PARAM_MASTER_PWD, $systemMasterPassHash); + } + + if (Hash::checkHashKey($userMasterPass, $systemMasterPassHash)) { + $response = $this->create( + $userMasterPass, + $userLoginDto->getLoginUser(), + $userLoginDto->getLoginPass() + ); + + $this->userRepository->updateMasterPassById( + $userData->getId(), + $response->getCryptMasterPass(), + $response->getCryptSecuredKey() + ); + +// $this->context->setTrasientKey(self::SESSION_MASTERPASS_UPDATED, true); + + $this->setMasterKeyInContext($userMasterPass); + + return $response; + } + + return new UserMasterPassDto(UserMasterPassStatus::Invalid); + } catch (Exception $e) { + throw ServiceException::from($e); + } + } + + /** + * Actualizar la clave maestra del usuario en la BBDD. + * + * @throws ServiceException + */ + public function create(string $masterPass, string $userLogin, string $userPass): UserMasterPassDto + { + $key = $this->makeKeyForUser($userLogin, $userPass); + + try { + $securedKey = $this->crypt->makeSecuredKey($key); + + if (strlen($securedKey) > 1000) { + throw ServiceException::error(__u('Internal error'), null, Service::STATUS_INTERNAL_ERROR); + } + + $encryptedMasterPass = $this->crypt->encrypt($masterPass, $securedKey, $key); + + if (strlen($encryptedMasterPass) > 1000) { + throw ServiceException::error(__u('Internal error'), null, Service::STATUS_INTERNAL_ERROR); + } + + return new UserMasterPassDto(UserMasterPassStatus::Ok, $masterPass, $encryptedMasterPass, $securedKey); + } catch (CryptException $e) { + throw ServiceException::from($e); + } + } +} diff --git a/lib/SP/Domain/User/Services/UserMasterPassStatus.php b/lib/SP/Domain/User/Services/UserMasterPassStatus.php new file mode 100644 index 00000000..da4e0afe --- /dev/null +++ b/lib/SP/Domain/User/Services/UserMasterPassStatus.php @@ -0,0 +1,37 @@ +. + */ + +namespace SP\Domain\User\Services; + +/** + * Enum UserMasterPassStatus + */ +enum UserMasterPassStatus +{ + case Invalid; + case Ok; + case NotSet; + case Changed; + case CheckOld; +} diff --git a/lib/SP/Domain/User/Services/UserPass.php b/lib/SP/Domain/User/Services/UserPass.php new file mode 100644 index 00000000..cf94f892 --- /dev/null +++ b/lib/SP/Domain/User/Services/UserPass.php @@ -0,0 +1,71 @@ +. + */ + +namespace SP\Domain\User\Services; + +use SP\Core\Application; +use SP\Core\Crypt\Hash; +use SP\Domain\Common\Services\Service; +use SP\Domain\Core\Exceptions\ConstraintException; +use SP\Domain\Core\Exceptions\QueryException; +use SP\Domain\User\Models\User; +use SP\Domain\User\Ports\UserRepository; +use SP\Infrastructure\Common\Repositories\NoSuchItemException; + +use function SP\__u; + +/** + * Class UserPass + */ +final class UserPass extends Service implements UserPassService +{ + public function __construct( + Application $application, + private readonly UserRepository $userRepository + ) { + parent::__construct($application); + } + + /** + * @throws ConstraintException + * @throws QueryException + * @throws NoSuchItemException + */ + public function migrateUserPassById(int $id, string $userPass): void + { + $user = new User( + [ + 'id' => $id, + 'pass' => Hash::hashKey($userPass), + 'isChangePass' => 0, + 'isChangedPass' => 1, + 'isMigrate' => 0 + ] + ); + + if ($this->userRepository->updatePassById($user) === 0) { + throw NoSuchItemException::info(__u('User does not exist')); + } + } +} diff --git a/lib/SP/Domain/User/Services/UserPassService.php b/lib/SP/Domain/User/Services/UserPassService.php index 67e90227..55deeb10 100644 --- a/lib/SP/Domain/User/Services/UserPassService.php +++ b/lib/SP/Domain/User/Services/UserPassService.php @@ -24,228 +24,19 @@ namespace SP\Domain\User\Services; -use Defuse\Crypto\Exception\CryptoException; -use SP\Core\Application; -use SP\Core\Crypt\Crypt; -use SP\Core\Crypt\Hash; -use SP\DataModel\UserLoginData; -use SP\Domain\Common\Services\Service; -use SP\Domain\Config\Ports\ConfigService; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; -use SP\Domain\Core\Exceptions\SPException; -use SP\Domain\User\Ports\UserPassServiceInterface; -use SP\Domain\User\Ports\UserRepository; use SP\Infrastructure\Common\Repositories\NoSuchItemException; /** - * Class UserPassService - * - * @package SP\Domain\User\Services + * Class UserPass */ -final class UserPassService extends Service implements UserPassServiceInterface +interface UserPassService { - // La clave maestra incorrecta - public const MPASS_WRONG = 0; - // La clave maestra correcta - public const MPASS_OK = 1; - // La clave maestra no está guardada - public const MPASS_NOTSET = 2; - // La clave maestra ha cambiado - public const MPASS_CHANGED = 3; - // Comprobar la clave maestra con la clave del usuario anterior - public const MPASS_CHECKOLD = 4; - - private UserRepository $userRepository; - private ConfigService $configService; - - public function __construct( - Application $application, - UserRepository $userRepository, - ConfigService $configService - ) { - parent::__construct($application); - - $this->userRepository = $userRepository; - $this->configService = $configService; - } - - /** - * Actualizar la clave maestra con la clave anterior del usuario - * - * @throws SPException - * @throws CryptoException - */ - public function updateMasterPassFromOldPass( - string $oldUserPass, - UserLoginData $userLoginData - ): UserPassResponse { - $response = $this->loadUserMPass($userLoginData, $oldUserPass); - - if ($response->getStatus() === self::MPASS_OK) { - return $this->updateMasterPassOnLogin($response->getClearMasterPass(), $userLoginData); - } - - return new UserPassResponse(self::MPASS_WRONG); - } - - /** - * Comprueba la clave maestra del usuario. - * - * @throws SPException - */ - public function loadUserMPass( - UserLoginData $userLoginData, - ?string $userPass = null - ): UserPassResponse { - $userLoginResponse = $userLoginData->getUserLoginResponse(); - - $configHashMPass = $this->configService->getByParam('masterPwd'); - - if (empty($configHashMPass) - || $userLoginResponse === null - || empty($userLoginResponse->getMPass()) - || empty($userLoginResponse->getMKey()) - ) { - return new UserPassResponse(self::MPASS_NOTSET); - } - - if ($userLoginResponse->getLastUpdateMPass() < $this->configService->getByParam('lastupdatempass')) { - return new UserPassResponse(self::MPASS_CHANGED); - } - - if ($userPass === null && $userLoginResponse->getIsChangedPass()) { - return new UserPassResponse(self::MPASS_CHECKOLD); - } - - try { - $key = $this->makeKeyForUser( - $userLoginData->getLoginUser(), - $userPass ?: $userLoginData->getLoginPass() - ); - - $clearMPass = Crypt::decrypt( - $userLoginResponse->getMPass(), - $userLoginResponse->getMKey(), - $key - ); - - // Comprobamos el hash de la clave del usuario con la guardada - if (Hash::checkHashKey($clearMPass, $configHashMPass)) { - $this->setMasterKeyInContext($clearMPass); - - $response = new UserPassResponse(self::MPASS_OK, $clearMPass); - $response->setCryptMasterPass($userLoginResponse->getMPass()); - $response->setCryptSecuredKey($userLoginResponse->getMKey()); - - return $response; - } - } catch (CryptoException $e) { - return new UserPassResponse(self::MPASS_CHECKOLD); - } - - return new UserPassResponse(self::MPASS_WRONG); - } - - /** - * Obtener una clave de cifrado basada en la clave del usuario y un salt. - * - * @return string con la clave de cifrado - */ - public function makeKeyForUser(string $userLogin, string $userPass): string - { - return trim($userPass . $userLogin . $this->config->getConfigData()->getPasswordSalt()); - } - - /** - * Actualizar la clave maestra del usuario al realizar login - * - * @throws SPException - * @throws CryptoException - * @throws SPException - */ - public function updateMasterPassOnLogin(string $userMPass, UserLoginData $userLoginData): UserPassResponse - { - $userData = $userLoginData->getUserLoginResponse(); - $configHashMPass = $this->configService->getByParam('masterPwd'); - - if ($configHashMPass === false) { - return new UserPassResponse(self::MPASS_NOTSET); - } - - if (null === $configHashMPass) { - $configHashMPass = Hash::hashKey($userMPass); - - $this->configService->save('masterPwd', $configHashMPass); - } - - if (Hash::checkHashKey($userMPass, $configHashMPass)) { - $response = $this->createMasterPass( - $userMPass, - $userLoginData->getLoginUser(), - $userLoginData->getLoginPass() - ); - - $this->userRepository->updateMasterPassById( - $userData->getId(), - $response->getCryptMasterPass(), - $response->getCryptSecuredKey() - ); - - // Tells that the master password has been updated - $this->context->setTrasientKey('mpass_updated', true); - - $this->setMasterKeyInContext($userMPass); - - return $response; - } - - return new UserPassResponse(self::MPASS_WRONG); - } - - /** - * Actualizar la clave maestra del usuario en la BBDD. - * - * @throws CryptoException - * @throws SPException - */ - public function createMasterPass(string $masterPass, string $userLogin, string $userPass): UserPassResponse - { - $key = $this->makeKeyForUser($userLogin, $userPass); - - $securedKey = Crypt::makeSecuredKey($key); - $cryptMPass = Crypt::encrypt($masterPass, $securedKey, $key); - - if (strlen($securedKey) > 1000 || strlen($cryptMPass) > 1000) { - throw new SPException( - __u('Internal error'), - SPException::ERROR, - '', - Service::STATUS_INTERNAL_ERROR - ); - } - - $response = new UserPassResponse(self::MPASS_OK, $masterPass); - $response->setCryptMasterPass($cryptMPass); - $response->setCryptSecuredKey($securedKey); - - return $response; - } - /** * @throws ConstraintException * @throws QueryException * @throws NoSuchItemException */ - public function migrateUserPassById(int $id, string $userPass): void - { - $updatePassById = $this->userRepository->updatePassById( - $id, - new UpdatePassRequest(Hash::hashKey($userPass)) - ); - - if ($updatePassById === 0) { - throw new NoSuchItemException(__u('User does not exist')); - } - } + public function migrateUserPassById(int $id, string $userPass): void; } diff --git a/lib/SP/Domain/User/Services/UserService.php b/lib/SP/Domain/User/Services/UserService.php index 48c9d754..32f6e571 100644 --- a/lib/SP/Domain/User/Services/UserService.php +++ b/lib/SP/Domain/User/Services/UserService.php @@ -36,7 +36,7 @@ use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; use SP\Domain\User\Models\User as UserModel; use SP\Domain\User\Models\UserPreferences; -use SP\Domain\User\Ports\UserPassServiceInterface; +use SP\Domain\User\Ports\UserMasterPassService; use SP\Domain\User\Ports\UserRepository; use SP\Domain\User\Ports\UserServiceInterface; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; @@ -53,13 +53,13 @@ final class UserService extends Service implements UserServiceInterface { use ServiceItemTrait; - private UserRepository $userRepository; - private UserPassServiceInterface $userPassService; + private UserRepository $userRepository; + private UserMasterPassService $userPassService; public function __construct( - Application $application, - UserRepository $userRepository, - UserPassServiceInterface $userPassService + Application $application, + UserRepository $userRepository, + UserMasterPassService $userPassService ) { parent::__construct($application); @@ -67,33 +67,6 @@ final class UserService extends Service implements UserServiceInterface $this->userPassService = $userPassService; } - public static function mapUserLoginResponse( - UserModel $user - ): UserLoginResponse { - // TODO: create static method UserLoginResponse::from($user) - return (new UserLoginResponse())->setId($user->getId()) - ->setName($user->getName()) - ->setLogin($user->getLogin()) - ->setSsoLogin($user->getSsoLogin()) - ->setEmail($user->getEmail()) - ->setPass($user->getPass()) - ->setHashSalt($user->getHashSalt()) - ->setMPass($user->getMPass()) - ->setMKey($user->getMKey()) - ->setLastUpdateMPass($user->getLastUpdateMPass()) - ->setUserGroupId($user->getUserGroupId()) - ->setUserProfileId($user->getUserProfileId()) - ->setPreferences(self::getUserPreferences($user->getPreferences())) - ->setIsLdap($user->isLdap()) - ->setIsAdminAcc($user->isAdminAcc()) - ->setIsAdminApp($user->isAdminApp()) - ->setIsMigrate($user->isMigrate()) - ->setIsChangedPass($user->isChangedPass()) - ->setIsChangePass($user->isChangePass()) - ->setIsDisabled($user->isDisabled()) - ->setLastUpdate((int)strtotime($user->getLastUpdate())); - } - /** * Returns user's preferences object */ @@ -251,7 +224,7 @@ final class UserService extends Service implements UserServiceInterface */ public function createWithMasterPass(UserModel $itemData, string $userPass, string $masterPass): int { - $response = $this->userPassService->createMasterPass( + $response = $this->userPassService->create( $masterPass, $itemData->getLogin(), $userPass diff --git a/lib/SP/Infrastructure/User/Repositories/User.php b/lib/SP/Infrastructure/User/Repositories/User.php index 0b5ee96a..1c8e7b86 100644 --- a/lib/SP/Infrastructure/User/Repositories/User.php +++ b/lib/SP/Infrastructure/User/Repositories/User.php @@ -130,10 +130,9 @@ final class User extends BaseRepository implements UserRepository $query = $this->queryFactory ->newUpdate() ->table(UserModel::TABLE) - ->cols($user->toArray(['pass', 'isChangePass', 'isChangedPass'])) + ->cols($user->toArray(['pass', 'isChangePass', 'isChangedPass', 'isMigrate'])) ->set('lastUpdate', 'NOW()') ->set('hashSalt', '') - ->set('isMigrate', 0) ->where('id = :id', ['id' => $user->getId()]) ->limit(1); diff --git a/lib/SP/Providers/Auth/AuthInterface.php b/lib/SP/Providers/Auth/AuthInterface.php index fec7b72a..aeadac9f 100644 --- a/lib/SP/Providers/Auth/AuthInterface.php +++ b/lib/SP/Providers/Auth/AuthInterface.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -24,7 +24,7 @@ namespace SP\Providers\Auth; -use SP\DataModel\UserLoginData; +use SP\Domain\Auth\Dtos\UserLoginDto; /** * Interface AuthInterface @@ -37,10 +37,10 @@ interface AuthInterface /** * Authenticate using user's data * - * @param UserLoginData $userLoginData + * @param UserLoginDto $userLoginData * @return T */ - public function authenticate(UserLoginData $userLoginData): AuthDataBase; + public function authenticate(UserLoginDto $userLoginData): AuthDataBase; /** * Indica si es requerida para acceder a la aplicación diff --git a/lib/SP/Providers/Auth/AuthProvider.php b/lib/SP/Providers/Auth/AuthProvider.php index 57c51d94..fadeb08c 100644 --- a/lib/SP/Providers/Auth/AuthProvider.php +++ b/lib/SP/Providers/Auth/AuthProvider.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -25,7 +25,7 @@ namespace SP\Providers\Auth; use SP\Core\Application; -use SP\DataModel\UserLoginData; +use SP\Domain\Auth\Dtos\UserLoginDto; use SP\Domain\Auth\Services\AuthException; use SP\Domain\Core\Exceptions\SPException; use SP\Providers\Provider; @@ -87,11 +87,11 @@ class AuthProvider extends Provider implements AuthProviderInterface /** * Probar los métodos de autentificación * - * @param UserLoginData $userLoginData + * @param UserLoginDto $userLoginData * * @return false|AuthResult[] */ - public function doAuth(UserLoginData $userLoginData): array|bool + public function doAuth(UserLoginDto $userLoginData): array|bool { $authsResult = []; diff --git a/lib/SP/Providers/Auth/AuthProviderInterface.php b/lib/SP/Providers/Auth/AuthProviderInterface.php index bcd0de42..360446d6 100644 --- a/lib/SP/Providers/Auth/AuthProviderInterface.php +++ b/lib/SP/Providers/Auth/AuthProviderInterface.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -24,8 +24,7 @@ namespace SP\Providers\Auth; -use SP\DataModel\UserLoginData; -use SP\Domain\Auth\Services\AuthException; +use SP\Domain\Auth\Dtos\UserLoginDto; /** * Class Auth @@ -39,9 +38,9 @@ interface AuthProviderInterface /** * Probar los métodos de autentificación * - * @param UserLoginData $userLoginData + * @param UserLoginDto $userLoginData * * @return false|AuthResult[] */ - public function doAuth(UserLoginData $userLoginData): array|bool; + public function doAuth(UserLoginDto $userLoginData): array|bool; } diff --git a/lib/SP/Providers/Auth/Browser/BrowserAuth.php b/lib/SP/Providers/Auth/Browser/BrowserAuth.php index 8d8dd035..7bf3ae82 100644 --- a/lib/SP/Providers/Auth/Browser/BrowserAuth.php +++ b/lib/SP/Providers/Auth/Browser/BrowserAuth.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -24,7 +24,7 @@ namespace SP\Providers\Auth\Browser; -use SP\DataModel\UserLoginData; +use SP\Domain\Auth\Dtos\UserLoginDto; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Http\RequestInterface; use SP\Providers\Auth\AuthInterface; @@ -50,10 +50,10 @@ final class BrowserAuth implements BrowserAuthInterface /** * Authenticate using user's data * - * @param UserLoginData $userLoginData + * @param UserLoginDto $userLoginData * @return BrowserAuthData */ - public function authenticate(UserLoginData $userLoginData): BrowserAuthData + public function authenticate(UserLoginDto $userLoginData): BrowserAuthData { $browserAuthData = new BrowserAuthData($this->isAuthGranted()); diff --git a/lib/SP/Providers/Auth/Database/DatabaseAuth.php b/lib/SP/Providers/Auth/Database/DatabaseAuth.php index 29933c0f..9efa2cd8 100644 --- a/lib/SP/Providers/Auth/Database/DatabaseAuth.php +++ b/lib/SP/Providers/Auth/Database/DatabaseAuth.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -26,36 +26,31 @@ namespace SP\Providers\Auth\Database; use Exception; use SP\Core\Crypt\Hash; -use SP\DataModel\UserLoginData; -use SP\Domain\User\Ports\UserPassServiceInterface; +use SP\Domain\Auth\Dtos\UserLoginDto; +use SP\Domain\User\Dtos\UserDataDto; use SP\Domain\User\Ports\UserServiceInterface; -use SP\Domain\User\Services\UserLoginResponse; -use SP\Domain\User\Services\UserService; +use SP\Domain\User\Services\UserPassService; use function SP\processException; /** - * Class Database - * - * Autentificación basada en base de datos - * - * @package SP\Providers\Auth\Database + * Class DatabaseAuth */ -final class DatabaseAuth implements DatabaseAuthInterface +final readonly class DatabaseAuth implements DatabaseAuthService { public function __construct( - private readonly UserServiceInterface $userService, - private readonly UserPassServiceInterface $userPassService + private UserServiceInterface $userService, + private UserPassService $userPassService ) { } /** * Authenticate using user's data * - * @param UserLoginData $userLoginData + * @param UserLoginDto $userLoginData * @return DatabaseAuthData */ - public function authenticate(UserLoginData $userLoginData): DatabaseAuthData + public function authenticate(UserLoginDto $userLoginData): DatabaseAuthData { $authData = new DatabaseAuthData($this->isAuthGranted()); @@ -72,17 +67,14 @@ final class DatabaseAuth implements DatabaseAuthInterface return true; } - protected function authUser(UserLoginData $userLoginData): bool + private function authUser(UserLoginDto $userLoginData): bool { try { - $userLoginResponse = - UserService::mapUserLoginResponse($this->userService->getByLogin($userLoginData->getLoginUser())); + $userLoginResponse = new UserDataDto($this->userService->getByLogin($userLoginData->getLoginUser())); - $userLoginData->setUserLoginResponse($userLoginResponse); + $userLoginData->setUserDataDto($userLoginResponse); - if ($userLoginResponse->getIsMigrate() - && $this->checkMigrateUser($userLoginResponse, $userLoginData) - ) { + if ($userLoginResponse->getIsMigrate() && $this->checkMigrateUser($userLoginResponse, $userLoginData)) { $this->userPassService->migrateUserPassById( $userLoginResponse->getId(), $userLoginData->getLoginPass() @@ -99,7 +91,7 @@ final class DatabaseAuth implements DatabaseAuthInterface return false; } - protected function checkMigrateUser(UserLoginResponse $userLoginResponse, UserLoginData $userLoginData): bool + private function checkMigrateUser(UserDataDto $userLoginResponse, UserLoginDto $userLoginData): bool { $passHashSha = sha1($userLoginResponse->getHashSalt() . $userLoginData->getLoginPass()); diff --git a/lib/SP/Providers/Auth/Database/DatabaseAuthInterface.php b/lib/SP/Providers/Auth/Database/DatabaseAuthService.php similarity index 90% rename from lib/SP/Providers/Auth/Database/DatabaseAuthInterface.php rename to lib/SP/Providers/Auth/Database/DatabaseAuthService.php index 30e18de5..7b9c5dc4 100644 --- a/lib/SP/Providers/Auth/Database/DatabaseAuthInterface.php +++ b/lib/SP/Providers/Auth/Database/DatabaseAuthService.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -24,7 +24,6 @@ namespace SP\Providers\Auth\Database; - use SP\Providers\Auth\AuthInterface; /** @@ -34,7 +33,7 @@ use SP\Providers\Auth\AuthInterface; * * @extends AuthInterface */ -interface DatabaseAuthInterface extends AuthInterface +interface DatabaseAuthService extends AuthInterface { /** * Indica si es requerida para acceder a la aplicación diff --git a/lib/SP/Providers/Auth/Ldap/LdapAuth.php b/lib/SP/Providers/Auth/Ldap/LdapAuth.php index 40d19e0a..d244a741 100644 --- a/lib/SP/Providers/Auth/Ldap/LdapAuth.php +++ b/lib/SP/Providers/Auth/Ldap/LdapAuth.php @@ -27,7 +27,7 @@ namespace SP\Providers\Auth\Ldap; use SP\Core\Events\Event; use SP\Core\Events\EventDispatcher; use SP\Core\Events\EventMessage; -use SP\DataModel\UserLoginData; +use SP\Domain\Auth\Dtos\UserLoginDto; use SP\Domain\Auth\Ports\LdapAuthService; use SP\Domain\Auth\Ports\LdapService; use SP\Domain\Config\Ports\ConfigDataInterface; @@ -60,10 +60,10 @@ final class LdapAuth implements LdapAuthService /** * Authenticate using user's data * - * @param UserLoginData $userLoginData + * @param UserLoginDto $userLoginData * @return LdapAuthData */ - public function authenticate(UserLoginData $userLoginData): LdapAuthData + public function authenticate(UserLoginDto $userLoginData): LdapAuthData { $ldapAuthData = new LdapAuthData($this->isAuthGranted()); diff --git a/tests/SPT/Core/LanguageTest.php b/tests/SPT/Core/LanguageTest.php index fce5476e..09a7c43f 100644 --- a/tests/SPT/Core/LanguageTest.php +++ b/tests/SPT/Core/LanguageTest.php @@ -29,8 +29,9 @@ use PHPUnit\Framework\MockObject\MockObject; use SP\Core\Language; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Http\RequestInterface; +use SP\Domain\User\Dtos\UserDataDto; +use SP\Domain\User\Models\User; use SP\Domain\User\Models\UserPreferences; -use SP\Domain\User\Services\UserLoginResponse; use SPT\UnitaryTestCase; /** @@ -78,9 +79,10 @@ class LanguageTest extends UnitaryTestCase ->method('getSiteLang') ->willReturn(self::$faker->locale); - $userData = $this->context->getUserData(); + $user = (new User(['id' => self::$faker->randomNumber(2)])) + ->dehydrate(new UserPreferences(['lang' => $locale])); - $userData->setPreferences(new UserPreferences(['lang' => $locale])); + $this->context->setUserData(new UserDataDto($user)); $this->language->setLanguage(true); @@ -96,7 +98,8 @@ class LanguageTest extends UnitaryTestCase $appLocale = 'en_US'; $this->context->setLocale($locale); - $this->context->setUserData(new UserLoginResponse()); + + $this->context->setUserData(new UserDataDto(new User())); $this->configData ->expects(self::once()) @@ -117,7 +120,8 @@ class LanguageTest extends UnitaryTestCase $browserLocale = 'en_US'; $this->context->setLocale($locale); - $this->context->setUserData(new UserLoginResponse()); + + $this->context->setUserData(new UserDataDto(new User())); $this->configData ->expects(self::once()) diff --git a/tests/SPT/Core/UI/ThemeTest.php b/tests/SPT/Core/UI/ThemeTest.php index e0ad618f..cdd6d544 100644 --- a/tests/SPT/Core/UI/ThemeTest.php +++ b/tests/SPT/Core/UI/ThemeTest.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -33,7 +33,7 @@ use SP\Core\UI\Theme; use SP\Domain\Core\Context\SessionContextInterface; use SP\Domain\Core\UI\ThemeContextInterface; use SP\Domain\Core\UI\ThemeIconsInterface; -use SP\Domain\User\Services\UserLoginResponse; +use SP\Domain\User\Dtos\UserDataDto; use SPT\Generators\UserDataGenerator; use SPT\UnitaryTestCase; @@ -88,21 +88,18 @@ class ThemeTest extends UnitaryTestCase ->method('isLoggedIn') ->willReturn(true); - $userLoginResponse = new UserLoginResponse(); - $userPreferencesData = UserDataGenerator::factory()->buildUserPreferencesData(); - - $userLoginResponse->setPreferences($userPreferencesData); + $userDataDto = new UserDataDto(UserDataGenerator::factory()->buildUserData()); $context->expects(self::once()) ->method('getUserData') - ->willReturn($userLoginResponse); + ->willReturn($userDataDto); $configData = $this->config->getConfigData(); $configData->setSiteTheme(self::$faker->colorName); $current = Theme::getThemeName($this->config->getConfigData(), $context); - $this->assertEquals($userPreferencesData->getTheme(), $current); + $this->assertEquals($userDataDto->getPreferences()->getTheme(), $current); } public function testGetViewsPath() diff --git a/tests/SPT/Domain/Account/Services/AccountAclTest.php b/tests/SPT/Domain/Account/Services/AccountAclTest.php index 1ea2e0a8..381babd6 100644 --- a/tests/SPT/Domain/Account/Services/AccountAclTest.php +++ b/tests/SPT/Domain/Account/Services/AccountAclTest.php @@ -27,6 +27,7 @@ namespace SPT\Domain\Account\Services; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\MockObject\Exception; +use PHPUnit\Framework\MockObject\MockObject; use SP\Core\Acl\Acl; use SP\DataModel\Item; use SP\Domain\Account\Adapters\AccountPermission; @@ -38,8 +39,11 @@ use SP\Domain\Core\Acl\ActionsInterface; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Storage\Ports\FileCacheService; +use SP\Domain\User\Dtos\UserDataDto; +use SP\Domain\User\Models\User; use SP\Domain\User\Ports\UserToUserGroupServiceInterface; use SP\Infrastructure\File\FileException; +use SPT\Generators\UserDataGenerator; use SPT\UnitaryTestCase; /** @@ -62,8 +66,9 @@ class AccountAclTest extends UnitaryTestCase AclActionsInterface::ACCOUNT_COPY_PASS, AclActionsInterface::ACCOUNT_DELETE, ]; - private static array $accounts; - private AccountAcl $accountAcl; + private static array $accounts; + private Acl $acl; + private UserToUserGroupServiceInterface|MockObject $userToUserGroupService; public static function setUpBeforeClass(): void { @@ -192,8 +197,7 @@ class AccountAclTest extends UnitaryTestCase self::$faker->numberBetween(1, 4), self::$faker->randomNumber(), self::$faker->randomNumber(), - 1, - 0 + true ), $this->getExampleAclForAdmin() ); @@ -210,10 +214,16 @@ class AccountAclTest extends UnitaryTestCase AccountAclDto $accountAclDto, AccountPermission $example ): void { + $accountAcl = new AccountAcl( + $this->application, + $this->acl, + $this->userToUserGroupService + ); + foreach (self::ACTIONS as $action) { $example->setActionId($action); - $aclUnderTest = $this->accountAcl->getAcl($action, $accountAclDto); + $aclUnderTest = $accountAcl->getAcl($action, $accountAclDto); $this->assertTrue($aclUnderTest->isCompiledAccountAccess()); $this->assertTrue($aclUnderTest->isCompiledShowAccess()); @@ -321,12 +331,18 @@ class AccountAclTest extends UnitaryTestCase bool $isAdminApp = false, bool $isAdminAcc = false ): AccountAclDto { - $this->context - ->getUserData() - ->setId($userId) - ->setUserGroupId($groupId) - ->setIsAdminApp($isAdminApp) - ->setIsAdminAcc($isAdminAcc); + $this->context->setUserData( + new UserDataDto( + new User( + [ + 'id' => $userId, + 'userGroupId' => $groupId, + 'isAdminApp' => $isAdminApp, + 'isAdminAcc' => $isAdminAcc + ] + ) + ) + ); return new AccountAclDto( $accountId, @@ -481,7 +497,6 @@ class AccountAclTest extends UnitaryTestCase */ #[Group('acl:admin')] #[DataProvider('accountPropertiesProvider')] - public function testEditPass( int $accountId, int $userId, @@ -674,6 +689,12 @@ class AccountAclTest extends UnitaryTestCase $fileCache = $this->createMock(FileCacheService::class); $actions = $this->createMock(ActionsInterface::class); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory()->buildUserData()->mutate(['lastUpdate' => $dto->getDateEdit() + 10]) + ) + ); + $accountAclService = new AccountAcl( $this->application, new Acl($this->context, $this->application->getEventDispatcher(), $actions), @@ -681,8 +702,6 @@ class AccountAclTest extends UnitaryTestCase $fileCache ); - $this->context->getUserData()->setLastUpdate($dto->getDateEdit() + 10); - $acl = new AccountPermission(self::$faker->randomNumber()); $acl->setTime($dto->getDateEdit() + 10); @@ -824,20 +843,14 @@ class AccountAclTest extends UnitaryTestCase $actions = $this->createMock(ActionsInterface::class); - $acl = new Acl($this->context, $this->application->getEventDispatcher(), $actions); - $userToUserGroupService = $this->createMock(UserToUserGroupServiceInterface::class); - $userToUserGroupService->method('getGroupsForUser') - ->willReturnMap([ - [1, [new Simple(['userGroupId' => 2])]], - [2, [new Simple(['userGroupId' => 1])]], - [3, [new Simple(['userGroupId' => 2])]], - [4, []], - ]); - - $this->accountAcl = new AccountAcl( - $this->application, - $acl, - $userToUserGroupService - ); + $this->acl = new Acl($this->context, $this->application->getEventDispatcher(), $actions); + $this->userToUserGroupService = $this->createMock(UserToUserGroupServiceInterface::class); + $this->userToUserGroupService->method('getGroupsForUser') + ->willReturnMap([ + [1, [new Simple(['userGroupId' => 2])]], + [2, [new Simple(['userGroupId' => 1])]], + [3, [new Simple(['userGroupId' => 2])]], + [4, []], + ]); } } diff --git a/tests/SPT/Domain/Account/Services/AccountFilterUserTest.php b/tests/SPT/Domain/Account/Services/AccountFilterUserTest.php index 3644467d..466be145 100644 --- a/tests/SPT/Domain/Account/Services/AccountFilterUserTest.php +++ b/tests/SPT/Domain/Account/Services/AccountFilterUserTest.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -31,6 +31,8 @@ use PHPUnit\Framework\Constraint\Callback; use PHPUnit\Framework\MockObject\Exception; use PHPUnit\Framework\MockObject\MockObject; use SP\Domain\Account\Services\Builders\AccountFilter; +use SP\Domain\User\Dtos\UserDataDto; +use SPT\Generators\UserDataGenerator; use SPT\UnitaryTestCase; /** @@ -149,7 +151,11 @@ class AccountFilterUserTest extends UnitaryTestCase public function testBuildFilterWithGlobalSearchForAdminAcc() { - $this->context->getUserData()->setIsAdminAcc(true); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory()->buildUserData()->mutate(['isAdminAcc' => true]) + ) + ); $this->setExpectationForGlobalSearch('Account'); @@ -183,7 +189,11 @@ class AccountFilterUserTest extends UnitaryTestCase public function testBuildFilterWithGlobalSearchForAdminApp() { - $this->context->getUserData()->setIsAdminApp(true); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory()->buildUserData()->mutate(['isAdminApp' => true]) + ) + ); $this->setExpectationForGlobalSearch('Account'); @@ -209,7 +219,11 @@ class AccountFilterUserTest extends UnitaryTestCase public function testBuildFilterHistoryWithGlobalSearchForAdminAcc() { - $this->context->getUserData()->setIsAdminAcc(true); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory()->buildUserData()->mutate(['isAdminAcc' => true]) + ) + ); $this->setExpectationForGlobalSearch('AccountHistory'); @@ -218,7 +232,11 @@ class AccountFilterUserTest extends UnitaryTestCase public function testBuildFilterHistoryWithGlobalSearchForAdminApp() { - $this->context->getUserData()->setIsAdminApp(true); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory()->buildUserData()->mutate(['isAdminApp' => true]) + ) + ); $this->setExpectationForGlobalSearch('AccountHistory'); diff --git a/tests/SPT/Domain/Account/Services/AccountTest.php b/tests/SPT/Domain/Account/Services/AccountTest.php index 19236ed3..63cff804 100644 --- a/tests/SPT/Domain/Account/Services/AccountTest.php +++ b/tests/SPT/Domain/Account/Services/AccountTest.php @@ -28,6 +28,7 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Constraint\Callback; use PHPUnit\Framework\MockObject\MockObject; use SP\DataModel\ItemPreset\AccountPrivate; +use SP\DataModel\ProfileData; use SP\Domain\Account\Dtos\AccountHistoryCreateDto; use SP\Domain\Account\Dtos\AccountUpdateBulkDto; use SP\Domain\Account\Dtos\AccountUpdateDto; @@ -51,10 +52,12 @@ use SP\Domain\Core\Exceptions\SPException; use SP\Domain\ItemPreset\Models\ItemPreset; use SP\Domain\ItemPreset\Ports\ItemPresetInterface; use SP\Domain\ItemPreset\Ports\ItemPresetService; +use SP\Domain\User\Dtos\UserDataDto; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Infrastructure\Database\QueryResult; use SPT\Generators\AccountDataGenerator; use SPT\Generators\ItemSearchDataGenerator; +use SPT\Generators\UserDataGenerator; use SPT\Stubs\AccountRepositoryStub; use SPT\UnitaryTestCase; @@ -86,7 +89,11 @@ class AccountTest extends UnitaryTestCase $accountDataGenerator = AccountDataGenerator::factory(); $accountUpdateDto = $accountDataGenerator->buildAccountUpdateDto(); - $this->context->getUserData()->setIsAdminApp(true); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory()->buildUserData()->mutate(['isAdminApp' => true]) + ) + ); $this->configService->expects(self::once())->method('getByParam') ->with('masterPwd')->willReturn(self::$faker->password); @@ -115,7 +122,11 @@ class AccountTest extends UnitaryTestCase $accountDataGenerator = AccountDataGenerator::factory(); $accountUpdateDto = $accountDataGenerator->buildAccountUpdateDto(); - $this->context->getUserData()->setIsAdminApp(false); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory()->buildUserData()->mutate(['isAdminApp' => false]) + ) + ); $this->configService->expects(self::once())->method('getByParam') ->with('masterPwd')->willReturn(self::$faker->password); @@ -144,8 +155,14 @@ class AccountTest extends UnitaryTestCase $accountDataGenerator = AccountDataGenerator::factory(); $accountUpdateDto = $accountDataGenerator->buildAccountUpdateDto(); - $this->context->getUserData()->setIsAdminApp(false); - $this->context->getUserData()->setIsAdminAcc(true); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isAdminApp' => false, 'isAdminAcc' => true]) + ) + ); + $this->context->getUserProfile()->setAccPermission(false); $this->configService->expects(self::once())->method('getByParam') @@ -175,8 +192,14 @@ class AccountTest extends UnitaryTestCase $accountDataGenerator = AccountDataGenerator::factory(); $accountUpdateDto = $accountDataGenerator->buildAccountUpdateDto(); - $this->context->getUserData()->setIsAdminApp(false); - $this->context->getUserData()->setIsAdminAcc(false); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isAdminApp' => false, 'isAdminAcc' => false]) + ) + ); + $this->context->getUserProfile()->setAccPermission(true); $this->configService->expects(self::once())->method('getByParam') @@ -216,10 +239,20 @@ class AccountTest extends UnitaryTestCase 'data' => serialize(new AccountPrivate(true, true)), ]); - $userData = $this->context->getUserData(); - $userData->setIsAdminApp(true); - $userData->setId($accountUpdateDto->getUserId()); - $userData->setUserGroupId($accountUpdateDto->getUserGroupId()); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'id' => $accountUpdateDto->getUserId(), + 'userGroupId' => $accountUpdateDto->getUserGroupId(), + 'isAdminApp' => true, + 'isAdminAcc' => false + ] + ) + ) + ); $this->configService->expects(self::once())->method('getByParam') ->with('masterPwd')->willReturn(self::$faker->password); @@ -283,10 +316,20 @@ class AccountTest extends UnitaryTestCase 'data' => serialize(new AccountPrivate(true, true)), ]); - $userData = $this->context->getUserData(); - $userData->setIsAdminApp(true); - $userData->setId($accountUpdateDto->getUserId()); - $userData->setUserGroupId($accountUpdateDto->getUserGroupId()); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'id' => $accountUpdateDto->getUserId(), + 'userGroupId' => $accountUpdateDto->getUserGroupId(), + 'isAdminApp' => true, + 'isAdminAcc' => false + ] + ) + ) + ); $this->configService->expects(self::once())->method('getByParam') ->with('masterPwd')->willReturn(self::$faker->password); @@ -513,7 +556,18 @@ class AccountTest extends UnitaryTestCase $accountsId = range(0, 4); $accountUpdateBulkDto = new AccountUpdateBulkDto($accountsId, $accounts); - $this->context->getUserData()->setIsAdminApp(true); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'isAdminApp' => true, + 'isAdminAcc' => false + ] + ) + ) + ); $consecutive = array_merge($accountsId, $accountsId); sort($consecutive); @@ -545,7 +599,18 @@ class AccountTest extends UnitaryTestCase $accountsId = range(0, 4); $accountUpdateBulkDto = new AccountUpdateBulkDto($accountsId, $accounts); - $this->context->getUserData()->setIsAdminApp(false); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'isAdminApp' => false, + 'isAdminAcc' => false + ] + ) + ) + ); $this->accountRepository->expects(self::exactly(count($accountsId)))->method('getById') ->with(...self::withConsecutive(...array_map(fn($v) => [$v], $accountsId))) @@ -574,9 +639,20 @@ class AccountTest extends UnitaryTestCase $accountsId = range(0, 4); $accountUpdateBulkDto = new AccountUpdateBulkDto($accountsId, $accounts); - $this->context->getUserData()->setIsAdminApp(false); - $this->context->getUserData()->setIsAdminAcc(true); - $this->context->getUserProfile()->setAccPermission(false); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'isAdminApp' => true, + 'isAdminAcc' => false + ] + ) + ) + ); + + $this->context->setUserProfile(new ProfileData(['accPermission' => false])); $consecutive = array_merge($accountsId, $accountsId); sort($consecutive); @@ -608,9 +684,20 @@ class AccountTest extends UnitaryTestCase $accountsId = range(0, 4); $accountUpdateBulkDto = new AccountUpdateBulkDto($accountsId, $accounts); - $this->context->getUserData()->setIsAdminApp(false); - $this->context->getUserData()->setIsAdminAcc(false); - $this->context->getUserProfile()->setAccPermission(true); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'isAdminApp' => false, + 'isAdminAcc' => false + ] + ) + ) + ); + + $this->context->setUserProfile(new ProfileData(['accPermission' => true])); $consecutive = array_merge($accountsId, $accountsId); sort($consecutive); @@ -623,8 +710,10 @@ class AccountTest extends UnitaryTestCase $this->accountItemsService->expects(self::exactly(count($accountsId)))->method('updateItems') ->with( ...self::withConsecutive( - ...array_map(fn($v) => [$v, true, $accounts[$v]], - $accountsId) + ...array_map( + fn($v) => [$v, true, $accounts[$v]], + $accountsId + ) ) ); @@ -669,8 +758,6 @@ class AccountTest extends UnitaryTestCase $this->accountHistoryService->expects(self::once())->method('create') ->with($accountHistoryCreateDto); - $queryResult = new QueryResult(); - $this->accountRepository->expects(self::once())->method('delete') ->with($id) ->willReturn(new QueryResult(null, 1)); @@ -980,7 +1067,18 @@ class AccountTest extends UnitaryTestCase $accountDataGenerator = AccountDataGenerator::factory(); $accountCreateDto = $accountDataGenerator->buildAccountCreateDto(); - $this->context->getUserData()->setIsAdminApp(true); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'isAdminApp' => true, + 'isAdminAcc' => false + ] + ) + ) + ); $encryptedPassword = new EncryptedPassword(self::$faker->password, self::$faker->password); @@ -1012,10 +1110,24 @@ class AccountTest extends UnitaryTestCase $id = self::$faker->randomNumber(); $accountDataGenerator = AccountDataGenerator::factory(); $userData = $this->context->getUserData(); - $accountCreateDto = $accountDataGenerator->buildAccountCreateDto()->withUserId($userData->getId()) + $accountCreateDto = $accountDataGenerator->buildAccountCreateDto() + ->withUserId($userData->getId()) ->withUserGroupId($userData->getUserGroupId()); - $userData->setIsAdminApp(false); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'id' => $userData->getId(), + 'userGroupId' => $userData->getUserGroupId(), + 'isAdminApp' => false, + 'isAdminAcc' => false + ] + ) + ) + ); $encryptedPassword = new EncryptedPassword(self::$faker->password, self::$faker->password); @@ -1058,9 +1170,21 @@ class AccountTest extends UnitaryTestCase 'data' => serialize(new AccountPrivate(true, true)), ]); - $userData = $this->context->getUserData(); - $userData->setIsAdminApp(true); - $userData->setId($accountCreateDto->getUserId()); + + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'id' => $accountCreateDto->getUserId(), + 'isAdminApp' => true, + 'isAdminAcc' => false + ] + ) + ) + ); + $encryptedPassword = new EncryptedPassword(self::$faker->password, self::$faker->password); @@ -1113,9 +1237,19 @@ class AccountTest extends UnitaryTestCase 'data' => serialize(new AccountPrivate(true, true)), ]); - $userData = $this->context->getUserData(); - $userData->setIsAdminApp(true); - $userData->setUserGroupId($accountCreateDto->getUserGroupId()); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'userGroupId' => $accountCreateDto->getUserGroupId(), + 'isAdminApp' => true, + 'isAdminAcc' => false + ] + ) + ) + ); $encryptedPassword = new EncryptedPassword(self::$faker->password, self::$faker->password); diff --git a/tests/SPT/Domain/Export/Services/XmlExportTest.php b/tests/SPT/Domain/Export/Services/XmlExportTest.php index b0ac2629..d81b29ad 100644 --- a/tests/SPT/Domain/Export/Services/XmlExportTest.php +++ b/tests/SPT/Domain/Export/Services/XmlExportTest.php @@ -30,6 +30,7 @@ use Defuse\Crypto\KeyProtectedByPassword; use DOMDocument; use DOMElement; use DOMException; +use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Constraint\Callback; use PHPUnit\Framework\MockObject\Exception; use PHPUnit\Framework\MockObject\MockObject; @@ -46,10 +47,11 @@ use SP\Domain\Export\Ports\XmlClientExportService; use SP\Domain\Export\Ports\XmlTagExportService; use SP\Domain\Export\Services\XmlExport; use SP\Domain\File\Ports\DirectoryHandlerService; +use SP\Domain\User\Dtos\UserDataDto; use SP\Infrastructure\File\FileException; use SP\Util\VersionUtil; +use SPT\Generators\UserDataGenerator; use SPT\UnitaryTestCase; -use PHPUnit\Framework\Attributes\Group; /** * Class XmlExportTest @@ -78,10 +80,18 @@ class XmlExportTest extends UnitaryTestCase */ public function testExport() { - $userData = $this->context->getUserData(); - $userData->setLogin('test_user'); - $userData->setUserGroupName('test_group'); - $this->context->setUserData($userData); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'login' => 'test_user', + 'userGroup.name' => 'test_group', + ] + ) + ) + ); $exportPath = $this->createMock(DirectoryHandlerService::class); $exportPath->expects(self::once()) @@ -216,10 +226,18 @@ class XmlExportTest extends UnitaryTestCase */ public function testExportWithCheckDirectoryException() { - $userData = $this->context->getUserData(); - $userData->setLogin('test_user'); - $userData->setUserGroupName('test_group'); - $this->context->setUserData($userData); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'login' => 'test_user', + 'userGroup.name' => 'test_group', + ] + ) + ) + ); $exportPath = $this->createMock(DirectoryHandlerService::class); $exportPath->expects(self::once()) @@ -240,10 +258,18 @@ class XmlExportTest extends UnitaryTestCase */ public function testExportWithExportCategoryException() { - $userData = $this->context->getUserData(); - $userData->setLogin('test_user'); - $userData->setUserGroupName('test_group'); - $this->context->setUserData($userData); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'login' => 'test_user', + 'userGroup.name' => 'test_group', + ] + ) + ) + ); $exportPath = $this->createMock(DirectoryHandlerService::class); $exportPath->expects(self::once()) @@ -274,10 +300,18 @@ class XmlExportTest extends UnitaryTestCase */ public function testExportWithExportClientException() { - $userData = $this->context->getUserData(); - $userData->setLogin('test_user'); - $userData->setUserGroupName('test_group'); - $this->context->setUserData($userData); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'login' => 'test_user', + 'userGroup.name' => 'test_group', + ] + ) + ) + ); $exportPath = $this->createMock(DirectoryHandlerService::class); $exportPath->expects(self::once()) @@ -315,10 +349,18 @@ class XmlExportTest extends UnitaryTestCase */ public function testExportWithExportTagException() { - $userData = $this->context->getUserData(); - $userData->setLogin('test_user'); - $userData->setUserGroupName('test_group'); - $this->context->setUserData($userData); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'login' => 'test_user', + 'userGroup.name' => 'test_group', + ] + ) + ) + ); $exportPath = $this->createMock(DirectoryHandlerService::class); $exportPath->expects(self::once()) @@ -361,10 +403,18 @@ class XmlExportTest extends UnitaryTestCase */ public function testExportWithExportAccountException() { - $userData = $this->context->getUserData(); - $userData->setLogin('test_user'); - $userData->setUserGroupName('test_group'); - $this->context->setUserData($userData); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'login' => 'test_user', + 'userGroup.name' => 'test_group', + ] + ) + ) + ); $exportPath = $this->createMock(DirectoryHandlerService::class); $exportPath->expects(self::once()) @@ -411,10 +461,18 @@ class XmlExportTest extends UnitaryTestCase */ public function testExportWithCryptException() { - $userData = $this->context->getUserData(); - $userData->setLogin('test_user'); - $userData->setUserGroupName('test_group'); - $this->context->setUserData($userData); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'login' => 'test_user', + 'userGroup.name' => 'test_group', + ] + ) + ) + ); $exportPath = $this->createMock(DirectoryHandlerService::class); $exportPath->expects(self::once()) diff --git a/tests/SPT/Domain/Notification/Services/NotificationTest.php b/tests/SPT/Domain/Notification/Services/NotificationTest.php index 637768de..7e59b00b 100644 --- a/tests/SPT/Domain/Notification/Services/NotificationTest.php +++ b/tests/SPT/Domain/Notification/Services/NotificationTest.php @@ -34,9 +34,11 @@ use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Notification\Models\Notification as NotificationModel; use SP\Domain\Notification\Ports\NotificationRepository; use SP\Domain\Notification\Services\Notification; +use SP\Domain\User\Dtos\UserDataDto; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Infrastructure\Database\QueryResult; use SPT\Generators\NotificationDataGenerator; +use SPT\Generators\UserDataGenerator; use SPT\UnitaryTestCase; /** @@ -84,15 +86,24 @@ class NotificationTest extends UnitaryTestCase public function testSearchWithAdmin() { - $userData = $this->context->getUserData()->setIsAdminApp(true); - $this->context->setUserData($userData); + $userDataDto = new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'isAdminApp' => true, + ] + ) + ); + + $this->context->setUserData($userDataDto); $itemSearchData = new ItemSearchData(); $this->notificationRepository ->expects($this->once()) ->method('searchForAdmin') - ->with($itemSearchData, $userData->getId()); + ->with($itemSearchData, $userDataDto->getId()); $this->notification->search($itemSearchData); } @@ -151,8 +162,16 @@ class NotificationTest extends UnitaryTestCase */ public function testGetAllActiveForCurrentUserWithAdmin() { - $userData = $this->context->getUserData()->setIsAdminApp(true); - $this->context->setUserData($userData); + $userDataDto = new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'isAdminApp' => true, + ] + ) + ); + $this->context->setUserData($userDataDto); $queryResult = $this->createMock(QueryResult::class); $queryResult->expects($this->once()) @@ -163,7 +182,7 @@ class NotificationTest extends UnitaryTestCase $this->notificationRepository ->expects($this->once()) ->method('getAllActiveForAdmin') - ->with($userData->getId()) + ->with($userDataDto->getId()) ->willReturn($queryResult); $out = $this->notification->getAllActiveForCurrentUser(); diff --git a/tests/SPT/Domain/User/Services/UserMasterPassTest.php b/tests/SPT/Domain/User/Services/UserMasterPassTest.php new file mode 100644 index 00000000..c25efc12 --- /dev/null +++ b/tests/SPT/Domain/User/Services/UserMasterPassTest.php @@ -0,0 +1,761 @@ +. + */ + +namespace SPT\Domain\User\Services; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\MockObject\MockObject; +use RuntimeException; +use SP\Core\Crypt\Hash; +use SP\Domain\Auth\Dtos\UserLoginDto; +use SP\Domain\Common\Services\ServiceException; +use SP\Domain\Config\Ports\ConfigService; +use SP\Domain\Core\Crypt\CryptInterface; +use SP\Domain\Core\Exceptions\CryptException; +use SP\Domain\User\Dtos\UserDataDto; +use SP\Domain\User\Ports\UserRepository; +use SP\Domain\User\Services\UserMasterPass; +use SP\Domain\User\Services\UserMasterPassStatus; +use SPT\Generators\UserDataGenerator; +use SPT\UnitaryTestCase; + +/** + * Class UserMasterPassTest + */ +#[Group('unitary')] +class UserMasterPassTest extends UnitaryTestCase +{ + + private MockObject|UserRepository $userRepository; + private MockObject|ConfigService $configService; + private MockObject|CryptInterface $crypt; + private UserMasterPass $userMasterPass; + + /** + * @throws ServiceException + */ + public function testLoad() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->exactly(2)) + ->method('getByParam') + ->with(...self::withConsecutive(['masterPwd'], ['lastupdatempass'])) + ->willReturn(Hash::hashKey('a_master_pass'), '5'); + + $key = $userLoginDto->getLoginPass() . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('decrypt') + ->with($user->getMPass(), $user->getMKey(), $key) + ->willReturn('a_master_pass'); + + $out = $this->userMasterPass->load($userLoginDto); + + $this->assertEquals(UserMasterPassStatus::Ok, $out->getUserMasterPassStatus()); + $this->assertEquals('a_master_pass', $out->getClearMasterPass()); + $this->assertEquals($userDataDto->getMPass(), $out->getCryptMasterPass()); + $this->assertEquals($userDataDto->getMKey(), $out->getCryptSecuredKey()); + } + + /** + * @throws ServiceException + */ + public function testLoadWithUserPass() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->exactly(2)) + ->method('getByParam') + ->with(...self::withConsecutive(['masterPwd'], ['lastupdatempass'])) + ->willReturn(Hash::hashKey('a_master_pass'), '5'); + + $key = 'a_password' . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('decrypt') + ->with($user->getMPass(), $user->getMKey(), $key) + ->willReturn('a_master_pass'); + + $out = $this->userMasterPass->load($userLoginDto, 'a_password'); + + $this->assertEquals(UserMasterPassStatus::Ok, $out->getUserMasterPassStatus()); + $this->assertEquals('a_master_pass', $out->getClearMasterPass()); + $this->assertEquals($userDataDto->getMPass(), $out->getCryptMasterPass()); + $this->assertEquals($userDataDto->getMKey(), $out->getCryptSecuredKey()); + } + + /** + * @throws ServiceException + */ + public function testLoadWithNotSet() + { + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password()); + + $this->configService + ->expects($this->never()) + ->method('getByParam'); + + $this->crypt + ->expects($this->never()) + ->method('decrypt'); + + $out = $this->userMasterPass->load($userLoginDto); + + $this->assertEquals(UserMasterPassStatus::NotSet, $out->getUserMasterPassStatus()); + } + + /** + * @throws ServiceException + */ + public function testLoadWithNotSetAndEmptyPass() + { + $userLoginDto = new UserLoginDto(self::$faker->userName()); + + $this->configService + ->expects($this->never()) + ->method('getByParam'); + + $this->crypt + ->expects($this->never()) + ->method('decrypt'); + + $out = $this->userMasterPass->load($userLoginDto); + + $this->assertEquals(UserMasterPassStatus::NotSet, $out->getUserMasterPassStatus()); + } + + /** + * @throws ServiceException + */ + public function testLoadWithNotSetAndEmptyUser() + { + $userLoginDto = new UserLoginDto(); + + $this->configService + ->expects($this->never()) + ->method('getByParam'); + + $this->crypt + ->expects($this->never()) + ->method('decrypt'); + + $out = $this->userMasterPass->load($userLoginDto); + + $this->assertEquals(UserMasterPassStatus::NotSet, $out->getUserMasterPassStatus()); + } + + /** + * @throws ServiceException + */ + public function testLoadWithNotSetAndNullHash() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->once()) + ->method('getByParam') + ->willReturn(null); + + $this->crypt + ->expects($this->never()) + ->method('decrypt'); + + $out = $this->userMasterPass->load($userLoginDto); + + $this->assertEquals(UserMasterPassStatus::NotSet, $out->getUserMasterPassStatus()); + } + + /** + * @throws ServiceException + */ + public function testLoadWithChanged() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 0]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->exactly(2)) + ->method('getByParam') + ->with(...self::withConsecutive(['masterPwd'], ['lastupdatempass'])) + ->willReturn(Hash::hashKey('a_master_pass'), '5'); + + $key = $userLoginDto->getLoginPass() . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->never()) + ->method('decrypt'); + + $out = $this->userMasterPass->load($userLoginDto); + + $this->assertEquals(UserMasterPassStatus::Changed, $out->getUserMasterPassStatus()); + } + + /** + * @throws ServiceException + */ + public function testLoadWithCheckOld() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => true, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), null, $userDataDto); + + $this->configService + ->expects($this->exactly(2)) + ->method('getByParam') + ->with(...self::withConsecutive(['masterPwd'], ['lastupdatempass'])) + ->willReturn(Hash::hashKey('a_master_pass'), '5'); + + $key = $userLoginDto->getLoginPass() . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->never()) + ->method('decrypt'); + + $out = $this->userMasterPass->load($userLoginDto); + + $this->assertEquals(UserMasterPassStatus::CheckOld, $out->getUserMasterPassStatus()); + } + + /** + * @throws ServiceException + */ + public function testLoadWithCryptException() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->exactly(2)) + ->method('getByParam') + ->with(...self::withConsecutive(['masterPwd'], ['lastupdatempass'])) + ->willReturn(Hash::hashKey('a_master_pass'), '5'); + + $key = $userLoginDto->getLoginPass() . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('decrypt') + ->willThrowException(CryptException::error('test')); + + $out = $this->userMasterPass->load($userLoginDto); + + $this->assertEquals(UserMasterPassStatus::CheckOld, $out->getUserMasterPassStatus()); + } + + /** + * @throws ServiceException + */ + public function testLoadWithInvalid() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->exactly(2)) + ->method('getByParam') + ->with(...self::withConsecutive(['masterPwd'], ['lastupdatempass'])) + ->willReturn(Hash::hashKey('a_master_pass'), '5'); + + $key = $userLoginDto->getLoginPass() . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('decrypt') + ->with($user->getMPass(), $user->getMKey(), $key) + ->willReturn('a_pass'); + + $out = $this->userMasterPass->load($userLoginDto); + + $this->assertEquals(UserMasterPassStatus::Invalid, $out->getUserMasterPassStatus()); + } + + /** + * @throws ServiceException + */ + public function testLoadWithException() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->exactly(2)) + ->method('getByParam') + ->with(...self::withConsecutive(['masterPwd'], ['lastupdatempass'])) + ->willReturn(Hash::hashKey('a_master_pass'), '5'); + + $key = $userLoginDto->getLoginPass() . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('decrypt') + ->willThrowException(new RuntimeException('test')); + + $this->expectException(ServiceException::class); + $this->expectExceptionMessage('test'); + + $this->userMasterPass->load($userLoginDto); + } + + + /** + * @throws ServiceException + */ + public function testUpdateFromOldPass() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->exactly(3)) + ->method('getByParam') + ->with(...self::withConsecutive(['masterPwd'], ['lastupdatempass'], ['masterPwd'])) + ->willReturn(Hash::hashKey('a_master_pass'), '5', Hash::hashKey('a_master_pass')); + + $oldKey = 'an_old_user_pass' . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('decrypt') + ->with($user->getMPass(), $user->getMKey(), $oldKey) + ->willReturn('a_master_pass'); + + $key = $userLoginDto->getLoginPass() . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('makeSecuredKey') + ->with($key) + ->willReturn('a_secure_key'); + + $this->crypt + ->expects($this->once()) + ->method('encrypt') + ->with('a_master_pass', 'a_secure_key', $key) + ->willReturn('encrypted'); + + $this->userRepository + ->expects($this->once()) + ->method('updateMasterPassById') + ->with($userDataDto->getId(), 'encrypted', 'a_secure_key'); + + $out = $this->userMasterPass->updateFromOldPass('an_old_user_pass', $userLoginDto); + + $this->assertEquals(UserMasterPassStatus::Ok, $out->getUserMasterPassStatus()); + $this->assertEquals('encrypted', $out->getCryptMasterPass()); + $this->assertEquals('a_secure_key', $out->getCryptSecuredKey()); + $this->assertEquals('a_master_pass', $out->getClearMasterPass()); + } + + /** + * @throws ServiceException + */ + public function testUpdateFromOldPassWithInvalid() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->exactly(2)) + ->method('getByParam') + ->with(...self::withConsecutive(['masterPwd'], ['lastupdatempass'])) + ->willReturn(Hash::hashKey('a_master_pass'), '5'); + + $oldKey = 'an_old_user_pass' . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('decrypt') + ->with($user->getMPass(), $user->getMKey(), $oldKey) + ->willReturn('another_master_pass'); + + $this->crypt + ->expects($this->never()) + ->method('makeSecuredKey'); + + $this->crypt + ->expects($this->never()) + ->method('encrypt'); + + $this->userRepository + ->expects($this->never()) + ->method('updateMasterPassById'); + + $out = $this->userMasterPass->updateFromOldPass('an_old_user_pass', $userLoginDto); + + $this->assertEquals(UserMasterPassStatus::Invalid, $out->getUserMasterPassStatus()); + } + + /** + * @throws ServiceException + */ + public function testUpdateOnLogin() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->once()) + ->method('getByParam') + ->with('masterPwd') + ->willReturn(Hash::hashKey('a_master_pass')); + + $key = $userLoginDto->getLoginPass() . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('makeSecuredKey') + ->with($key) + ->willReturn('a_secure_key'); + + $this->crypt + ->expects($this->once()) + ->method('encrypt') + ->with('a_master_pass', 'a_secure_key', $key) + ->willReturn('encrypted'); + + $this->userRepository + ->expects($this->once()) + ->method('updateMasterPassById') + ->with($userDataDto->getId(), 'encrypted', 'a_secure_key'); + + $out = $this->userMasterPass->updateOnLogin('a_master_pass', $userLoginDto); + + $this->assertEquals(UserMasterPassStatus::Ok, $out->getUserMasterPassStatus()); + $this->assertEquals('encrypted', $out->getCryptMasterPass()); + $this->assertEquals('a_secure_key', $out->getCryptSecuredKey()); + $this->assertEquals('a_master_pass', $out->getClearMasterPass()); + } + + /** + * @throws ServiceException + */ + public function testUpdateOnLoginWithSaveHash() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->once()) + ->method('getByParam') + ->with('masterPwd') + ->willReturn(null); + + $this->configService + ->expects($this->once()) + ->method('save') + ->with( + 'masterPwd', + self::callback(static function (string $hash) { + return Hash::checkHashKey('a_master_pass', $hash); + }) + ); + + $key = $userLoginDto->getLoginPass() . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('makeSecuredKey') + ->with($key) + ->willReturn('a_secure_key'); + + $this->crypt + ->expects($this->once()) + ->method('encrypt') + ->with('a_master_pass', 'a_secure_key', $key) + ->willReturn('encrypted'); + + $this->userRepository + ->expects($this->once()) + ->method('updateMasterPassById') + ->with($userDataDto->getId(), 'encrypted', 'a_secure_key'); + + $out = $this->userMasterPass->updateOnLogin('a_master_pass', $userLoginDto); + + $this->assertEquals(UserMasterPassStatus::Ok, $out->getUserMasterPassStatus()); + $this->assertEquals('encrypted', $out->getCryptMasterPass()); + $this->assertEquals('a_secure_key', $out->getCryptSecuredKey()); + $this->assertEquals('a_master_pass', $out->getClearMasterPass()); + } + + /** + * @throws ServiceException + */ + public function testUpdateOnLoginWithException() + { + $user = UserDataGenerator::factory() + ->buildUserData() + ->mutate(['isChangedPass' => false, 'lastUpdateMPass' => 10]); + + $userDataDto = new UserDataDto($user); + $userLoginDto = new UserLoginDto(self::$faker->userName(), self::$faker->password(), $userDataDto); + + $this->configService + ->expects($this->once()) + ->method('getByParam') + ->with('masterPwd') + ->willReturn(null); + + $this->configService + ->expects($this->once()) + ->method('save') + ->with( + 'masterPwd', + self::callback(static function (string $hash) { + return Hash::checkHashKey('a_master_pass', $hash); + }) + ); + + $key = $userLoginDto->getLoginPass() . + $userLoginDto->getLoginUser() . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('makeSecuredKey') + ->with($key) + ->willReturn('a_secure_key'); + + $this->crypt + ->expects($this->once()) + ->method('encrypt') + ->with('a_master_pass', 'a_secure_key', $key) + ->willReturn('encrypted'); + + $this->userRepository + ->expects($this->once()) + ->method('updateMasterPassById') + ->willThrowException(new RuntimeException('test')); + + $this->expectException(ServiceException::class); + $this->expectExceptionMessage('test'); + + $this->userMasterPass->updateOnLogin('a_master_pass', $userLoginDto); + } + + /** + * @throws ServiceException + */ + public function testCreate() + { + $key = 'a_password' . + 'a_login' . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('makeSecuredKey') + ->with($key) + ->willReturn('a_secure_key'); + + $this->crypt + ->expects($this->once()) + ->method('encrypt') + ->with('a_master_pass', 'a_secure_key', $key) + ->willReturn('encrypted'); + + $out = $this->userMasterPass->create('a_master_pass', 'a_login', 'a_password'); + + $this->assertEquals(UserMasterPassStatus::Ok, $out->getUserMasterPassStatus()); + $this->assertEquals('encrypted', $out->getCryptMasterPass()); + $this->assertEquals('a_secure_key', $out->getCryptSecuredKey()); + $this->assertEquals('a_master_pass', $out->getClearMasterPass()); + } + + /** + * @throws ServiceException + */ + public function testCreateWithLongKey() + { + $key = 'a_password' . + 'a_login' . + $this->config->getConfigData()->getPasswordSalt(); + + $longKey = str_repeat('a', 1001); + + $this->crypt + ->expects($this->once()) + ->method('makeSecuredKey') + ->with($key) + ->willReturn($longKey); + + $this->crypt + ->expects($this->never()) + ->method('encrypt'); + + $this->expectException(ServiceException::class); + $this->expectExceptionMessage('Internal error'); + + $this->userMasterPass->create('a_master_pass', 'a_login', 'a_password'); + } + + /** + * @throws ServiceException + */ + public function testCreateWithLongMasterPass() + { + $key = 'a_password' . + 'a_login' . + $this->config->getConfigData()->getPasswordSalt(); + + + $this->crypt + ->expects($this->once()) + ->method('makeSecuredKey') + ->with($key) + ->willReturn('a_secured_key'); + + $this->crypt + ->expects($this->once()) + ->method('encrypt') + ->with('a_master_pass', 'a_secured_key', $key) + ->willReturn(str_repeat('a', 1001)); + + $this->expectException(ServiceException::class); + $this->expectExceptionMessage('Internal error'); + + $this->userMasterPass->create('a_master_pass', 'a_login', 'a_password'); + } + + /** + * @throws ServiceException + */ + public function testCreateWithException() + { + $key = 'a_password' . + 'a_login' . + $this->config->getConfigData()->getPasswordSalt(); + + $this->crypt + ->expects($this->once()) + ->method('makeSecuredKey') + ->with($key) + ->willReturn('a_secured_key'); + + $this->crypt + ->expects($this->once()) + ->method('encrypt') + ->with('a_master_pass', 'a_secured_key', $key) + ->willThrowException(CryptException::error('test')); + + $this->expectException(ServiceException::class); + $this->expectExceptionMessage('test'); + + $this->userMasterPass->create('a_master_pass', 'a_login', 'a_password'); + } + + protected function setUp(): void + { + parent::setUp(); + + $this->userRepository = $this->createMock(UserRepository::class); + $this->configService = $this->createMock(ConfigService::class); + $this->crypt = $this->createMock(CryptInterface::class); + + $this->userMasterPass = new UserMasterPass( + $this->application, + $this->userRepository, + $this->configService, + $this->crypt + ); + } +} diff --git a/tests/SPT/Generators/ConfigDataGenerator.php b/tests/SPT/Generators/ConfigDataGenerator.php index 4de59bd5..83885d61 100644 --- a/tests/SPT/Generators/ConfigDataGenerator.php +++ b/tests/SPT/Generators/ConfigDataGenerator.php @@ -37,6 +37,6 @@ final class ConfigDataGenerator extends DataGenerator { return new ConfigData([ ConfigDataInterface::PASSWORD_SALT => $this->faker->sha1(), - ]); + ]); } } diff --git a/tests/SPT/Infrastructure/User/Repositories/UserTest.php b/tests/SPT/Infrastructure/User/Repositories/UserTest.php index bd159909..5934a088 100644 --- a/tests/SPT/Infrastructure/User/Repositories/UserTest.php +++ b/tests/SPT/Infrastructure/User/Repositories/UserTest.php @@ -38,6 +38,7 @@ use SP\Domain\Common\Models\Simple as SimpleModel; use SP\Domain\Core\Exceptions\ConstraintException; use SP\Domain\Core\Exceptions\QueryException; use SP\Domain\Core\Exceptions\SPException; +use SP\Domain\User\Dtos\UserDataDto; use SP\Domain\User\Models\User as UserModel; use SP\Infrastructure\Common\Repositories\DuplicatedItemException; use SP\Infrastructure\Database\DatabaseInterface; @@ -599,10 +600,17 @@ class UserTest extends UnitaryTestCase */ public function testSearchWithAdmin() { - $userData = $this->context->getUserData(); - $userData->setIsAdminApp(true); - - $this->context->setUserData($userData); + $this->context->setUserData( + new UserDataDto( + UserDataGenerator::factory() + ->buildUserData() + ->mutate( + [ + 'isAdminApp' => true, + ] + ) + ) + ); $item = new ItemSearchData(self::$faker->name); @@ -673,11 +681,12 @@ class UserTest extends UnitaryTestCase $query = $arg->getQuery(); $params = $query->getBindValues(); - return count($params) === 4 + return count($params) === 5 && $params['id'] === $user->getId() && $params['pass'] === $user->getPass() && $params['isChangePass'] === $user->isChangePass() && $params['isChangedPass'] === $user->isChangedPass() + && $params['isMigrate'] === $user->isMigrate() && is_a($query, UpdateInterface::class) && !empty($query->getStatement()); } diff --git a/tests/SPT/Providers/Auth/AuthProviderTest.php b/tests/SPT/Providers/Auth/AuthProviderTest.php index 60f0782e..506ff0c9 100644 --- a/tests/SPT/Providers/Auth/AuthProviderTest.php +++ b/tests/SPT/Providers/Auth/AuthProviderTest.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -26,7 +26,7 @@ namespace SPT\Providers\Auth; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\MockObject\Exception; -use SP\DataModel\UserLoginData; +use SP\Domain\Auth\Dtos\UserLoginDto; use SP\Domain\Auth\Services\AuthException; use SP\Providers\Auth\AuthInterface; use SP\Providers\Auth\AuthProvider; @@ -66,7 +66,7 @@ class AuthProviderTest extends UnitaryTestCase */ public function testDoAuth() { - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser(self::$faker->userName); $userLoginData->setLoginPass(self::$faker->password); diff --git a/tests/SPT/Providers/Auth/Browser/BrowserAuthTest.php b/tests/SPT/Providers/Auth/Browser/BrowserAuthTest.php index 5bbcbe4b..6e6ad68a 100644 --- a/tests/SPT/Providers/Auth/Browser/BrowserAuthTest.php +++ b/tests/SPT/Providers/Auth/Browser/BrowserAuthTest.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -26,7 +26,7 @@ namespace SPT\Providers\Auth\Browser; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\MockObject\MockObject; -use SP\DataModel\UserLoginData; +use SP\Domain\Auth\Dtos\UserLoginDto; use SP\Domain\Config\Ports\ConfigDataInterface; use SP\Domain\Http\RequestInterface; use SP\Providers\Auth\Browser\BrowserAuth; @@ -83,7 +83,7 @@ class BrowserAuthTest extends UnitaryTestCase $user = self::$faker->userName; $pass = self::$faker->password; - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser($user); $userLoginData->setLoginPass($pass); @@ -125,7 +125,7 @@ class BrowserAuthTest extends UnitaryTestCase ->with(...$this->withConsecutive(['PHP_AUTH_USER'], ['PHP_AUTH_PW'])) ->willReturn($user, $pass); - $out = $this->browserAuth->authenticate(new UserLoginData()); + $out = $this->browserAuth->authenticate(new UserLoginDto()); self::assertInstanceOf(BrowserAuthData::class, $out); self::assertTrue($out->isOk()); @@ -146,7 +146,7 @@ class BrowserAuthTest extends UnitaryTestCase ->with(...$this->withConsecutive(['PHP_AUTH_USER'], ['REMOTE_USER'], ['PHP_AUTH_PW'])) ->willReturn('', '', '', $pass); - $out = $this->browserAuth->authenticate(new UserLoginData()); + $out = $this->browserAuth->authenticate(new UserLoginDto()); self::assertInstanceOf(BrowserAuthData::class, $out); self::assertFalse($out->isOk()); @@ -167,7 +167,7 @@ class BrowserAuthTest extends UnitaryTestCase ->with(...$this->withConsecutive(['PHP_AUTH_USER'], ['PHP_AUTH_PW'])) ->willReturn($user, ''); - $out = $this->browserAuth->authenticate(new UserLoginData()); + $out = $this->browserAuth->authenticate(new UserLoginDto()); self::assertInstanceOf(BrowserAuthData::class, $out); self::assertFalse($out->isOk()); @@ -188,7 +188,7 @@ class BrowserAuthTest extends UnitaryTestCase ->with('PHP_AUTH_USER') ->willReturn($user); - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser($user); $out = $this->browserAuth->authenticate($userLoginData); @@ -212,7 +212,7 @@ class BrowserAuthTest extends UnitaryTestCase ->with('PHP_AUTH_USER') ->willReturn($user); - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser(self::$faker->userName); $out = $this->browserAuth->authenticate($userLoginData); diff --git a/tests/SPT/Providers/Auth/Database/DatabaseAuthTest.php b/tests/SPT/Providers/Auth/Database/DatabaseAuthTest.php index ab6c4eb3..cef370a5 100644 --- a/tests/SPT/Providers/Auth/Database/DatabaseAuthTest.php +++ b/tests/SPT/Providers/Auth/Database/DatabaseAuthTest.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2023, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2024, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -27,9 +27,9 @@ namespace SPT\Providers\Auth\Database; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\MockObject\MockObject; use SP\Core\Crypt\Hash; -use SP\DataModel\UserLoginData; -use SP\Domain\User\Ports\UserPassServiceInterface; +use SP\Domain\Auth\Dtos\UserLoginDto; use SP\Domain\User\Ports\UserServiceInterface; +use SP\Domain\User\Services\UserPassService; use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Providers\Auth\Database\DatabaseAuth; use SPT\Generators\UserDataGenerator; @@ -43,9 +43,9 @@ use SPT\UnitaryTestCase; class DatabaseAuthTest extends UnitaryTestCase { - private UserServiceInterface|MockObject $userService; - private MockObject|UserPassServiceInterface $userPassService; - private DatabaseAuth $databaseAuth; + private UserServiceInterface|MockObject $userService; + private MockObject|UserPassService $userPassService; + private DatabaseAuth $databaseAuth; public function testAuthenticate() { @@ -61,7 +61,7 @@ class DatabaseAuthTest extends UnitaryTestCase ->with($user) ->willReturn($userData); - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser($user); $userLoginData->setLoginPass($pass); @@ -79,7 +79,7 @@ class DatabaseAuthTest extends UnitaryTestCase ->with($user) ->willThrowException(new NoSuchItemException('User does not exist')); - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser($user); $userLoginData->setLoginPass($pass); @@ -99,7 +99,7 @@ class DatabaseAuthTest extends UnitaryTestCase ->with($user) ->willReturn($userData); - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser($user); $userLoginData->setLoginPass($pass); @@ -132,7 +132,7 @@ class DatabaseAuthTest extends UnitaryTestCase ->method('migrateUserPassById') ->with($userData->getId(), $pass); - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser($user); $userLoginData->setLoginPass($pass); @@ -167,7 +167,7 @@ class DatabaseAuthTest extends UnitaryTestCase ->method('migrateUserPassById') ->with($userData->getId(), $pass); - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser($user); $userLoginData->setLoginPass($pass); @@ -202,7 +202,7 @@ class DatabaseAuthTest extends UnitaryTestCase ->method('migrateUserPassById') ->with($userData->getId(), $pass); - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser($user); $userLoginData->setLoginPass($pass); @@ -236,7 +236,7 @@ class DatabaseAuthTest extends UnitaryTestCase ->method('migrateUserPassById') ->with($userData->getId(), $pass); - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser($user); $userLoginData->setLoginPass($pass); @@ -253,7 +253,7 @@ class DatabaseAuthTest extends UnitaryTestCase parent::setUp(); $this->userService = $this->createMock(UserServiceInterface::class); - $this->userPassService = $this->createMock(UserPassServiceInterface::class); + $this->userPassService = $this->createMock(UserPassService::class); $this->databaseAuth = new DatabaseAuth($this->userService, $this->userPassService); } diff --git a/tests/SPT/Providers/Auth/Ldap/LdapAuthTest.php b/tests/SPT/Providers/Auth/Ldap/LdapAuthTest.php index 23034117..7970b22e 100644 --- a/tests/SPT/Providers/Auth/Ldap/LdapAuthTest.php +++ b/tests/SPT/Providers/Auth/Ldap/LdapAuthTest.php @@ -29,7 +29,7 @@ use PHPUnit\Framework\Constraint\Callback; use PHPUnit\Framework\MockObject\Exception; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\Rule\InvokedCount; -use SP\DataModel\UserLoginData; +use SP\Domain\Auth\Dtos\UserLoginDto; use SP\Domain\Auth\Ports\LdapActionsService; use SP\Domain\Auth\Ports\LdapService; use SP\Domain\Config\Ports\ConfigDataInterface; @@ -58,7 +58,7 @@ class LdapAuthTest extends UnitaryTestCase */ public function testAuthenticate() { - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser(self::$faker->userName); $userLoginData->setLoginPass(self::$faker->password); @@ -140,7 +140,7 @@ class LdapAuthTest extends UnitaryTestCase */ public function testAuthenticateWithExpireFail() { - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser(self::$faker->userName); $userLoginData->setLoginPass(self::$faker->password); @@ -188,7 +188,7 @@ class LdapAuthTest extends UnitaryTestCase */ public function testAuthenticateWithGroupFail() { - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser(self::$faker->userName); $userLoginData->setLoginPass(self::$faker->password); @@ -236,7 +236,7 @@ class LdapAuthTest extends UnitaryTestCase */ public function testAuthenticateFailConnect() { - $userLoginData = new UserLoginData(); + $userLoginData = new UserLoginDto(); $userLoginData->setLoginUser(self::$faker->userName); $userLoginData->setLoginPass(self::$faker->password); diff --git a/tests/SPT/UnitaryTestCase.php b/tests/SPT/UnitaryTestCase.php index 0322cc97..817f9093 100644 --- a/tests/SPT/UnitaryTestCase.php +++ b/tests/SPT/UnitaryTestCase.php @@ -35,7 +35,8 @@ use SP\DataModel\ProfileData; use SP\Domain\Config\Ports\ConfigFileService; use SP\Domain\Core\Context\ContextInterface; use SP\Domain\Core\Events\EventDispatcherInterface; -use SP\Domain\User\Services\UserLoginResponse; +use SP\Domain\User\Dtos\UserDataDto; +use SP\Domain\User\Models\User; use SPT\Generators\ConfigDataGenerator; /** @@ -95,17 +96,9 @@ abstract class UnitaryTestCase extends TestCase */ private function mockApplication(): Application { - $userLogin = new UserLoginResponse(); - $userLogin - ->setLogin(self::$faker->userName) - ->setName(self::$faker->userName) - ->setId(self::$faker->randomNumber(2)) - ->setUserGroupId(self::$faker->randomNumber(2)) - ->setUserProfileId(self::$faker->randomNumber(2)); - $this->context = new StatelessContext(); $this->context->initialize(); - $this->context->setUserData($userLogin); + $this->context->setUserData($this->getUserDataDto()); $this->context->setUserProfile(new ProfileData()); return new Application( @@ -115,6 +108,24 @@ abstract class UnitaryTestCase extends TestCase ); } + /** + * @return UserDataDto + */ + private function getUserDataDto(): UserDataDto + { + return new UserDataDto( + new User( + [ + 'login' => self::$faker->userName, + 'name' => self::$faker->userName, + 'id' => self::$faker->randomNumber(2), + 'userGroupId' => self::$faker->randomNumber(2), + 'userProfileId' => self::$faker->randomNumber(2) + ] + ) + ); + } + /** * @throws Exception */ diff --git a/tests/SPT/bootstrap.php b/tests/SPT/bootstrap.php index 4b467a3d..ed98c69c 100644 --- a/tests/SPT/bootstrap.php +++ b/tests/SPT/bootstrap.php @@ -32,7 +32,7 @@ use SP\Core\Context\ContextException; use SP\DataModel\ProfileData; use SP\Domain\Core\Context\ContextInterface; use SP\Domain\Core\Exceptions\FileNotFoundException; -use SP\Domain\User\Services\UserLoginResponse; +use SP\Domain\User\Dtos\UserDataDto; use SP\Infrastructure\Database\DatabaseConnectionData; use SP\Infrastructure\Database\DbStorageHandler; use SP\Infrastructure\Database\MysqlHandler; @@ -127,7 +127,7 @@ function setupContext(): Container $context->setTrasientKey('_masterpass', '12345678900'); - $userData = new UserLoginResponse(); + $userData = new UserDataDto(); $userData->setId(1); $userData->setLogin('Admin'); $userData->setUserGroupName('Admins');