diff --git a/src/applications/auth/provider/PhabricatorAuthProvider.php b/src/applications/auth/provider/PhabricatorAuthProvider.php index 72d901b488..787d56b587 100644 --- a/src/applications/auth/provider/PhabricatorAuthProvider.php +++ b/src/applications/auth/provider/PhabricatorAuthProvider.php @@ -1,208 +1,211 @@ getAdapter()->getAdapterKey(); } public function getProviderType() { return $this->getAdapter()->getAdapterType(); } public function getProviderDomain() { return $this->getAdapter()->getAdapterDomain(); } public static function getAllProviders() { static $providers; if ($providers === null) { $objects = id(new PhutilSymbolLoader()) ->setAncestorClass(__CLASS__) ->loadObjects(); $providers = array(); $from_class_map = array(); foreach ($objects as $object) { $from_class = get_class($object); $object_providers = $object->createProviders(); assert_instances_of($object_providers, 'PhabricatorAuthProvider'); foreach ($object_providers as $provider) { $key = $provider->getProviderKey(); if (isset($providers[$key])) { $first_class = $from_class_map[$key]; throw new Exception( "PhabricatorAuthProviders '{$first_class}' and '{$from_class}' ". "both created authentication providers identified by key ". "'{$key}'. Provider keys must be unique."); } $providers[$key] = $provider; $from_class_map[$key] = $from_class; } } } return $providers; } public static function getAllEnabledProviders() { $providers = self::getAllProviders(); foreach ($providers as $key => $provider) { if (!$provider->isEnabled()) { unset($providers[$key]); } } return $providers; } public static function getEnabledProviderByKey($provider_key) { return idx(self::getAllEnabledProviders(), $provider_key); } abstract public function getProviderName(); abstract public function getAdapter(); public function isEnabled() { return true; } abstract public function shouldAllowLogin(); abstract public function shouldAllowRegistration(); abstract public function shouldAllowAccountLink(); abstract public function shouldAllowAccountUnlink(); public function buildLoginForm( PhabricatorAuthStartController $controller) { return $this->renderLoginForm($controller->getRequest(), $is_link = false); } abstract public function processLoginRequest( PhabricatorAuthLoginController $controller); public function buildLinkForm( PhabricatorAuthLinkController $controller) { return $this->renderLoginForm($controller->getRequest(), $is_link = true); } protected function renderLoginForm( AphrontRequest $request, $is_link) { throw new Exception("Not implemented!"); } public function createProviders() { return array($this); } protected function willSaveAccount(PhabricatorExternalAccount $account) { return; } public function willRegisterAccount(PhabricatorExternalAccount $account) { return; } protected function loadOrCreateAccount($account_id) { if (!strlen($account_id)) { throw new Exception( "loadOrCreateAccount(...): empty account ID!"); } $adapter = $this->getAdapter(); $adapter_class = get_class($adapter); if (!strlen($adapter->getAdapterType())) { throw new Exception( "AuthAdapter (of class '{$adapter_class}') has an invalid ". "implementation: no adapter type."); } if (!strlen($adapter->getAdapterDomain())) { throw new Exception( "AuthAdapter (of class '{$adapter_class}') has an invalid ". "implementation: no adapter domain."); } $account = id(new PhabricatorExternalAccount())->loadOneWhere( 'accountType = %s AND accountDomain = %s AND accountID = %s', $adapter->getAdapterType(), $adapter->getAdapterDomain(), $account_id); if (!$account) { $account = id(new PhabricatorExternalAccount()) ->setAccountType($adapter->getAdapterType()) ->setAccountDomain($adapter->getAdapterDomain()) ->setAccountID($account_id); } $account->setUsername($adapter->getAccountName()); $account->setRealName($adapter->getAccountRealName()); $account->setEmail($adapter->getAccountEmail()); $account->setAccountURI($adapter->getAccountURI()); try { $name = PhabricatorSlug::normalize($this->getProviderName()); $name = $name.'-profile.jpg'; // TODO: If the image has not changed, we do not need to make a new // 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. - $image_uri = $account->getAccountImageURI(); - $image_file = PhabricatorFile::newFromFileDownload( - $image_uri, - array( - 'name' => $name, - )); + $image_uri = $adapter->getAccountImageURI(); + + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); + $image_file = PhabricatorFile::newFromFileDownload( + $image_uri, + array( + 'name' => $name, + )); + unset($unguarded); $account->setProfileImagePHID($image_file->getPHID()); } catch (Exception $ex) { $account->setProfileImagePHID(null); } $this->willSaveAccount($account); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $account->save(); unset($unguarded); return $account; } protected function getLoginURI() { $app = PhabricatorApplication::getByClass('PhabricatorApplicationAuth'); $uri = $app->getApplicationURI('/login/'.$this->getProviderKey().'/'); return PhabricatorEnv::getURI($uri); } protected function getCancelLinkURI() { return '/settings/panel/external/'; } public function isDefaultRegistrationProvider() { return false; } public function shouldRequireRegistrationPassword() { return false; } public function getDefaultExternalAccount() { throw new Exception("Not implemented!"); } public function getLoginOrder() { return '500-'.$this->getProviderName(); } protected function getLoginIcon() { return 'Generic'; } public function isLoginFormAButton() { return false; } } diff --git a/src/applications/auth/view/PhabricatorAuthAccountView.php b/src/applications/auth/view/PhabricatorAuthAccountView.php index 0b3d1f18a1..9cf19e65df 100644 --- a/src/applications/auth/view/PhabricatorAuthAccountView.php +++ b/src/applications/auth/view/PhabricatorAuthAccountView.php @@ -1,115 +1,115 @@ externalAccount = $external_account; return $this; } public function setAuthProvider(PhabricatorAuthProvider $provider) { $this->provider = $provider; return $this; } public function render() { $account = $this->externalAccount; $provider = $this->provider; require_celerity_resource('auth-css'); $content = array(); $dispname = $account->getDisplayName(); $username = $account->getUsername(); $realname = $account->getRealName(); $use_name = null; if (strlen($dispname)) { $use_name = $dispname; } else if (strlen($username) && strlen($realname)) { $use_name = $username.' ('.$realname.')'; } else if (strlen($username)) { $use_name = $username; } else if (strlen($realname)) { $use_name = $realname; } else { $use_name = $account->getAccountID(); } $content[] = phutil_tag( 'div', array( 'class' => 'auth-account-view-name', ), $use_name); if ($provider) { $prov_name = pht('%s Account', $provider->getProviderName()); } else { $prov_name = pht('"%s" Account', $account->getProviderType()); } $content[] = phutil_tag( 'div', array( 'class' => 'auth-account-view-provider-name', ), array( $prov_name, " \xC2\xB7 ", $account->getAccountID(), )); $account_uri = $account->getAccountURI(); if (strlen($account_uri)) { // Make sure we don't link a "javascript:" URI if a user somehow // managed to get one here. if (PhabricatorEnv::isValidRemoteWebResource($account_uri)) { $account_uri = phutil_tag( 'a', array( 'href' => $account_uri, 'target' => '_blank', ), $account_uri); } $content[] = phutil_tag( 'div', array( 'class' => 'auth-account-view-account-uri', ), $account_uri); } // TODO: This fetch is sketchy. We should probably build // ExternalAccountQuery and move the logic there. $image_uri = PhabricatorUser::getDefaultProfileImageURI(); if ($account->getProfileImagePHID()) { $image = id(new PhabricatorFileQuery()) - ->setUser(PhabricatorUser::getOmnipotentUser()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs(array($account->getProfileImagePHID())) ->executeOne(); if ($image) { $image_uri = $image->getProfileThumbURI(); } } return phutil_tag( 'div', array( 'class' => 'auth-account-view', 'style' => 'background-image: url('.$image_uri.')', ), $content); } }