Add an "ExternalAccountIdentifier" table
Summary: Depends on D21010. Ref T13493. External accounts may have multiple different unique identifiers, most often when v1 of the API makes a questionable choice (and provies a mutable, non-unique, or PII identifier) and v2 of the API uses an immutable, unique, random identifier. Allow Phabricator to store multiple identifiers per external account. Test Plan: Storage only, see followup changes. Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam Maniphest Tasks: T13493 Differential Revision: https://secure.phabricator.com/D21011
This commit is contained in:
		
							
								
								
									
										10
									
								
								resources/sql/autopatches/20200220.xaccount.01.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								resources/sql/autopatches/20200220.xaccount.01.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | CREATE TABLE {$NAMESPACE}_user.user_externalaccountidentifier ( | ||||||
|  |   id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, | ||||||
|  |   phid VARBINARY(64) NOT NULL, | ||||||
|  |   externalAccountPHID VARBINARY(64) NOT NULL, | ||||||
|  |   providerConfigPHID VARBINARY(64) NOT NULL, | ||||||
|  |   identifierHash BINARY(12) NOT NULL, | ||||||
|  |   identifierRaw LONGTEXT NOT NULL, | ||||||
|  |   dateCreated INT UNSIGNED NOT NULL, | ||||||
|  |   dateModified INT UNSIGNED NOT NULL | ||||||
|  | ) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT}; | ||||||
| @@ -3318,6 +3318,8 @@ phutil_register_library_map(array( | |||||||
|     'PhabricatorExtendingPhabricatorConfigOptions' => 'applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php', |     'PhabricatorExtendingPhabricatorConfigOptions' => 'applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php', | ||||||
|     'PhabricatorExtensionsSetupCheck' => 'applications/config/check/PhabricatorExtensionsSetupCheck.php', |     'PhabricatorExtensionsSetupCheck' => 'applications/config/check/PhabricatorExtensionsSetupCheck.php', | ||||||
|     'PhabricatorExternalAccount' => 'applications/people/storage/PhabricatorExternalAccount.php', |     'PhabricatorExternalAccount' => 'applications/people/storage/PhabricatorExternalAccount.php', | ||||||
|  |     'PhabricatorExternalAccountIdentifier' => 'applications/people/storage/PhabricatorExternalAccountIdentifier.php', | ||||||
|  |     'PhabricatorExternalAccountIdentifierQuery' => 'applications/auth/query/PhabricatorExternalAccountIdentifierQuery.php', | ||||||
|     'PhabricatorExternalAccountQuery' => 'applications/auth/query/PhabricatorExternalAccountQuery.php', |     'PhabricatorExternalAccountQuery' => 'applications/auth/query/PhabricatorExternalAccountQuery.php', | ||||||
|     'PhabricatorExternalAccountsSettingsPanel' => 'applications/settings/panel/PhabricatorExternalAccountsSettingsPanel.php', |     'PhabricatorExternalAccountsSettingsPanel' => 'applications/settings/panel/PhabricatorExternalAccountsSettingsPanel.php', | ||||||
|     'PhabricatorExtraConfigSetupCheck' => 'applications/config/check/PhabricatorExtraConfigSetupCheck.php', |     'PhabricatorExtraConfigSetupCheck' => 'applications/config/check/PhabricatorExtraConfigSetupCheck.php', | ||||||
| @@ -4103,6 +4105,7 @@ phutil_register_library_map(array( | |||||||
|     'PhabricatorPeopleDisableController' => 'applications/people/controller/PhabricatorPeopleDisableController.php', |     'PhabricatorPeopleDisableController' => 'applications/people/controller/PhabricatorPeopleDisableController.php', | ||||||
|     'PhabricatorPeopleEmailLoginMailEngine' => 'applications/people/mail/PhabricatorPeopleEmailLoginMailEngine.php', |     'PhabricatorPeopleEmailLoginMailEngine' => 'applications/people/mail/PhabricatorPeopleEmailLoginMailEngine.php', | ||||||
|     'PhabricatorPeopleEmpowerController' => 'applications/people/controller/PhabricatorPeopleEmpowerController.php', |     'PhabricatorPeopleEmpowerController' => 'applications/people/controller/PhabricatorPeopleEmpowerController.php', | ||||||
|  |     'PhabricatorPeopleExternalIdentifierPHIDType' => 'applications/people/phid/PhabricatorPeopleExternalIdentifierPHIDType.php', | ||||||
|     'PhabricatorPeopleExternalPHIDType' => 'applications/people/phid/PhabricatorPeopleExternalPHIDType.php', |     'PhabricatorPeopleExternalPHIDType' => 'applications/people/phid/PhabricatorPeopleExternalPHIDType.php', | ||||||
|     'PhabricatorPeopleIconSet' => 'applications/people/icon/PhabricatorPeopleIconSet.php', |     'PhabricatorPeopleIconSet' => 'applications/people/icon/PhabricatorPeopleIconSet.php', | ||||||
|     'PhabricatorPeopleInviteController' => 'applications/people/controller/PhabricatorPeopleInviteController.php', |     'PhabricatorPeopleInviteController' => 'applications/people/controller/PhabricatorPeopleInviteController.php', | ||||||
| @@ -9763,6 +9766,11 @@ phutil_register_library_map(array( | |||||||
|       'PhabricatorUserDAO', |       'PhabricatorUserDAO', | ||||||
|       'PhabricatorPolicyInterface', |       'PhabricatorPolicyInterface', | ||||||
|     ), |     ), | ||||||
|  |     'PhabricatorExternalAccountIdentifier' => array( | ||||||
|  |       'PhabricatorUserDAO', | ||||||
|  |       'PhabricatorPolicyInterface', | ||||||
|  |     ), | ||||||
|  |     'PhabricatorExternalAccountIdentifierQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', | ||||||
|     'PhabricatorExternalAccountQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', |     'PhabricatorExternalAccountQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', | ||||||
|     'PhabricatorExternalAccountsSettingsPanel' => 'PhabricatorSettingsPanel', |     'PhabricatorExternalAccountsSettingsPanel' => 'PhabricatorSettingsPanel', | ||||||
|     'PhabricatorExtraConfigSetupCheck' => 'PhabricatorSetupCheck', |     'PhabricatorExtraConfigSetupCheck' => 'PhabricatorSetupCheck', | ||||||
| @@ -10681,6 +10689,7 @@ phutil_register_library_map(array( | |||||||
|     'PhabricatorPeopleDisableController' => 'PhabricatorPeopleController', |     'PhabricatorPeopleDisableController' => 'PhabricatorPeopleController', | ||||||
|     'PhabricatorPeopleEmailLoginMailEngine' => 'PhabricatorPeopleMailEngine', |     'PhabricatorPeopleEmailLoginMailEngine' => 'PhabricatorPeopleMailEngine', | ||||||
|     'PhabricatorPeopleEmpowerController' => 'PhabricatorPeopleController', |     'PhabricatorPeopleEmpowerController' => 'PhabricatorPeopleController', | ||||||
|  |     'PhabricatorPeopleExternalIdentifierPHIDType' => 'PhabricatorPHIDType', | ||||||
|     'PhabricatorPeopleExternalPHIDType' => 'PhabricatorPHIDType', |     'PhabricatorPeopleExternalPHIDType' => 'PhabricatorPHIDType', | ||||||
|     'PhabricatorPeopleIconSet' => 'PhabricatorIconSet', |     'PhabricatorPeopleIconSet' => 'PhabricatorIconSet', | ||||||
|     'PhabricatorPeopleInviteController' => 'PhabricatorPeopleController', |     'PhabricatorPeopleInviteController' => 'PhabricatorPeopleController', | ||||||
|   | |||||||
| @@ -0,0 +1,94 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | final class PhabricatorExternalAccountIdentifierQuery | ||||||
|  |   extends PhabricatorCursorPagedPolicyAwareQuery { | ||||||
|  |  | ||||||
|  |   private $ids; | ||||||
|  |   private $phids; | ||||||
|  |   private $providerConfigPHIDs; | ||||||
|  |   private $externalAccountPHIDs; | ||||||
|  |   private $rawIdentifiers; | ||||||
|  |  | ||||||
|  |   public function withIDs($ids) { | ||||||
|  |     $this->ids = $ids; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function withPHIDs(array $phids) { | ||||||
|  |     $this->phids = $phids; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function withProviderConfigPHIDs(array $phids) { | ||||||
|  |     $this->providerConfigPHIDs = $phids; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function withExternalAccountPHIDs(array $phids) { | ||||||
|  |     $this->externalAccountPHIDs = $phids; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function withRawIdentifiers(array $identifiers) { | ||||||
|  |     $this->rawIdentifiers = $identifiers; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function newResultObject() { | ||||||
|  |     return new PhabricatorExternalAccountIdentifier(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected function loadPage() { | ||||||
|  |     return $this->loadStandardPage($this->newResultObject()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { | ||||||
|  |     $where = parent::buildWhereClauseParts($conn); | ||||||
|  |  | ||||||
|  |     if ($this->ids !== null) { | ||||||
|  |       $where[] = qsprintf( | ||||||
|  |         $conn, | ||||||
|  |         'id IN (%Ld)', | ||||||
|  |         $this->ids); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ($this->phids !== null) { | ||||||
|  |       $where[] = qsprintf( | ||||||
|  |         $conn, | ||||||
|  |         'phid IN (%Ls)', | ||||||
|  |         $this->phids); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ($this->providerConfigPHIDs !== null) { | ||||||
|  |       $where[] = qsprintf( | ||||||
|  |         $conn, | ||||||
|  |         'providerConfigPHID IN (%Ls)', | ||||||
|  |         $this->providerConfigPHIDs); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ($this->externalAccountPHIDs !== null) { | ||||||
|  |       $where[] = qsprintf( | ||||||
|  |         $conn, | ||||||
|  |         'externalAccountPHID IN (%Ls)', | ||||||
|  |         $this->externalAccountPHIDs); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ($this->rawIdentifiers !== null) { | ||||||
|  |       $hashes = array(); | ||||||
|  |       foreach ($this->rawIdentifiers as $raw_identifier) { | ||||||
|  |         $hashes[] = PhabricatorHash::digestForIndex($raw_identifier); | ||||||
|  |       } | ||||||
|  |       $where[] = qsprintf( | ||||||
|  |         $conn, | ||||||
|  |         'identifierHash IN (%Ls)', | ||||||
|  |         $hashes); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return $where; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getQueryApplicationClass() { | ||||||
|  |     return 'PhabricatorPeopleApplication'; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,38 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | final class PhabricatorPeopleExternalIdentifierPHIDType | ||||||
|  |   extends PhabricatorPHIDType { | ||||||
|  |  | ||||||
|  |   const TYPECONST = 'XIDT'; | ||||||
|  |  | ||||||
|  |   public function getTypeName() { | ||||||
|  |     return pht('External Account Identifier'); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function newObject() { | ||||||
|  |     return new PhabricatorExternalAccountIdentifier(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getPHIDTypeApplicationClass() { | ||||||
|  |     return 'PhabricatorPeopleApplication'; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected function buildQueryForObjects( | ||||||
|  |     PhabricatorObjectQuery $query, | ||||||
|  |     array $phids) { | ||||||
|  |  | ||||||
|  |     return id(new PhabricatorExternalAccountIdentifierQuery()) | ||||||
|  |       ->withPHIDs($phids); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function loadHandles( | ||||||
|  |     PhabricatorHandleQuery $query, | ||||||
|  |     array $handles, | ||||||
|  |     array $objects) { | ||||||
|  |  | ||||||
|  |     foreach ($handles as $phid => $handle) { | ||||||
|  |       $identifier = $objects[$phid]; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,67 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | final class PhabricatorExternalAccountIdentifier | ||||||
|  |   extends PhabricatorUserDAO | ||||||
|  |   implements PhabricatorPolicyInterface { | ||||||
|  |  | ||||||
|  |   protected $externalAccountPHID; | ||||||
|  |   protected $providerConfigPHID; | ||||||
|  |   protected $identifierHash; | ||||||
|  |   protected $identifierRaw; | ||||||
|  |  | ||||||
|  |   public function getPHIDType() { | ||||||
|  |     return PhabricatorPeopleExternalIdentifierPHIDType::TYPECONST; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected function getConfiguration() { | ||||||
|  |     return array( | ||||||
|  |       self::CONFIG_AUX_PHID => true, | ||||||
|  |       self::CONFIG_COLUMN_SCHEMA => array( | ||||||
|  |         'identifierHash' => 'bytes12', | ||||||
|  |         'identifierRaw' => 'text', | ||||||
|  |       ), | ||||||
|  |       self::CONFIG_KEY_SCHEMA => array( | ||||||
|  |         'key_identifier' => array( | ||||||
|  |           'columns' => array('providerConfigPHID', 'identifierHash'), | ||||||
|  |           'unique' => true, | ||||||
|  |         ), | ||||||
|  |         'key_account' => array( | ||||||
|  |           'columns' => array('externalAccountPHID'), | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ) + parent::getConfiguration(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function save() { | ||||||
|  |     $identifier_raw = $this->getIdentifierRaw(); | ||||||
|  |     $this->identiferHash = PhabricatorHash::digestForIndex($identifier_raw); | ||||||
|  |     return parent::save(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* -(  PhabricatorPolicyInterface  )----------------------------------------- */ | ||||||
|  |  | ||||||
|  |   // TODO: These permissions aren't very good. They should just be the same | ||||||
|  |   // as the associated ExternalAccount. See T13381. | ||||||
|  |  | ||||||
|  |   public function getCapabilities() { | ||||||
|  |     return array( | ||||||
|  |       PhabricatorPolicyCapability::CAN_VIEW, | ||||||
|  |       PhabricatorPolicyCapability::CAN_EDIT, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getPolicy($capability) { | ||||||
|  |     switch ($capability) { | ||||||
|  |       case PhabricatorPolicyCapability::CAN_VIEW: | ||||||
|  |         return PhabricatorPolicies::getMostOpenPolicy(); | ||||||
|  |       case PhabricatorPolicyCapability::CAN_EDIT: | ||||||
|  |         return PhabricatorPolicies::POLICY_NOONE; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley