1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-02 02:40:58 +01:00

Consolidate use of magical cookie name strings

Summary: Ref T4339. We have more magical cookie names than we should, move them all to a central location.

Test Plan: Registered, logged in, linked account, logged out. See inlines.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T4339

Differential Revision: https://secure.phabricator.com/D8041
This commit is contained in:
epriestley 2014-01-23 14:01:35 -08:00
parent 02aa193cb0
commit 0727418023
15 changed files with 116 additions and 46 deletions

View file

@ -1319,6 +1319,7 @@ phutil_register_library_map(array(
'PhabricatorContentSource' => 'applications/metamta/contentsource/PhabricatorContentSource.php', 'PhabricatorContentSource' => 'applications/metamta/contentsource/PhabricatorContentSource.php',
'PhabricatorContentSourceView' => 'applications/metamta/contentsource/PhabricatorContentSourceView.php', 'PhabricatorContentSourceView' => 'applications/metamta/contentsource/PhabricatorContentSourceView.php',
'PhabricatorController' => 'applications/base/controller/PhabricatorController.php', 'PhabricatorController' => 'applications/base/controller/PhabricatorController.php',
'PhabricatorCookies' => 'applications/auth/constants/PhabricatorCookies.php',
'PhabricatorCoreConfigOptions' => 'applications/config/option/PhabricatorCoreConfigOptions.php', 'PhabricatorCoreConfigOptions' => 'applications/config/option/PhabricatorCoreConfigOptions.php',
'PhabricatorCountdown' => 'applications/countdown/storage/PhabricatorCountdown.php', 'PhabricatorCountdown' => 'applications/countdown/storage/PhabricatorCountdown.php',
'PhabricatorCountdownCapabilityDefaultView' => 'applications/countdown/capability/PhabricatorCountdownCapabilityDefaultView.php', 'PhabricatorCountdownCapabilityDefaultView' => 'applications/countdown/capability/PhabricatorCountdownCapabilityDefaultView.php',
@ -3934,6 +3935,7 @@ phutil_register_library_map(array(
'PhabricatorConpherencePHIDTypeThread' => 'PhabricatorPHIDType', 'PhabricatorConpherencePHIDTypeThread' => 'PhabricatorPHIDType',
'PhabricatorContentSourceView' => 'AphrontView', 'PhabricatorContentSourceView' => 'AphrontView',
'PhabricatorController' => 'AphrontController', 'PhabricatorController' => 'AphrontController',
'PhabricatorCookies' => 'Phobject',
'PhabricatorCoreConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorCoreConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorCountdown' => 'PhabricatorCountdown' =>
array( array(

View file

@ -58,12 +58,17 @@ final class DarkConsoleDataController extends PhabricatorController {
$panel = $obj->renderPanel(); $panel = $obj->renderPanel();
if (!empty($_COOKIE['phsid'])) { // Because cookie names can now be prefixed, wipe out any cookie value
$panel = PhutilSafeHTML::applyFunction( // with the session cookie name anywhere in its name.
'str_replace', $pattern = '('.preg_quote(PhabricatorCookies::COOKIE_SESSION).')';
$_COOKIE['phsid'], foreach ($_COOKIE as $cookie_name => $cookie_value) {
'(session-key)', if (preg_match($pattern, $cookie_name)) {
$panel); $panel = PhutilSafeHTML::applyFunction(
'str_replace',
$cookie_value,
'(session-key)',
$panel);
}
} }
$output['panel'][$class] = $panel; $output['panel'][$class] = $panel;

View file

@ -0,0 +1,48 @@
<?php
/**
* Consolidates Phabricator application cookies, including registration
* and session management.
*/
final class PhabricatorCookies extends Phobject {
/**
* Stores the login username for password authentication. This is just a
* display value for convenience, used to prefill the login form. It is not
* authoritative.
*/
const COOKIE_USERNAME = 'phusr';
/**
* Stores the user's current session ID. This is authoritative and establishes
* the user's identity.
*/
const COOKIE_SESSION = 'phsid';
/**
* Stores a secret used during new account registration to prevent an attacker
* from tricking a victim into registering an account which is linked to
* credentials the attacker controls.
*/
const COOKIE_REGISTRATION = 'phreg';
/**
* Stores a secret used during OAuth2 handshakes to prevent various attacks
* where an attacker hands a victim a URI corresponding to the middle of an
* OAuth2 workflow and we might otherwise do something sketchy. Particularly,
* this corresponds to the OAuth2 "code".
*/
const COOKIE_CLIENTID = 'phcid';
/**
* Stores the URI to redirect the user to after login. This allows users to
* visit a path like `/feed/`, be prompted to login, and then be redirected
* back to `/feed/` after the workflow completes.
*/
const COOKIE_NEXTURI = 'next_uri';
}

View file

@ -88,8 +88,12 @@ abstract class PhabricatorAuthController extends PhabricatorController {
// there's no check for users being disabled here. // there's no check for users being disabled here.
$request = $this->getRequest(); $request = $this->getRequest();
$request->setCookie('phusr', $user->getUsername()); $request->setCookie(
$request->setCookie('phsid', $session_key); PhabricatorCookies::COOKIE_USERNAME,
$user->getUsername());
$request->setCookie(
PhabricatorCookies::COOKIE_SESSION,
$session_key);
$this->clearRegistrationCookies(); $this->clearRegistrationCookies();
} }
@ -101,15 +105,15 @@ abstract class PhabricatorAuthController extends PhabricatorController {
$request = $this->getRequest(); $request = $this->getRequest();
// Clear the registration key. // Clear the registration key.
$request->clearCookie('phreg'); $request->clearCookie(PhabricatorCookies::COOKIE_REGISTRATION);
// Clear the client ID / OAuth state key. // Clear the client ID / OAuth state key.
$request->clearCookie('phcid'); $request->clearCookie(PhabricatorCookies::COOKIE_CLIENTID);
} }
private function buildLoginValidateResponse(PhabricatorUser $user) { private function buildLoginValidateResponse(PhabricatorUser $user) {
$validate_uri = new PhutilURI($this->getApplicationURI('validate/')); $validate_uri = new PhutilURI($this->getApplicationURI('validate/'));
$validate_uri->setQueryParam('phusr', $user->getUsername()); $validate_uri->setQueryParam('expect', $user->getUsername());
return id(new AphrontRedirectResponse())->setURI((string)$validate_uri); return id(new AphrontRedirectResponse())->setURI((string)$validate_uri);
} }
@ -168,7 +172,8 @@ abstract class PhabricatorAuthController extends PhabricatorController {
return array($account, $provider, $response); return array($account, $provider, $response);
} }
$registration_key = $request->getCookie('phreg'); $registration_key = $request->getCookie(
PhabricatorCookies::COOKIE_REGISTRATION);
// NOTE: This registration key check is not strictly necessary, because // NOTE: This registration key check is not strictly necessary, because
// we're only creating new accounts, not linking existing accounts. It // we're only creating new accounts, not linking existing accounts. It
@ -181,7 +186,7 @@ abstract class PhabricatorAuthController extends PhabricatorController {
// since you could have simply completed the process yourself. // since you could have simply completed the process yourself.
if (!$registration_key) { if (!$registration_key) {
$response = $this->renderError( $response = $this->renderError(
pht( pht(
'Your browser did not submit a registration key with the request. '. 'Your browser did not submit a registration key with the request. '.
'You must use the same browser to begin and complete registration. '. 'You must use the same browser to begin and complete registration. '.

View file

@ -79,7 +79,10 @@ final class PhabricatorAuthLinkController
$panel_uri = '/settings/panel/external/'; $panel_uri = '/settings/panel/external/';
$request->setCookie('phcid', Filesystem::readRandomCharacters(16)); $request->setCookie(
PhabricatorCookies::COOKIE_CLIENTID,
Filesystem::readRandomCharacters(16));
switch ($this->action) { switch ($this->action) {
case 'link': case 'link':
$form = $provider->buildLinkForm($this); $form = $provider->buildLinkForm($this);

View file

@ -166,7 +166,9 @@ final class PhabricatorAuthLoginController
$account->save(); $account->save();
unset($unguarded); unset($unguarded);
$this->getRequest()->setCookie('phreg', $registration_key); $this->getRequest()->setCookie(
PhabricatorCookies::COOKIE_REGISTRATION,
$registration_key);
return id(new AphrontRedirectResponse())->setURI($next_uri); return id(new AphrontRedirectResponse())->setURI($next_uri);
} }

View file

@ -24,10 +24,10 @@ final class PhabricatorAuthStartController
return $this->processConduitRequest(); return $this->processConduitRequest();
} }
if ($request->getCookie('phusr') && $request->getCookie('phsid')) { if (strlen($request->getCookie(PhabricatorCookies::COOKIE_SESSION))) {
// The session cookie is invalid, so clear it. // The session cookie is invalid, so clear it.
$request->clearCookie('phusr'); $request->clearCookie(PhabricatorCookies::COOKIE_USERNAME);
$request->clearCookie('phsid'); $request->clearCookie(PhabricatorCookies::COOKIE_SESSION);
return $this->renderError( return $this->renderError(
pht( pht(
@ -71,8 +71,12 @@ final class PhabricatorAuthStartController
} }
if (!$request->isFormPost()) { if (!$request->isFormPost()) {
$request->setCookie('next_uri', $next_uri); $request->setCookie(
$request->setCookie('phcid', Filesystem::readRandomCharacters(16)); PhabricatorCookies::COOKIE_NEXTURI,
$next_uri);
$request->setCookie(
PhabricatorCookies::COOKIE_CLIENTID,
Filesystem::readRandomCharacters(16));
} }
$not_buttons = array(); $not_buttons = array();

View file

@ -13,7 +13,7 @@ final class PhabricatorAuthValidateController
$failures = array(); $failures = array();
if (!strlen($request->getStr('phusr'))) { if (!strlen($request->getStr('expect'))) {
return $this->renderErrors( return $this->renderErrors(
array( array(
pht( pht(
@ -21,8 +21,8 @@ final class PhabricatorAuthValidateController
'phusr'))); 'phusr')));
} }
$expect_phusr = $request->getStr('phusr'); $expect_phusr = $request->getStr('expect');
$actual_phusr = $request->getCookie('phusr'); $actual_phusr = $request->getCookie(PhabricatorCookies::COOKIE_USERNAME);
if ($actual_phusr != $expect_phusr) { if ($actual_phusr != $expect_phusr) {
if ($actual_phusr) { if ($actual_phusr) {
$failures[] = pht( $failures[] = pht(
@ -54,8 +54,8 @@ final class PhabricatorAuthValidateController
return $this->renderErrors($failures); return $this->renderErrors($failures);
} }
$next = $request->getCookie('next_uri'); $next = $request->getCookie(PhabricatorCookies::COOKIE_NEXTURI);
$request->clearCookie('next_uri'); $request->clearCookie(PhabricatorCookies::COOKIE_NEXTURI);
if (!PhabricatorEnv::isValidLocalWebResource($next)) { if (!PhabricatorEnv::isValidLocalWebResource($next)) {
$next = '/'; $next = '/';

View file

@ -86,7 +86,7 @@ final class PhabricatorEmailTokenController
)); ));
} }
$request->setCookie('next_uri', $next); $request->setCookie(PhabricatorCookies::COOKIE_NEXTURI, $next);
return $this->loginUser($target_user); return $this->loginUser($target_user);
} }

View file

@ -32,8 +32,8 @@ final class PhabricatorLogoutController
// Destroy the user's session in the database so logout works even if // Destroy the user's session in the database so logout works even if
// their cookies have some issues. We'll detect cookie issues when they // their cookies have some issues. We'll detect cookie issues when they
// try to login again and tell them to clear any junk. // try to login again and tell them to clear any junk.
$phsid = $request->getCookie('phsid'); $phsid = $request->getCookie(PhabricatorCookies::COOKIE_SESSION);
if ($phsid) { if (strlen($phsid)) {
$session = id(new PhabricatorAuthSessionQuery()) $session = id(new PhabricatorAuthSessionQuery())
->setViewer($user) ->setViewer($user)
->withSessionKeys(array($phsid)) ->withSessionKeys(array($phsid))
@ -42,7 +42,7 @@ final class PhabricatorLogoutController
$session->delete(); $session->delete();
} }
} }
$request->clearCookie('phsid'); $request->clearCookie(PhabricatorCookies::COOKIE_SESSION);
return id(new AphrontRedirectResponse()) return id(new AphrontRedirectResponse())
->setURI('/login/'); ->setURI('/login/');
@ -52,8 +52,7 @@ final class PhabricatorLogoutController
$dialog = id(new AphrontDialogView()) $dialog = id(new AphrontDialogView())
->setUser($user) ->setUser($user)
->setTitle(pht('Log out of Phabricator?')) ->setTitle(pht('Log out of Phabricator?'))
->appendChild(phutil_tag('p', array(), pht( ->appendChild(pht('Are you sure you want to log out?'))
'Are you sure you want to log out?')))
->addSubmitButton(pht('Logout')) ->addSubmitButton(pht('Logout'))
->addCancelButton('/'); ->addCancelButton('/');

View file

@ -35,9 +35,11 @@ abstract class PhabricatorAuthProviderOAuth extends PhabricatorAuthProvider {
protected function renderLoginForm(AphrontRequest $request, $mode) { protected function renderLoginForm(AphrontRequest $request, $mode) {
$adapter = $this->getAdapter(); $adapter = $this->getAdapter();
$adapter->setState(PhabricatorHash::digest($request->getCookie('phcid'))); $adapter->setState(
PhabricatorHash::digest(
$request->getCookie(PhabricatorCookies::COOKIE_CLIENTID)));
$scope = $request->getStr("scope"); $scope = $request->getStr('scope');
if ($scope) { if ($scope) {
$adapter->setScope($scope); $adapter->setScope($scope);
} }
@ -81,14 +83,15 @@ abstract class PhabricatorAuthProviderOAuth extends PhabricatorAuthProvider {
} }
if ($adapter->supportsStateParameter()) { if ($adapter->supportsStateParameter()) {
$phcid = $request->getCookie('phcid'); $phcid = $request->getCookie(PhabricatorCookies::COOKIE_CLIENTID);
if (!strlen($phcid)) { if (!strlen($phcid)) {
$response = $controller->buildProviderErrorResponse( $response = $controller->buildProviderErrorResponse(
$this, $this,
pht( pht(
'Your browser did not submit a "phcid" cookie with OAuth state '. 'Your browser did not submit a "%s" cookie with OAuth state '.
'information in the request. Check that cookies are enabled. '. 'information in the request. Check that cookies are enabled. '.
'If this problem persists, you may need to clear your cookies.')); 'If this problem persists, you may need to clear your cookies.',
PhabricatorCookies::COOKIE_CLIENTID));
} }
$state = $request->getStr('state'); $state = $request->getStr('state');

View file

@ -87,7 +87,7 @@ final class PhabricatorAuthProviderPassword
$v_user = nonempty( $v_user = nonempty(
$request->getStr('username'), $request->getStr('username'),
$request->getCookie('phusr')); $request->getCookie(PhabricatorCookies::COOKIE_USERNAME));
$e_user = null; $e_user = null;
$e_pass = null; $e_pass = null;
@ -191,8 +191,8 @@ final class PhabricatorAuthProviderPassword
PhabricatorUserLog::ACTION_LOGIN_FAILURE); PhabricatorUserLog::ACTION_LOGIN_FAILURE);
$log->save(); $log->save();
$request->clearCookie('phusr'); $request->clearCookie(PhabricatorCookies::COOKIE_USERNAME);
$request->clearCookie('phsid'); $request->clearCookie(PhabricatorCookies::COOKIE_SESSION);
$response = $controller->buildProviderPageResponse( $response = $controller->buildProviderPageResponse(
$this, $this,

View file

@ -35,7 +35,7 @@ abstract class PhabricatorController extends AphrontController {
} else { } else {
$user = new PhabricatorUser(); $user = new PhabricatorUser();
$phsid = $request->getCookie('phsid'); $phsid = $request->getCookie(PhabricatorCookies::COOKIE_SESSION);
if ($phsid) { if ($phsid) {
$session_user = id(new PhabricatorAuthSessionEngine()) $session_user = id(new PhabricatorAuthSessionEngine())
->loadUserForSession(PhabricatorAuthSession::TYPE_WEB, $phsid); ->loadUserForSession(PhabricatorAuthSession::TYPE_WEB, $phsid);

View file

@ -66,7 +66,9 @@ final class PhabricatorUserLog extends PhabricatorUserDAO {
$this->remoteAddr = idx($_SERVER, 'REMOTE_ADDR', ''); $this->remoteAddr = idx($_SERVER, 'REMOTE_ADDR', '');
} }
if (!$this->session) { if (!$this->session) {
$this->setSession(idx($_COOKIE, 'phsid')); // TODO: This is not correct if there's a cookie prefix. This object
// should take an AphrontRequest.
$this->setSession(idx($_COOKIE, PhabricatorCookies::COOKIE_SESSION));
} }
$this->details['host'] = php_uname('n'); $this->details['host'] = php_uname('n');
$this->details['user_agent'] = AphrontRequest::getHTTPHeader('User-Agent'); $this->details['user_agent'] = AphrontRequest::getHTTPHeader('User-Agent');

View file

@ -40,11 +40,8 @@ final class PhabricatorSettingsPanelSessions
->withPHIDs($identity_phids) ->withPHIDs($identity_phids)
->execute(); ->execute();
// TODO: Once this has a real ID column, use that instead. $current_key = PhabricatorHash::digest(
$sessions = msort($sessions, 'getSessionStart'); $request->getCookie(PhabricatorCookies::COOKIE_SESSION));
$sessions = array_reverse($sessions);
$current_key = PhabricatorHash::digest($request->getCookie('phsid'));
$rows = array(); $rows = array();
$rowc = array(); $rowc = array();