mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-09 22:31:03 +01:00
Add a "refresh" action for external accounts
Summary: Ref T1536. This is equivalent to logging out and logging back in again, but a bit less disruptive for users. For some providers (like Google), this may eventually do something different (Google has a "force" parameter which forces re-auth and is ostensibly required to refresh long-lived tokens). Broadly, this process fixes OAuth accounts with busted access tokens so we can do API stuff. For other accounts, it mostly just syncs profile pictures. Test Plan: Refreshed LDAP and Oauth accounts, linked OAuth accounts, hit error conditions. {F47390} {F47391} {F47392} {F47393} {F47394} {F47395} Reviewers: btrahan, chad Reviewed By: btrahan CC: aran Maniphest Tasks: T1536 Differential Revision: https://secure.phabricator.com/D6290
This commit is contained in:
parent
e826842179
commit
fe71b34c68
8 changed files with 108 additions and 22 deletions
|
@ -66,7 +66,8 @@ final class PhabricatorApplicationAuth extends PhabricatorApplication {
|
||||||
'start/' => 'PhabricatorAuthStartController',
|
'start/' => 'PhabricatorAuthStartController',
|
||||||
'validate/' => 'PhabricatorAuthValidateController',
|
'validate/' => 'PhabricatorAuthValidateController',
|
||||||
'unlink/(?P<pkey>[^/]+)/' => 'PhabricatorAuthUnlinkController',
|
'unlink/(?P<pkey>[^/]+)/' => 'PhabricatorAuthUnlinkController',
|
||||||
'link/(?P<pkey>[^/]+)/' => 'PhabricatorAuthLinkController',
|
'(?P<action>link|refresh)/(?P<pkey>[^/]+)/'
|
||||||
|
=> 'PhabricatorAuthLinkController',
|
||||||
'confirmlink/(?P<akey>[^/]+)/'
|
'confirmlink/(?P<akey>[^/]+)/'
|
||||||
=> 'PhabricatorAuthConfirmLinkController',
|
=> 'PhabricatorAuthConfirmLinkController',
|
||||||
),
|
),
|
||||||
|
|
|
@ -3,10 +3,12 @@
|
||||||
final class PhabricatorAuthLinkController
|
final class PhabricatorAuthLinkController
|
||||||
extends PhabricatorAuthController {
|
extends PhabricatorAuthController {
|
||||||
|
|
||||||
|
private $action;
|
||||||
private $providerKey;
|
private $providerKey;
|
||||||
|
|
||||||
public function willProcessRequest(array $data) {
|
public function willProcessRequest(array $data) {
|
||||||
$this->providerKey = $data['pkey'];
|
$this->providerKey = $data['pkey'];
|
||||||
|
$this->action = $data['action'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processRequest() {
|
public function processRequest() {
|
||||||
|
@ -19,6 +21,8 @@ final class PhabricatorAuthLinkController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch ($this->action) {
|
||||||
|
case 'link':
|
||||||
if (!$provider->shouldAllowAccountLink()) {
|
if (!$provider->shouldAllowAccountLink()) {
|
||||||
return $this->renderErrorPage(
|
return $this->renderErrorPage(
|
||||||
pht('Account Not Linkable'),
|
pht('Account Not Linkable'),
|
||||||
|
@ -26,12 +30,28 @@ final class PhabricatorAuthLinkController
|
||||||
pht('This provider is not configured to allow linking.'),
|
pht('This provider is not configured to allow linking.'),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 'refresh':
|
||||||
|
if (!$provider->shouldAllowAccountRefresh()) {
|
||||||
|
return $this->renderErrorPage(
|
||||||
|
pht('Account Not Refreshable'),
|
||||||
|
array(
|
||||||
|
pht('This provider does not allow refreshing.'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new Aphront400Response();
|
||||||
|
}
|
||||||
|
|
||||||
$account = id(new PhabricatorExternalAccount())->loadOneWhere(
|
$account = id(new PhabricatorExternalAccount())->loadOneWhere(
|
||||||
'accountType = %s AND accountDomain = %s AND userPHID = %s',
|
'accountType = %s AND accountDomain = %s AND userPHID = %s',
|
||||||
$provider->getProviderType(),
|
$provider->getProviderType(),
|
||||||
$provider->getProviderDomain(),
|
$provider->getProviderDomain(),
|
||||||
$viewer->getPHID());
|
$viewer->getPHID());
|
||||||
|
|
||||||
|
switch ($this->action) {
|
||||||
|
case 'link':
|
||||||
if ($account) {
|
if ($account) {
|
||||||
return $this->renderErrorPage(
|
return $this->renderErrorPage(
|
||||||
pht('Account Already Linked'),
|
pht('Account Already Linked'),
|
||||||
|
@ -41,11 +61,35 @@ final class PhabricatorAuthLinkController
|
||||||
'account for this provider.'),
|
'account for this provider.'),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 'refresh':
|
||||||
|
if (!$account) {
|
||||||
|
return $this->renderErrorPage(
|
||||||
|
pht('No Account Linked'),
|
||||||
|
array(
|
||||||
|
pht(
|
||||||
|
'You do not have a linked account on this provider, and thus '.
|
||||||
|
'can not refresh it.'),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new Aphront400Response();
|
||||||
|
}
|
||||||
|
|
||||||
$panel_uri = '/settings/panel/external/';
|
$panel_uri = '/settings/panel/external/';
|
||||||
|
|
||||||
$request->setCookie('phcid', Filesystem::readRandomCharacters(16));
|
$request->setCookie('phcid', Filesystem::readRandomCharacters(16));
|
||||||
|
switch ($this->action) {
|
||||||
|
case 'link':
|
||||||
$form = $provider->buildLinkForm($this);
|
$form = $provider->buildLinkForm($this);
|
||||||
|
break;
|
||||||
|
case 'refresh':
|
||||||
|
$form = $provider->buildRefreshForm($this);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new Aphront400Response();
|
||||||
|
}
|
||||||
|
|
||||||
if ($provider->isLoginFormAButton()) {
|
if ($provider->isLoginFormAButton()) {
|
||||||
require_celerity_resource('auth-css');
|
require_celerity_resource('auth-css');
|
||||||
|
@ -57,6 +101,19 @@ final class PhabricatorAuthLinkController
|
||||||
$form);
|
$form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch ($this->action) {
|
||||||
|
case 'link':
|
||||||
|
$name = pht('Link Account');
|
||||||
|
$title = pht('Link %s Account', $provider->getProviderName());
|
||||||
|
break;
|
||||||
|
case 'refresh':
|
||||||
|
$name = pht('Refresh Account');
|
||||||
|
$title = pht('Refresh %s Account', $provider->getProviderName());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return new Aphront400Response();
|
||||||
|
}
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs();
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
$crumbs->addCrumb(
|
$crumbs->addCrumb(
|
||||||
id(new PhabricatorCrumbView())
|
id(new PhabricatorCrumbView())
|
||||||
|
@ -64,7 +121,7 @@ final class PhabricatorAuthLinkController
|
||||||
->setHref($panel_uri));
|
->setHref($panel_uri));
|
||||||
$crumbs->addCrumb(
|
$crumbs->addCrumb(
|
||||||
id(new PhabricatorCrumbView())
|
id(new PhabricatorCrumbView())
|
||||||
->setName($provider->getProviderName()));
|
->setName($provider->getProviderName($name)));
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
return $this->buildApplicationPage(
|
||||||
array(
|
array(
|
||||||
|
@ -72,7 +129,7 @@ final class PhabricatorAuthLinkController
|
||||||
$form,
|
$form,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'title' => pht('Link %s Account', $provider->getProviderName()),
|
'title' => $title,
|
||||||
'dust' => true,
|
'dust' => true,
|
||||||
'device' => true,
|
'device' => true,
|
||||||
));
|
));
|
||||||
|
|
|
@ -50,10 +50,11 @@ final class PhabricatorAuthLoginController
|
||||||
$provider->getProviderName()));
|
$provider->getProviderName()));
|
||||||
}
|
}
|
||||||
} else if ($viewer->getPHID() == $account->getUserPHID()) {
|
} else if ($viewer->getPHID() == $account->getUserPHID()) {
|
||||||
return $this->renderError(
|
// This is either an attempt to re-link an existing and already
|
||||||
pht(
|
// linked account (which is silly) or a refresh of an external account
|
||||||
'This external account ("%s") is already linked to your '.
|
// (e.g., an OAuth account).
|
||||||
'Phabricator account.'));
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI('/settings/panel/external/');
|
||||||
} else {
|
} else {
|
||||||
return $this->renderError(
|
return $this->renderError(
|
||||||
pht(
|
pht(
|
||||||
|
|
|
@ -154,6 +154,15 @@ abstract class PhabricatorAuthProvider {
|
||||||
return $this->renderLoginForm($controller->getRequest(), $mode = 'link');
|
return $this->renderLoginForm($controller->getRequest(), $mode = 'link');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAllowAccountRefresh() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildRefreshForm(
|
||||||
|
PhabricatorAuthLinkController $controller) {
|
||||||
|
return $this->renderLoginForm($controller->getRequest(), $mode = 'refresh');
|
||||||
|
}
|
||||||
|
|
||||||
protected function renderLoginForm(
|
protected function renderLoginForm(
|
||||||
AphrontRequest $request,
|
AphrontRequest $request,
|
||||||
$mode) {
|
$mode) {
|
||||||
|
|
|
@ -68,6 +68,10 @@ final class PhabricatorAuthProviderLDAP
|
||||||
$dialog->setTitle(pht('Link LDAP Account'));
|
$dialog->setTitle(pht('Link LDAP Account'));
|
||||||
$dialog->addSubmitButton(pht('Link Accounts'));
|
$dialog->addSubmitButton(pht('Link Accounts'));
|
||||||
$dialog->addCancelButton($this->getSettingsURI());
|
$dialog->addCancelButton($this->getSettingsURI());
|
||||||
|
} else if ($mode == 'refresh') {
|
||||||
|
$dialog->setTitle(pht('Refresh LDAP Account'));
|
||||||
|
$dialog->addSubmitButton(pht('Refresh Account'));
|
||||||
|
$dialog->addCancelButton($this->getSettingsURI());
|
||||||
} else {
|
} else {
|
||||||
if ($this->shouldAllowRegistration()) {
|
if ($this->shouldAllowRegistration()) {
|
||||||
$dialog->setTitle(pht('Login or Register with LDAP'));
|
$dialog->setTitle(pht('Login or Register with LDAP'));
|
||||||
|
|
|
@ -38,6 +38,8 @@ abstract class PhabricatorAuthProviderOAuth extends PhabricatorAuthProvider {
|
||||||
|
|
||||||
if ($mode == 'link') {
|
if ($mode == 'link') {
|
||||||
$button_text = pht('Link External Account');
|
$button_text = pht('Link External Account');
|
||||||
|
} else if ($mode == 'refresh') {
|
||||||
|
$button_text = pht('Refresh Account Link');
|
||||||
} else if ($this->shouldAllowRegistration()) {
|
} else if ($this->shouldAllowRegistration()) {
|
||||||
$button_text = pht('Login or Register');
|
$button_text = pht('Login or Register');
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -246,4 +246,8 @@ final class PhabricatorAuthProviderPassword
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldAllowAccountRefresh() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,14 @@ final class PhabricatorSettingsPanelExternalAccounts
|
||||||
|
|
||||||
$can_unlink = $can_unlink && (!$can_login || ($login_accounts > 1));
|
$can_unlink = $can_unlink && (!$can_login || ($login_accounts > 1));
|
||||||
|
|
||||||
|
$can_refresh = $provider && $provider->shouldAllowAccountRefresh();
|
||||||
|
if ($can_refresh) {
|
||||||
|
$item->addAction(
|
||||||
|
id(new PHUIListItemView())
|
||||||
|
->setIcon('refresh')
|
||||||
|
->setHref('/auth/refresh/'.$account->getProviderKey().'/'));
|
||||||
|
}
|
||||||
|
|
||||||
$item->addAction(
|
$item->addAction(
|
||||||
id(new PHUIListItemView())
|
id(new PHUIListItemView())
|
||||||
->setIcon('delete')
|
->setIcon('delete')
|
||||||
|
|
Loading…
Reference in a new issue