@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Allow "bin/auth recover" to generate a link which forces a full login session

Summary:
Depends on D19902. Ref T13222. This is mostly a "while I'm in here..." change since MFA is getting touched so much anyway.

Doing cluster support, I sometimes need to log into user accounts on instances that have MFA. I currently accomplish this by doing `bin/auth recover`, getting a parital session, and then forcing it into a full session in the database. This is inconvenient and somewhat dangerous.

Instead, allow `bin/auth recover` to generate a link that skips the "partial session" stage: adding required MFA, providing MFA, and signing legalpad documents.

Anyone who can run `bin/auth recover` can do this anyway, this just reduces the chance I accidentally bypass MFA on the wrong session when doing support stuff.

Test Plan:
- Logged in with `bin/auth recover`, was prompted for MFA.
- Logged in with `bin/auth recover --force-full-session`, was not prompted for MFA.
- Did a password reset, followed reset link, was prompted for MFA.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13222

Differential Revision: https://secure.phabricator.com/D19903

+44 -7
+11 -2
src/applications/auth/controller/PhabricatorAuthController.php
··· 45 45 * event and do something else if they prefer. 46 46 * 47 47 * @param PhabricatorUser User to log the viewer in as. 48 + * @param bool True to issue a full session immediately, bypassing MFA. 48 49 * @return AphrontResponse Response which continues the login process. 49 50 */ 50 - protected function loginUser(PhabricatorUser $user) { 51 + protected function loginUser( 52 + PhabricatorUser $user, 53 + $force_full_session = false) { 51 54 52 55 $response = $this->buildLoginValidateResponse($user); 53 56 $session_type = PhabricatorAuthSession::TYPE_WEB; ··· 66 69 67 70 $should_login = $event->getValue('shouldLogin'); 68 71 if ($should_login) { 72 + if ($force_full_session) { 73 + $partial_session = false; 74 + } else { 75 + $partial_session = true; 76 + } 77 + 69 78 $session_key = id(new PhabricatorAuthSessionEngine()) 70 - ->establishSession($session_type, $user->getPHID(), $partial = true); 79 + ->establishSession($session_type, $user->getPHID(), $partial_session); 71 80 72 81 // NOTE: We allow disabled users to login and roadblock them later, so 73 82 // there's no check for users being disabled here.
+6 -1
src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php
··· 152 152 153 153 PhabricatorCookies::setNextURICookie($request, $next, $force = true); 154 154 155 - return $this->loginUser($target_user); 155 + $force_full_session = false; 156 + if ($link_type === PhabricatorAuthSessionEngine::ONETIME_RECOVER) { 157 + $force_full_session = $token->getShouldForceFullSession(); 158 + } 159 + 160 + return $this->loginUser($target_user, $force_full_session); 156 161 } 157 162 158 163 // NOTE: We need to CSRF here so attackers can't generate an email link,
+6 -2
src/applications/auth/engine/PhabricatorAuthSessionEngine.php
··· 893 893 * link is used. 894 894 * @param string Optional context string for the URI. This is purely cosmetic 895 895 * and used only to customize workflow and error messages. 896 + * @param bool True to generate a URI which forces an immediate upgrade to 897 + * a full session, bypassing MFA and other login checks. 896 898 * @return string Login URI. 897 899 * @task onetime 898 900 */ 899 901 public function getOneTimeLoginURI( 900 902 PhabricatorUser $user, 901 903 PhabricatorUserEmail $email = null, 902 - $type = self::ONETIME_RESET) { 904 + $type = self::ONETIME_RESET, 905 + $force_full_session = false) { 903 906 904 907 $key = Filesystem::readRandomCharacters(32); 905 908 $key_hash = $this->getOneTimeLoginKeyHash($user, $email, $key); 906 909 $onetime_type = PhabricatorAuthOneTimeLoginTemporaryTokenType::TOKENTYPE; 907 910 908 911 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 909 - id(new PhabricatorAuthTemporaryToken()) 912 + $token = id(new PhabricatorAuthTemporaryToken()) 910 913 ->setTokenResource($user->getPHID()) 911 914 ->setTokenType($onetime_type) 912 915 ->setTokenExpires(time() + phutil_units('1 day in seconds')) 913 916 ->setTokenCode($key_hash) 917 + ->setShouldForceFullSession($force_full_session) 914 918 ->save(); 915 919 unset($unguarded); 916 920
+11 -2
src/applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php
··· 13 13 'of Phabricator.')) 14 14 ->setArguments( 15 15 array( 16 - 'username' => array( 16 + array( 17 + 'name' => 'force-full-session', 18 + 'help' => pht( 19 + 'Recover directly into a full session without requiring MFA '. 20 + 'or other login checks.'), 21 + ), 22 + array( 17 23 'name' => 'username', 18 24 'wildcard' => true, 19 25 ), ··· 54 60 $username)); 55 61 } 56 62 63 + $force_full_session = $args->getArg('force-full-session'); 64 + 57 65 $engine = new PhabricatorAuthSessionEngine(); 58 66 $onetime_uri = $engine->getOneTimeLoginURI( 59 67 $user, 60 68 null, 61 - PhabricatorAuthSessionEngine::ONETIME_RECOVER); 69 + PhabricatorAuthSessionEngine::ONETIME_RECOVER, 70 + $force_full_session); 62 71 63 72 $console = PhutilConsole::getConsole(); 64 73 $console->writeOut(
+10
src/applications/auth/storage/PhabricatorAuthTemporaryToken.php
··· 106 106 return $this; 107 107 } 108 108 109 + public function setShouldForceFullSession($force_full) { 110 + return $this->setTemporaryTokenProperty('force-full-session', $force_full); 111 + } 112 + 113 + public function getShouldForceFullSession() { 114 + return $this->getTemporaryTokenProperty('force-full-session', false); 115 + } 116 + 117 + 118 + 109 119 /* -( PhabricatorPolicyInterface )----------------------------------------- */ 110 120 111 121