mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 06:42:42 +01:00
Make external account identifier APIs return multiple identifiers
Summary: Depends on D21012. Ref T13493. Currently, auth adapters return a single identifier for each external account. Allow them to return more than one identifier, to better handle cases where an API changes from providing a lower-quality identifier to a higher-quality identifier. On its own, this change doesn't change any user-facing behavior. Test Plan: Linked and unlinked external accounts. Maniphest Tasks: T13493 Differential Revision: https://secure.phabricator.com/D21013
This commit is contained in:
parent
4094624828
commit
e43ecad8af
6 changed files with 62 additions and 41 deletions
|
@ -34,6 +34,11 @@ abstract class PhutilAuthAdapter extends Phobject {
|
|||
return $identifiers;
|
||||
}
|
||||
|
||||
final protected function newAccountIdentifier($raw_identifier) {
|
||||
return id(new PhabricatorExternalAccountIdentifier())
|
||||
->setIdentifierRaw($raw_identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a unique identifier associated with the account.
|
||||
*
|
||||
|
|
|
@ -56,9 +56,12 @@ final class PhabricatorAuthManagementLDAPWorkflow
|
|||
$console->writeOut("\n");
|
||||
$console->writeOut("%s\n", pht('Connecting to LDAP...'));
|
||||
|
||||
$account_id = $adapter->getAccountID();
|
||||
if ($account_id) {
|
||||
$console->writeOut("%s\n", pht('Found LDAP Account: %s', $account_id));
|
||||
$account_ids = $adapter->getAccountIdentifiers();
|
||||
if ($account_ids) {
|
||||
$value_list = mpull($account_ids, 'getIdentifierRaw');
|
||||
$value_list = implode(', ', $value_list);
|
||||
|
||||
$console->writeOut("%s\n", pht('Found LDAP Account: %s', $value_list));
|
||||
} else {
|
||||
$console->writeOut("%s\n", pht('Unable to find LDAP account!'));
|
||||
}
|
||||
|
|
|
@ -190,39 +190,51 @@ abstract class PhabricatorAuthProvider extends Phobject {
|
|||
return;
|
||||
}
|
||||
|
||||
protected function loadOrCreateAccount($account_id) {
|
||||
if (!strlen($account_id)) {
|
||||
throw new Exception(pht('Empty account ID!'));
|
||||
protected function loadOrCreateAccount(array $identifiers) {
|
||||
assert_instances_of($identifiers, 'PhabricatorExternalAccountIdentifier');
|
||||
|
||||
if (!$identifiers) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Authentication provider (of class "%s") is attempting to '.
|
||||
'load or create an external account, but provided no account '.
|
||||
'identifiers.',
|
||||
get_class($this)));
|
||||
}
|
||||
|
||||
if (count($identifiers) !== 1) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Unexpected number of account identifiers returned (by class "%s").',
|
||||
get_class($this)));
|
||||
}
|
||||
|
||||
$config = $this->getProviderConfig();
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
|
||||
$raw_identifiers = mpull($identifiers, 'getIdentifierRaw');
|
||||
|
||||
$accounts = id(new PhabricatorExternalAccountQuery())
|
||||
->setViewer($viewer)
|
||||
->withProviderConfigPHIDs(array($config->getPHID()))
|
||||
->withAccountIDs($raw_identifiers)
|
||||
->execute();
|
||||
if (!$accounts) {
|
||||
$account = $this->newExternalAccount()
|
||||
->setAccountID(head($raw_identifiers));
|
||||
} else if (count($accounts) === 1) {
|
||||
$account = head($accounts);
|
||||
} else {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Authentication provider (of class "%s") is attempting to load '.
|
||||
'or create an external account, but provided a list of '.
|
||||
'account identifiers which map to more than one account: %s.',
|
||||
get_class($this),
|
||||
implode(', ', $raw_identifiers)));
|
||||
}
|
||||
|
||||
$adapter = $this->getAdapter();
|
||||
$adapter_class = get_class($adapter);
|
||||
|
||||
if (!strlen($adapter->getAdapterType())) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
"AuthAdapter (of class '%s') has an invalid implementation: ".
|
||||
"no adapter type.",
|
||||
$adapter_class));
|
||||
}
|
||||
|
||||
if (!strlen($adapter->getAdapterDomain())) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
"AuthAdapter (of class '%s') has an invalid implementation: ".
|
||||
"no adapter domain.",
|
||||
$adapter_class));
|
||||
}
|
||||
|
||||
$account = id(new PhabricatorExternalAccount())->loadOneWhere(
|
||||
'accountType = %s AND accountDomain = %s AND accountID = %s',
|
||||
$adapter->getAdapterType(),
|
||||
$adapter->getAdapterDomain(),
|
||||
$account_id);
|
||||
if (!$account) {
|
||||
$account = $this->newExternalAccount()
|
||||
->setAccountID($account_id);
|
||||
}
|
||||
|
||||
$account->setUsername($adapter->getAccountName());
|
||||
$account->setRealName($adapter->getAccountRealName());
|
||||
|
@ -240,6 +252,7 @@ abstract class PhabricatorAuthProvider extends Phobject {
|
|||
// file entry for it, but there's no convenient way to do this with
|
||||
// PhabricatorFile right now. The storage will get shared, so the impact
|
||||
// here is negligible.
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
$image_file = PhabricatorFile::newFromFileDownload(
|
||||
$image_uri,
|
||||
|
|
|
@ -164,7 +164,7 @@ final class PhabricatorLDAPAuthProvider extends PhabricatorAuthProvider {
|
|||
// See T3351.
|
||||
|
||||
DarkConsoleErrorLogPluginAPI::enableDiscardMode();
|
||||
$account_id = $adapter->getAccountID();
|
||||
$identifiers = $adapter->getAccountIdentifiers();
|
||||
DarkConsoleErrorLogPluginAPI::disableDiscardMode();
|
||||
} else {
|
||||
throw new Exception(pht('Username and password are required!'));
|
||||
|
@ -180,7 +180,7 @@ final class PhabricatorLDAPAuthProvider extends PhabricatorAuthProvider {
|
|||
}
|
||||
}
|
||||
|
||||
return array($this->loadOrCreateAccount($account_id), $response);
|
||||
return array($this->loadOrCreateAccount($identifiers), $response);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -100,13 +100,13 @@ abstract class PhabricatorOAuth1AuthProvider
|
|||
// an access token.
|
||||
|
||||
try {
|
||||
$account_id = $adapter->getAccountID();
|
||||
$identifiers = $adapter->getAccountIdentifiers();
|
||||
} catch (Exception $ex) {
|
||||
// TODO: Handle this in a more user-friendly way.
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
if (!strlen($account_id)) {
|
||||
if (!$identifiers) {
|
||||
$response = $controller->buildProviderErrorResponse(
|
||||
$this,
|
||||
pht(
|
||||
|
@ -115,7 +115,7 @@ abstract class PhabricatorOAuth1AuthProvider
|
|||
return array($account, $response);
|
||||
}
|
||||
|
||||
return array($this->loadOrCreateAccount($account_id), $response);
|
||||
return array($this->loadOrCreateAccount($identifiers), $response);
|
||||
}
|
||||
|
||||
public function processEditForm(
|
||||
|
|
|
@ -80,13 +80,13 @@ abstract class PhabricatorOAuth2AuthProvider
|
|||
// an access token.
|
||||
|
||||
try {
|
||||
$account_id = $adapter->getAccountID();
|
||||
$identifiers = $adapter->getAccountIdentifiers();
|
||||
} catch (Exception $ex) {
|
||||
// TODO: Handle this in a more user-friendly way.
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
if (!strlen($account_id)) {
|
||||
if (!$identifiers) {
|
||||
$response = $controller->buildProviderErrorResponse(
|
||||
$this,
|
||||
pht(
|
||||
|
@ -95,7 +95,7 @@ abstract class PhabricatorOAuth2AuthProvider
|
|||
return array($account, $response);
|
||||
}
|
||||
|
||||
return array($this->loadOrCreateAccount($account_id), $response);
|
||||
return array($this->loadOrCreateAccount($identifiers), $response);
|
||||
}
|
||||
|
||||
public function processEditForm(
|
||||
|
|
Loading…
Reference in a new issue