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; | |||||
| } | |||||
| } | } | ||||