diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php index ad45303fa7c3b2cc67a784254ef4b960cb3cbb0c..19aba58b0562ca5732acb1231a64c4fd2aaaf682 100644 --- a/lib/private/Authentication/Token/DefaultTokenProvider.php +++ b/lib/private/Authentication/Token/DefaultTokenProvider.php @@ -338,4 +338,14 @@ class DefaultTokenProvider implements IProvider { } } + public function markPasswordInvalid(IToken $token, string $tokenId) { + if (!($token instanceof DefaultToken)) { + throw new InvalidTokenException(); + } + + //No need to mark as invalid. We just invalide default tokens + $this->invalidateToken($tokenId); + } + + } diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php index ab46bd121262af3882dc066fd4116929e182a77a..d1b067868b4c0d0008aa60b3ec874eed25575d00 100644 --- a/lib/private/Authentication/Token/IProvider.php +++ b/lib/private/Authentication/Token/IProvider.php @@ -156,4 +156,12 @@ interface IProvider { * @return IToken */ public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken; + + /** + * Marks a token as having an invalid password. + * + * @param IToken $token + * @param string $tokenId + */ + public function markPasswordInvalid(IToken $token, string $tokenId); } diff --git a/lib/private/Authentication/Token/Manager.php b/lib/private/Authentication/Token/Manager.php index 254a1598943d287e3bce9fcbb269969e55f8684c..711d211039396192e4a048778ef336600ea78f89 100644 --- a/lib/private/Authentication/Token/Manager.php +++ b/lib/private/Authentication/Token/Manager.php @@ -227,4 +227,9 @@ class Manager implements IProvider { } throw new InvalidTokenException(); } + + + public function markPasswordInvalid(IToken $token, string $tokenId) { + $this->getProvider($token)->markPasswordInvalid($token, $tokenId); + } } diff --git a/lib/private/Authentication/Token/PublicKeyToken.php b/lib/private/Authentication/Token/PublicKeyToken.php index 0e793ce8c7c5a79912bea250488b6a6c0dfd2f9f..9896915ca33ef961c032751aa1fb607ece518730 100644 --- a/lib/private/Authentication/Token/PublicKeyToken.php +++ b/lib/private/Authentication/Token/PublicKeyToken.php @@ -43,6 +43,8 @@ use OCP\AppFramework\Db\Entity; * @method string getPublicKey() * @method void setPublicKey(string $key) * @method void setVersion(int $version) + * @method bool getPasswordInvalid() + * @method void setPasswordInvalid(bool $invalid); */ class PublicKeyToken extends Entity implements IToken { @@ -90,6 +92,9 @@ class PublicKeyToken extends Entity implements IToken { /** @var int */ protected $version; + /** @var bool */ + protected $passwordInvalid; + public function __construct() { $this->addType('uid', 'string'); $this->addType('loginName', 'string'); @@ -105,6 +110,7 @@ class PublicKeyToken extends Entity implements IToken { $this->addType('publicKey', 'string'); $this->addType('privateKey', 'string'); $this->addType('version', 'int'); + $this->addType('passwordInvalid', 'bool'); } public function getId(): int { diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php index 7e98ee939cec12600f2e340de5a5dbd347a56125..9afdb5a8ff52fd097072d42911f72bb62d49af85 100644 --- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php +++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php @@ -317,4 +317,15 @@ class PublicKeyTokenProvider implements IProvider { return $dbToken; } + + public function markPasswordInvalid(IToken $token, string $tokenId) { + if (!($token instanceof PublicKeyToken)) { + throw new InvalidTokenException(); + } + + $token->setPasswordInvalid(true); + $this->mapper->update($token); + } + + } diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php index 5593e178ca3c0ea1c63fb419122329192f7441b3..8ac42eac4eb12222617afe6566ca6794b5786a90 100644 --- a/lib/private/User/Session.php +++ b/lib/private/User/Session.php @@ -694,12 +694,19 @@ class Session implements IUserSession, Emitter { return true; } - if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false - || (!is_null($this->activeUser) && !$this->activeUser->isEnabled())) { + // Invalidate token if the user is no longer active + if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) { $this->tokenProvider->invalidateToken($token); - // Password has changed or user was disabled -> log user out return false; } + + // If the token password is no longer valid mark it as such + if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false) { + $this->tokenProvider->markPasswordInvalid($dbToken, $token); + // User is logged out + return false; + } + $dbToken->setLastCheck($now); return true; } diff --git a/tests/lib/User/SessionTest.php b/tests/lib/User/SessionTest.php index 24677b57dd67d0ac4ae111c610525f02feb347ec..81ceade9e02c41da5ad4291aef7190eb104f89eb 100644 --- a/tests/lib/User/SessionTest.php +++ b/tests/lib/User/SessionTest.php @@ -1017,10 +1017,8 @@ class SessionTest extends \Test\TestCase { ->method('getPassword') ->with($token, 'APP-PASSWORD') ->will($this->returnValue('123456')); - $userManager->expects($this->once()) - ->method('checkPassword') - ->with('susan', '123456') - ->will($this->returnValue(true)); + $userManager->expects($this->never()) + ->method('checkPassword'); $user->expects($this->once()) ->method('isEnabled') ->will($this->returnValue(false));