Differential D20120 Diff 48132 src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/auth/controller/PhabricatorAuthOneTimeLoginController.php
<?php | <?php | ||||
final class PhabricatorAuthOneTimeLoginController | final class PhabricatorAuthOneTimeLoginController | ||||
extends PhabricatorAuthController { | extends PhabricatorAuthController { | ||||
public function shouldRequireLogin() { | public function shouldRequireLogin() { | ||||
return false; | return false; | ||||
} | } | ||||
public function handleRequest(AphrontRequest $request) { | public function handleRequest(AphrontRequest $request) { | ||||
$viewer = $this->getViewer(); | $viewer = $this->getViewer(); | ||||
$id = $request->getURIData('id'); | $id = $request->getURIData('id'); | ||||
$link_type = $request->getURIData('type'); | $link_type = $request->getURIData('type'); | ||||
$key = $request->getURIData('key'); | $key = $request->getURIData('key'); | ||||
$email_id = $request->getURIData('emailID'); | $email_id = $request->getURIData('emailID'); | ||||
if ($request->getUser()->isLoggedIn()) { | |||||
return $this->renderError( | |||||
pht('You are already logged in.')); | |||||
} | |||||
$target_user = id(new PhabricatorPeopleQuery()) | $target_user = id(new PhabricatorPeopleQuery()) | ||||
->setViewer(PhabricatorUser::getOmnipotentUser()) | ->setViewer(PhabricatorUser::getOmnipotentUser()) | ||||
->withIDs(array($id)) | ->withIDs(array($id)) | ||||
->executeOne(); | ->executeOne(); | ||||
if (!$target_user) { | if (!$target_user) { | ||||
return new Aphront404Response(); | return new Aphront404Response(); | ||||
} | } | ||||
// NOTE: We allow you to use a one-time login link for your own current | |||||
// login account. This supports the "Set Password" flow. | |||||
$is_logged_in = false; | |||||
if ($viewer->isLoggedIn()) { | |||||
if ($viewer->getPHID() !== $target_user->getPHID()) { | |||||
return $this->renderError( | |||||
pht('You are already logged in.')); | |||||
} else { | |||||
$is_logged_in = true; | |||||
} | |||||
} | |||||
// NOTE: As a convenience to users, these one-time login URIs may also | // NOTE: As a convenience to users, these one-time login URIs may also | ||||
// be associated with an email address which will be verified when the | // be associated with an email address which will be verified when the | ||||
// URI is used. | // URI is used. | ||||
// This improves the new user experience for users receiving "Welcome" | // This improves the new user experience for users receiving "Welcome" | ||||
// emails on installs that require verification: if we did not verify the | // emails on installs that require verification: if we did not verify the | ||||
// email, they'd immediately get roadblocked with a "Verify Your Email" | // email, they'd immediately get roadblocked with a "Verify Your Email" | ||||
// error and have to go back to their email account, wait for a | // error and have to go back to their email account, wait for a | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (!$target_user->canEstablishWebSessions()) { | ||||
$target_user->getUsername())) | $target_user->getUsername())) | ||||
->appendParagraph( | ->appendParagraph( | ||||
pht( | pht( | ||||
'Special users like daemons and mailing lists are not permitted '. | 'Special users like daemons and mailing lists are not permitted '. | ||||
'to log in via the web. Log in as a normal user instead.')) | 'to log in via the web. Log in as a normal user instead.')) | ||||
->addCancelButton('/'); | ->addCancelButton('/'); | ||||
} | } | ||||
if ($request->isFormPost()) { | if ($request->isFormPost() || $is_logged_in) { | ||||
// If we have an email bound into this URI, verify email so that clicking | // If we have an email bound into this URI, verify email so that clicking | ||||
// the link in the "Welcome" email is good enough, without requiring users | // the link in the "Welcome" email is good enough, without requiring users | ||||
// to go through a second round of email verification. | // to go through a second round of email verification. | ||||
$editor = id(new PhabricatorUserEditor()) | $editor = id(new PhabricatorUserEditor()) | ||||
->setActor($target_user); | ->setActor($target_user); | ||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); | $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); | ||||
// Nuke the token and all other outstanding password reset tokens. | // Nuke the token and all other outstanding password reset tokens. | ||||
// There is no particular security benefit to destroying them all, but | // There is no particular security benefit to destroying them all, but | ||||
// it should reduce HackerOne reports of nebulous harm. | // it should reduce HackerOne reports of nebulous harm. | ||||
$editor->revokePasswordResetLinks($target_user); | $editor->revokePasswordResetLinks($target_user); | ||||
if ($target_email) { | if ($target_email) { | ||||
$editor->verifyEmail($target_user, $target_email); | $editor->verifyEmail($target_user, $target_email); | ||||
} | } | ||||
unset($unguarded); | unset($unguarded); | ||||
$next_uri = $this->getNextStepURI($target_user); | $next_uri = $this->getNextStepURI($target_user); | ||||
// If the user is already logged in, we're just doing a "password set" | |||||
// flow. Skip directly to the next step. | |||||
if ($is_logged_in) { | |||||
return id(new AphrontRedirectResponse())->setURI($next_uri); | |||||
} | |||||
PhabricatorCookies::setNextURICookie($request, $next_uri, $force = true); | PhabricatorCookies::setNextURICookie($request, $next_uri, $force = true); | ||||
$force_full_session = false; | $force_full_session = false; | ||||
if ($link_type === PhabricatorAuthSessionEngine::ONETIME_RECOVER) { | if ($link_type === PhabricatorAuthSessionEngine::ONETIME_RECOVER) { | ||||
$force_full_session = $token->getShouldForceFullSession(); | $force_full_session = $token->getShouldForceFullSession(); | ||||
} | } | ||||
return $this->loginUser($target_user, $force_full_session); | return $this->loginUser($target_user, $force_full_session); | ||||
▲ Show 20 Lines • Show All 102 Lines • Show Last 20 Lines |