1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-09-20 09:18:48 +02:00

Send old login code to the bottom of the sea

Summary:
Ref T1536. This is extremely reachable and changes the login code to the new stuff.

Notes:

  - I've hard-disabled password registration since I want installs to explicitly flip it on via config if they want it. New installs will get it by default in the future, but old installs shouldn't have their auth options change.
  - Google doesn't let us change the redirect URI, so keep the old one working.
  - We need to keep a bit of LDAP around for now for LDAP import.
  - **Facebook:** This causes substantive changes in what login code is executed.

Test Plan:
  - Logged in / logged out / registered, hit new flows.
  - Logged in with google.
  - Verified no password registration by default.

Reviewers: btrahan, chad

Reviewed By: chad

CC: wez, nh, aran, mbishopim3

Maniphest Tasks: T1536

Differential Revision: https://secure.phabricator.com/D6222
This commit is contained in:
epriestley 2013-06-19 01:33:27 -07:00
parent 8c8ab25fa1
commit 73c2c1d2e6
26 changed files with 46 additions and 2593 deletions

View file

@ -828,6 +828,7 @@ phutil_register_library_map(array(
'PhabricatorAuthManagementRecoverWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php',
'PhabricatorAuthManagementWorkflow' => 'applications/auth/management/PhabricatorAuthManagementWorkflow.php',
'PhabricatorAuthNewController' => 'applications/auth/controller/config/PhabricatorAuthNewController.php',
'PhabricatorAuthOldOAuthRedirectController' => 'applications/auth/controller/PhabricatorAuthOldOAuthRedirectController.php',
'PhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorAuthProvider.php',
'PhabricatorAuthProviderConfig' => 'applications/auth/storage/PhabricatorAuthProviderConfig.php',
'PhabricatorAuthProviderConfigController' => 'applications/auth/controller/config/PhabricatorAuthProviderConfigController.php',
@ -1128,9 +1129,7 @@ phutil_register_library_map(array(
'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php',
'PhabricatorKeyValueDatabaseCache' => 'applications/cache/PhabricatorKeyValueDatabaseCache.php',
'PhabricatorLDAPConfigOptions' => 'applications/config/option/PhabricatorLDAPConfigOptions.php',
'PhabricatorLDAPLoginController' => 'applications/auth/controller/PhabricatorLDAPLoginController.php',
'PhabricatorLDAPProvider' => 'applications/auth/ldap/PhabricatorLDAPProvider.php',
'PhabricatorLDAPRegistrationController' => 'applications/auth/controller/PhabricatorLDAPRegistrationController.php',
'PhabricatorLDAPUnknownUserException' => 'applications/auth/ldap/PhabricatorLDAPUnknownUserException.php',
'PhabricatorLintEngine' => 'infrastructure/lint/PhabricatorLintEngine.php',
'PhabricatorLipsumArtist' => 'applications/lipsum/image/PhabricatorLipsumArtist.php',
@ -1140,7 +1139,6 @@ phutil_register_library_map(array(
'PhabricatorLiskDAO' => 'infrastructure/storage/lisk/PhabricatorLiskDAO.php',
'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php',
'PhabricatorLocalTimeTestCase' => 'view/__tests__/PhabricatorLocalTimeTestCase.php',
'PhabricatorLoginController' => 'applications/auth/controller/PhabricatorLoginController.php',
'PhabricatorLogoutController' => 'applications/auth/controller/PhabricatorLogoutController.php',
'PhabricatorMacroCommentController' => 'applications/macro/controller/PhabricatorMacroCommentController.php',
'PhabricatorMacroConfigOptions' => 'applications/macro/config/PhabricatorMacroConfigOptions.php',
@ -1236,18 +1234,6 @@ phutil_register_library_map(array(
'PhabricatorOAuthClientEditController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientEditController.php',
'PhabricatorOAuthClientListController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientListController.php',
'PhabricatorOAuthClientViewController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientViewController.php',
'PhabricatorOAuthDefaultRegistrationController' => 'applications/auth/controller/oauthregistration/PhabricatorOAuthDefaultRegistrationController.php',
'PhabricatorOAuthDiagnosticsController' => 'applications/auth/controller/PhabricatorOAuthDiagnosticsController.php',
'PhabricatorOAuthFailureView' => 'applications/auth/view/PhabricatorOAuthFailureView.php',
'PhabricatorOAuthLoginController' => 'applications/auth/controller/PhabricatorOAuthLoginController.php',
'PhabricatorOAuthProvider' => 'applications/auth/oauth/provider/PhabricatorOAuthProvider.php',
'PhabricatorOAuthProviderDisqus' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderDisqus.php',
'PhabricatorOAuthProviderException' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderException.php',
'PhabricatorOAuthProviderFacebook' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderFacebook.php',
'PhabricatorOAuthProviderGitHub' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderGitHub.php',
'PhabricatorOAuthProviderGoogle' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderGoogle.php',
'PhabricatorOAuthProviderPhabricator' => 'applications/auth/oauth/provider/PhabricatorOAuthProviderPhabricator.php',
'PhabricatorOAuthRegistrationController' => 'applications/auth/controller/oauthregistration/PhabricatorOAuthRegistrationController.php',
'PhabricatorOAuthResponse' => 'applications/oauthserver/PhabricatorOAuthResponse.php',
'PhabricatorOAuthServer' => 'applications/oauthserver/PhabricatorOAuthServer.php',
'PhabricatorOAuthServerAccessToken' => 'applications/oauthserver/storage/PhabricatorOAuthServerAccessToken.php',
@ -1585,7 +1571,6 @@ phutil_register_library_map(array(
'PhabricatorUserEditor' => 'applications/people/editor/PhabricatorUserEditor.php',
'PhabricatorUserEmail' => 'applications/people/storage/PhabricatorUserEmail.php',
'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php',
'PhabricatorUserOAuthInfo' => 'applications/people/storage/PhabricatorUserOAuthInfo.php',
'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php',
'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php',
'PhabricatorUserProfileEditor' => 'applications/people/editor/PhabricatorUserProfileEditor.php',
@ -2714,6 +2699,7 @@ phutil_register_library_map(array(
'PhabricatorAuthManagementRecoverWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementWorkflow' => 'PhutilArgumentWorkflow',
'PhabricatorAuthNewController' => 'PhabricatorAuthProviderConfigController',
'PhabricatorAuthOldOAuthRedirectController' => 'PhabricatorAuthController',
'PhabricatorAuthProviderConfig' =>
array(
0 => 'PhabricatorAuthDAO',
@ -3019,8 +3005,6 @@ phutil_register_library_map(array(
'PhabricatorJavelinLinter' => 'ArcanistLinter',
'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache',
'PhabricatorLDAPConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorLDAPLoginController' => 'PhabricatorAuthController',
'PhabricatorLDAPRegistrationController' => 'PhabricatorAuthController',
'PhabricatorLDAPUnknownUserException' => 'Exception',
'PhabricatorLintEngine' => 'PhutilLintEngine',
'PhabricatorLipsumGenerateWorkflow' => 'PhabricatorLipsumManagementWorkflow',
@ -3029,7 +3013,6 @@ phutil_register_library_map(array(
'PhabricatorLiskDAO' => 'LiskDAO',
'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorLocalTimeTestCase' => 'PhabricatorTestCase',
'PhabricatorLoginController' => 'PhabricatorAuthController',
'PhabricatorLogoutController' => 'PhabricatorAuthController',
'PhabricatorMacroCommentController' => 'PhabricatorMacroController',
'PhabricatorMacroConfigOptions' => 'PhabricatorApplicationConfigOptions',
@ -3121,17 +3104,6 @@ phutil_register_library_map(array(
'PhabricatorOAuthClientEditController' => 'PhabricatorOAuthClientBaseController',
'PhabricatorOAuthClientListController' => 'PhabricatorOAuthClientBaseController',
'PhabricatorOAuthClientViewController' => 'PhabricatorOAuthClientBaseController',
'PhabricatorOAuthDefaultRegistrationController' => 'PhabricatorOAuthRegistrationController',
'PhabricatorOAuthDiagnosticsController' => 'PhabricatorAuthController',
'PhabricatorOAuthFailureView' => 'AphrontView',
'PhabricatorOAuthLoginController' => 'PhabricatorAuthController',
'PhabricatorOAuthProviderDisqus' => 'PhabricatorOAuthProvider',
'PhabricatorOAuthProviderException' => 'Exception',
'PhabricatorOAuthProviderFacebook' => 'PhabricatorOAuthProvider',
'PhabricatorOAuthProviderGitHub' => 'PhabricatorOAuthProvider',
'PhabricatorOAuthProviderGoogle' => 'PhabricatorOAuthProvider',
'PhabricatorOAuthProviderPhabricator' => 'PhabricatorOAuthProvider',
'PhabricatorOAuthRegistrationController' => 'PhabricatorAuthController',
'PhabricatorOAuthResponse' => 'AphrontResponse',
'PhabricatorOAuthServerAccessToken' => 'PhabricatorOAuthServerDAO',
'PhabricatorOAuthServerAuthController' => 'PhabricatorAuthController',

View file

@ -56,18 +56,6 @@ abstract class AphrontApplicationConfiguration {
public function willBuildRequest() {
}
/**
* Hook for synchronizing account information from OAuth workflows.
*
* @task hook
*/
public function willAuthenticateUserWithOAuth(
PhabricatorUser $user,
PhabricatorUserOAuthInfo $oauth_info,
PhabricatorOAuthProvider $provider) {
return;
}
/* -( URI Routing )-------------------------------------------------------- */
@ -106,10 +94,10 @@ abstract class AphrontApplicationConfiguration {
if (PhabricatorEnv::getEnvConfig('security.require-https')) {
if (!$request->isHTTPS()) {
$uri = $request->getRequestURI();
$uri->setDomain($request->getHost());
$uri->setProtocol('https');
return $this->buildRedirectController($uri);
$https_uri = $request->getRequestURI();
$https_uri->setDomain($request->getHost());
$https_uri->setProtocol('https');
return $this->buildRedirectController($https_uri);
}
}
@ -183,8 +171,8 @@ abstract class AphrontApplicationConfiguration {
// will be a GET without parameters.
if ($controller && !$request->isHTTPPost()) {
$uri = $request->getRequestURI()->setPath($path.'/');
return $this->buildRedirectController($uri);
$slash_uri = $request->getRequestURI()->setPath($path.'/');
return $this->buildRedirectController($slash_uri);
}
}
return $this->build404Controller();

View file

@ -130,7 +130,7 @@ class AphrontDefaultApplicationConfiguration
//
// Possibly we should add a header here like "you need to login to see
// the thing you are trying to look at".
$login_controller = new PhabricatorLoginController($request);
$login_controller = new PhabricatorAuthStartController($request);
return $login_controller->processRequest();
}

View file

@ -63,8 +63,10 @@ final class PhabricatorApplicationAuth extends PhabricatorApplication {
=> 'PhabricatorAuthConfirmLinkController',
),
'/oauth/google/login/' => 'PhabricatorAuthOldOAuthRedirectController',
'/login/' => array(
'' => 'PhabricatorLoginController',
'' => 'PhabricatorAuthStartController',
'email/' => 'PhabricatorEmailLoginController',
'etoken/(?P<token>\w+)/' => 'PhabricatorEmailTokenController',
'refresh/' => 'PhabricatorRefreshCSRFController',
@ -72,17 +74,6 @@ final class PhabricatorApplicationAuth extends PhabricatorApplication {
),
'/logout/' => 'PhabricatorLogoutController',
'/oauth/' => array(
'(?P<provider>\w+)/' => array(
'login/' => 'PhabricatorOAuthLoginController',
'diagnose/' => 'PhabricatorOAuthDiagnosticsController',
),
),
'/ldap/' => array(
'login/' => 'PhabricatorLDAPLoginController',
),
);
}

View file

@ -0,0 +1,21 @@
<?php
final class PhabricatorAuthOldOAuthRedirectController
extends PhabricatorAuthController {
public function shouldRequireLogin() {
return false;
}
public function processRequest() {
// TODO: Most OAuth providers are OK with changing the redirect URI, but
// Google is strict. We need to respect the old OAuth URI until we can
// get installs to migrate. This just keeps the old OAuth URI working
// by redirecting to the new one.
$uri = $this->getRequest()->getRequestURI();
$uri->setPath($this->getApplicationURI('login/google:google.com/'));
return id(new AphrontRedirectResponse())->setURI($uri);
}
}

View file

@ -139,7 +139,7 @@ final class PhabricatorAuthStartController
private function processAjaxRequest() {
$request = $this->getRequest();
$viewer = $request->getViewer();
$viewer = $request->getUser();
// We end up here if the user clicks a workflow link that they need to
// login to use. We give them a dialog saying "You need to login...".
@ -162,7 +162,7 @@ final class PhabricatorAuthStartController
private function processConduitRequest() {
$request = $this->getRequest();
$viewer = $request->getViewer();
$viewer = $request->getUser();
// A common source of errors in Conduit client configuration is getting
// the request path wrong. The client will end up here, so make some

View file

@ -1,168 +0,0 @@
<?php
final class PhabricatorLDAPLoginController extends PhabricatorAuthController {
private $provider;
public function shouldRequireLogin() {
return false;
}
public function willProcessRequest(array $data) {
$this->provider = new PhabricatorLDAPProvider();
}
public function processRequest() {
if (!$this->provider->isProviderEnabled()) {
return new Aphront400Response();
}
$current_user = $this->getRequest()->getUser();
$request = $this->getRequest();
$ldap_username = $request->getCookie('phusr');
if ($request->isFormPost()) {
$ldap_username = $request->getStr('username');
try {
$envelope = new PhutilOpaqueEnvelope($request->getStr('password'));
$this->provider->auth($ldap_username, $envelope);
} catch (Exception $e) {
$errors[] = $e->getMessage();
}
if (empty($errors)) {
$ldap_info = $this->retrieveLDAPInfo($this->provider);
if ($current_user->getPHID()) {
if ($ldap_info->getID()) {
$existing_ldap = id(new PhabricatorExternalAccount())->loadOneWhere(
'accountType = %s AND accountDomain = %s AND userPHID = %s',
'ldap',
'self',
$current_user->getPHID());
if ($ldap_info->getUserPHID() != $current_user->getPHID() ||
$existing_ldap) {
$dialog = new AphrontDialogView();
$dialog->setUser($current_user);
$dialog->setTitle(pht('Already Linked to Another Account'));
$dialog->appendChild(phutil_tag('p', array(), pht(
'The LDAP account you just authorized is already '.
'linked toanother Phabricator account. Before you can link it '.
'to a different LDAP account, you must unlink the old '.
'account.')));
$dialog->addCancelButton('/settings/panel/ldap/');
return id(new AphrontDialogResponse())->setDialog($dialog);
} else {
return id(new AphrontRedirectResponse())
->setURI('/settings/panel/ldap/');
}
}
if (!$request->isDialogFormPost()) {
$dialog = new AphrontDialogView();
$dialog->setUser($current_user);
$dialog->setTitle(pht('Link LDAP Account'));
$dialog->appendChild(phutil_tag('p', array(), pht(
'Link your LDAP account to your Phabricator account?')));
$dialog->addHiddenInput('username', $request->getStr('username'));
$dialog->addHiddenInput('password', $request->getStr('password'));
$dialog->addSubmitButton(pht('Link Accounts'));
$dialog->addCancelButton('/settings/panel/ldap/');
return id(new AphrontDialogResponse())->setDialog($dialog);
}
$ldap_info->setUserPHID($current_user->getPHID());
$this->saveLDAPInfo($ldap_info);
return id(new AphrontRedirectResponse())
->setURI('/settings/panel/ldap/');
}
if ($ldap_info->getUserPHID()) {
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$known_user = id(new PhabricatorUser())->loadOneWhere(
'phid = %s',
$ldap_info->getUserPHID());
$this->saveLDAPInfo($ldap_info);
return $this->loginUser($known_user);
}
$controller = newv('PhabricatorLDAPRegistrationController',
array($this->getRequest()));
$controller->setLDAPProvider($this->provider);
$controller->setLDAPInfo($ldap_info);
return $this->delegateToController($controller);
}
}
$ldap_form = new AphrontFormView();
$ldap_form
->setUser($request->getUser())
->setAction('/ldap/login/')
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('LDAP username'))
->setName('username')
->setValue($ldap_username))
->appendChild(
id(new AphrontFormPasswordControl())
->setLabel(pht('Password'))
->setName('password'));
$ldap_form
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Login')));
$panel = new AphrontPanelView();
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->appendChild(phutil_tag('h1', array(), pht('LDAP login')));
$panel->appendChild($ldap_form);
$error_view = null;
if (isset($errors) && count($errors) > 0) {
$error_view = new AphrontErrorView();
$error_view->setTitle(pht('Login Failed'));
$error_view->setErrors($errors);
}
return $this->buildStandardPageResponse(
array(
$error_view,
$panel,
),
array(
'title' => pht('Login'),
));
}
private function retrieveLDAPInfo(PhabricatorLDAPProvider $provider) {
$ldap_info = id(new PhabricatorExternalAccount())->loadOneWhere(
'accountType = %s AND accountDomain = %s AND accountID = %s',
'ldap',
'self',
$provider->retrieveUsername());
if (!$ldap_info) {
$ldap_info = id(new PhabricatorExternalAccount())
->setAccountType('ldap')
->setAccountDomain('self')
->setAccountID($provider->retrieveUsername());
}
return $ldap_info;
}
private function saveLDAPInfo(PhabricatorExternalAccount $info) {
// UNGUARDED WRITES: Logging-in users don't have their CSRF set up yet.
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$info->save();
}
}

View file

@ -1,220 +0,0 @@
<?php
final class PhabricatorLDAPRegistrationController
extends PhabricatorAuthController {
private $ldapProvider;
private $ldapInfo;
public function setLDAPProvider($provider) {
$this->ldapProvider = $provider;
return $this;
}
public function getLDAProvider() {
return $this->ldapProvider;
}
public function setLDAPInfo($info) {
$this->ldapInfo = $info;
return $this;
}
public function getLDAPInfo() {
return $this->ldapInfo;
}
public function processRequest() {
$provider = $this->getLDAProvider();
$ldap_info = $this->getLDAPInfo();
$request = $this->getRequest();
$errors = array();
$e_username = true;
$e_email = true;
$e_realname = true;
$user = new PhabricatorUser();
$user->setUsername($provider->retrieveUsername());
$user->setRealname($provider->retrieveUserRealName());
$new_email = $provider->retrieveUserEmail();
if ($new_email) {
// If the user's LDAP provider account has an email address but the
// email address domain is not allowed by the Phabricator configuration,
// we just pretend the provider did not supply an address.
//
// For instance, if the user uses LDAP Auth and their email address
// is "joe@personal.com" but Phabricator is configured to require users
// use "@company.com" addresses, we show a prompt below and tell the user
// to provide their "@company.com" address. They can still use the LDAP
// account to login, they just need to associate their account with an
// allowed address.
//
// If the email address is fine, we just use it and don't prompt the user.
if (!PhabricatorUserEmail::isAllowedAddress($new_email)) {
$new_email = null;
}
}
$show_email_input = ($new_email === null);
if ($request->isFormPost()) {
$user->setUsername($request->getStr('username'));
$username = $user->getUsername();
if (!strlen($user->getUsername())) {
$e_username = pht('Required');
$errors[] = pht('Username is required.');
} else if (!PhabricatorUser::validateUsername($username)) {
$e_username = pht('Invalid');
$errors[] = PhabricatorUser::describeValidUsername();
} else {
$e_username = null;
}
if (!$new_email) {
$new_email = trim($request->getStr('email'));
if (!$new_email) {
$e_email = pht('Required');
$errors[] = pht('Email is required.');
} else {
$e_email = null;
}
}
if ($new_email) {
if (!PhabricatorUserEmail::isAllowedAddress($new_email)) {
$e_email = pht('Invalid');
$errors[] = PhabricatorUserEmail::describeAllowedAddresses();
}
}
if (!strlen($user->getRealName())) {
$user->setRealName($request->getStr('realname'));
if (!strlen($user->getRealName())) {
$e_realname = pht('Required');
$errors[] = pht('Real name is required.');
} else {
$e_realname = null;
}
}
if (!$errors) {
try {
// NOTE: We don't verify LDAP email addresses by default because
// LDAP providers might associate email addresses with accounts that
// haven't actually verified they own them. We could selectively
// auto-verify some providers that we trust here, but the stakes for
// verifying an email address are high because having a corporate
// address at a company is sometimes the key to the castle.
$email_obj = id(new PhabricatorUserEmail())
->setAddress($new_email)
->setIsVerified(0);
id(new PhabricatorUserEditor())
->setActor($user)
->createNewUser($user, $email_obj);
$ldap_info->setUserPHID($user->getPHID());
$ldap_info->save();
$session_key = $user->establishSession('web');
$request->setCookie('phusr', $user->getUsername());
$request->setCookie('phsid', $session_key);
$email_obj->sendVerificationEmail($user);
return id(new AphrontRedirectResponse())->setURI('/');
} catch (AphrontQueryDuplicateKeyException $exception) {
$same_username = id(new PhabricatorUser())->loadOneWhere(
'userName = %s',
$user->getUserName());
$same_email = id(new PhabricatorUserEmail())->loadOneWhere(
'address = %s',
$new_email);
if ($same_username) {
$e_username = pht('Duplicate');
$errors[] = pht('That username or email is not unique.');
} else if ($same_email) {
$e_email = pht('Duplicate');
$errors[] = pht('That email is not unique.');
} else {
throw $exception;
}
}
}
}
$error_view = null;
if ($errors) {
$error_view = new AphrontErrorView();
$error_view->setTitle(pht('Registration Failed'));
$error_view->setErrors($errors);
}
// Strip the URI down to the path, because otherwise we'll trigger
// external CSRF protection (by having a protocol in the form "action")
// and generate a form with no CSRF token.
$action_uri = new PhutilURI('/ldap/login/');
$action_path = $action_uri->getPath();
$form = new AphrontFormView();
$form
->setUser($request->getUser())
->setAction($action_path)
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Username'))
->setName('username')
->setValue($user->getUsername())
->setError($e_username));
$form->appendChild(
id(new AphrontFormPasswordControl())
->setLabel(pht('Password'))
->setName('password'));
if ($show_email_input) {
$form->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Email'))
->setName('email')
->setValue($request->getStr('email'))
->setError($e_email));
}
if ($provider->retrieveUserRealName() === null) {
$form->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Real Name'))
->setName('realname')
->setValue($request->getStr('realname'))
->setError($e_realname));
}
$form
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Create Account')));
$panel = new AphrontPanelView();
$panel->setHeader(pht('Create New Account'));
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->appendChild($form);
return $this->buildStandardPageResponse(
array(
$error_view,
$panel,
),
array(
'title' => pht('Create New Account'),
));
}
}

View file

@ -1,303 +0,0 @@
<?php
final class PhabricatorLoginController
extends PhabricatorAuthController {
public function shouldRequireLogin() {
return false;
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
if ($user->isLoggedIn()) {
// Kick the user out if they're already logged in.
return id(new AphrontRedirectResponse())->setURI('/');
}
if ($request->isAjax()) {
// We end up here if the user clicks a workflow link that they need to
// login to use. We give them a dialog saying "You need to login..".
if ($request->isDialogFormPost()) {
return id(new AphrontRedirectResponse())->setURI(
$request->getRequestURI());
}
$dialog = new AphrontDialogView();
$dialog->setUser($user);
$dialog->setTitle(pht('Login Required'));
$dialog->appendChild(phutil_tag('p', array(), pht(
'You must login to continue.')));
$dialog->addSubmitButton(pht('Login'));
$dialog->addCancelButton('/', pht('Cancel'));
return id(new AphrontDialogResponse())->setDialog($dialog);
}
if ($request->isConduit()) {
// A common source of errors in Conduit client configuration is getting
// the request path wrong. The client will end up here, so make some
// effort to give them a comprehensible error message.
$request_path = $this->getRequest()->getPath();
$conduit_path = '/api/<method>';
$example_path = '/api/conduit.ping';
$message =
"ERROR: You are making a Conduit API request to '{$request_path}', ".
"but the correct HTTP request path to use in order to access a ".
"Conduit method is '{$conduit_path}' (for example, ".
"'{$example_path}'). Check your configuration.";
return id(new AphrontPlainTextResponse())->setContent($message);
}
$error_view = null;
if ($request->getCookie('phusr') && $request->getCookie('phsid')) {
// The session cookie is invalid, so clear it.
$request->clearCookie('phusr');
$request->clearCookie('phsid');
$error_view = new AphrontErrorView();
$error_view->setTitle(pht('Invalid Session'));
$error_view->setErrors(array(
pht("Your login session is invalid. Try logging in again. If that ".
"doesn't work, clear your browser cookies.")
));
}
$next_uri = $request->getStr('next');
if (!$next_uri) {
$next_uri_path = $this->getRequest()->getPath();
if ($next_uri_path == '/login/') {
$next_uri = '/';
} else {
$next_uri = $this->getRequest()->getRequestURI();
}
}
if (!$request->isFormPost()) {
$request->setCookie('next_uri', $next_uri);
}
$password_auth = PhabricatorEnv::getEnvConfig('auth.password-auth-enabled');
$username_or_email = $request->getCookie('phusr');
$forms = array();
$errors = array();
if ($password_auth) {
$require_captcha = false;
$e_captcha = true;
if ($request->isFormPost()) {
if (AphrontFormRecaptchaControl::isRecaptchaEnabled()) {
$failed_attempts = PhabricatorUserLog::loadRecentEventsFromThisIP(
PhabricatorUserLog::ACTION_LOGIN_FAILURE,
60 * 15);
if (count($failed_attempts) > 5) {
$require_captcha = true;
if (!AphrontFormRecaptchaControl::processCaptcha($request)) {
if (AphrontFormRecaptchaControl::hasCaptchaResponse($request)) {
$e_captcha = pht('Invalid');
$errors[] = pht('CAPTCHA was not entered correctly.');
} else {
$e_captcha = pht('Required');
$errors[] = pht('Too many login failures recently. You must '.
'submit a CAPTCHA with your login request.');
}
}
}
}
$username_or_email = $request->getStr('username_or_email');
$user = id(new PhabricatorUser())->loadOneWhere(
'username = %s',
$username_or_email);
if (!$user) {
$user = PhabricatorUser::loadOneWithEmailAddress($username_or_email);
}
if (!$errors) {
// Perform username/password tests only if we didn't get rate limited
// by the CAPTCHA.
$envelope = new PhutilOpaqueEnvelope($request->getStr('password'));
if (!$user || !$user->comparePassword($envelope)) {
$errors[] = pht('Bad username/password.');
}
}
if (!$errors) {
return $this->loginUser($user);
} else {
$log = PhabricatorUserLog::newLog(
null,
$user,
PhabricatorUserLog::ACTION_LOGIN_FAILURE);
$log->save();
$request->clearCookie('phusr');
$request->clearCookie('phsid');
}
}
if ($errors) {
$error_view = new AphrontErrorView();
$error_view->setTitle(pht('Login Failed'));
$error_view->setErrors($errors);
}
$form = new AphrontFormView();
$form
->setUser($request->getUser())
->setAction('/login/')
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Username/Email'))
->setName('username_or_email')
->setValue($username_or_email))
->appendChild(
id(new AphrontFormPasswordControl())
->setLabel(pht('Password'))
->setName('password')
->setCaption(hsprintf(
'<a href="/login/email/">%s</a>',
pht('Forgot your password? / Email Login'))));
if ($require_captcha) {
$form->appendChild(
id(new AphrontFormRecaptchaControl())
->setError($e_captcha));
}
$form
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Login')));
// $panel->setCreateButton('Register New Account', '/login/register/');
$forms['Phabricator Login'] = $form;
}
$ldap_provider = new PhabricatorLDAPProvider();
if ($ldap_provider->isProviderEnabled()) {
$ldap_form = new AphrontFormView();
$ldap_form
->setUser($request->getUser())
->setAction('/ldap/login/')
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('LDAP username'))
->setName('username')
->setValue($username_or_email))
->appendChild(
id(new AphrontFormPasswordControl())
->setLabel(pht('Password'))
->setName('password'));
$ldap_form
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Login')));
$forms['LDAP Login'] = $ldap_form;
}
$providers = PhabricatorOAuthProvider::getAllProviders();
foreach ($providers as $provider) {
$enabled = $provider->isProviderEnabled();
if (!$enabled) {
continue;
}
$auth_uri = $provider->getAuthURI();
$redirect_uri = $provider->getRedirectURI();
$client_id = $provider->getClientID();
$provider_name = $provider->getProviderName();
$minimum_scope = $provider->getMinimumScope();
$extra_auth = $provider->getExtraAuthParameters();
// TODO: In theory we should use 'state' to prevent CSRF, but the total
// effect of the CSRF attack is that an attacker can cause a user to login
// to Phabricator if they're already logged into some OAuth provider. This
// does not seem like the most severe threat in the world, and generating
// CSRF for logged-out users is vaugely tricky.
if ($provider->isProviderRegistrationEnabled()) {
$title = pht("Login or Register with %s", $provider_name);
$body = pht('Login or register for Phabricator using your %s account.',
$provider_name);
$button = pht("Login or Register with %s", $provider_name);
} else {
$title = pht("Login with %s", $provider_name);
$body = hsprintf(
'%s<br /><br /><strong>%s</strong>',
pht(
'Login to your existing Phabricator account using your %s account.',
$provider_name),
pht(
'You can not use %s to register a new account.',
$provider_name));
$button = pht("Log in with %s", $provider_name);
}
$auth_form = new AphrontFormView();
$auth_form
->setAction($auth_uri)
->addHiddenInput('client_id', $client_id)
->addHiddenInput('redirect_uri', $redirect_uri)
->addHiddenInput('scope', $minimum_scope);
foreach ($extra_auth as $key => $value) {
$auth_form->addHiddenInput($key, $value);
}
$auth_form
->setUser($request->getUser())
->setMethod('GET')
->appendChild(hsprintf(
'<p class="aphront-form-instructions">%s</p>',
$body))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue("{$button} \xC2\xBB"));
$forms[$title] = $auth_form;
}
$panel = new AphrontPanelView();
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->setNoBackground();
foreach ($forms as $name => $form) {
$panel->appendChild(phutil_tag('h1', array(), $name));
$panel->appendChild($form);
$panel->appendChild(phutil_tag('br'));
}
$login_message = PhabricatorEnv::getEnvConfig('auth.login-message');
return $this->buildApplicationPage(
array(
$error_view,
phutil_safe_html($login_message),
$panel,
),
array(
'title' => pht('Login'),
'device' => true
));
}
}

View file

@ -1,203 +0,0 @@
<?php
final class PhabricatorOAuthDiagnosticsController
extends PhabricatorAuthController {
private $provider;
public function shouldRequireLogin() {
return false;
}
public function willProcessRequest(array $data) {
$this->provider = PhabricatorOAuthProvider::newProvider($data['provider']);
}
public function processRequest() {
$provider = $this->provider;
$auth_enabled = $provider->isProviderEnabled();
$client_id = $provider->getClientID();
$client_secret = $provider->getClientSecret();
$key = $provider->getProviderKey();
$name = $provider->getProviderName();
$res_ok = hsprintf('<strong style="color: #00aa00;">OK</strong>');
$res_no = hsprintf('<strong style="color: #aa0000;">NO</strong>');
$res_na = hsprintf('<strong style="color: #999999;">N/A</strong>');
$results = array();
$auth_key = $key . '.auth-enabled';
if (!$auth_enabled) {
$results[$auth_key] = array(
$res_no,
'false',
$name . ' authentication is disabled in the configuration. Edit the '.
'Phabricator configuration to enable "'.$auth_key.'".');
} else {
$results[$auth_key] = array(
$res_ok,
'true',
$name.' authentication is enabled.');
}
$client_id_key = $key. '.application-id';
if (!$client_id) {
$results[$client_id_key] = array(
$res_no,
null,
'No '.$name.' Application ID is configured. Edit the Phabricator '.
'configuration to specify an application ID in '.
'"'.$client_id_key.'". '.$provider->renderGetClientIDHelp());
} else {
$results[$client_id_key] = array(
$res_ok,
$client_id,
'Application ID is set.');
}
$client_secret_key = $key.'.application-secret';
if (!$client_secret) {
$results[$client_secret_key] = array(
$res_no,
null,
'No '.$name.' Application secret is configured. Edit the '.
'Phabricator configuration to specify an Application Secret, in '.
'"'.$client_secret_key.'". '.$provider->renderGetClientSecretHelp());
} else {
$results[$client_secret_key] = array(
$res_ok,
"It's a secret!",
'Application secret is set.');
}
$timeout = 5;
$internet = HTTPSFuture::loadContent("http://google.com/", $timeout);
if ($internet === false) {
$results['internet'] = array(
$res_no,
null,
'Unable to make an HTTP request to Google. Check your outbound '.
'internet connection and firewall/filtering settings.');
} else {
$results['internet'] = array(
$res_ok,
null,
'Internet seems OK.');
}
$test_uris = $provider->getTestURIs();
foreach ($test_uris as $uri) {
$success = HTTPSFuture::loadContent($uri, $timeout);
if ($success === false) {
$results[$uri] = array(
$res_no,
null,
"Unable to make an HTTP request to {$uri}. {$name} may be ".
'down or inaccessible.');
} else {
$results[$uri] = array(
$res_ok,
null,
'Made a request to '.$uri.'.');
}
}
if ($provider->shouldDiagnoseAppLogin()) {
$test_uri = new PhutilURI($provider->getTokenURI());
$test_uri->setQueryParams(
array(
'client_id' => $client_id,
'client_secret' => $client_secret,
'grant_type' => 'client_credentials',
));
$future = new HTTPSFuture($test_uri);
$future->setTimeout($timeout);
try {
list($body) = $future->resolvex();
$results['App Login'] = array(
$res_ok,
'(A Valid Token)',
"Raw application login to {$name} works.");
} catch (Exception $ex) {
if ($ex instanceof HTTPFutureResponseStatusCURL) {
$results['App Login'] = array(
$res_no,
null,
"Unable to perform an application login with your Application ID ".
"and Application Secret. You may have mistyped or misconfigured ".
"them; {$name} may have revoked your authorization; or {$name} ".
"may be having technical problems.");
} else {
$data = json_decode($token_value, true);
if (!is_array($data)) {
$results['App Login'] = array(
$res_no,
$token_value,
"Application Login failed but the provider did not respond ".
"with valid JSON error information. {$name} may be experiencing ".
"technical problems.");
} else {
$results['App Login'] = array(
$res_no,
null,
"Application Login failed with error: ".$token_value);
}
}
}
}
return $this->renderResults($results);
}
private function renderResults($results) {
$provider = $this->provider;
$rows = array();
foreach ($results as $key => $result) {
$rows[] = array(
$key,
$result[0],
$result[1],
$result[2],
);
}
$table_view = new AphrontTableView($rows);
$table_view->setHeaders(
array(
'Test',
'Result',
'Value',
'Details',
));
$table_view->setColumnClasses(
array(
null,
null,
null,
'wide',
));
$title = $provider->getProviderName() . ' Auth Diagnostics';
$panel_view = new AphrontPanelView();
$panel_view->setHeader($title);
$panel_view->appendChild(hsprintf(
'<p class="aphront-panel-instructions">These tests may be able to '.
'help diagnose the root cause of problems you experience with %s '.
'Authentication. Reload the page to run the tests again.</p>',
$provider->getProviderName()));
$panel_view->appendChild($table_view);
return $this->buildStandardPageResponse(
$panel_view,
array(
'title' => $title,
));
}
}

View file

@ -1,294 +0,0 @@
<?php
final class PhabricatorOAuthLoginController
extends PhabricatorAuthController {
private $provider;
private $userID;
private $accessToken;
private $oauthState;
public function shouldRequireLogin() {
return false;
}
public function willProcessRequest(array $data) {
$this->provider = PhabricatorOAuthProvider::newProvider($data['provider']);
}
public function processRequest() {
$current_user = $this->getRequest()->getUser();
$provider = $this->provider;
if (!$provider->isProviderEnabled()) {
return new Aphront400Response();
}
$provider_name = $provider->getProviderName();
$provider_key = $provider->getProviderKey();
$request = $this->getRequest();
if ($request->getStr('error')) {
$error_view = id(new PhabricatorOAuthFailureView())
->setRequest($request);
return $this->buildErrorResponse($error_view);
}
$error_response = $this->retrieveAccessToken($provider);
if ($error_response) {
return $error_response;
}
$userinfo_uri = new PhutilURI($provider->getUserInfoURI());
$userinfo_uri->setQueryParam('access_token', $this->accessToken);
$userinfo_uri = (string)$userinfo_uri;
try {
$user_data_request = new HTTPSFuture($userinfo_uri);
// NOTE: GitHub requires a User-Agent header.
$user_data_request->addHeader('User-Agent', 'Phabricator');
list($body) = $user_data_request->resolvex();
$provider->setUserData($body);
} catch (PhabricatorOAuthProviderException $e) {
return $this->buildErrorResponse(new PhabricatorOAuthFailureView(), $e);
}
$provider->setAccessToken($this->accessToken);
$user_id = $provider->retrieveUserID();
$provider_key = $provider->getProviderKey();
$oauth_info = $this->retrieveOAuthInfo($provider);
if ($current_user->getPHID()) {
if ($oauth_info->getID()) {
if ($oauth_info->getUserID() != $current_user->getID()) {
$dialog = new AphrontDialogView();
$dialog->setUser($current_user);
$dialog->setTitle(pht('Already Linked to Another Account'));
$dialog->appendChild(phutil_tag(
'p',
array(),
pht(
'The %s account you just authorized is already linked to '.
'another Phabricator account. Before you can associate your %s '.
'account with this Phabriactor account, you must unlink it from '.
'the Phabricator account it is currently linked to.',
$provider_name,
$provider_name)));
$dialog->addCancelButton($provider->getSettingsPanelURI());
return id(new AphrontDialogResponse())->setDialog($dialog);
} else {
$this->saveOAuthInfo($oauth_info); // Refresh token.
return id(new AphrontRedirectResponse())
->setURI($provider->getSettingsPanelURI());
}
}
$existing_oauth = PhabricatorUserOAuthInfo::loadOneByUserAndProviderKey(
$current_user,
$provider_key);
if ($existing_oauth) {
$dialog = new AphrontDialogView();
$dialog->setUser($current_user);
$dialog->setTitle(
pht('Already Linked to an Account From This Provider'));
$dialog->appendChild(phutil_tag(
'p',
array(),
pht(
'The account you are logged in with is already linked to a %s '.
'account. Before you can link it to a different %s account, you '.
'must unlink the old account.',
$provider_name,
$provider_name)));
$dialog->addCancelButton($provider->getSettingsPanelURI());
return id(new AphrontDialogResponse())->setDialog($dialog);
}
if (!$request->isDialogFormPost()) {
$dialog = new AphrontDialogView();
$dialog->setUser($current_user);
$dialog->setTitle(pht('Link %s Account', $provider_name));
$dialog->appendChild(phutil_tag('p', array(), pht(
'Link your %s account to your Phabricator account?',
$provider_name)));
$dialog->addHiddenInput('confirm_token', $provider->getAccessToken());
$dialog->addHiddenInput('state', $this->oauthState);
$dialog->addSubmitButton('Link Accounts');
$dialog->addCancelButton($provider->getSettingsPanelURI());
return id(new AphrontDialogResponse())->setDialog($dialog);
}
$oauth_info->setUserID($current_user->getID());
$this->saveOAuthInfo($oauth_info);
return id(new AphrontRedirectResponse())
->setURI($provider->getSettingsPanelURI());
}
// Login with known auth.
if ($oauth_info->getID()) {
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$known_user = id(new PhabricatorUser())->load($oauth_info->getUserID());
$request->getApplicationConfiguration()->willAuthenticateUserWithOAuth(
$known_user,
$oauth_info,
$provider);
$this->saveOAuthInfo($oauth_info);
return $this->loginUser($known_user);
}
$oauth_email = $provider->retrieveUserEmail();
if ($oauth_email) {
$known_email = id(new PhabricatorUserEmail())
->loadOneWhere('address = %s', $oauth_email);
if ($known_email) {
$dialog = new AphrontDialogView();
$dialog->setUser($current_user);
$dialog->setTitle(pht('Already Linked to Another Account'));
$dialog->appendChild(phutil_tag(
'p',
array(),
pht(
'The %s account you just authorized has an email address which '.
'is already in use by another Phabricator account. To link the '.
'accounts, log in to your Phabricator account and then go to '.
'Settings.',
$provider_name)));
$dialog->addCancelButton('/login/');
return id(new AphrontDialogResponse())->setDialog($dialog);
}
}
if (!$provider->isProviderRegistrationEnabled()) {
$dialog = new AphrontDialogView();
$dialog->setUser($current_user);
$dialog->setTitle(pht('No Account Registration with %s', $provider_name));
$dialog->appendChild(phutil_tag(
'p',
array(),
pht(
'You can not register a new account using %s; you can only use '.
'your %s account to log into an existing Phabricator account which '.
'you have registered through other means.',
$provider_name,
$provider_name)));
$dialog->addCancelButton('/login/');
return id(new AphrontDialogResponse())->setDialog($dialog);
}
$controller = PhabricatorEnv::newObjectFromConfig(
'controller.oauth-registration',
array($this->getRequest()));
$controller->setOAuthProvider($provider);
$controller->setOAuthInfo($oauth_info);
$controller->setOAuthState($this->oauthState);
return $this->delegateToController($controller);
}
private function buildErrorResponse(PhabricatorOAuthFailureView $view,
Exception $e = null) {
$provider = $this->provider;
$provider_name = $provider->getProviderName();
$view->setOAuthProvider($provider);
if ($e) {
$view->setException($e);
}
return $this->buildStandardPageResponse(
$view,
array(
'title' => pht('Auth Failed'),
));
}
private function retrieveAccessToken(PhabricatorOAuthProvider $provider) {
$request = $this->getRequest();
$token = $request->getStr('confirm_token');
if ($token) {
$this->accessToken = $token;
$this->oauthState = $request->getStr('state');
return null;
}
$client_id = $provider->getClientID();
$client_secret = $provider->getClientSecret();
$redirect_uri = $provider->getRedirectURI();
$auth_uri = $provider->getTokenURI();
$code = $request->getStr('code');
$query_data = array(
'client_id' => $client_id,
'client_secret' => $client_secret,
'redirect_uri' => $redirect_uri,
'code' => $code,
) + $provider->getExtraTokenParameters();
$future = new HTTPSFuture($auth_uri, $query_data);
$future->setMethod('POST');
try {
list($response) = $future->resolvex();
} catch (Exception $ex) {
return $this->buildErrorResponse(new PhabricatorOAuthFailureView());
}
$data = $provider->decodeTokenResponse($response);
$token = idx($data, 'access_token');
if (!$token) {
return $this->buildErrorResponse(new PhabricatorOAuthFailureView());
}
$this->accessToken = $token;
$this->oauthState = $request->getStr('state');
return null;
}
private function retrieveOAuthInfo(PhabricatorOAuthProvider $provider) {
$oauth_info = PhabricatorUserOAuthInfo::loadOneByProviderKeyAndAccountID(
$provider->getProviderKey(),
$provider->retrieveUserID());
if (!$oauth_info) {
$oauth_info = new PhabricatorUserOAuthInfo(
new PhabricatorExternalAccount());
$oauth_info->setOAuthProvider($provider->getProviderKey());
$oauth_info->setOAuthUID($provider->retrieveUserID());
}
$oauth_info->setAccountURI($provider->retrieveUserAccountURI());
$oauth_info->setAccountName($provider->retrieveUserAccountName());
$oauth_info->setToken($provider->getAccessToken());
return $oauth_info;
}
private function saveOAuthInfo(PhabricatorUserOAuthInfo $info) {
// UNGUARDED WRITES: Logging-in users don't have their CSRF set up yet.
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$info->save();
}
}

View file

@ -1,224 +0,0 @@
<?php
final class PhabricatorOAuthDefaultRegistrationController
extends PhabricatorOAuthRegistrationController {
public function processRequest() {
$provider = $this->getOAuthProvider();
$oauth_info = $this->getOAuthInfo();
$request = $this->getRequest();
$errors = array();
$e_username = true;
$e_email = true;
$e_realname = true;
$user = new PhabricatorUser();
$user->setUsername($provider->retrieveUserAccountName());
$user->setRealName($provider->retrieveUserRealName());
$new_email = $provider->retrieveUserEmail();
if ($new_email) {
// If the user's OAuth provider account has an email address but the
// email address domain is not allowed by the Phabricator configuration,
// we just pretend the provider did not supply an address.
//
// For instance, if the user uses Google OAuth and their Google address
// is "joe@personal.com" but Phabricator is configured to require users
// use "@company.com" addresses, we show a prompt below and tell the user
// to provide their "@company.com" address. They can still use the OAuth
// account to login, they just need to associate their account with an
// allowed address.
//
// If the OAuth address is fine, we just use it and don't prompt the user.
if (!PhabricatorUserEmail::isAllowedAddress($new_email)) {
$new_email = null;
}
}
$show_email_input = ($new_email === null);
if ($request->isFormPost()) {
$user->setUsername($request->getStr('username'));
$username = $user->getUsername();
if (!strlen($user->getUsername())) {
$e_username = pht('Required');
$errors[] = pht('Username is required.');
} else if (!PhabricatorUser::validateUsername($username)) {
$e_username = pht('Invalid');
$errors[] = PhabricatorUser::describeValidUsername();
} else {
$e_username = null;
}
if (!$new_email) {
$new_email = trim($request->getStr('email'));
if (!$new_email) {
$e_email = pht('Required');
$errors[] = pht('Email is required.');
} else {
$e_email = null;
}
}
if ($new_email) {
$email_ok = PhabricatorUserEmail::isAllowedAddress($new_email);
if (!$email_ok) {
$e_email = pht('Invalid');
$errors[] = PhabricatorUserEmail::describeAllowedAddresses();
}
}
if (!strlen($user->getRealName())) {
$user->setRealName($request->getStr('realname'));
if (!strlen($user->getRealName())) {
$e_realname = pht('Required');
$errors[] = pht('Real name is required.');
} else {
$e_realname = null;
}
}
if (!$errors) {
$image = $provider->retrieveUserProfileImage();
if ($image) {
$file = PhabricatorFile::newFromFileData(
$image,
array(
'name' => $provider->getProviderKey().'-profile.jpg',
'authorPHID' => $user->getPHID(),
));
$xformer = new PhabricatorImageTransformer();
// Resize OAuth image to a reasonable size
$small_xformed = $xformer->executeProfileTransform(
$file,
$width = 50,
$min_height = 50,
$max_height = 50);
$user->setProfileImagePHID($small_xformed->getPHID());
}
try {
// NOTE: We don't verify OAuth email addresses by default because
// OAuth providers might associate email addresses with accounts that
// haven't actually verified they own them. We could selectively
// auto-verify some providers that we trust here, but the stakes for
// verifying an email address are high because having a corporate
// address at a company is sometimes the key to the castle.
$email_obj = id(new PhabricatorUserEmail())
->setAddress($new_email)
->setIsVerified(0);
id(new PhabricatorUserEditor())
->setActor($user)
->createNewUser($user, $email_obj);
$oauth_info->setUserID($user->getID());
$oauth_info->save();
$session_key = $user->establishSession('web');
$request->setCookie('phusr', $user->getUsername());
$request->setCookie('phsid', $session_key);
$email_obj->sendVerificationEmail($user);
return id(new AphrontRedirectResponse())->setURI('/');
} catch (AphrontQueryDuplicateKeyException $exception) {
$same_username = id(new PhabricatorUser())->loadOneWhere(
'userName = %s',
$user->getUserName());
$same_email = id(new PhabricatorUserEmail())->loadOneWhere(
'address = %s',
$new_email);
if ($same_username) {
$e_username = pht('Duplicate');
$errors[] = pht('That username or email is not unique.');
} else if ($same_email) {
$e_email = pht('Duplicate');
$errors[] = pht('That email is not unique.');
} else {
throw $exception;
}
}
}
}
$error_view = null;
if ($errors) {
$error_view = new AphrontErrorView();
$error_view->setTitle(pht('Registration Failed'));
$error_view->setErrors($errors);
}
// Strip the URI down to the path, because otherwise we'll trigger
// external CSRF protection (by having a protocol in the form "action")
// and generate a form with no CSRF token.
$action_uri = new PhutilURI($provider->getRedirectURI());
$action_path = $action_uri->getPath();
$form = new AphrontFormView();
$form
->addHiddenInput('confirm_token', $provider->getAccessToken())
->addHiddenInput('state', $this->getOAuthState())
->setUser($request->getUser())
->setAction($action_path)
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Username'))
->setName('username')
->setValue($user->getUsername())
->setError($e_username));
if ($show_email_input) {
$form->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Email'))
->setName('email')
->setValue($request->getStr('email'))
->setCaption(PhabricatorUserEmail::describeAllowedAddresses())
->setError($e_email));
}
if ($provider->retrieveUserRealName() === null) {
$form->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Real Name'))
->setName('realname')
->setValue($request->getStr('realname'))
->setError($e_realname));
}
$form
->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Create Account')));
$panel = new AphrontPanelView();
$panel->setHeader(pht('Create New Account'));
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
$panel->appendChild($form);
$panel->setNoBackground();
return $this->buildApplicationPage(
array(
$error_view,
$panel,
),
array(
'title' => pht('Create New Account'),
'device' => true
));
}
}

View file

@ -1,37 +0,0 @@
<?php
abstract class PhabricatorOAuthRegistrationController
extends PhabricatorAuthController {
private $oauthProvider;
private $oauthInfo;
private $oauthState;
final public function setOAuthInfo($info) {
$this->oauthInfo = $info;
return $this;
}
final public function getOAuthInfo() {
return $this->oauthInfo;
}
final public function setOAuthProvider($provider) {
$this->oauthProvider = $provider;
return $this;
}
final public function getOAuthProvider() {
return $this->oauthProvider;
}
final public function setOAuthState($state) {
$this->oauthState = $state;
return $this;
}
final public function getOAuthState() {
return $this->oauthState;
}
}

View file

@ -1,164 +0,0 @@
<?php
abstract class PhabricatorOAuthProvider {
const PROVIDER_FACEBOOK = 'facebook';
const PROVIDER_GITHUB = 'github';
const PROVIDER_GOOGLE = 'google';
const PROVIDER_PHABRICATOR = 'phabricator';
const PROVIDER_DISQUS = 'disqus';
private $accessToken;
abstract public function getProviderKey();
abstract public function getProviderName();
abstract public function isProviderEnabled();
abstract public function isProviderLinkPermanent();
abstract public function isProviderRegistrationEnabled();
abstract public function getClientID();
abstract public function renderGetClientIDHelp();
abstract public function getClientSecret();
abstract public function renderGetClientSecretHelp();
abstract public function getAuthURI();
abstract public function getTestURIs();
public function getSettingsPanelURI() {
return '/settings/panel/external/';
}
/**
* If the provider needs extra stuff in the auth request, return it here.
* For example, Google needs a response_type parameter.
*/
public function getExtraAuthParameters() {
return array();
}
/**
* If the provider supports application login, the diagnostics page can try
* to test it. Most providers do not support this (Facebook does).
*/
public function shouldDiagnoseAppLogin() {
return false;
}
abstract public function getTokenURI();
/**
* Access tokens expire based on an implementation-specific key.
*/
abstract protected function getTokenExpiryKey();
public function getTokenExpiryFromArray(array $data) {
$key = $this->getTokenExpiryKey();
if ($key) {
$expiry_value = idx($data, $key, 0);
if ($expiry_value) {
return time() + $expiry_value;
}
}
return 0;
}
/**
* If the provider needs extra stuff in the token request, return it here.
* For example, Google needs a grant_type parameter.
*/
public function getExtraTokenParameters() {
return array();
}
abstract public function getUserInfoURI();
abstract public function getMinimumScope();
abstract public function setUserData($data);
abstract public function retrieveUserID();
abstract public function retrieveUserEmail();
abstract public function retrieveUserAccountName();
abstract public function retrieveUserProfileImage();
abstract public function retrieveUserAccountURI();
abstract public function retrieveUserRealName();
/**
* Override this if the provider returns the token response as, e.g., JSON
* or XML.
*/
public function decodeTokenResponse($response) {
$data = null;
parse_str($response, $data);
return $data;
}
public function __construct() {
}
/**
* This is where the OAuth provider will redirect the user after the user
* grants Phabricator access.
*/
final public function getRedirectURI() {
$key = $this->getProviderKey();
return PhabricatorEnv::getURI('/oauth/'.$key.'/login/');
}
final public function setAccessToken($access_token) {
$this->accessToken = $access_token;
return $this;
}
final public function getAccessToken() {
return $this->accessToken;
}
/**
* Often used within setUserData to make sure $data is not completely
* junk. More granular validations of data might be necessary depending on
* the provider and are generally encouraged.
*/
final protected function validateUserData($data) {
if (empty($data) || !is_array($data)) {
throw new PhabricatorOAuthProviderException();
}
return true;
}
public static function newProvider($which) {
switch ($which) {
case self::PROVIDER_FACEBOOK:
$class = 'PhabricatorOAuthProviderFacebook';
break;
case self::PROVIDER_GITHUB:
$class = 'PhabricatorOAuthProviderGitHub';
break;
case self::PROVIDER_GOOGLE:
$class = 'PhabricatorOAuthProviderGoogle';
break;
case self::PROVIDER_PHABRICATOR:
$class = 'PhabricatorOAuthProviderPhabricator';
break;
case self::PROVIDER_DISQUS:
$class = 'PhabricatorOAuthProviderDisqus';
break;
default:
throw new Exception('Unknown OAuth provider.');
}
return newv($class, array());
}
public static function getAllProviders() {
$all = array(
self::PROVIDER_FACEBOOK,
self::PROVIDER_GITHUB,
self::PROVIDER_GOOGLE,
self::PROVIDER_PHABRICATOR,
self::PROVIDER_DISQUS,
);
$providers = array();
foreach ($all as $provider) {
$providers[$provider] = self::newProvider($provider);
}
return $providers;
}
}

View file

@ -1,128 +0,0 @@
<?php
final class PhabricatorOAuthProviderDisqus extends PhabricatorOAuthProvider {
private $userData;
public function getProviderKey() {
return self::PROVIDER_DISQUS;
}
public function getProviderName() {
return 'Disqus';
}
public function isProviderEnabled() {
return PhabricatorEnv::getEnvConfig('disqus.auth-enabled');
}
public function isProviderLinkPermanent() {
return PhabricatorEnv::getEnvConfig('disqus.auth-permanent');
}
public function isProviderRegistrationEnabled() {
return PhabricatorEnv::getEnvConfig('disqus.registration-enabled');
}
public function getClientID() {
return PhabricatorEnv::getEnvConfig('disqus.application-id');
}
public function renderGetClientIDHelp() {
return null;
}
public function getClientSecret() {
return PhabricatorEnv::getEnvConfig('disqus.application-secret');
}
public function renderGetClientSecretHelp() {
return null;
}
public function getAuthURI() {
return 'https://disqus.com/api/oauth/2.0/authorize/';
}
public function getTokenURI() {
return 'https://disqus.com/api/oauth/2.0/access_token/';
}
protected function getTokenExpiryKey() {
return 'expires_in';
}
public function getExtraAuthParameters() {
return array(
'response_type' => 'code',
);
}
public function getExtraTokenParameters() {
return array(
'grant_type' => 'authorization_code',
);
}
public function decodeTokenResponse($response) {
return json_decode($response, true);
}
public function getTestURIs() {
return array(
'http://disqus.com',
$this->getUserInfoURI(),
);
}
public function getUserInfoURI() {
return 'https://disqus.com/api/3.0/users/details.json?'.
'api_key='.$this->getClientID();
}
public function getMinimumScope() {
return 'read';
}
public function setUserData($data) {
$data = idx(json_decode($data, true), 'response');
$this->validateUserData($data);
$this->userData = $data;
return $this;
}
public function retrieveUserID() {
return $this->userData['id'];
}
public function retrieveUserEmail() {
return idx($this->userData, 'email');
}
public function retrieveUserAccountName() {
return $this->userData['username'];
}
public function retrieveUserProfileImage() {
$avatar = idx($this->userData, 'avatar');
if ($avatar) {
$uri = idx($avatar, 'permalink');
if ($uri) {
return HTTPSFuture::loadContent($uri);
}
}
return null;
}
public function retrieveUserAccountURI() {
return idx($this->userData, 'profileUrl');
}
public function retrieveUserRealName() {
return idx($this->userData, 'name');
}
public function shouldDiagnoseAppLogin() {
return true;
}
}

View file

@ -1,4 +0,0 @@
<?php
final class PhabricatorOAuthProviderException extends Exception {
}

View file

@ -1,126 +0,0 @@
<?php
final class PhabricatorOAuthProviderFacebook extends PhabricatorOAuthProvider {
private $userData;
public function getProviderKey() {
return self::PROVIDER_FACEBOOK;
}
public function getProviderName() {
return 'Facebook';
}
public function isProviderEnabled() {
return PhabricatorEnv::getEnvConfig('facebook.auth-enabled');
}
public function isProviderLinkPermanent() {
return PhabricatorEnv::getEnvConfig('facebook.auth-permanent');
}
public function isProviderRegistrationEnabled() {
return PhabricatorEnv::getEnvConfig('facebook.registration-enabled');
}
public function getClientID() {
return PhabricatorEnv::getEnvConfig('facebook.application-id');
}
public function renderGetClientIDHelp() {
return 'To generate an ID, sign into Facebook, install the "Developer"'.
' application, and use it to create a new Facebook application.';
}
public function getClientSecret() {
return PhabricatorEnv::getEnvConfig('facebook.application-secret');
}
public function renderGetClientSecretHelp() {
return 'You can find the application secret in the Facebook'.
' "Developer" application on Facebook.';
}
public function getAuthURI() {
return 'https://www.facebook.com/dialog/oauth';
}
public function getTestURIs() {
return array(
'http://facebook.com',
'https://graph.facebook.com/me'
);
}
public function getTokenURI() {
return 'https://graph.facebook.com/oauth/access_token';
}
protected function getTokenExpiryKey() {
return 'expires';
}
public function getUserInfoURI() {
$fields = array('id', 'name', 'email', 'link', 'security_settings');
return 'https://graph.facebook.com/me?fields='.
implode(',', $fields);
}
public function getMinimumScope() {
return 'email';
}
public function setUserData($data) {
$data = json_decode($data, true);
$this->validateUserData($data);
if (PhabricatorEnv::getEnvConfig('facebook.require-https-auth')) {
if (!$data['security_settings']['secure_browsing']['enabled']) {
throw new PhabricatorOAuthProviderException(
'You must enable Secure Browsing on your Facebook account in'.
' order to log in to Phabricator. For more information, check'.
' out http://www.facebook.com/help/?faq=215897678434749'
);
}
}
$this->userData = $data;
return $this;
}
public function retrieveUserID() {
return $this->userData['id'];
}
public function retrieveUserEmail() {
return $this->userData['email'];
}
public function retrieveUserAccountName() {
$matches = null;
$link = $this->userData['link'];
if (preg_match('@/([a-zA-Z0-9]+)$@', $link, $matches)) {
return $matches[1];
}
return null;
}
public function retrieveUserProfileImage() {
$uri = 'https://graph.facebook.com/me/picture?access_token=';
return HTTPSFuture::loadContent($uri.$this->getAccessToken());
}
public function retrieveUserAccountURI() {
return $this->userData['link'];
}
public function retrieveUserRealName() {
return $this->userData['name'];
}
public function shouldDiagnoseAppLogin() {
return true;
}
}

View file

@ -1,113 +0,0 @@
<?php
final class PhabricatorOAuthProviderGitHub extends PhabricatorOAuthProvider {
private $userData;
public function getProviderKey() {
return self::PROVIDER_GITHUB;
}
public function getProviderName() {
return 'GitHub';
}
public function isProviderEnabled() {
return PhabricatorEnv::getEnvConfig('github.auth-enabled');
}
public function isProviderLinkPermanent() {
return PhabricatorEnv::getEnvConfig('github.auth-permanent');
}
public function isProviderRegistrationEnabled() {
return PhabricatorEnv::getEnvConfig('github.registration-enabled');
}
public function getClientID() {
return PhabricatorEnv::getEnvConfig('github.application-id');
}
public function renderGetClientIDHelp() {
return null;
}
public function getClientSecret() {
return PhabricatorEnv::getEnvConfig('github.application-secret');
}
public function renderGetClientSecretHelp() {
return null;
}
public function getAuthURI() {
return 'https://github.com/login/oauth/authorize';
}
public function getTokenURI() {
return 'https://github.com/login/oauth/access_token';
}
protected function getTokenExpiryKey() {
// github access tokens do not have time-based expiry
return null;
}
public function getTestURIs() {
return array(
'http://api.github.com',
);
}
public function getUserInfoURI() {
return 'https://api.github.com/user';
}
public function getMinimumScope() {
return null;
}
public function setUserData($data) {
$data = json_decode($data, true);
$this->validateUserData($data);
$this->userData = $data;
return $this;
}
public function retrieveUserID() {
return $this->userData['id'];
}
public function retrieveUserEmail() {
return idx($this->userData, 'email');
}
public function retrieveUserAccountName() {
return $this->userData['login'];
}
public function retrieveUserProfileImage() {
$uri = idx($this->userData, 'avatar_url');
if ($uri) {
return HTTPSFuture::loadContent($uri);
}
return null;
}
public function retrieveUserAccountURI() {
$username = $this->retrieveUserAccountName();
if (strlen($username)) {
return 'https://github.com/'.$username;
}
return null;
}
public function retrieveUserRealName() {
return idx($this->userData, 'name');
}
public function shouldDiagnoseAppLogin() {
return true;
}
}

View file

@ -1,130 +0,0 @@
<?php
final class PhabricatorOAuthProviderGoogle extends PhabricatorOAuthProvider {
private $userData;
public function getProviderKey() {
return self::PROVIDER_GOOGLE;
}
public function getProviderName() {
return 'Google';
}
public function isProviderEnabled() {
return PhabricatorEnv::getEnvConfig('google.auth-enabled');
}
public function isProviderLinkPermanent() {
return PhabricatorEnv::getEnvConfig('google.auth-permanent');
}
public function isProviderRegistrationEnabled() {
return PhabricatorEnv::getEnvConfig('google.registration-enabled');
}
public function getClientID() {
return PhabricatorEnv::getEnvConfig('google.application-id');
}
public function renderGetClientIDHelp() {
return null;
}
public function getClientSecret() {
return PhabricatorEnv::getEnvConfig('google.application-secret');
}
public function renderGetClientSecretHelp() {
return null;
}
public function getAuthURI() {
return 'https://accounts.google.com/o/oauth2/auth';
}
public function getTestURIs() {
return array(
'http://www.google.com'
);
}
public function getTokenURI() {
return 'https://accounts.google.com/o/oauth2/token';
}
protected function getTokenExpiryKey() {
return 'expires_in';
}
public function getUserInfoURI() {
return 'https://www.googleapis.com/oauth2/v1/userinfo';
}
public function getMinimumScope() {
$scopes = array(
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
);
return implode(' ', $scopes);
}
public function setUserData($data) {
$data = json_decode($data, true);
$this->validateUserData($data);
// Guess account name from email address, this is just a hint anyway.
$data['account'] = head(explode('@', $data['email']));
$this->userData = $data;
return $this;
}
public function retrieveUserID() {
return $this->userData['email'];
}
public function retrieveUserEmail() {
return $this->userData['email'];
}
public function retrieveUserAccountName() {
return $this->userData['account'];
}
public function retrieveUserProfileImage() {
$uri = idx($this->userData, 'picture');
if ($uri) {
return HTTPSFuture::loadContent($uri);
}
return null;
}
public function retrieveUserAccountURI() {
return 'https://plus.google.com/'.$this->userData['id'];
}
public function retrieveUserRealName() {
return $this->userData['name'];
}
public function getExtraAuthParameters() {
return array(
'response_type' => 'code',
);
}
public function getExtraTokenParameters() {
return array(
'grant_type' => 'authorization_code',
);
}
public function decodeTokenResponse($response) {
return json_decode($response, true);
}
}

View file

@ -1,131 +0,0 @@
<?php
final class PhabricatorOAuthProviderPhabricator
extends PhabricatorOAuthProvider {
private $userData;
public function getExtraAuthParameters() {
return array(
'response_type' => 'code',
);
}
public function getExtraTokenParameters() {
return array(
'grant_type' => 'authorization_code',
);
}
public function decodeTokenResponse($response) {
$decoded = json_decode($response, true);
if (!is_array($decoded)) {
throw new Exception('Invalid token response.');
}
return $decoded;
}
public function getProviderKey() {
return self::PROVIDER_PHABRICATOR;
}
public function getProviderName() {
return 'Phabricator';
}
public function isProviderEnabled() {
return PhabricatorEnv::getEnvConfig('phabricator.auth-enabled');
}
public function isProviderLinkPermanent() {
return PhabricatorEnv::getEnvConfig('phabricator.auth-permanent');
}
public function isProviderRegistrationEnabled() {
return PhabricatorEnv::getEnvConfig('phabricator.registration-enabled');
}
public function getClientID() {
return PhabricatorEnv::getEnvConfig('phabricator.application-id');
}
public function renderGetClientIDHelp() {
return null;
}
public function getClientSecret() {
return PhabricatorEnv::getEnvConfig('phabricator.application-secret');
}
public function renderGetClientSecretHelp() {
return null;
}
public function getAuthURI() {
return $this->getURI('/oauthserver/auth/');
}
public function getTestURIs() {
return array(
$this->getURI('/'),
$this->getURI('/api/user.whoami/')
);
}
public function getTokenURI() {
return $this->getURI('/oauthserver/token/');
}
protected function getTokenExpiryKey() {
return 'expires_in';
}
public function getUserInfoURI() {
return $this->getURI('/api/user.whoami');
}
public function getMinimumScope() {
return 'whoami';
}
public function setUserData($data) {
// legacy conditionally strip shield. see D3265 for discussion.
if (strncmp($data, 'for(;;);', 8) === 0) {
$data = substr($data, 8);
}
$data = idx(json_decode($data, true), 'result');
$this->validateUserData($data);
$this->userData = $data;
return $this;
}
public function retrieveUserID() {
return $this->userData['phid'];
}
public function retrieveUserEmail() {
return $this->userData['email'];
}
public function retrieveUserAccountName() {
return $this->userData['userName'];
}
public function retrieveUserProfileImage() {
$uri = $this->userData['image'];
return HTTPSFuture::loadContent($uri);
}
public function retrieveUserAccountURI() {
return $this->userData['uri'];
}
public function retrieveUserRealName() {
return $this->userData['realName'];
}
private function getURI($path) {
return
rtrim(PhabricatorEnv::getEnvConfig('phabricator.oauth-uri'), '/') .
$path;
}
}

View file

@ -48,4 +48,9 @@ final class PhabricatorAuthProviderOAuthGoogle
return !PhabricatorEnv::getEnvConfig('google.auth-permanent');
}
public function getLoginURI() {
// TODO: Clean this up. See PhabricatorAuthOldOAuthRedirectController.
return PhabricatorEnv::getURI('/oauth/google/login/');
}
}

View file

@ -39,7 +39,9 @@ final class PhabricatorAuthProviderPassword
}
public function shouldAllowRegistration() {
return true;
// TODO: Hard code this as "false" for now so we don't inadvertantly open
// up password registration where it did not previously exist.
return false;
}
public function shouldAllowAccountLink() {

View file

@ -1,90 +0,0 @@
<?php
final class PhabricatorOAuthFailureView extends AphrontView {
private $request;
private $provider;
private $exception;
public function setRequest(AphrontRequest $request) {
$this->request = $request;
return $this;
}
public function setOAuthProvider($provider) {
$this->provider = $provider;
return $this;
}
public function setException(Exception $e) {
$this->exception = $e;
return $this;
}
public function render() {
$request = $this->request;
$provider = $this->provider;
$provider_name = $provider->getProviderName();
$diagnose = null;
$view = new AphrontRequestFailureView();
$view->setHeader(pht('%s Auth Failed', $provider_name));
if ($this->request) {
$view->appendChild(
hsprintf(
'<p><strong>Description:</strong> %s</p>',
$request->getStr('error_description')));
$view->appendChild(
hsprintf(
'<p><strong>Error:</strong> %s</p>',
$request->getStr('error')));
$view->appendChild(
hsprintf(
'<p><strong>Error Reason:</strong> %s</p>',
$request->getStr('error_reason')));
} else if ($this->exception) {
$view->appendChild(
hsprintf(
'<p><strong>Error Details:</strong> %s</p>',
$this->exception->getMessage()));
} else {
// TODO: We can probably refine this.
$view->appendChild(
hsprintf(
'<p>Unable to authenticate with %s. '.
'There are several reasons this might happen:</p>'.
'<ul>'.
'<li>Phabricator may be configured with the wrong Application '.
'Secret; or</li>'.
'<li>the %s OAuth access token may have expired; or</li>'.
'<li>%s may have revoked authorization for the Application; '.
'or</li>'.
'<li>%s may be having technical problems.</li>'.
'</ul>'.
'<p>You can try again, or login using another method.</p>',
$provider_name,
$provider_name,
$provider_name,
$provider_name));
$provider_key = $provider->getProviderKey();
$diagnose = hsprintf(
'<a href="/oauth/%s/diagnose/" class="button green">'.
'Diagnose %s OAuth Problems'.
'</a>',
$provider_key,
$provider_name);
}
$view->appendChild(hsprintf(
'<div class="aphront-failure-continue">'.
'%s<a href="/login/" class="button">%s</a>'.
'</div>',
$diagnose,
pht('Continue')));
return $view->render();
}
}

View file

@ -100,7 +100,9 @@ abstract class PhabricatorController extends AphrontController {
}
if ($this->shouldRequireLogin() && !$user->getPHID()) {
$login_controller = new PhabricatorLoginController($request);
$login_controller = new PhabricatorAuthStartController($request);
$login_controller->setCurrentApplication(
PhabricatorApplication::getByClass('PhabricatorApplicationAuth'));
return $this->delegateToController($login_controller);
}

View file

@ -64,39 +64,6 @@ final class PhabricatorPeopleProfileController
// NOTE: applications install the various links through PhabricatorEvent
// listeners
$oauths = PhabricatorUserOAuthInfo::loadAllOAuthProvidersByUser($user);
$oauths = mpull($oauths, null, 'getOAuthProvider');
$providers = PhabricatorOAuthProvider::getAllProviders();
$added_label = false;
foreach ($providers as $provider) {
if (!$provider->isProviderEnabled()) {
continue;
}
$provider_key = $provider->getProviderKey();
if (!isset($oauths[$provider_key])) {
continue;
}
$name = pht('%s Profile', $provider->getProviderName());
$href = $oauths[$provider_key]->getAccountURI();
if ($href) {
if (!$added_label) {
$menu->newLabel(pht('Linked Accounts'), 'linked_accounts');
$added_label = true;
}
$menu->addMenuItem(
id(new PHUIListItemView())
->setIsExternal(true)
->setName($name)
->setHref($href)
->setType(PHUIListItemView::TYPE_LINK));
}
}
$event = new PhabricatorEvent(
PhabricatorEventType::TYPE_PEOPLE_DIDRENDERMENU,
array(

View file

@ -1,160 +0,0 @@
<?php
final class PhabricatorUserOAuthInfo {
private $account;
private $token;
public function getID() {
return $this->account->getID();
}
public function setToken($token) {
$this->token = $token;
return $this;
}
public function getToken() {
return $this->token;
}
public function __construct(PhabricatorExternalAccount $account) {
$this->account = $account;
}
public function setAccountURI($value) {
$this->account->setAccountURI($value);
return $this;
}
public function getAccountURI() {
return $this->account->getAccountURI();
}
public function setAccountName($account_name) {
$this->account->setUsername($account_name);
return $this;
}
public function getAccountName() {
return $this->account->getUsername();
}
public function setUserID($user_id) {
$user = id(new PhabricatorUser())->loadOneWhere('id = %d', $user_id);
if (!$user) {
throw new Exception("No such user with given ID!");
}
$this->account->setUserPHID($user->getPHID());
return $this;
}
public function getUserID() {
$phid = $this->account->getUserPHID();
if (!$phid) {
return null;
}
$user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $phid);
if (!$user) {
throw new Exception("No such user with given PHID!");
}
return $user->getID();
}
public function setOAuthUID($oauth_uid) {
$this->account->setAccountID($oauth_uid);
return $this;
}
public function getOAuthUID() {
return $this->account->getAccountID();
}
public function setOAuthProvider($oauth_provider) {
$domain = self::getDomainForProvider($oauth_provider);
$this->account->setAccountType($oauth_provider);
$this->account->setAccountDomain($domain);
return $this;
}
public function getOAuthProvider() {
return $this->account->getAccountType();
}
public static function loadOneByUserAndProviderKey(
PhabricatorUser $user,
$provider_key) {
$account = id(new PhabricatorExternalAccount())->loadOneWhere(
'userPHID = %s AND accountType = %s AND accountDomain = %s',
$user->getPHID(),
$provider_key,
self::getDomainForProvider($provider_key));
if (!$account) {
return null;
}
return new PhabricatorUserOAuthInfo($account);
}
public static function loadAllOAuthProvidersByUser(
PhabricatorUser $user) {
$accounts = id(new PhabricatorExternalAccount())->loadAllWhere(
'userPHID = %s',
$user->getPHID());
$results = array();
foreach ($accounts as $account) {
$results[] = new PhabricatorUserOAuthInfo($account);
}
return $results;
}
public static function loadOneByProviderKeyAndAccountID(
$provider_key,
$account_id) {
$account = id(new PhabricatorExternalAccount())->loadOneWhere(
'accountType = %s AND accountDomain = %s AND accountID = %s',
$provider_key,
self::getDomainForProvider($provider_key),
$account_id);
if (!$account) {
return null;
}
return new PhabricatorUserOAuthInfo($account);
}
public function save() {
$this->account->save();
return $this;
}
private static function getDomainForProvider($provider_key) {
$domain_map = array(
'disqus' => 'disqus.com',
'facebook' => 'facebook.com',
'github' => 'github.com',
'google' => 'google.com',
);
try {
$phabricator_oauth_uri = new PhutilURI(
PhabricatorEnv::getEnvConfig('phabricator.oauth-uri'));
$domain_map['phabricator'] = $phabricator_oauth_uri->getDomain();
} catch (Exception $ex) {
// Ignore.
}
return idx($domain_map, $provider_key);
}
}