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: