Changeset View
Changeset View
Standalone View
Standalone View
src/applications/auth/engine/PhabricatorAuthSessionEngine.php
| Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | final class PhabricatorAuthSessionEngine extends Phobject { | ||||
| const ONETIME_RECOVER = 'recover'; | const ONETIME_RECOVER = 'recover'; | ||||
| const ONETIME_RESET = 'reset'; | const ONETIME_RESET = 'reset'; | ||||
| const ONETIME_WELCOME = 'welcome'; | const ONETIME_WELCOME = 'welcome'; | ||||
| const ONETIME_USERNAME = 'rename'; | const ONETIME_USERNAME = 'rename'; | ||||
| private $workflowKey; | private $workflowKey; | ||||
| private $request; | |||||
| public function setWorkflowKey($workflow_key) { | public function setWorkflowKey($workflow_key) { | ||||
| $this->workflowKey = $workflow_key; | $this->workflowKey = $workflow_key; | ||||
| return $this; | return $this; | ||||
| } | } | ||||
| public function getWorkflowKey() { | public function getWorkflowKey() { | ||||
| // TODO: A workflow key should become required in order to issue an MFA | // TODO: A workflow key should become required in order to issue an MFA | ||||
| // challenge, but allow things to keep working for now until we can update | // challenge, but allow things to keep working for now until we can update | ||||
| // callsites. | // callsites. | ||||
| if ($this->workflowKey === null) { | if ($this->workflowKey === null) { | ||||
| return 'legacy'; | return 'legacy'; | ||||
| } | } | ||||
| return $this->workflowKey; | return $this->workflowKey; | ||||
| } | } | ||||
| public function getRequest() { | |||||
| return $this->request; | |||||
| } | |||||
| /** | /** | ||||
| * Get the session kind (e.g., anonymous, user, external account) from a | * Get the session kind (e.g., anonymous, user, external account) from a | ||||
| * session token. Returns a `KIND_` constant. | * session token. Returns a `KIND_` constant. | ||||
| * | * | ||||
| * @param string Session token. | * @param string Session token. | ||||
| * @return const Session kind constant. | * @return const Session kind constant. | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 399 Lines • ▼ Show 20 Lines | private function newHighSecurityToken( | ||||
| // without putting the session into high security mode. This is generally | // without putting the session into high security mode. This is generally | ||||
| // easier for users. A minor but desirable side effect is that when a user | // easier for users. A minor but desirable side effect is that when a user | ||||
| // adds an auth factor, existing sessions won't get a free pass into hisec, | // adds an auth factor, existing sessions won't get a free pass into hisec, | ||||
| // since they never actually got marked as hisec. | // since they never actually got marked as hisec. | ||||
| if (!$factors) { | if (!$factors) { | ||||
| return $this->issueHighSecurityToken($session, true); | return $this->issueHighSecurityToken($session, true); | ||||
| } | } | ||||
| $this->request = $request; | |||||
| foreach ($factors as $factor) { | foreach ($factors as $factor) { | ||||
| $factor->setSessionEngine($this); | $factor->setSessionEngine($this); | ||||
| } | } | ||||
| // Check for a rate limit without awarding points, so the user doesn't | // Check for a rate limit without awarding points, so the user doesn't | ||||
| // get partway through the workflow only to get blocked. | // get partway through the workflow only to get blocked. | ||||
| PhabricatorSystemActionEngine::willTakeAction( | PhabricatorSystemActionEngine::willTakeAction( | ||||
| array($viewer->getPHID()), | array($viewer->getPHID()), | ||||
| Show All 27 Lines | private function newHighSecurityToken( | ||||
| // prevents you from receiving or responding to a TOTP challenge if another | // prevents you from receiving or responding to a TOTP challenge if another | ||||
| // challenge was recently issued to a different session. | // challenge was recently issued to a different session. | ||||
| foreach ($factors as $factor) { | foreach ($factors as $factor) { | ||||
| $factor_phid = $factor->getPHID(); | $factor_phid = $factor->getPHID(); | ||||
| $issued_challenges = idx($challenge_map, $factor_phid, array()); | $issued_challenges = idx($challenge_map, $factor_phid, array()); | ||||
| $provider = $factor->getFactorProvider(); | $provider = $factor->getFactorProvider(); | ||||
| $impl = $provider->getFactor(); | $impl = $provider->getFactor(); | ||||
| try { | |||||
| $new_challenges = $impl->getNewIssuedChallenges( | $new_challenges = $impl->getNewIssuedChallenges( | ||||
| $factor, | $factor, | ||||
| $viewer, | $viewer, | ||||
| $issued_challenges); | $issued_challenges); | ||||
| } catch (PhabricatorAuthFactorResultException $ex) { | |||||
| $ok = false; | |||||
| $validation_results[$factor_phid] = $ex->getResult(); | |||||
| $challenge_map[$factor_phid] = $issued_challenges; | |||||
| continue; | |||||
| } | |||||
epriestley: Factors may now produce a result directly from the challenge step. This happens when… | |||||
| foreach ($new_challenges as $new_challenge) { | foreach ($new_challenges as $new_challenge) { | ||||
| $issued_challenges[] = $new_challenge; | $issued_challenges[] = $new_challenge; | ||||
| } | } | ||||
| $challenge_map[$factor_phid] = $issued_challenges; | $challenge_map[$factor_phid] = $issued_challenges; | ||||
| if (!$issued_challenges) { | if (!$issued_challenges) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| $result = $impl->getResultFromIssuedChallenges( | $result = $impl->getResultFromIssuedChallenges( | ||||
| $factor, | $factor, | ||||
| $viewer, | $viewer, | ||||
| $issued_challenges); | $issued_challenges); | ||||
| if (!$result) { | if (!$result) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (!$result->getIsValid()) { | |||||
| $ok = false; | $ok = false; | ||||
| } | |||||
| $validation_results[$factor_phid] = $result; | $validation_results[$factor_phid] = $result; | ||||
Done Inline ActionsIssuing challenges may now find an approval (Duo/push), so an early result doesn't necessarily mean a validity issue anymore. epriestley: Issuing challenges may now find an approval (Duo/push), so an early result doesn't necessarily… | |||||
| } | } | ||||
| if ($request->isHTTPPost()) { | if ($request->isHTTPPost()) { | ||||
| $request->validateCSRF(); | $request->validateCSRF(); | ||||
| if ($request->getExists(AphrontRequest::TYPE_HISEC)) { | if ($request->getExists(AphrontRequest::TYPE_HISEC)) { | ||||
| // Limit factor verification rates to prevent brute force attacks. | // Limit factor verification rates to prevent brute force attacks. | ||||
| $any_attempt = false; | $any_attempt = false; | ||||
| ▲ Show 20 Lines • Show All 570 Lines • Show Last 20 Lines | |||||
Factors may now produce a result directly from the challenge step. This happens when: