Changeset View
Changeset View
Standalone View
Standalone View
src/applications/auth/factor/PhabricatorAuthFactor.php
Show All 27 Lines | public static function getAllFactors() { | ||||
return id(new PhutilClassMapQuery()) | return id(new PhutilClassMapQuery()) | ||||
->setAncestorClass(__CLASS__) | ->setAncestorClass(__CLASS__) | ||||
->setUniqueMethod('getFactorKey') | ->setUniqueMethod('getFactorKey') | ||||
->execute(); | ->execute(); | ||||
} | } | ||||
protected function newConfigForUser(PhabricatorUser $user) { | protected function newConfigForUser(PhabricatorUser $user) { | ||||
return id(new PhabricatorAuthFactorConfig()) | return id(new PhabricatorAuthFactorConfig()) | ||||
->setUserPHID($user->getPHID()); | ->setUserPHID($user->getPHID()) | ||||
->setFactorSecret(''); | |||||
} | } | ||||
protected function newResult() { | protected function newResult() { | ||||
return new PhabricatorAuthFactorResult(); | return new PhabricatorAuthFactorResult(); | ||||
} | } | ||||
public function newIconView() { | public function newIconView() { | ||||
return id(new PHUIIconView()) | return id(new PHUIIconView()) | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | abstract class PhabricatorAuthFactor extends Phobject { | ||||
final public function getNewIssuedChallenges( | final public function getNewIssuedChallenges( | ||||
PhabricatorAuthFactorConfig $config, | PhabricatorAuthFactorConfig $config, | ||||
PhabricatorUser $viewer, | PhabricatorUser $viewer, | ||||
array $challenges) { | array $challenges) { | ||||
assert_instances_of($challenges, 'PhabricatorAuthChallenge'); | assert_instances_of($challenges, 'PhabricatorAuthChallenge'); | ||||
$now = PhabricatorTime::getNow(); | $now = PhabricatorTime::getNow(); | ||||
// Factor implementations may need to perform writes in order to issue | |||||
// challenges, particularly push factors like SMS. | |||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); | |||||
$new_challenges = $this->newIssuedChallenges( | $new_challenges = $this->newIssuedChallenges( | ||||
$config, | $config, | ||||
$viewer, | $viewer, | ||||
$challenges); | $challenges); | ||||
assert_instances_of($new_challenges, 'PhabricatorAuthChallenge'); | assert_instances_of($new_challenges, 'PhabricatorAuthChallenge'); | ||||
foreach ($new_challenges as $new_challenge) { | foreach ($new_challenges as $new_challenge) { | ||||
$ttl = $new_challenge->getChallengeTTL(); | $ttl = $new_challenge->getChallengeTTL(); | ||||
if (!$ttl) { | if (!$ttl) { | ||||
throw new Exception( | throw new Exception( | ||||
pht('Newly issued MFA challenges must have a valid TTL!')); | pht('Newly issued MFA challenges must have a valid TTL!')); | ||||
} | } | ||||
if ($ttl < $now) { | if ($ttl < $now) { | ||||
throw new Exception( | throw new Exception( | ||||
pht( | pht( | ||||
'Newly issued MFA challenges must have a future TTL. This '. | 'Newly issued MFA challenges must have a future TTL. This '. | ||||
'factor issued a bad TTL ("%s"). (Did you use a relative '. | 'factor issued a bad TTL ("%s"). (Did you use a relative '. | ||||
'time instead of an epoch?)', | 'time instead of an epoch?)', | ||||
$ttl)); | $ttl)); | ||||
} | } | ||||
} | } | ||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); | |||||
foreach ($new_challenges as $challenge) { | foreach ($new_challenges as $challenge) { | ||||
$challenge->save(); | $challenge->save(); | ||||
} | } | ||||
unset($unguarded); | unset($unguarded); | ||||
return $new_challenges; | return $new_challenges; | ||||
} | } | ||||
abstract protected function newIssuedChallenges( | abstract protected function newIssuedChallenges( | ||||
PhabricatorAuthFactorConfig $config, | PhabricatorAuthFactorConfig $config, | ||||
PhabricatorUser $viewer, | PhabricatorUser $viewer, | ||||
▲ Show 20 Lines • Show All 200 Lines • ▼ Show 20 Lines | /* -( Synchronizing New Factors )------------------------------------------ */ | ||||
private function getMFASyncTokenFormKey() { | private function getMFASyncTokenFormKey() { | ||||
return 'sync.key'; | return 'sync.key'; | ||||
} | } | ||||
private function getMFASyncTokenTTL() { | private function getMFASyncTokenTTL() { | ||||
return phutil_units('1 hour in seconds'); | return phutil_units('1 hour in seconds'); | ||||
} | } | ||||
final protected function getChallengeForCurrentContext( | |||||
PhabricatorAuthFactorConfig $config, | |||||
PhabricatorUser $viewer, | |||||
array $challenges) { | |||||
$session_phid = $viewer->getSession()->getPHID(); | |||||
$engine = $config->getSessionEngine(); | |||||
$workflow_key = $engine->getWorkflowKey(); | |||||
foreach ($challenges as $challenge) { | |||||
if ($challenge->getSessionPHID() !== $session_phid) { | |||||
continue; | |||||
} | |||||
if ($challenge->getWorkflowKey() !== $workflow_key) { | |||||
continue; | |||||
} | |||||
if ($challenge->getIsCompleted()) { | |||||
continue; | |||||
} | |||||
if ($challenge->getIsReusedChallenge()) { | |||||
continue; | |||||
} | |||||
return $challenge; | |||||
} | |||||
return null; | |||||
} | |||||
} | } |