Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/auth/controller/PhabricatorAuthController.php b/src/applications/auth/controller/PhabricatorAuthController.php
index f3c20cfde8..173aae06e4 100644
--- a/src/applications/auth/controller/PhabricatorAuthController.php
+++ b/src/applications/auth/controller/PhabricatorAuthController.php
@@ -1,57 +1,102 @@
<?php
abstract class PhabricatorAuthController extends PhabricatorController {
public function buildStandardPageResponse($view, array $data) {
$page = $this->buildStandardPageView();
$page->setApplicationName(pht('Login'));
$page->setBaseURI('/login/');
$page->setTitle(idx($data, 'title'));
$page->appendChild($view);
$response = new AphrontWebpageResponse();
return $response->setContent($page->render());
}
protected function renderErrorPage($title, array $messages) {
$view = new AphrontErrorView();
$view->setTitle($title);
$view->setErrors($messages);
return $this->buildApplicationPage(
$view,
array(
'title' => $title,
'device' => true,
'dust' => true,
));
}
- protected function establishWebSession(PhabricatorUser $user) {
- $session_key = $user->establishSession('web');
+ /**
+ * Log a user into a web session and return an @{class:AphrontResponse} which
+ * corresponds to continuing the login process.
+ *
+ * Normally, this is a redirect to the validation controller which makes sure
+ * the user's cookies are set. However, event listeners can intercept this
+ * event and do something else if they prefer.
+ *
+ * @param PhabricatorUser User to log the viewer in as.
+ * @return AphrontResponse Response which continues the login process.
+ */
+ protected function loginUser(PhabricatorUser $user) {
+
+ $response = $this->buildLoginValidateResponse($user);
+ $session_type = 'web';
+
+ $event_type = PhabricatorEventType::TYPE_AUTH_WILLLOGINUSER;
+ $event_data = array(
+ 'user' => $user,
+ 'type' => $session_type,
+ 'response' => $response,
+ 'shouldLogin' => true,
+ );
+
+ $event = id(new PhabricatorEvent($event_type, $event_data))
+ ->setUser($user);
+ PhutilEventEngine::dispatchEvent($event);
+
+ $should_login = $event->getValue('shouldLogin');
+ if ($should_login) {
+ $session_key = $user->establishSession($session_type);
+
+ // NOTE: We allow disabled users to login and roadblock them later, so
+ // there's no check for users being disabled here.
+
+ $request = $this->getRequest();
+ $request->setCookie('phusr', $user->getUsername());
+ $request->setCookie('phsid', $session_key);
+
+ $this->clearRegistrationCookies();
+ }
+
+ return $event->getValue('response');
+ }
+ protected function clearRegistrationCookies() {
$request = $this->getRequest();
- // NOTE: We allow disabled users to login and roadblock them later, so
- // there's no check for users being disabled here.
-
- $request->setCookie('phusr', $user->getUsername());
- $request->setCookie('phsid', $session_key);
-
// Clear the registration key.
$request->clearCookie('phreg');
// Clear the client ID / OAuth state key.
$request->clearCookie('phcid');
}
- protected function buildLoginValidateResponse(PhabricatorUser $user) {
+ private function buildLoginValidateResponse(PhabricatorUser $user) {
$validate_uri = new PhutilURI($this->getApplicationURI('validate/'));
$validate_uri->setQueryParam('phusr', $user->getUsername());
return id(new AphrontRedirectResponse())->setURI((string)$validate_uri);
}
+ protected function renderError($message) {
+ return $this->renderErrorPage(
+ pht('Authentication Error'),
+ array(
+ $message,
+ ));
+ }
+
}
diff --git a/src/applications/auth/controller/PhabricatorAuthLoginController.php b/src/applications/auth/controller/PhabricatorAuthLoginController.php
index b11482d36d..4a4711a34d 100644
--- a/src/applications/auth/controller/PhabricatorAuthLoginController.php
+++ b/src/applications/auth/controller/PhabricatorAuthLoginController.php
@@ -1,217 +1,215 @@
<?php
final class PhabricatorAuthLoginController
extends PhabricatorAuthController {
private $providerKey;
private $provider;
public function shouldRequireLogin() {
return false;
}
public function willProcessRequest(array $data) {
$this->providerKey = $data['pkey'];
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$response = $this->loadProvider();
if ($response) {
return $response;
}
$provider = $this->provider;
list($account, $response) = $provider->processLoginRequest($this);
if ($response) {
return $response;
}
if (!$account) {
throw new Exception(
"Auth provider failed to load an account from processLoginRequest()!");
}
if ($account->getUserPHID()) {
// The account is already attached to a Phabricator user, so this is
// either a login or a bad account link request.
if (!$viewer->isLoggedIn()) {
if ($provider->shouldAllowLogin()) {
return $this->processLoginUser($account);
} else {
return $this->renderError(
pht(
'The external account ("%s") you just authenticated with is '.
'not configured to allow logins on this Phabricator install. '.
'An administrator may have recently disabled it.',
$provider->getProviderName()));
}
} else if ($viewer->getPHID() == $account->getUserPHID()) {
return $this->renderError(
pht(
'This external account ("%s") is already linked to your '.
'Phabricator account.'));
} else {
return $this->renderError(
pht(
'The external account ("%s") you just used to login is alerady '.
'associated with another Phabricator user account. Login to the '.
'other Phabricator account and unlink the external account before '.
'linking it to a new Phabricator account.',
$provider->getProviderName()));
}
} else {
// The account is not yet attached to a Phabricator user, so this is
// either a registration or an account link request.
if (!$viewer->isLoggedIn()) {
if ($provider->shouldAllowRegistration()) {
return $this->processRegisterUser($account);
} else {
return $this->renderError(
pht(
'The external account ("%s") you just authenticated with is '.
'not configured to allow registration on this Phabricator '.
'install. An administrator may have recently disabled it.',
$provider->getProviderName()));
}
} else {
if ($provider->shouldAllowAccountLink()) {
return $this->processLinkUser($account);
} else {
return $this->renderError(
pht(
'The external account ("%s") you just authenticated with is '.
'not configured to allow account linking on this Phabricator '.
'install. An administrator may have recently disabled it.',
$provider->getProviderName()));
}
}
}
// This should be unreachable, but fail explicitly if we get here somehow.
return new Aphront400Response();
}
private function processLoginUser(PhabricatorExternalAccount $account) {
$user = id(new PhabricatorUser())->loadOneWhere(
'phid = %s',
$account->getUserPHID());
if (!$user) {
return $this->renderError(
pht(
'The external account you just logged in with is not associated '.
'with a valid Phabricator user.'));
}
- $this->establishWebSession($user);
-
- return $this->buildLoginValidateResponse($user);
+ return $this->loginUser($user);
}
private function processRegisterUser(PhabricatorExternalAccount $account) {
if ($account->getUserPHID()) {
throw new Exception("Account is already registered.");
}
// Regenerate the registration secret key, set it on the external account,
// set a cookie on the user's machine, and redirect them to registration.
// See PhabricatorAuthRegisterController for discussion of the registration
// key.
$registration_key = Filesystem::readRandomCharacters(32);
$account->setProperty(
'registrationKey',
PhabricatorHash::digest($registration_key));
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$account->save();
unset($unguarded);
$this->getRequest()->setCookie('phreg', $registration_key);
$account_secret = $account->getAccountSecret();
$register_uri = $this->getApplicationURI('register/'.$account_secret.'/');
return id(new AphrontRedirectResponse())->setURI($register_uri);
}
private function processLinkUser(PhabricatorExternalAccount $account) {
// TODO: Implement.
return new Aphront404Response();
}
private function loadProvider() {
$provider = PhabricatorAuthProvider::getEnabledProviderByKey(
$this->providerKey);
if (!$provider) {
return $this->renderError(
pht(
'The account you are attempting to login with uses a nonexistent '.
'or disabled authentication provider (with key "%s"). An '.
'administrator may have recently disabled this provider.',
$this->providerKey));
}
$this->provider = $provider;
return null;
}
- private function renderError($message) {
+ protected function renderError($message) {
$title = pht('Login Failed');
$view = new AphrontErrorView();
$view->setTitle($title);
$view->appendChild($message);
return $this->buildApplicationPage(
$view,
array(
'title' => $title,
'device' => true,
'dust' => true,
));
}
public function buildProviderPageResponse(
PhabricatorAuthProvider $provider,
$content) {
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName(pht('Login'))
->setHref($this->getApplicationURI('start/')));
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName($provider->getProviderName()));
return $this->buildApplicationPage(
array(
$crumbs,
$content,
),
array(
'title' => pht('Login'),
'device' => true,
'dust' => true,
));
}
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/controller/PhabricatorAuthRegisterController.php b/src/applications/auth/controller/PhabricatorAuthRegisterController.php
index 062ac4cc4a..a5df51f255 100644
--- a/src/applications/auth/controller/PhabricatorAuthRegisterController.php
+++ b/src/applications/auth/controller/PhabricatorAuthRegisterController.php
@@ -1,489 +1,487 @@
<?php
final class PhabricatorAuthRegisterController
extends PhabricatorAuthController {
private $accountKey;
private $account;
private $provider;
public function shouldRequireLogin() {
return false;
}
public function willProcessRequest(array $data) {
$this->accountKey = idx($data, 'akey');
}
public function processRequest() {
$request = $this->getRequest();
if ($request->getUser()->isLoggedIn()) {
return $this->renderError(pht('You are already logged in.'));
}
if (strlen($this->accountKey)) {
$response = $this->loadAccount();
} else {
$response = $this->loadDefaultAccount();
}
if ($response) {
return $response;
}
$account = $this->account;
$user = new PhabricatorUser();
$default_username = $account->getUsername();
$default_realname = $account->getRealName();
$default_email = $account->getEmail();
if ($default_email) {
// If the account source provided an email but it's not allowed by
// the configuration, just pretend we didn't get an email at all.
if (!PhabricatorUserEmail::isAllowedAddress($default_email)) {
$default_email = null;
}
// If the account source provided an email, but another account already
// has that email, just pretend we didn't get an email.
// TODO: See T3340.
if ($default_email) {
$same_email = id(new PhabricatorUserEmail())->loadOneWhere(
'address = %s',
$default_email);
if ($same_email) {
$default_email = null;
}
}
}
$profile = id(new PhabricatorRegistrationProfile())
->setDefaultUsername($default_username)
->setDefaultEmail($default_email)
->setDefaultRealName($default_realname)
->setCanEditUsername(true)
->setCanEditEmail(($default_email === null))
->setCanEditRealName(true)
->setShouldVerifyEmail(false);
$event_type = PhabricatorEventType::TYPE_AUTH_WILLREGISTERUSER;
$event_data = array(
'account' => $account,
'profile' => $profile,
);
$event = id(new PhabricatorEvent($event_type, $event_data))
->setUser($user);
PhutilEventEngine::dispatchEvent($event);
$default_username = $profile->getDefaultUsername();
$default_email = $profile->getDefaultEmail();
$default_realname = $profile->getDefaultRealName();
$can_edit_username = $profile->getCanEditUsername();
$can_edit_email = $profile->getCanEditEmail();
$can_edit_realname = $profile->getCanEditRealName();
$must_set_password = $this->provider->shouldRequireRegistrationPassword();
$can_edit_anything = $profile->getCanEditAnything() || $must_set_password;
$force_verify = $profile->getShouldVerifyEmail();
$value_username = $default_username;
$value_realname = $default_realname;
$value_email = $default_email;
$value_password = null;
$errors = array();
$e_username = strlen($value_username) ? null : true;
$e_realname = strlen($value_realname) ? null : true;
$e_email = strlen($value_email) ? null : true;
$e_password = true;
$min_len = PhabricatorEnv::getEnvConfig('account.minimum-password-length');
$min_len = (int)$min_len;
if ($request->isFormPost() || !$can_edit_anything) {
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
if ($can_edit_username) {
$value_username = $request->getStr('username');
if (!strlen($value_username)) {
$e_username = pht('Required');
$errors[] = pht('Username is required.');
} else if (!PhabricatorUser::validateUsername($value_username)) {
$e_username = pht('Invalid');
$errors[] = PhabricatorUser::describeValidUsername();
} else {
$e_username = null;
}
}
if ($must_set_password) {
$value_password = $request->getStr('password');
$value_confirm = $request->getStr('confirm');
if (!strlen($value_password)) {
$e_password = pht('Required');
$errors[] = pht('You must choose a password.');
} else if ($value_password !== $value_confirm) {
$e_password = pht('No Match');
$errors[] = pht('Password and confirmation must match.');
} else if (strlen($value_password) < $min_len) {
$e_password = pht('Too Short');
$errors[] = pht(
'Password is too short (must be at least %d characters long).',
$min_len);
} else {
$e_password = null;
}
}
if ($can_edit_email) {
$value_email = $request->getStr('email');
if (!strlen($value_email)) {
$e_email = pht('Required');
$errors[] = pht('Email is required.');
} else if (!PhabricatorUserEmail::isAllowedAddress($value_email)) {
$e_email = pht('Invalid');
$errors[] = PhabricatorUserEmail::describeAllowedAddresses();
} else {
$e_email = null;
}
}
if ($can_edit_realname) {
$value_realname = $request->getStr('realName');
if (!strlen($value_realname)) {
$e_realname = pht('Required');
$errors[] = pht('Real name is required.');
} else {
$e_realname = null;
}
}
if (!$errors) {
$image = $this->loadProfilePicture($account);
if ($image) {
$user->setProfileImagePHID($image->getPHID());
}
try {
if ($force_verify) {
$verify_email = true;
} else {
$verify_email =
($account->getEmailVerified()) &&
($value_email === $default_email);
}
$email_obj = id(new PhabricatorUserEmail())
->setAddress($value_email)
->setIsVerified((int)$verify_email);
$user->setUsername($value_username);
$user->setRealname($value_realname);
$user->openTransaction();
$editor = id(new PhabricatorUserEditor())
->setActor($user);
$editor->createNewUser($user, $email_obj);
if ($must_set_password) {
$envelope = new PhutilOpaqueEnvelope($value_password);
$editor->changePassword($user, $envelope);
}
$account->setUserPHID($user->getPHID());
$this->provider->willRegisterAccount($account);
$account->save();
$user->saveTransaction();
- $this->establishWebSession($user);
-
if (!$email_obj->getIsVerified()) {
$email_obj->sendVerificationEmail($user);
}
- return $this->buildLoginValidateResponse($user);
+ return $this->loginUser($user);
} catch (AphrontQueryDuplicateKeyException $exception) {
$same_username = id(new PhabricatorUser())->loadOneWhere(
'userName = %s',
$user->getUserName());
$same_email = id(new PhabricatorUserEmail())->loadOneWhere(
'address = %s',
$value_email);
if ($same_username) {
$e_username = pht('Duplicate');
$errors[] = pht('Another user already has that username.');
}
if ($same_email) {
// TODO: See T3340.
$e_email = pht('Duplicate');
$errors[] = pht('Another user already has that email.');
}
if (!$same_username && !$same_email) {
throw $exception;
}
}
}
unset($unguarded);
}
$error_view = null;
if ($errors) {
$error_view = new AphrontErrorView();
$error_view->setTitle(pht('Registration Failed'));
$error_view->setErrors($errors);
}
$form = id(new AphrontFormView())
->setUser($request->getUser())
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Username'))
->setName('username')
->setValue($value_username)
->setError($e_username));
if ($must_set_password) {
$form->appendChild(
id(new AphrontFormPasswordControl())
->setLabel(pht('Password'))
->setName('password')
->setError($e_password)
->setCaption(
$min_len
? pht('Minimum length of %d characters.', $min_len)
: null));
$form->appendChild(
id(new AphrontFormPasswordControl())
->setLabel(pht('Confirm Password'))
->setName('confirm')
->setError($e_password));
}
if ($can_edit_email) {
$form->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Email'))
->setName('email')
->setValue($value_email)
->setCaption(PhabricatorUserEmail::describeAllowedAddresses())
->setError($e_email));
}
if ($can_edit_realname) {
$form->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Real Name'))
->setName('realName')
->setValue($value_realname)
->setError($e_realname));
}
$form->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Create Account')));
$title = pht('Phabricator Registration');
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName(pht('Register')));
return $this->buildApplicationPage(
array(
$crumbs,
$error_view,
$form,
),
array(
'title' => $title,
'device' => true,
'dust' => true,
));
}
private function loadAccount() {
$request = $this->getRequest();
if (!$this->accountKey) {
return $this->renderError(pht('Request did not include account key.'));
}
$account = id(new PhabricatorExternalAccount())->loadOneWhere(
'accountSecret = %s',
$this->accountKey);
if (!$account) {
return $this->renderError(pht('No registration account.'));
}
if ($account->getUserPHID()) {
return $this->renderError(
pht(
'The account you are attempting to register with is already '.
'registered to another user.'));
}
$registration_key = $request->getCookie('phreg');
// NOTE: This registration key check is not strictly necessary, because
// we're only creating new accounts, not linking existing accounts. It
// might be more hassle than it is worth, especially for email.
//
// The attack this prevents is getting to the registration screen, then
// copy/pasting the URL and getting someone else to click it and complete
// the process. They end up with an account bound to credentials you
// control. This doesn't really let you do anything meaningful, though,
// since you could have simply completed the process yourself.
if (!$registration_key) {
return $this->renderError(
pht(
'Your browser did not submit a registration key with the request. '.
'You must use the same browser to begin and complete registration. '.
'Check that cookies are enabled and try again.'));
}
// We store the digest of the key rather than the key itself to prevent a
// theoretical attacker with read-only access to the database from
// hijacking registration sessions.
$actual = $account->getProperty('registrationKey');
$expect = PhabricatorHash::digest($registration_key);
if ($actual !== $expect) {
return $this->renderError(
pht(
'Your browser submitted a different registration key than the one '.
'associated with this account. You may need to clear your cookies.'));
}
$other_account = id(new PhabricatorExternalAccount())->loadAllWhere(
'accountType = %s AND accountDomain = %s AND accountID = %s
AND id != %d',
$account->getAccountType(),
$account->getAccountDomain(),
$account->getAccountID(),
$account->getID());
if ($other_account) {
return $this->renderError(
pht(
'The account you are attempting to register with already belongs '.
'to another user.'));
}
$provider = PhabricatorAuthProvider::getEnabledProviderByKey(
$account->getProviderKey());
if (!$provider) {
return $this->renderError(
pht(
'The account you are attempting to register with uses a nonexistent '.
'or disabled authentication provider (with key "%s"). An '.
'administrator may have recently disabled this provider.',
$account->getProviderKey()));
}
if (!$provider->shouldAllowRegistration()) {
// TODO: This is a routine error if you click "Login" on an external
// auth source which doesn't allow registration. The error should be
// more tailored.
return $this->renderError(
pht(
'The account you are attempting to register with uses an '.
'authentication provider ("%s") which does not allow registration. '.
'An administrator may have recently disabled registration with this '.
'provider.',
$provider->getProviderName()));
}
$this->account = $account;
$this->provider = $provider;
return null;
}
private function loadDefaultAccount() {
$providers = PhabricatorAuthProvider::getAllEnabledProviders();
foreach ($providers as $key => $provider) {
if (!$provider->shouldAllowRegistration()) {
unset($providers[$key]);
continue;
}
if (!$provider->isDefaultRegistrationProvider()) {
unset($providers[$key]);
}
}
if (!$providers) {
return $this->renderError(
pht(
"There are no configured default registration providers."));
} else if (count($providers) > 1) {
return $this->renderError(
pht(
"There are too many configured default registration providers."));
}
$this->account = $provider->getDefaultExternalAccount();
$this->provider = $provider;
return null;
}
private function loadProfilePicture(PhabricatorExternalAccount $account) {
$phid = $account->getProfileImagePHID();
if (!$phid) {
return null;
}
// NOTE: Use of omnipotent user is okay here because the registering user
// can not control the field value, and we can't use their user object to
// do meaningful policy checks anyway since they have not registered yet.
// Reaching this means the user holds the account secret key and the
// registration secret key, and thus has permission to view the image.
$file = id(new PhabricatorFileQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($phid))
->executeOne();
if (!$file) {
return null;
}
try {
$xformer = new PhabricatorImageTransformer();
return $xformer->executeProfileTransform(
$file,
$width = 50,
$min_height = 50,
$max_height = 50);
} catch (Exception $ex) {
phlog($ex);
return null;
}
}
- private function renderError($message) {
+ protected function renderError($message) {
return $this->renderErrorPage(
pht('Registration Failed'),
array($message));
}
}
diff --git a/src/applications/auth/controller/PhabricatorAuthStartController.php b/src/applications/auth/controller/PhabricatorAuthStartController.php
index 267a61b47f..0fa6222b36 100644
--- a/src/applications/auth/controller/PhabricatorAuthStartController.php
+++ b/src/applications/auth/controller/PhabricatorAuthStartController.php
@@ -1,189 +1,189 @@
<?php
final class PhabricatorAuthStartController
extends PhabricatorAuthController {
public function shouldRequireLogin() {
return false;
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
if ($viewer->isLoggedIn()) {
// Kick the user home if they are already logged in.
return id(new AphrontRedirectResponse())->setURI('/');
}
if ($request->isAjax()) {
return $this->processAjaxRequest();
}
if ($request->isConduit()) {
return $this->processConduitRequest();
}
if ($request->getCookie('phusr') && $request->getCookie('phsid')) {
// The session cookie is invalid, so clear it.
$request->clearCookie('phusr');
$request->clearCookie('phsid');
return $this->renderError(
pht(
"Your login session is invalid. Try reloading the page and logging ".
"in again. If that does not work, clear your browser cookies."));
}
$providers = PhabricatorAuthProvider::getAllEnabledProviders();
foreach ($providers as $key => $provider) {
if (!$provider->shouldAllowLogin()) {
unset($providers[$key]);
}
}
if (!$providers) {
return $this->renderError(
pht(
"This Phabricator install is not configured with any enabled ".
"authentication providers which can be used to log in."));
}
$next_uri = $request->getStr('next');
if (!$next_uri) {
$next_uri_path = $this->getRequest()->getPath();
if ($next_uri_path == '/auth/start/') {
$next_uri = '/';
} else {
$next_uri = $this->getRequest()->getRequestURI();
}
}
if (!$request->isFormPost()) {
$request->setCookie('next_uri', $next_uri);
$request->setCookie('phcid', Filesystem::readRandomCharacters(16));
}
$not_buttons = array();
$are_buttons = array();
$providers = msort($providers, 'getLoginOrder');
foreach ($providers as $provider) {
if ($provider->isLoginFormAButton()) {
$are_buttons[] = $provider->buildLoginForm($this);
} else {
$not_buttons[] = $provider->buildLoginForm($this);
}
}
$out = array();
$out[] = $not_buttons;
if ($are_buttons) {
require_celerity_resource('auth-css');
foreach ($are_buttons as $key => $button) {
$are_buttons[$key] = phutil_tag(
'div',
array(
'class' => 'phabricator-login-button mmb',
),
$button);
}
// If we only have one button, add a second pretend button so that we
// always have two columns. This makes it easier to get the alignments
// looking reasonable.
if (count($are_buttons) == 1) {
$are_buttons[] = null;
}
$button_columns = id(new AphrontMultiColumnView())
->setFluidLayout(true);
$are_buttons = array_chunk($are_buttons, ceil(count($are_buttons) / 2));
foreach ($are_buttons as $column) {
$button_columns->addColumn($column);
}
$out[] = phutil_tag(
'div',
array(
'class' => 'phabricator-login-buttons',
),
$button_columns);
}
$login_message = PhabricatorEnv::getEnvConfig('auth.login-message');
$login_message = phutil_safe_html($login_message);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName(pht('Login')));
return $this->buildApplicationPage(
array(
$crumbs,
$login_message,
$out,
),
array(
'title' => pht('Login to Phabricator'),
'device' => true,
'dust' => true,
));
}
private function processAjaxRequest() {
$request = $this->getRequest();
$viewer = $request->getViewer();
// 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($viewer);
$dialog->setTitle(pht('Login Required'));
$dialog->appendChild(pht('You must login to continue.'));
$dialog->addSubmitButton(pht('Login'));
$dialog->addCancelButton('/');
return id(new AphrontDialogResponse())->setDialog($dialog);
}
private function processConduitRequest() {
$request = $this->getRequest();
$viewer = $request->getViewer();
// 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 = pht(
'ERROR: You are making a Conduit API request to "%s", but the correct '.
'HTTP request path to use in order to access a COnduit method is "%s" '.
'(for example, "%s"). Check your configuration.',
$request_path,
$conduit_path,
$example_path);
return id(new AphrontPlainTextResponse())->setContent($message);
}
- private function renderError($message) {
+ protected function renderError($message) {
return $this->renderErrorPage(
pht('Authentication Failure'),
array($message));
}
}
diff --git a/src/applications/auth/controller/PhabricatorEmailTokenController.php b/src/applications/auth/controller/PhabricatorEmailTokenController.php
index 1edd109011..5b4401564b 100644
--- a/src/applications/auth/controller/PhabricatorEmailTokenController.php
+++ b/src/applications/auth/controller/PhabricatorEmailTokenController.php
@@ -1,100 +1,98 @@
<?php
final class PhabricatorEmailTokenController
extends PhabricatorAuthController {
private $token;
public function shouldRequireLogin() {
return false;
}
public function willProcessRequest(array $data) {
$this->token = $data['token'];
}
public function processRequest() {
$request = $this->getRequest();
$token = $this->token;
$email = $request->getStr('email');
// NOTE: We need to bind verification to **addresses**, not **users**,
// because we verify addresses when they're used to login this way, and if
// we have a user-based verification you can:
//
// - Add some address you do not own;
// - request a password reset;
// - change the URI in the email to the address you don't own;
// - login via the email link; and
// - get a "verified" address you don't control.
$target_email = id(new PhabricatorUserEmail())->loadOneWhere(
'address = %s',
$email);
$target_user = null;
if ($target_email) {
$target_user = id(new PhabricatorUser())->loadOneWhere(
'phid = %s',
$target_email->getUserPHID());
}
if (!$target_email ||
!$target_user ||
!$target_user->validateEmailToken($target_email, $token)) {
$view = new AphrontRequestFailureView();
$view->setHeader(pht('Unable to Login'));
$view->appendChild(phutil_tag('p', array(), pht(
'The authentication information in the link you clicked is '.
'invalid or out of date. Make sure you are copy-and-pasting the '.
'entire link into your browser. You can try again, or request '.
'a new email.')));
$view->appendChild(hsprintf(
'<div class="aphront-failure-continue">'.
'<a class="button" href="/login/email/">%s</a>'.
'</div>',
pht('Send Another Email')));
return $this->buildStandardPageResponse(
$view,
array(
'title' => pht('Login Failure'),
));
}
// Verify email so that clicking the link in the "Welcome" email is good
// enough, without requiring users to go through a second round of email
// verification.
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$target_email->setIsVerified(1);
$target_email->save();
unset($unguarded);
- $this->establishWebSession($target_user);
-
$next = '/';
if (!PhabricatorEnv::getEnvConfig('auth.password-auth-enabled')) {
$panels = id(new PhabricatorSettingsPanelOAuth())->buildPanels();
foreach ($panels as $panel) {
if ($panel->isEnabled()) {
$next = $panel->getPanelURI();
break;
}
}
} else if (PhabricatorEnv::getEnvConfig('account.editable')) {
$next = (string)id(new PhutilURI('/settings/panel/password/'))
->setQueryParams(
array(
'token' => $token,
'email' => $email,
));
}
$request->setCookie('next_uri', $next);
- return $this->buildLoginValidateResponse($target_user);
+ return $this->loginUser($target_user);
}
}
diff --git a/src/applications/auth/controller/PhabricatorLDAPLoginController.php b/src/applications/auth/controller/PhabricatorLDAPLoginController.php
index 99a3628024..fbf83874b2 100644
--- a/src/applications/auth/controller/PhabricatorLDAPLoginController.php
+++ b/src/applications/auth/controller/PhabricatorLDAPLoginController.php
@@ -1,170 +1,168 @@
<?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);
- $this->establishWebSession($known_user);
-
- return $this->buildLoginValidateResponse($known_user);
+ 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();
}
}
diff --git a/src/applications/auth/controller/PhabricatorLoginController.php b/src/applications/auth/controller/PhabricatorLoginController.php
index e0087f452f..e8bc401756 100644
--- a/src/applications/auth/controller/PhabricatorLoginController.php
+++ b/src/applications/auth/controller/PhabricatorLoginController.php
@@ -1,304 +1,303 @@
<?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) {
- $this->establishWebSession($user);
- return $this->buildLoginValidateResponse($user);
+ 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
));
}
}
diff --git a/src/applications/auth/controller/PhabricatorOAuthLoginController.php b/src/applications/auth/controller/PhabricatorOAuthLoginController.php
index 59a8973e7c..9191430a4f 100644
--- a/src/applications/auth/controller/PhabricatorOAuthLoginController.php
+++ b/src/applications/auth/controller/PhabricatorOAuthLoginController.php
@@ -1,296 +1,294 @@
<?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);
- $this->establishWebSession($known_user);
-
- return $this->buildLoginValidateResponse($known_user);
+ 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();
}
}
diff --git a/src/infrastructure/events/constant/PhabricatorEventType.php b/src/infrastructure/events/constant/PhabricatorEventType.php
index a1b5bb3494..aec70db8d2 100644
--- a/src/infrastructure/events/constant/PhabricatorEventType.php
+++ b/src/infrastructure/events/constant/PhabricatorEventType.php
@@ -1,41 +1,42 @@
<?php
/**
* For detailed explanations of these events, see
* @{article:Events User Guide: Installing Event Listeners}.
*
* @group events
*/
final class PhabricatorEventType extends PhutilEventType {
const TYPE_CONTROLLER_CHECKREQUEST = 'controller.checkRequest';
const TYPE_MANIPHEST_WILLEDITTASK = 'maniphest.willEditTask';
const TYPE_MANIPHEST_DIDEDITTASK = 'maniphest.didEditTask';
const TYPE_DIFFERENTIAL_WILLSENDMAIL = 'differential.willSendMail';
const TYPE_DIFFERENTIAL_WILLMARKGENERATED = 'differential.willMarkGenerated';
const TYPE_DIFFERENTIAL_WILLEDITREVISION = 'differential.willEditRevision';
const TYPE_DIFFERENTIAL_DIDEDITREVISION = 'differential.didEditRevision';
const TYPE_DIFFUSION_DIDDISCOVERCOMMIT = 'diffusion.didDiscoverCommit';
const TYPE_DIFFUSION_LOOKUPUSER = 'diffusion.lookupUser';
const TYPE_EDGE_WILLEDITEDGES = 'edge.willEditEdges';
const TYPE_EDGE_DIDEDITEDGES = 'edge.didEditEdges';
const TYPE_TEST_DIDRUNTEST = 'test.didRunTest';
const TYPE_UI_DIDRENDERACTIONS = 'ui.didRenderActions';
const TYPE_UI_WILLRENDEROBJECTS = 'ui.willRenderObjects';
const TYPE_UI_DDIDRENDEROBJECT = 'ui.didRenderObject';
const TYPE_UI_DIDRENDEROBJECTS = 'ui.didRenderObjects';
const TYPE_UI_WILLRENDERPROPERTIES = 'ui.willRenderProperties';
const TYPE_UI_DIDRENDERHOVERCARD = 'ui.didRenderHovercard';
const TYPE_PEOPLE_DIDRENDERMENU = 'people.didRenderMenu';
const TYPE_AUTH_WILLREGISTERUSER = 'auth.willRegisterUser';
+ const TYPE_AUTH_WILLLOGINUSER = 'auth.willLoginUser';
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 14, 6:04 AM (1 d, 7 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
336827
Default Alt Text
(64 KB)

Event Timeline