Move all account link / unlink to new registration flow
Summary: Ref T1536. Currently, we have separate panels for each link/unlink and separate controllers for OAuth vs LDAP. Instead, provide a single "External Accounts" panel which shows all linked accounts and allows you to link/unlink more easily. Move link/unlink over to a full externalaccount-based workflow. Test Plan: - Linked and unlinked OAuth accounts. - Linked and unlinked LDAP accounts. - Registered new accounts. - Exercised most/all of the error cases. Reviewers: btrahan, chad Reviewed By: btrahan CC: aran, mbishopim3 Maniphest Tasks: T1536 Differential Revision: https://secure.phabricator.com/D6189
This commit is contained in:
@@ -29,6 +29,7 @@ abstract class PhabricatorAuthController extends PhabricatorController {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log a user into a web session and return an @{class:AphrontResponse} which
|
||||
* corresponds to continuing the login process.
|
||||
@@ -99,4 +100,108 @@ abstract class PhabricatorAuthController extends PhabricatorController {
|
||||
));
|
||||
}
|
||||
|
||||
protected function loadAccountForRegistrationOrLinking($account_key) {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$account = null;
|
||||
$provider = null;
|
||||
$response = null;
|
||||
|
||||
if (!$account_key) {
|
||||
$response = $this->renderError(
|
||||
pht('Request did not include account key.'));
|
||||
return array($account, $provider, $response);
|
||||
}
|
||||
|
||||
$account = id(new PhabricatorExternalAccount())->loadOneWhere(
|
||||
'accountSecret = %s',
|
||||
$account_key);
|
||||
if (!$account) {
|
||||
$response = $this->renderError(pht('No valid linkable account.'));
|
||||
return array($account, $provider, $response);
|
||||
}
|
||||
|
||||
if ($account->getUserPHID()) {
|
||||
if ($account->getUserPHID() != $viewer->getUserPHID()) {
|
||||
$response = $this->renderError(
|
||||
pht(
|
||||
'The account you are attempting to register or link is already '.
|
||||
'linked to another user.'));
|
||||
} else {
|
||||
$response = $this->renderError(
|
||||
pht(
|
||||
'The account you are attempting to link is already linked '.
|
||||
'to your account.'));
|
||||
}
|
||||
return array($account, $provider, $response);
|
||||
}
|
||||
|
||||
$registration_key = $request->getCookie('phreg');
|
||||
|
||||
// NOTE: This registration key check is not strictly necessary, because
|
||||
// we're only creating new accounts, not linking existing accounts. It
|
||||
// might be more hassle than it is worth, especially for email.
|
||||
//
|
||||
// The attack this prevents is getting to the registration screen, then
|
||||
// copy/pasting the URL and getting someone else to click it and complete
|
||||
// the process. They end up with an account bound to credentials you
|
||||
// control. This doesn't really let you do anything meaningful, though,
|
||||
// since you could have simply completed the process yourself.
|
||||
|
||||
if (!$registration_key) {
|
||||
$response = $this->renderError(
|
||||
pht(
|
||||
'Your browser did not submit a registration key with the request. '.
|
||||
'You must use the same browser to begin and complete registration. '.
|
||||
'Check that cookies are enabled and try again.'));
|
||||
return array($account, $provider, $response);
|
||||
}
|
||||
|
||||
// We store the digest of the key rather than the key itself to prevent a
|
||||
// theoretical attacker with read-only access to the database from
|
||||
// hijacking registration sessions.
|
||||
|
||||
$actual = $account->getProperty('registrationKey');
|
||||
$expect = PhabricatorHash::digest($registration_key);
|
||||
if ($actual !== $expect) {
|
||||
$response = $this->renderError(
|
||||
pht(
|
||||
'Your browser submitted a different registration key than the one '.
|
||||
'associated with this account. You may need to clear your cookies.'));
|
||||
return array($account, $provider, $response);
|
||||
}
|
||||
|
||||
$other_account = id(new PhabricatorExternalAccount())->loadAllWhere(
|
||||
'accountType = %s AND accountDomain = %s AND accountID = %s
|
||||
AND id != %d',
|
||||
$account->getAccountType(),
|
||||
$account->getAccountDomain(),
|
||||
$account->getAccountID(),
|
||||
$account->getID());
|
||||
|
||||
if ($other_account) {
|
||||
$response = $this->renderError(
|
||||
pht(
|
||||
'The account you are attempting to register with already belongs '.
|
||||
'to another user.'));
|
||||
return array($account, $provider, $response);
|
||||
}
|
||||
|
||||
$provider = PhabricatorAuthProvider::getEnabledProviderByKey(
|
||||
$account->getProviderKey());
|
||||
|
||||
if (!$provider) {
|
||||
$response = $this->renderError(
|
||||
pht(
|
||||
'The account you are attempting to register with uses a nonexistent '.
|
||||
'or disabled authentication provider (with key "%s"). An '.
|
||||
'administrator may have recently disabled this provider.',
|
||||
$account->getProviderKey()));
|
||||
return array($account, $provider, $response);
|
||||
}
|
||||
|
||||
return array($account, $provider, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user