Changeset View
Changeset View
Standalone View
Standalone View
src/applications/auth/factor/PhabricatorTOTPAuthFactor.php
| <?php | <?php | ||||
| final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor { | final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor { | ||||
| const TEMPORARY_TOKEN_TYPE = 'mfa:totp:key'; | |||||
| public function getFactorKey() { | public function getFactorKey() { | ||||
| return 'totp'; | return 'totp'; | ||||
| } | } | ||||
| public function getFactorName() { | public function getFactorName() { | ||||
| return pht('Mobile Phone App (TOTP)'); | return pht('Mobile Phone App (TOTP)'); | ||||
| } | } | ||||
| public function getFactorDescription() { | public function getFactorDescription() { | ||||
| return pht( | return pht( | ||||
| 'Attach a mobile authenticator application (like Authy '. | 'Attach a mobile authenticator application (like Authy '. | ||||
| 'or Google Authenticator) to your account. When you need to '. | 'or Google Authenticator) to your account. When you need to '. | ||||
| 'authenticate, you will enter a code shown on your phone.'); | 'authenticate, you will enter a code shown on your phone.'); | ||||
| } | } | ||||
| public function processAddFactorForm( | public function processAddFactorForm( | ||||
| AphrontFormView $form, | AphrontFormView $form, | ||||
| AphrontRequest $request, | AphrontRequest $request, | ||||
| PhabricatorUser $user) { | PhabricatorUser $user) { | ||||
| $totp_token_type = PhabricatorAuthTOTPKeyTemporaryTokenType::TOKENTYPE; | |||||
| $key = $request->getStr('totpkey'); | $key = $request->getStr('totpkey'); | ||||
| if (strlen($key)) { | if (strlen($key)) { | ||||
| // If the user is providing a key, make sure it's a key we generated. | // If the user is providing a key, make sure it's a key we generated. | ||||
| // This raises the barrier to theoretical attacks where an attacker might | // This raises the barrier to theoretical attacks where an attacker might | ||||
| // provide a known key (such attacks are already prevented by CSRF, but | // provide a known key (such attacks are already prevented by CSRF, but | ||||
| // this is a second barrier to overcome). | // this is a second barrier to overcome). | ||||
| // (We store and verify the hash of the key, not the key itself, to limit | // (We store and verify the hash of the key, not the key itself, to limit | ||||
| // how useful the data in the table is to an attacker.) | // how useful the data in the table is to an attacker.) | ||||
| $temporary_token = id(new PhabricatorAuthTemporaryTokenQuery()) | $temporary_token = id(new PhabricatorAuthTemporaryTokenQuery()) | ||||
| ->setViewer($user) | ->setViewer($user) | ||||
| ->withTokenResources(array($user->getPHID())) | ->withTokenResources(array($user->getPHID())) | ||||
| ->withTokenTypes(array(self::TEMPORARY_TOKEN_TYPE)) | ->withTokenTypes(array($totp_token_type)) | ||||
| ->withExpired(false) | ->withExpired(false) | ||||
| ->withTokenCodes(array(PhabricatorHash::digest($key))) | ->withTokenCodes(array(PhabricatorHash::digest($key))) | ||||
| ->executeOne(); | ->executeOne(); | ||||
| if (!$temporary_token) { | if (!$temporary_token) { | ||||
| // If we don't have a matching token, regenerate the key below. | // If we don't have a matching token, regenerate the key below. | ||||
| $key = null; | $key = null; | ||||
| } | } | ||||
| } | } | ||||
| if (!strlen($key)) { | if (!strlen($key)) { | ||||
| $key = self::generateNewTOTPKey(); | $key = self::generateNewTOTPKey(); | ||||
| // Mark this key as one we generated, so the user is allowed to submit | // Mark this key as one we generated, so the user is allowed to submit | ||||
| // a response for it. | // a response for it. | ||||
| $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); | $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); | ||||
| id(new PhabricatorAuthTemporaryToken()) | id(new PhabricatorAuthTemporaryToken()) | ||||
| ->setTokenResource($user->getPHID()) | ->setTokenResource($user->getPHID()) | ||||
| ->setTokenType(self::TEMPORARY_TOKEN_TYPE) | ->setTokenType($totp_token_type) | ||||
| ->setTokenExpires(time() + phutil_units('1 hour in seconds')) | ->setTokenExpires(time() + phutil_units('1 hour in seconds')) | ||||
| ->setTokenCode(PhabricatorHash::digest($key)) | ->setTokenCode(PhabricatorHash::digest($key)) | ||||
| ->save(); | ->save(); | ||||
| unset($unguarded); | unset($unguarded); | ||||
| } | } | ||||
| $code = $request->getStr('totpcode'); | $code = $request->getStr('totpcode'); | ||||
| ▲ Show 20 Lines • Show All 238 Lines • Show Last 20 Lines | |||||