1
0
Fork 0
mirror of synced 2024-07-09 08:27:01 +12:00

Merge pull request #8081 from appwrite/fix-dont-kick-after-enabling-mfa

Don't kick user and require verification after enabling MFA
This commit is contained in:
Torsten Dittmann 2024-05-07 17:49:18 +02:00 committed by GitHub
commit 239a0b4dde
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 18 deletions

View file

@ -3495,14 +3495,33 @@ App::patch('/v1/account/mfa')
->inject('requestTimestamp') ->inject('requestTimestamp')
->inject('response') ->inject('response')
->inject('user') ->inject('user')
->inject('session')
->inject('dbForProject') ->inject('dbForProject')
->inject('queueForEvents') ->inject('queueForEvents')
->action(function (bool $mfa, ?\DateTime $requestTimestamp, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { ->action(function (bool $mfa, ?\DateTime $requestTimestamp, Response $response, Document $user, Document $session, Database $dbForProject, Event $queueForEvents) {
$user->setAttribute('mfa', $mfa); $user->setAttribute('mfa', $mfa);
$user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user)); $user = $dbForProject->withRequestTimestamp($requestTimestamp, fn () => $dbForProject->updateDocument('users', $user->getId(), $user));
if ($mfa) {
$factors = $session->getAttribute('factors', []);
$totp = TOTP::getAuthenticatorFromUser($user);
if ($totp !== null && $totp->getAttribute('verified', false)) {
$factors[] = Type::TOTP;
}
if ($user->getAttribute('email', false) && $user->getAttribute('emailVerification', false)) {
$factors[] = Type::EMAIL;
}
if ($user->getAttribute('phone', false) && $user->getAttribute('phoneVerification', false)) {
$factors[] = Type::PHONE;
}
$factors = \array_unique($factors);
$session->setAttribute('factors', $factors);
$dbForProject->updateDocument('sessions', $session->getId(), $session);
}
$queueForEvents->setParam('userId', $user->getId()); $queueForEvents->setParam('userId', $user->getId());
$response->dynamic($user, Response::MODEL_ACCOUNT); $response->dynamic($user, Response::MODEL_ACCOUNT);
@ -3633,10 +3652,10 @@ App::put('/v1/account/mfa/authenticators/:type')
->param('otp', '', new Text(256), 'Valid verification token.') ->param('otp', '', new Text(256), 'Valid verification token.')
->inject('response') ->inject('response')
->inject('user') ->inject('user')
->inject('project') ->inject('session')
->inject('dbForProject') ->inject('dbForProject')
->inject('queueForEvents') ->inject('queueForEvents')
->action(function (string $type, string $otp, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents) { ->action(function (string $type, string $otp, Response $response, Document $user, Document $session, Database $dbForProject, Event $queueForEvents) {
$authenticator = (match ($type) { $authenticator = (match ($type) {
Type::TOTP => TOTP::getAuthenticatorFromUser($user), Type::TOTP => TOTP::getAuthenticatorFromUser($user),
@ -3665,10 +3684,12 @@ App::put('/v1/account/mfa/authenticators/:type')
$dbForProject->updateDocument('authenticators', $authenticator->getId(), $authenticator); $dbForProject->updateDocument('authenticators', $authenticator->getId(), $authenticator);
$dbForProject->purgeCachedDocument('users', $user->getId()); $dbForProject->purgeCachedDocument('users', $user->getId());
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; $factors = $session->getAttribute('factors', []);
$sessionId = Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration); $factors[] = $type;
$session = $dbForProject->getDocument('sessions', $sessionId); $factors = \array_unique($factors);
$dbForProject->updateDocument('sessions', $sessionId, $session->setAttribute('factors', $type, Document::SET_TYPE_APPEND));
$session->setAttribute('factors', $factors);
$dbForProject->updateDocument('sessions', $session->getId(), $session);
$queueForEvents->setParam('userId', $user->getId()); $queueForEvents->setParam('userId', $user->getId());
@ -4057,9 +4078,10 @@ App::put('/v1/account/mfa/challenge')
->inject('project') ->inject('project')
->inject('response') ->inject('response')
->inject('user') ->inject('user')
->inject('session')
->inject('dbForProject') ->inject('dbForProject')
->inject('queueForEvents') ->inject('queueForEvents')
->action(function (string $challengeId, string $otp, Document $project, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { ->action(function (string $challengeId, string $otp, Document $project, Response $response, Document $user, Document $session, Database $dbForProject, Event $queueForEvents) {
$challenge = $dbForProject->getDocument('challenges', $challengeId); $challenge = $dbForProject->getDocument('challenges', $challengeId);
@ -4105,15 +4127,15 @@ App::put('/v1/account/mfa/challenge')
$dbForProject->deleteDocument('challenges', $challengeId); $dbForProject->deleteDocument('challenges', $challengeId);
$dbForProject->purgeCachedDocument('users', $user->getId()); $dbForProject->purgeCachedDocument('users', $user->getId());
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; $factors = $session->getAttribute('factors', []);
$sessionId = Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret, $authDuration); $factors[] = $type;
$session = $dbForProject->getDocument('sessions', $sessionId); $factors = \array_unique($factors);
$session = $session $session
->setAttribute('factors', $type, Document::SET_TYPE_APPEND) ->setAttribute('factors', $factors)
->setAttribute('mfaUpdatedAt', DateTime::now()); ->setAttribute('mfaUpdatedAt', DateTime::now());
$dbForProject->updateDocument('sessions', $sessionId, $session); $dbForProject->updateDocument('sessions', $session->getId(), $session);
$queueForEvents $queueForEvents
->setParam('userId', $user->getId()) ->setParam('userId', $user->getId())

View file

@ -1239,14 +1239,13 @@ App::setResource('project', function ($dbForConsole, $request, $console) {
return $project; return $project;
}, ['dbForConsole', 'request', 'console']); }, ['dbForConsole', 'request', 'console']);
App::setResource('session', function (Document $user, Document $project) { App::setResource('session', function (Document $user) {
if ($user->isEmpty()) { if ($user->isEmpty()) {
return; return;
} }
$sessions = $user->getAttribute('sessions', []); $sessions = $user->getAttribute('sessions', []);
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG; $sessionId = Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret);
$sessionId = Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret, $authDuration);
if (!$sessionId) { if (!$sessionId) {
return; return;
@ -1259,7 +1258,7 @@ App::setResource('session', function (Document $user, Document $project) {
} }
return; return;
}, ['user', 'project']); }, ['user']);
App::setResource('console', function () { App::setResource('console', function () {
return new Document([ return new Document([