mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +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;
|
return $identifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final protected function newAccountIdentifier($raw_identifier) {
|
||||||
|
return id(new PhabricatorExternalAccountIdentifier())
|
||||||
|
->setIdentifierRaw($raw_identifier);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a unique identifier associated with the account.
|
* Get a unique identifier associated with the account.
|
||||||
*
|
*
|
||||||
|
|
|
@ -56,9 +56,12 @@ final class PhabricatorAuthManagementLDAPWorkflow
|
||||||
$console->writeOut("\n");
|
$console->writeOut("\n");
|
||||||
$console->writeOut("%s\n", pht('Connecting to LDAP...'));
|
$console->writeOut("%s\n", pht('Connecting to LDAP...'));
|
||||||
|
|
||||||
$account_id = $adapter->getAccountID();
|
$account_ids = $adapter->getAccountIdentifiers();
|
||||||
if ($account_id) {
|
if ($account_ids) {
|
||||||
$console->writeOut("%s\n", pht('Found LDAP Account: %s', $account_id));
|
$value_list = mpull($account_ids, 'getIdentifierRaw');
|
||||||
|
$value_list = implode(', ', $value_list);
|
||||||
|
|
||||||
|
$console->writeOut("%s\n", pht('Found LDAP Account: %s', $value_list));
|
||||||
} else {
|
} else {
|
||||||
$console->writeOut("%s\n", pht('Unable to find LDAP account!'));
|
$console->writeOut("%s\n", pht('Unable to find LDAP account!'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,39 +190,51 @@ abstract class PhabricatorAuthProvider extends Phobject {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadOrCreateAccount($account_id) {
|
protected function loadOrCreateAccount(array $identifiers) {
|
||||||
if (!strlen($account_id)) {
|
assert_instances_of($identifiers, 'PhabricatorExternalAccountIdentifier');
|
||||||
throw new Exception(pht('Empty account ID!'));
|
|
||||||
|
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 = $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->setUsername($adapter->getAccountName());
|
||||||
$account->setRealName($adapter->getAccountRealName());
|
$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
|
// 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
|
// PhabricatorFile right now. The storage will get shared, so the impact
|
||||||
// here is negligible.
|
// here is negligible.
|
||||||
|
|
||||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||||
$image_file = PhabricatorFile::newFromFileDownload(
|
$image_file = PhabricatorFile::newFromFileDownload(
|
||||||
$image_uri,
|
$image_uri,
|
||||||
|
|
|
@ -164,7 +164,7 @@ final class PhabricatorLDAPAuthProvider extends PhabricatorAuthProvider {
|
||||||
// See T3351.
|
// See T3351.
|
||||||
|
|
||||||
DarkConsoleErrorLogPluginAPI::enableDiscardMode();
|
DarkConsoleErrorLogPluginAPI::enableDiscardMode();
|
||||||
$account_id = $adapter->getAccountID();
|
$identifiers = $adapter->getAccountIdentifiers();
|
||||||
DarkConsoleErrorLogPluginAPI::disableDiscardMode();
|
DarkConsoleErrorLogPluginAPI::disableDiscardMode();
|
||||||
} else {
|
} else {
|
||||||
throw new Exception(pht('Username and password are required!'));
|
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.
|
// an access token.
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$account_id = $adapter->getAccountID();
|
$identifiers = $adapter->getAccountIdentifiers();
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
// TODO: Handle this in a more user-friendly way.
|
// TODO: Handle this in a more user-friendly way.
|
||||||
throw $ex;
|
throw $ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strlen($account_id)) {
|
if (!$identifiers) {
|
||||||
$response = $controller->buildProviderErrorResponse(
|
$response = $controller->buildProviderErrorResponse(
|
||||||
$this,
|
$this,
|
||||||
pht(
|
pht(
|
||||||
|
@ -115,7 +115,7 @@ abstract class PhabricatorOAuth1AuthProvider
|
||||||
return array($account, $response);
|
return array($account, $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return array($this->loadOrCreateAccount($account_id), $response);
|
return array($this->loadOrCreateAccount($identifiers), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processEditForm(
|
public function processEditForm(
|
||||||
|
|
|
@ -80,13 +80,13 @@ abstract class PhabricatorOAuth2AuthProvider
|
||||||
// an access token.
|
// an access token.
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$account_id = $adapter->getAccountID();
|
$identifiers = $adapter->getAccountIdentifiers();
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
// TODO: Handle this in a more user-friendly way.
|
// TODO: Handle this in a more user-friendly way.
|
||||||
throw $ex;
|
throw $ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strlen($account_id)) {
|
if (!$identifiers) {
|
||||||
$response = $controller->buildProviderErrorResponse(
|
$response = $controller->buildProviderErrorResponse(
|
||||||
$this,
|
$this,
|
||||||
pht(
|
pht(
|
||||||
|
@ -95,7 +95,7 @@ abstract class PhabricatorOAuth2AuthProvider
|
||||||
return array($account, $response);
|
return array($account, $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return array($this->loadOrCreateAccount($account_id), $response);
|
return array($this->loadOrCreateAccount($identifiers), $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processEditForm(
|
public function processEditForm(
|
||||||
|
|
Loading…
Reference in a new issue