From a1cf1dfa0bb3b14f8301fbf25622a35d73420564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D?= Date: Sat, 18 Nov 2023 10:29:18 +0100 Subject: [PATCH] chore(tests): UT for UuidCookie MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rubén D --- app/modules/web/Init.php | 2 +- lib/SP/Core/Crypt/Cookie.php | 15 +- .../Crypt/{UUIDCookie.php => UuidCookie.php} | 6 +- lib/SP/Core/Crypt/UuidCookieInterface.php | 62 ++++++ lib/SP/Core/Definitions/CoreDefinitions.php | 4 +- lib/SP/Core/Definitions/DomainDefinitions.php | 4 +- .../Ports/SecureSessionServiceInterface.php | 5 +- .../Crypt/Services/SecureSessionService.php | 5 +- tests/SP/Core/Crypt/UuidCookieTest.php | 189 ++++++++++++++++++ .../Services/SecureSessionServiceTest.php | 8 +- 10 files changed, 278 insertions(+), 22 deletions(-) rename lib/SP/Core/Crypt/{UUIDCookie.php => UuidCookie.php} (94%) create mode 100644 lib/SP/Core/Crypt/UuidCookieInterface.php create mode 100644 tests/SP/Core/Crypt/UuidCookieTest.php diff --git a/app/modules/web/Init.php b/app/modules/web/Init.php index ee6ae907..d4dd8d24 100644 --- a/app/modules/web/Init.php +++ b/app/modules/web/Init.php @@ -36,7 +36,7 @@ use SP\Core\Crypt\CryptSessionHandler; use SP\Core\Crypt\Csrf; use SP\Core\Crypt\CsrfInterface; use SP\Core\Crypt\Session as CryptSession; -use SP\Core\Crypt\UUIDCookie; +use SP\Core\Crypt\UuidCookie; use SP\Core\Exceptions\ConstraintException; use SP\Core\Exceptions\InitializationException; use SP\Core\Exceptions\InvalidArgumentException; diff --git a/lib/SP/Core/Crypt/Cookie.php b/lib/SP/Core/Crypt/Cookie.php index 88bc960b..a035e1cd 100644 --- a/lib/SP/Core/Crypt/Cookie.php +++ b/lib/SP/Core/Crypt/Cookie.php @@ -26,6 +26,7 @@ namespace SP\Core\Crypt; use SP\Core\Bootstrap\BootstrapBase; use SP\Http\RequestInterface; + use function SP\logger; /** @@ -38,10 +39,12 @@ abstract class Cookie /** * Cookie constructor. * - * @param string $cookieName - * @param RequestInterface $request + * @param string $cookieName + * @param RequestInterface $request */ - protected function __construct(private readonly string $cookieName, protected readonly RequestInterface $request) {} + protected function __construct(private readonly string $cookieName, protected readonly RequestInterface $request) + { + } /** * Firmar la cookie para autentificación @@ -50,14 +53,14 @@ abstract class Cookie { $data = base64_encode($data); - return Hash::signMessage($data, $cypher).';'.$data; + return Hash::signMessage($data, $cypher) . ';' . $data; } /** * Comprobar la firma de la cookie y devolver los datos * - * @param string $data - * @param string $cypher + * @param string $data + * @param string $cypher * * @return bool|string */ diff --git a/lib/SP/Core/Crypt/UUIDCookie.php b/lib/SP/Core/Crypt/UuidCookie.php similarity index 94% rename from lib/SP/Core/Crypt/UUIDCookie.php rename to lib/SP/Core/Crypt/UuidCookie.php index 5e780cf5..e1b0b5cf 100644 --- a/lib/SP/Core/Crypt/UUIDCookie.php +++ b/lib/SP/Core/Crypt/UuidCookie.php @@ -27,18 +27,18 @@ namespace SP\Core\Crypt; use SP\Http\RequestInterface; /** - * Class SecureCookie + * Class UuidCookie * * @package SP\Core\Crypt */ -class UUIDCookie extends Cookie +class UuidCookie extends Cookie implements UuidCookieInterface { /** * Nombre de la cookie */ public const COOKIE_NAME = 'SYSPASS_UUID'; - public static function factory(RequestInterface $request): UUIDCookie + public static function factory(RequestInterface $request): UuidCookie { return new self(self::COOKIE_NAME, $request); } diff --git a/lib/SP/Core/Crypt/UuidCookieInterface.php b/lib/SP/Core/Crypt/UuidCookieInterface.php new file mode 100644 index 00000000..e5ae7502 --- /dev/null +++ b/lib/SP/Core/Crypt/UuidCookieInterface.php @@ -0,0 +1,62 @@ +. + */ + +namespace SP\Core\Crypt; + +/** + * Class UuidCookie + * + * @package SP\Core\Crypt + */ +interface UuidCookieInterface +{ + /** + * Firmar la cookie para autentificación + */ + public function sign(string $data, string $cypher): string; + + /** + * Comprobar la firma de la cookie y devolver los datos + * + * @param string $data + * @param string $cypher + * + * @return bool|string + */ + public function getCookieData(string $data, string $cypher): bool|string; + + /** + * Creates a cookie and sets its data + * + * @return string|false + */ + public function create(string $signKey): bool|string; + + /** + * Loads cookie data + * + * @return false|string + */ + public function load(string $signKey): bool|string; +} diff --git a/lib/SP/Core/Definitions/CoreDefinitions.php b/lib/SP/Core/Definitions/CoreDefinitions.php index 5d2d6c9e..baba1d01 100644 --- a/lib/SP/Core/Definitions/CoreDefinitions.php +++ b/lib/SP/Core/Definitions/CoreDefinitions.php @@ -41,7 +41,7 @@ use SP\Core\Crypt\CryptPKIInterface; use SP\Core\Crypt\Csrf; use SP\Core\Crypt\RequestBasedPassword; use SP\Core\Crypt\RequestBasedPasswordInterface; -use SP\Core\Crypt\UUIDCookie; +use SP\Core\Crypt\UuidCookie; use SP\Core\Exceptions\SPException; use SP\Core\Language; use SP\Core\LanguageInterface; @@ -223,7 +223,7 @@ final class CoreDefinitions ->constructorParameter('privateKeyFile', new FileHandler(CryptPKI::PRIVATE_KEY_FILE)), FileCacheInterface::class => create(FileCache::class), Application::class => autowire(Application::class), - UUIDCookie::class => factory([UUIDCookie::class, 'factory']) + UuidCookie::class => factory([UuidCookie::class, 'factory']) ->parameter( 'request', get(RequestInterface::class) diff --git a/lib/SP/Core/Definitions/DomainDefinitions.php b/lib/SP/Core/Definitions/DomainDefinitions.php index 0269ca53..288f2d67 100644 --- a/lib/SP/Core/Definitions/DomainDefinitions.php +++ b/lib/SP/Core/Definitions/DomainDefinitions.php @@ -28,7 +28,7 @@ use Psr\Container\ContainerInterface; use SP\Core\Application; use SP\Core\Crypt\CryptInterface; use SP\Core\Crypt\RequestBasedPassword; -use SP\Core\Crypt\UUIDCookie; +use SP\Core\Crypt\UuidCookie; use SP\Domain\Account\Ports\AccountSearchDataBuilderInterface; use SP\Domain\Account\Search\AccountSearchDataBuilder; use SP\Domain\Config\Ports\ConfigDataInterface; @@ -106,7 +106,7 @@ final class DomainDefinitions static function (ContainerInterface $c) { $fileCache = new FileCache( SecureSessionService::getFileNameFrom( - $c->get(UUIDCookie::class), + $c->get(UuidCookie::class), $c->get(ConfigDataInterface::class)->getPasswordSalt() ) ); diff --git a/lib/SP/Domain/Crypt/Ports/SecureSessionServiceInterface.php b/lib/SP/Domain/Crypt/Ports/SecureSessionServiceInterface.php index e77430f8..aee52133 100644 --- a/lib/SP/Domain/Crypt/Ports/SecureSessionServiceInterface.php +++ b/lib/SP/Domain/Crypt/Ports/SecureSessionServiceInterface.php @@ -25,7 +25,8 @@ namespace SP\Domain\Crypt\Ports; use Defuse\Crypto\Key; -use SP\Core\Crypt\UUIDCookie; +use SP\Core\Crypt\UuidCookie; +use SP\Core\Crypt\UuidCookieInterface; use SP\Domain\Common\Services\ServiceException; /** @@ -40,7 +41,7 @@ interface SecureSessionServiceInterface * * @throws ServiceException */ - public static function getFileNameFrom(UUIDCookie $cookie, string $seed): string; + public static function getFileNameFrom(UuidCookieInterface $cookie, string $seed): string; /** * Returns the encryption key diff --git a/lib/SP/Domain/Crypt/Services/SecureSessionService.php b/lib/SP/Domain/Crypt/Services/SecureSessionService.php index 159e8f3c..94d8eac9 100644 --- a/lib/SP/Domain/Crypt/Services/SecureSessionService.php +++ b/lib/SP/Domain/Crypt/Services/SecureSessionService.php @@ -30,7 +30,8 @@ use SP\Core\Application; use SP\Core\Crypt\CryptInterface; use SP\Core\Crypt\RequestBasedPassword; use SP\Core\Crypt\RequestBasedPasswordInterface; -use SP\Core\Crypt\UUIDCookie; +use SP\Core\Crypt\UuidCookie; +use SP\Core\Crypt\UuidCookieInterface; use SP\Core\Crypt\Vault; use SP\Domain\Common\Services\Service; use SP\Domain\Common\Services\ServiceException; @@ -64,7 +65,7 @@ final class SecureSessionService extends Service implements SecureSessionService * * @throws ServiceException */ - public static function getFileNameFrom(UUIDCookie $cookie, string $seed): string + public static function getFileNameFrom(UuidCookieInterface $cookie, string $seed): string { if (($uuid = $cookie->load($seed)) === false && ($uuid = $cookie->create($seed)) === false diff --git a/tests/SP/Core/Crypt/UuidCookieTest.php b/tests/SP/Core/Crypt/UuidCookieTest.php new file mode 100644 index 00000000..102b3eee --- /dev/null +++ b/tests/SP/Core/Crypt/UuidCookieTest.php @@ -0,0 +1,189 @@ +. + */ + +namespace SP\Tests\Core\Crypt; + +use Klein\DataCollection\DataCollection; +use Klein\Request; +use PHPUnit\Framework\MockObject\Exception; +use PHPUnit\Framework\MockObject\MockObject; +use SP\Core\Crypt\Hash; +use SP\Core\Crypt\UuidCookie; +use SP\Http\RequestInterface; +use SP\Tests\UnitaryTestCase; + +/** + * Class UuidCookieTest + * + * @group unitary + */ +class UuidCookieTest extends UnitaryTestCase +{ + + private RequestInterface|MockObject $requestInterface; + + + /** + * @throws Exception + */ + public function testLoad() + { + $key = self::$faker->sha1; + $message = base64_encode('test'); + $data = sprintf('%s;%s', Hash::signMessage($message, $key), $message); + + $cookies = $this->createMock(DataCollection::class); + $cookies->expects(self::once()) + ->method('get') + ->with('SYSPASS_UUID', false) + ->willReturn($data); + + $request = $this->createMock(Request::class); + $request->expects(self::once()) + ->method('cookies') + ->willReturn($cookies); + + $this->requestInterface + ->expects(self::once()) + ->method('getRequest') + ->willReturn($request); + + $cookie = UuidCookie::factory($this->requestInterface); + + self::assertEquals('test', $cookie->load($key)); + } + + /** + * @throws Exception + */ + public function testLoadWithNoData() + { + $key = self::$faker->sha1; + + $cookies = $this->createMock(DataCollection::class); + $cookies->expects(self::once()) + ->method('get') + ->with('SYSPASS_UUID', false) + ->willReturn(false); + + $request = $this->createMock(Request::class); + $request->expects(self::once()) + ->method('cookies') + ->willReturn($cookies); + + $this->requestInterface + ->expects(self::once()) + ->method('getRequest') + ->willReturn($request); + + $cookie = UuidCookie::factory($this->requestInterface); + + self::assertFalse($cookie->load($key)); + } + + /** + * @throws Exception + */ + public function testLoadWithInvalidData() + { + $key = self::$faker->sha1; + $data = self::$faker->text; + + $cookies = $this->createMock(DataCollection::class); + $cookies->expects(self::once()) + ->method('get') + ->with('SYSPASS_UUID', false) + ->willReturn($data); + + $request = $this->createMock(Request::class); + $request->expects(self::once()) + ->method('cookies') + ->willReturn($cookies); + + $this->requestInterface + ->expects(self::once()) + ->method('getRequest') + ->willReturn($request); + + $cookie = UuidCookie::factory($this->requestInterface); + + self::assertFalse($cookie->load($key)); + } + + /** + * @throws Exception + */ + public function testLoadWithInvalidSignature() + { + $key = self::$faker->sha1; + $data = sprintf('%s;%s', Hash::signMessage(base64_encode('invalid'), $key), base64_encode('test')); + + $cookies = $this->createMock(DataCollection::class); + $cookies->expects(self::once()) + ->method('get') + ->with('SYSPASS_UUID', false) + ->willReturn($data); + + $request = $this->createMock(Request::class); + $request->expects(self::once()) + ->method('cookies') + ->willReturn($cookies); + + $this->requestInterface + ->expects(self::once()) + ->method('getRequest') + ->willReturn($request); + + $cookie = UuidCookie::factory($this->requestInterface); + + self::assertFalse($cookie->load($key)); + } + + public function testCreate() + { + $uuidCookie = UuidCookie::factory($this->requestInterface); + + $key = self::$faker->sha1; + $cookie = $uuidCookie->create($key); + + self::assertNotEmpty($cookie); + } + + public function testSign() + { + $key = self::$faker->sha1; + $uuidCookie = UuidCookie::factory($this->requestInterface); + $cookieData = $uuidCookie->sign('test', $key); + $out = $uuidCookie->getCookieData($cookieData, $key); + + self::assertEquals('test', $out); + } + + protected function setUp(): void + { + parent::setUp(); + + $this->requestInterface = $this->createMock(RequestInterface::class); + } +} diff --git a/tests/SP/Domain/Crypt/Services/SecureSessionServiceTest.php b/tests/SP/Domain/Crypt/Services/SecureSessionServiceTest.php index 31399283..08ea6014 100644 --- a/tests/SP/Domain/Crypt/Services/SecureSessionServiceTest.php +++ b/tests/SP/Domain/Crypt/Services/SecureSessionServiceTest.php @@ -30,7 +30,7 @@ use PHPUnit\Framework\MockObject\MockObject; use SP\Core\Crypt\Crypt; use SP\Core\Crypt\CryptInterface; use SP\Core\Crypt\RequestBasedPasswordInterface; -use SP\Core\Crypt\UUIDCookie; +use SP\Core\Crypt\UuidCookie; use SP\Core\Crypt\Vault; use SP\Domain\Common\Services\ServiceException; use SP\Domain\Crypt\Services\SecureSessionService; @@ -140,7 +140,7 @@ class SecureSessionServiceTest extends UnitaryTestCase */ public function testGetFileNameFrom() { - $uuidCookie = $this->createMock(UUIDCookie::class); + $uuidCookie = $this->createMock(UuidCookie::class); $uuidCookie->method('load') ->willReturn(uniqid('', true)); @@ -156,7 +156,7 @@ class SecureSessionServiceTest extends UnitaryTestCase */ public function testGetFileNameFromErrorLoadingCookie() { - $uuidCookie = $this->createMock(UUIDCookie::class); + $uuidCookie = $this->createMock(UuidCookie::class); $uuidCookie->method('load')->willReturn(false); @@ -172,7 +172,7 @@ class SecureSessionServiceTest extends UnitaryTestCase */ public function testGetFileNameFromErrorCreatingCookie() { - $uuidCookie = $this->createMock(UUIDCookie::class); + $uuidCookie = $this->createMock(UuidCookie::class); $uuidCookie->method('create')->willReturn(false);