diff --git a/src/applications/auth/controller/PhabricatorAuthLoginController.php b/src/applications/auth/controller/PhabricatorAuthLoginController.php index bd5420b030..44eceec8a8 100644 --- a/src/applications/auth/controller/PhabricatorAuthLoginController.php +++ b/src/applications/auth/controller/PhabricatorAuthLoginController.php @@ -157,4 +157,16 @@ final class PhabricatorAuthLoginController )); } + public function buildProviderErrorResponse( + PhabricatorAuthProvider $provider, + $message) { + + $message = pht( + 'Authentication provider ("%s") encountered an error during login. %s', + $provider->getProviderName(), + $message); + + return $this->renderError($message); + } + } diff --git a/src/applications/auth/provider/PhabricatorAuthProvider.php b/src/applications/auth/provider/PhabricatorAuthProvider.php index 987d549960..3169bc2678 100644 --- a/src/applications/auth/provider/PhabricatorAuthProvider.php +++ b/src/applications/auth/provider/PhabricatorAuthProvider.php @@ -2,20 +2,6 @@ abstract class PhabricatorAuthProvider { - private $adapter; - - public function setAdapater(PhutilAuthAdapter $adapter) { - $this->adapter = $adapter; - return $this; - } - - public function getAdapater() { - if ($this->adapter === null) { - throw new Exception("Call setAdapter() before getAdapter()!"); - } - return $this->adapter; - } - public function getProviderKey() { return $this->getAdapter()->getAdapterKey(); } @@ -67,6 +53,7 @@ abstract class PhabricatorAuthProvider { } abstract public function getProviderName(); + abstract public function getAdapater(); abstract public function isEnabled(); abstract public function shouldAllowLogin(); abstract public function shouldAllowRegistration(); @@ -78,4 +65,61 @@ abstract class PhabricatorAuthProvider { return array($this); } + protected function willSaveAccount(PhabricatorExternalAccount $account) { + return; + } + + protected function loadOrCreateAccount($account_id) { + if (!strlen($account_id)) { + throw new Exception("loadOrCreateAccount(...): empty account ID!"); + } + + $adapter = $this->getAdapter(); + $account = id(new PhabricatorExternalAccount())->loadOneWhere( + 'accountType = %s AND accountDomain = %s AND accountID = %s', + $adapter->getProviderType(), + $adapter->getProviderDomain(), + $account_id); + if (!$account) { + $account = id(new PhabricatorExternalAccount()) + ->setAccountType($adapter->getProviderType()) + ->setAccountDomain($adapter->getProviderDomain()) + ->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, + )); + + $account->setProfileImagePHID($image_file->getPHID()); + } catch (Exception $ex) { + $account->setProfileImagePHID(null); + } + + $this->willSaveAccount($account); + + $account->save(); + + return $account; + } + + + } diff --git a/src/applications/auth/provider/PhabricatorAuthProviderOAuth.php b/src/applications/auth/provider/PhabricatorAuthProviderOAuth.php new file mode 100644 index 0000000000..d4fbd08f49 --- /dev/null +++ b/src/applications/auth/provider/PhabricatorAuthProviderOAuth.php @@ -0,0 +1,59 @@ +getRequest(); + $adapter = $this->getAdapter(); + $account = null; + $response = null; + + $error = $request->getStr('error'); + if ($error) { + $response = $controller->buildProviderErrorResponse( + $this, + pht( + 'The OAuth provider returned an error: %s', + $error)); + + return array($account, $response); + } + + $code = $request->getStr('code'); + if (!strlen($code)) { + $response = $controller->buildProviderErrorResponse( + $this, + pht( + 'The OAuth provider did not return a "code" parameter in its '. + 'response.')); + + return array($account, $response); + } + + $adapter->setCode($code); + + // NOTE: As a side effect, this will cause the OAuth adapter to request + // an access token. + + try { + $account_id = $adapter->getAccountID(); + } catch (Exception $ex) { + // TODO: Handle this in a more user-friendly way. + throw $ex; + } + + if (!strlen($account_id)) { + $response = $controller->buildProviderErrorResponse( + $this, + pht( + 'The OAuth provider failed to retrieve an account ID.')); + + return array($account, $response); + } + + return array($this->loadOrCreateAccount($account_id), $response); + } + +}