From 8ffd30bbf93d13b77c0977ab3de03d35c64a888b Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Wed, 20 Aug 2025 16:55:33 +0200 Subject: [PATCH 1/4] feat(auth): dispatch new TokenInvalidatedEvent when PublicKeyTokenProvider::invalidateTokenById is called Signed-off-by: Julien Veyssier --- lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + .../Token/PublicKeyTokenProvider.php | 11 ++++- .../Events/TokenInvalidatedEvent.php | 47 +++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 lib/public/Authentication/Events/TokenInvalidatedEvent.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 84f75545b2585..fa3f15309593c 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -157,6 +157,7 @@ 'OCP\\App\\ManagerEvent' => $baseDir . '/lib/public/App/ManagerEvent.php', 'OCP\\Authentication\\Events\\AnyLoginFailedEvent' => $baseDir . '/lib/public/Authentication/Events/AnyLoginFailedEvent.php', 'OCP\\Authentication\\Events\\LoginFailedEvent' => $baseDir . '/lib/public/Authentication/Events/LoginFailedEvent.php', + 'OCP\\Authentication\\Events\\TokenInvalidatedEvent' => $baseDir . '/lib/public/Authentication/Events/TokenInvalidatedEvent.php', 'OCP\\Authentication\\Exceptions\\CredentialsUnavailableException' => $baseDir . '/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php', 'OCP\\Authentication\\Exceptions\\ExpiredTokenException' => $baseDir . '/lib/public/Authentication/Exceptions/ExpiredTokenException.php', 'OCP\\Authentication\\Exceptions\\InvalidTokenException' => $baseDir . '/lib/public/Authentication/Exceptions/InvalidTokenException.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index d533a3bcf1c26..d5651a5438130 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -198,6 +198,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\App\\ManagerEvent' => __DIR__ . '/../../..' . '/lib/public/App/ManagerEvent.php', 'OCP\\Authentication\\Events\\AnyLoginFailedEvent' => __DIR__ . '/../../..' . '/lib/public/Authentication/Events/AnyLoginFailedEvent.php', 'OCP\\Authentication\\Events\\LoginFailedEvent' => __DIR__ . '/../../..' . '/lib/public/Authentication/Events/LoginFailedEvent.php', + 'OCP\\Authentication\\Events\\TokenInvalidatedEvent' => __DIR__ . '/../../..' . '/lib/public/Authentication/Events/TokenInvalidatedEvent.php', 'OCP\\Authentication\\Exceptions\\CredentialsUnavailableException' => __DIR__ . '/../../..' . '/lib/public/Authentication/Exceptions/CredentialsUnavailableException.php', 'OCP\\Authentication\\Exceptions\\ExpiredTokenException' => __DIR__ . '/../../..' . '/lib/public/Authentication/Exceptions/ExpiredTokenException.php', 'OCP\\Authentication\\Exceptions\\InvalidTokenException' => __DIR__ . '/../../..' . '/lib/public/Authentication/Exceptions/InvalidTokenException.php', diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index 12c3a1d535bd1..2272c74c0ff20 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -15,7 +15,9 @@ use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\TTransactional; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Authentication\Events\TokenInvalidatedEvent; use OCP\Authentication\Token\IToken as OCPIToken; +use OCP\EventDispatcher\IEventDispatcher; use OCP\ICache; use OCP\ICacheFactory; use OCP\IConfig; @@ -55,6 +57,8 @@ class PublicKeyTokenProvider implements IProvider { /** @var IHasher */ private $hasher; + private IEventDispatcher $eventDispatcher; + public function __construct(PublicKeyTokenMapper $mapper, ICrypto $crypto, IConfig $config, @@ -62,7 +66,9 @@ public function __construct(PublicKeyTokenMapper $mapper, LoggerInterface $logger, ITimeFactory $time, IHasher $hasher, - ICacheFactory $cacheFactory) { + ICacheFactory $cacheFactory, + IEventDispatcher $eventDispatcher, + ) { $this->mapper = $mapper; $this->crypto = $crypto; $this->config = $config; @@ -74,6 +80,7 @@ public function __construct(PublicKeyTokenMapper $mapper, ? $cacheFactory->createLocal('authtoken_') : $cacheFactory->createInMemory(); $this->hasher = $hasher; + $this->eventDispatcher = $eventDispatcher; } /** @@ -275,7 +282,7 @@ public function invalidateTokenById(string $uid, int $id) { } $this->mapper->invalidate($token->getToken()); $this->cacheInvalidHash($token->getToken()); - + $this->eventDispatcher->dispatchTyped(new TokenInvalidatedEvent($uid, $id)); } public function invalidateOldTokens() { diff --git a/lib/public/Authentication/Events/TokenInvalidatedEvent.php b/lib/public/Authentication/Events/TokenInvalidatedEvent.php new file mode 100644 index 0000000000000..9e54c629ace98 --- /dev/null +++ b/lib/public/Authentication/Events/TokenInvalidatedEvent.php @@ -0,0 +1,47 @@ +userId; + } + + /** + * returns the ID of the token that is being invalidated + * + * @since 32.0.0 + */ + public function getTokenId(): int { + return $this->tokenId; + } +} From 3da919c78318da13b9446cdd8086d8432d51b0b1 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Wed, 20 Aug 2025 17:20:49 +0200 Subject: [PATCH 2/4] feat(auth): dispatch new TokenInvalidatedEvent when PublicKeyTokenProvider::invalidateToken is called Signed-off-by: Julien Veyssier --- .../Authentication/Token/PublicKeyTokenProvider.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index 2272c74c0ff20..de9c808e00744 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -270,9 +270,16 @@ public function renewSessionToken(string $oldSessionId, string $sessionId): OCPI public function invalidateToken(string $token) { $tokenHash = $this->hashToken($token); + $tokenEntry = null; + try { + $tokenEntry = $this->mapper->getToken($tokenHash); + } catch (DoesNotExistException) {} $this->mapper->invalidate($this->hashToken($token)); $this->mapper->invalidate($this->hashTokenWithEmptySecret($token)); $this->cacheInvalidHash($tokenHash); + if ($tokenEntry !== null) { + $this->eventDispatcher->dispatchTyped(new TokenInvalidatedEvent($tokenEntry->getUID(), $tokenEntry->getId())); + } } public function invalidateTokenById(string $uid, int $id) { From 4a35837741656ec02c792027e90a63b938fd50c0 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Wed, 20 Aug 2025 18:05:24 +0200 Subject: [PATCH 3/4] feat(auth): adjust PublicKeyTokenProviderTest Signed-off-by: Julien Veyssier --- lib/private/Authentication/Token/PublicKeyTokenProvider.php | 3 ++- .../lib/Authentication/Token/PublicKeyTokenProviderTest.php | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index de9c808e00744..1261960dd71bc 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -273,7 +273,8 @@ public function invalidateToken(string $token) { $tokenEntry = null; try { $tokenEntry = $this->mapper->getToken($tokenHash); - } catch (DoesNotExistException) {} + } catch (DoesNotExistException) { + } $this->mapper->invalidate($this->hashToken($token)); $this->mapper->invalidate($this->hashTokenWithEmptySecret($token)); $this->cacheInvalidHash($tokenHash); diff --git a/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php b/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php index 7e7f949965fd5..51915fc1d4b5a 100644 --- a/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php +++ b/tests/lib/Authentication/Token/PublicKeyTokenProviderTest.php @@ -18,6 +18,7 @@ use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Authentication\Token\IToken; +use OCP\EventDispatcher\IEventDispatcher; use OCP\ICacheFactory; use OCP\IConfig; use OCP\IDBConnection; @@ -49,6 +50,8 @@ class PublicKeyTokenProviderTest extends TestCase { private $cacheFactory; /** @var int */ private $time; + /** @var IEventDispatcher */ + private $eventDispatcher; protected function setUp(): void { parent::setUp(); @@ -72,6 +75,7 @@ protected function setUp(): void { $this->timeFactory->method('getTime') ->willReturn($this->time); $this->cacheFactory = $this->createMock(ICacheFactory::class); + $this->eventDispatcher = Server::get(IEventDispatcher::class); $this->tokenProvider = new PublicKeyTokenProvider( $this->mapper, @@ -82,6 +86,7 @@ protected function setUp(): void { $this->timeFactory, $this->hasher, $this->cacheFactory, + $this->eventDispatcher, ); } From 3d368342846cfc28299b6d93cdc83c0b50a6e173 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Thu, 21 Aug 2025 12:42:24 +0200 Subject: [PATCH 4/4] feat(auth): include the token entity in TokenInvalidatedEvent Signed-off-by: Julien Veyssier --- .../Token/PublicKeyTokenProvider.php | 4 ++-- .../Events/TokenInvalidatedEvent.php | 19 +++++-------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index 1261960dd71bc..87063f5ccd1c5 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -279,7 +279,7 @@ public function invalidateToken(string $token) { $this->mapper->invalidate($this->hashTokenWithEmptySecret($token)); $this->cacheInvalidHash($tokenHash); if ($tokenEntry !== null) { - $this->eventDispatcher->dispatchTyped(new TokenInvalidatedEvent($tokenEntry->getUID(), $tokenEntry->getId())); + $this->eventDispatcher->dispatchTyped(new TokenInvalidatedEvent($tokenEntry)); } } @@ -290,7 +290,7 @@ public function invalidateTokenById(string $uid, int $id) { } $this->mapper->invalidate($token->getToken()); $this->cacheInvalidHash($token->getToken()); - $this->eventDispatcher->dispatchTyped(new TokenInvalidatedEvent($uid, $id)); + $this->eventDispatcher->dispatchTyped(new TokenInvalidatedEvent($token)); } public function invalidateOldTokens() { diff --git a/lib/public/Authentication/Events/TokenInvalidatedEvent.php b/lib/public/Authentication/Events/TokenInvalidatedEvent.php index 9e54c629ace98..f2d3a6c1594d1 100644 --- a/lib/public/Authentication/Events/TokenInvalidatedEvent.php +++ b/lib/public/Authentication/Events/TokenInvalidatedEvent.php @@ -8,6 +8,7 @@ */ namespace OCP\Authentication\Events; +use OCP\Authentication\Token\IToken; use OCP\EventDispatcher\Event; /** @@ -21,27 +22,17 @@ class TokenInvalidatedEvent extends Event { * @since 32.0.0 */ public function __construct( - private string $userId, - private int $tokenId, + private IToken $token, ) { parent::__construct(); } /** - * returns the uid of the user associated with the invalidated token + * returns the token that has been invalidated * * @since 32.0.0 */ - public function getUserId(): string { - return $this->userId; - } - - /** - * returns the ID of the token that is being invalidated - * - * @since 32.0.0 - */ - public function getTokenId(): int { - return $this->tokenId; + public function getToken(): IToken { + return $this->token; } }