Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/b-7.2.x' into b-7.2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcelOxid committed Oct 30, 2024
2 parents e4d5358 + e19f6d0 commit 54f954e
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGELOG-v10.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- New methods:
- `OxidEsales\GraphQL\Base\Infrastructure\RefreshTokenRepositoryInterface::invalidateUserTokens`
- `OxidEsales\GraphQL\Base\Infrastructure\Token::invalidateUserTokens`
- `OxidEsales\GraphQL\Base\Infrastructure\Token::isTokenExpired`
- New event subscriber:
- `OxidEsales\GraphQL\Base\Event\Subscriber\PasswordChangeSubscriber`

Expand Down
20 changes: 20 additions & 0 deletions src/Infrastructure/Token.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ public function isTokenRegistered(string $tokenId): bool
return $storage->isLoaded();
}

public function isTokenExpired(string $tokenId): bool
{
$queryBuilder = $this->queryBuilderFactory->create()
->select('oxid')
->from('oegraphqltoken')
->where('OXID = :tokenId')
->andWhere('EXPIRES_AT <= NOW()')
->setParameters([
'tokenId' => $tokenId,
]);

$result = $queryBuilder->execute();

if (is_object($result)) {
return $result->fetchOne() > 0;
}

return false;
}

public function removeExpiredTokens(UserInterface $user): void
{
$queryBuilder = $this->queryBuilderFactory->create()
Expand Down
7 changes: 6 additions & 1 deletion src/Service/TokenValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function __construct(
*/
public function validateToken(UnencryptedToken $token): void
{
if (!$this->areConstraintsValid($token)) {
if (!$this->areConstraintsValid($token) || $this->isTokenExpired($token)) {
throw new InvalidToken();
}

Expand All @@ -62,6 +62,11 @@ private function areConstraintsValid(UnencryptedToken $token): bool
return $validator->validate($token, ...$config->validationConstraints());
}

private function isTokenExpired(UnencryptedToken $token): bool
{
return $this->tokenInfrastructure->isTokenExpired($token->claims()->get(Token::CLAIM_TOKENID));
}

private function isUserBlocked(?string $userId): bool
{
$groups = $this->legacyInfrastructure->getUserGroupIds($userId);
Expand Down
44 changes: 25 additions & 19 deletions tests/Integration/Infrastructure/TokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
use Lcobucci\JWT\Token\DataSet;
use Lcobucci\JWT\UnencryptedToken;
use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\EshopCommunity\Internal\Framework\Database\ConnectionProviderInterface;
use OxidEsales\EshopCommunity\Tests\Integration\IntegrationTestCase;
use OxidEsales\EshopCommunity\Tests\TestContainerFactory;
use OxidEsales\GraphQL\Base\DataType\Token as TokenDataType;
use OxidEsales\GraphQL\Base\DataType\User as UserDataType;
use OxidEsales\GraphQL\Base\Infrastructure\Model\Token as TokenModel;
use OxidEsales\GraphQL\Base\Infrastructure\Token as TokenInfrastructure;
use OxidEsales\GraphQL\Base\Service\Token;
use OxidEsales\GraphQL\Base\Service\Token as TokenService;

class TokenTest extends IntegrationTestCase
Expand All @@ -31,17 +31,13 @@ class TokenTest extends IntegrationTestCase
/** @var TokenInfrastructure */
private $tokenInfrastructure;

/** @var ConnectionProviderInterface */
private $connection;

public function setUp(): void
{
parent::setUp();
$containerFactory = new TestContainerFactory();
$container = $containerFactory->create();
$container->compile();
$this->tokenInfrastructure = $container->get(TokenInfrastructure::class);
$this->connection = $container->get(ConnectionProviderInterface::class)->get();
}

public function testRegisterToken(): void
Expand Down Expand Up @@ -74,6 +70,28 @@ public function testIsTokenRegisteredNo(): void
$this->assertFalse($this->tokenInfrastructure->isTokenRegistered('not_registered_token'));
}

public function testIsTokenExpired(): void
{
$this->tokenInfrastructure->registerToken(
$this->getTokenMock('valid_token'),
new DateTimeImmutable('now'),
new DateTimeImmutable('+8 hours')
);

$this->assertFalse($this->tokenInfrastructure->isTokenExpired('valid_token'));
}

public function testIsTokenExpiredNo(): void
{
$this->tokenInfrastructure->registerToken(
$this->getTokenMock('expired_token'),
new DateTimeImmutable('now'),
new DateTimeImmutable('-8 hours')
);

$this->assertTrue($this->tokenInfrastructure->isTokenExpired('expired_token'));
}

public function testRemoveExpiredTokens(): void
{
$this->tokenInfrastructure->registerToken(
Expand Down Expand Up @@ -323,13 +341,7 @@ public function testInvalidateAccessTokens(): void
);

$this->tokenInfrastructure->invalidateUserTokens($userId);
$result = $this->connection->executeQuery(
"select expires_at from `oegraphqltoken` where oxid=:tokenId",
['tokenId' => $token]
);
$expiresAtAfterChange = $result->fetchOne();

$this->assertTrue(new DateTimeImmutable($expiresAtAfterChange) <= new DateTimeImmutable('now'));
$this->assertTrue($this->tokenInfrastructure->isTokenExpired($token));
}

public function testInvalidateAccessTokensWrongUserId(): void
Expand All @@ -344,13 +356,7 @@ public function testInvalidateAccessTokensWrongUserId(): void
);

$this->tokenInfrastructure->invalidateUserTokens('wrong_user_id');
$result = $this->connection->executeQuery(
"select expires_at from `oegraphqltoken` where oxid=:tokenId",
['tokenId' => $token]
);
$expiresAtAfterChange = $result->fetchOne();

$this->assertFalse(new DateTimeImmutable($expiresAtAfterChange) <= new DateTimeImmutable('now'));
$this->assertFalse($this->tokenInfrastructure->isTokenExpired($token));
}

private function getTokenMock(
Expand Down
5 changes: 5 additions & 0 deletions tests/Integration/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ public function isTokenRegistered(string $tokenId): bool
return true;
}

public function isTokenExpired(string $tokenId): bool
{
return false;
}

public function registerToken(UnencryptedToken $token, DateTimeImmutable $time, DateTimeImmutable $expire): void
{
}
Expand Down
12 changes: 6 additions & 6 deletions tests/Unit/Service/TokenValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function testTokenShopIdValidation(): void

$tokenInfrastructure = $this->createPartialMock(
TokenInfrastructure::class,
['registerToken', 'isTokenRegistered', 'removeExpiredTokens', 'canIssueToken']
['registerToken', 'isTokenRegistered', 'isTokenExpired', 'removeExpiredTokens', 'canIssueToken']
);
$tokenInfrastructure->method('isTokenRegistered')->willReturn(true);
$tokenInfrastructure->method('canIssueToken')->willReturn(true);
Expand Down Expand Up @@ -54,7 +54,7 @@ public function testTokenShopUrlValidation(): void

$tokenInfrastructure = $this->createPartialMock(
TokenInfrastructure::class,
['registerToken', 'isTokenRegistered', 'removeExpiredTokens', 'canIssueToken']
['registerToken', 'isTokenRegistered', 'isTokenExpired', 'removeExpiredTokens', 'canIssueToken']
);
$tokenInfrastructure->method('isTokenRegistered')->willReturn(true);
$tokenInfrastructure->method('canIssueToken')->willReturn(true);
Expand Down Expand Up @@ -85,7 +85,7 @@ public function testTokenUserInBlockedGroup(): void

$tokenInfrastructure = $this->createPartialMock(
TokenInfrastructure::class,
['registerToken', 'isTokenRegistered', 'removeExpiredTokens', 'canIssueToken']
['registerToken', 'isTokenRegistered', 'isTokenExpired', 'removeExpiredTokens', 'canIssueToken']
);
$tokenInfrastructure->method('isTokenRegistered')->willReturn(true);
$tokenInfrastructure->method('canIssueToken')->willReturn(true);
Expand All @@ -108,7 +108,7 @@ public function testExpiredToken(): void

$tokenInfrastructure = $this->createPartialMock(
TokenInfrastructure::class,
['registerToken', 'isTokenRegistered', 'removeExpiredTokens', 'canIssueToken']
['registerToken', 'isTokenRegistered', 'isTokenExpired', 'removeExpiredTokens', 'canIssueToken']
);
$tokenInfrastructure->method('isTokenRegistered')->willReturn(true);
$tokenInfrastructure->method('canIssueToken')->willReturn(true);
Expand All @@ -134,7 +134,7 @@ public function testDeletedToken(): void

$tokenInfrastructure = $this->createPartialMock(
TokenInfrastructure::class,
['registerToken', 'isTokenRegistered', 'removeExpiredTokens', 'canIssueToken']
['registerToken', 'isTokenRegistered', 'isTokenExpired', 'removeExpiredTokens', 'canIssueToken']
);
$tokenInfrastructure->method('isTokenRegistered')->willReturn(false);
$tokenInfrastructure->method('canIssueToken')->willReturn(true);
Expand All @@ -157,7 +157,7 @@ public function testAnonymousToken(): void

$tokenInfrastructure = $this->createPartialMock(
TokenInfrastructure::class,
['registerToken', 'isTokenRegistered', 'removeExpiredTokens', 'canIssueToken']
['registerToken', 'isTokenRegistered', 'isTokenExpired', 'removeExpiredTokens', 'canIssueToken']
);
$tokenInfrastructure->method('canIssueToken')->willReturn(true);
$validator = $this->getTokenValidator($legacy, $tokenInfrastructure);
Expand Down

0 comments on commit 54f954e

Please sign in to comment.