Commit 12abe621 authored by alexpott's avatar alexpott

Issue #2228341 by sun, znerol, skipyT, ParisLiakos: Objectify session...

Issue #2228341 by sun, znerol, skipyT, ParisLiakos: Objectify session management functions + remove session.inc.
parent bfa4a9fd
...@@ -46,8 +46,7 @@ ...@@ -46,8 +46,7 @@
* TRUE if the current user can run authorize.php, and FALSE if not. * TRUE if the current user can run authorize.php, and FALSE if not.
*/ */
function authorize_access_allowed() { function authorize_access_allowed() {
require_once DRUPAL_ROOT . '/' . Settings::get('session_inc', 'core/includes/session.inc'); \Drupal::service('session_manager')->initialize();
drupal_session_initialize();
return Settings::get('allow_authorize_operations', TRUE) && user_access('administer software updates'); return Settings::get('allow_authorize_operations', TRUE) && user_access('administer software updates');
} }
......
...@@ -102,7 +102,7 @@ services: ...@@ -102,7 +102,7 @@ services:
arguments: ['@config.storage', '@config.storage.schema', '@cache.config'] arguments: ['@config.storage', '@config.storage.schema', '@cache.config']
cron: cron:
class: Drupal\Core\Cron class: Drupal\Core\Cron
arguments: ['@module_handler', '@lock', '@queue', '@state', '@current_user'] arguments: ['@module_handler', '@lock', '@queue', '@state', '@current_user', '@session_manager']
database: database:
class: Drupal\Core\Database\Connection class: Drupal\Core\Database\Connection
factory_class: Drupal\Core\Database\Database factory_class: Drupal\Core\Database\Database
...@@ -712,6 +712,7 @@ services: ...@@ -712,6 +712,7 @@ services:
class: Drupal\Core\Authentication\AuthenticationManager class: Drupal\Core\Authentication\AuthenticationManager
authentication.cookie: authentication.cookie:
class: Drupal\Core\Authentication\Provider\Cookie class: Drupal\Core\Authentication\Provider\Cookie
arguments: ['@session_manager']
tags: tags:
- { name: authentication_provider, priority: 0 } - { name: authentication_provider, priority: 0 }
authentication_subscriber: authentication_subscriber:
...@@ -722,6 +723,11 @@ services: ...@@ -722,6 +723,11 @@ services:
current_user: current_user:
class: Drupal\Core\Session\AccountProxy class: Drupal\Core\Session\AccountProxy
arguments: ['@authentication', '@request'] arguments: ['@authentication', '@request']
session_manager:
class: Drupal\Core\Session\SessionManager
arguments: ['@request_stack', '@database']
tags:
- { name: persist }
asset.css.collection_renderer: asset.css.collection_renderer:
class: Drupal\Core\Asset\CssCollectionRenderer class: Drupal\Core\Asset\CssCollectionRenderer
arguments: [ '@state' ] arguments: [ '@state' ]
......
...@@ -1466,7 +1466,9 @@ function drupal_handle_request($test_only = FALSE) { ...@@ -1466,7 +1466,9 @@ function drupal_handle_request($test_only = FALSE) {
// Create a request object from the HttpFoundation. // Create a request object from the HttpFoundation.
$request = Request::createFromGlobals(); $request = Request::createFromGlobals();
\Drupal::getContainer()->set('request', $request); $container = \Drupal::getContainer();
$container->set('request', $request);
$container->get('request_stack')->push($request);
drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE); drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE);
...@@ -1616,7 +1618,9 @@ function _drupal_bootstrap_kernel() { ...@@ -1616,7 +1618,9 @@ function _drupal_bootstrap_kernel() {
$kernel = new DrupalKernel('prod', drupal_classloader()); $kernel = new DrupalKernel('prod', drupal_classloader());
$kernel->boot(); $kernel->boot();
$request = Request::createFromGlobals(); $request = Request::createFromGlobals();
\Drupal::getContainer()->set('request', $request); $container = \Drupal::getContainer();
$container->set('request', $request);
$container->get('request_stack')->push($request);
} }
} }
...@@ -2173,12 +2177,12 @@ function drupal_classloader_register($name, $path) { ...@@ -2173,12 +2177,12 @@ function drupal_classloader_register($name, $path) {
* *
* Example: * Example:
* @code * @code
* function drupal_session_started($set = NULL) { * function mymodule_log_stream_handle($new_handle = NULL) {
* static $session_started = FALSE; * static $handle;
* if (isset($set)) { * if (isset($new_handle)) {
* $session_started = $set; * $handle = $new_handle;
* } * }
* return $session_started && session_id(); * return $handle;
* } * }
* @endcode * @endcode
* *
......
...@@ -2877,7 +2877,7 @@ function drupal_get_private_key() { ...@@ -2877,7 +2877,7 @@ function drupal_get_private_key() {
* *
* @see drupal_get_hash_salt() * @see drupal_get_hash_salt()
* @see \Drupal\Core\Access\CsrfTokenGenerator * @see \Drupal\Core\Access\CsrfTokenGenerator
* @see drupal_session_start() * @see \Drupal\Core\Session\SessionManager::start()
* *
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0. * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::csrfToken()->get(). * Use \Drupal::csrfToken()->get().
......
...@@ -306,7 +306,6 @@ function install_begin_request(&$install_state) { ...@@ -306,7 +306,6 @@ function install_begin_request(&$install_state) {
// Load module basics (needed for hook invokes). // Load module basics (needed for hook invokes).
include_once __DIR__ . '/module.inc'; include_once __DIR__ . '/module.inc';
include_once __DIR__ . '/session.inc';
require_once __DIR__ . '/entity.inc'; require_once __DIR__ . '/entity.inc';
// Create a minimal mocked container to support calls to t() in the pre-kernel // Create a minimal mocked container to support calls to t() in the pre-kernel
...@@ -546,7 +545,7 @@ function install_run_task($task, &$install_state) { ...@@ -546,7 +545,7 @@ function install_run_task($task, &$install_state) {
$response = batch_process(install_redirect_url($install_state), install_full_redirect_url($install_state)); $response = batch_process(install_redirect_url($install_state), install_full_redirect_url($install_state));
if ($response instanceof Response) { if ($response instanceof Response) {
// Save $_SESSION data from batch. // Save $_SESSION data from batch.
drupal_session_commit(); \Drupal::service('session_manager')->save();
// Send the response. // Send the response.
$response->send(); $response->send();
exit; exit;
...@@ -1780,8 +1779,7 @@ function install_load_profile(&$install_state) { ...@@ -1780,8 +1779,7 @@ function install_load_profile(&$install_state) {
*/ */
function install_bootstrap_full() { function install_bootstrap_full() {
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
require_once DRUPAL_ROOT . '/' . Settings::get('session_inc', 'core/includes/session.inc'); \Drupal::service('session_manager')->initialize();
drupal_session_initialize();
} }
/** /**
......
<?php
/**
* @file
* User session handling functions.
*/
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Settings;
use Drupal\Core\Session\AnonymousUserSession;
use Drupal\Core\Session\SessionHandler;
/**
* Initializes the session handler, starting a session if needed.
*/
function drupal_session_initialize() {
global $user;
// Register the default session handler.
// @todo: Extract session storage from session handler into a service.
$handler = new SessionHandler(\Drupal::request(), \Drupal::database());
session_set_save_handler($handler, TRUE);
$is_https = \Drupal::request()->isSecure();
$cookies = \Drupal::request()->cookies;
if (($cookies->has(session_name()) && ($session_name = $cookies->get(session_name()))) || ($is_https && Settings::get('mixed_mode_sessions', FALSE) && ($cookies->has(substr(session_name(), 1))) && ($session_name = $cookies->get(substr(session_name(), 1))))) {
// If a session cookie exists, initialize the session. Otherwise the
// session is only started on demand in drupal_session_commit(), making
// anonymous users not use a session cookie unless something is stored in
// $_SESSION. This allows HTTP proxies to cache anonymous pageviews.
drupal_session_start();
if ($user->isAuthenticated() || !empty($_SESSION)) {
drupal_page_is_cacheable(FALSE);
}
}
else {
// Set a session identifier for this request. This is necessary because
// we lazily start sessions at the end of this request, and some
// processes (like drupal_get_token()) needs to know the future
// session ID in advance.
$GLOBALS['lazy_session'] = TRUE;
$user = new AnonymousUserSession();
// Less random sessions (which are much faster to generate) are used for
// anonymous users than are generated in drupal_session_regenerate() when
// a user becomes authenticated.
session_id(Crypt::randomBytesBase64());
if ($is_https && Settings::get('mixed_mode_sessions', FALSE)) {
$insecure_session_name = substr(session_name(), 1);
$session_id = Crypt::randomBytesBase64();
$cookies->set($insecure_session_name, $session_id);
}
}
date_default_timezone_set(drupal_get_user_timezone());
}
/**
* Starts a session forcefully, preserving already set session data.
*
* @ingroup php_wrappers
*/
function drupal_session_start() {
// Command line clients do not support cookies nor sessions.
if (!drupal_session_started() && !drupal_is_cli()) {
// Save current session data before starting it, as PHP will destroy it.
$session_data = isset($_SESSION) ? $_SESSION : NULL;
session_start();
drupal_session_started(TRUE);
// Restore session data.
if (!empty($session_data)) {
$_SESSION += $session_data;
}
}
}
/**
* Commits the current session, if necessary.
*
* If an anonymous user already have an empty session, destroy it.
*/
function drupal_session_commit() {
global $user;
if (!drupal_save_session()) {
// We don't have anything to do if we are not allowed to save the session.
return;
}
if ($user->isAnonymous() && empty($_SESSION)) {
// There is no session data to store, destroy the session if it was
// previously started.
if (drupal_session_started()) {
session_destroy();
}
}
else {
// There is session data to store. Start the session if it is not already
// started.
if (!drupal_session_started()) {
drupal_session_start();
if (\Drupal::request()->isSecure() && Settings::get('mixed_mode_sessions', FALSE)) {
$insecure_session_name = substr(session_name(), 1);
$params = session_get_cookie_params();
$expire = $params['lifetime'] ? REQUEST_TIME + $params['lifetime'] : 0;
$cookie_params = \Drupal::request()->cookies;
setcookie($insecure_session_name, $cookie_params->get($insecure_session_name), $expire, $params['path'], $params['domain'], FALSE, $params['httponly']);
}
}
// Write the session data.
session_write_close();
}
}
/**
* Returns whether a session has been started.
*/
function drupal_session_started($set = NULL) {
static $session_started = FALSE;
if (isset($set)) {
$session_started = $set;
}
return $session_started && session_status() === \PHP_SESSION_ACTIVE;
}
/**
* Called when an anonymous user becomes authenticated or vice-versa.
*
* @ingroup php_wrappers
*/
function drupal_session_regenerate() {
global $user;
// Nothing to do if we are not allowed to change the session.
if (!drupal_save_session()) {
return;
}
$is_https = \Drupal::request()->isSecure();
$cookies = \Drupal::request()->cookies;
if ($is_https && Settings::get('mixed_mode_sessions', FALSE)) {
$insecure_session_name = substr(session_name(), 1);
if (!isset($GLOBALS['lazy_session']) && $cookies->has($insecure_session_name)) {
$old_insecure_session_id = $cookies->get($insecure_session_name);
}
$params = session_get_cookie_params();
$session_id = Crypt::randomBytesBase64();
// If a session cookie lifetime is set, the session will expire
// $params['lifetime'] seconds from the current request. If it is not set,
// it will expire when the browser is closed.
$expire = $params['lifetime'] ? REQUEST_TIME + $params['lifetime'] : 0;
setcookie($insecure_session_name, $session_id, $expire, $params['path'], $params['domain'], FALSE, $params['httponly']);
$cookies->set($insecure_session_name, $session_id);
}
if (drupal_session_started()) {
$old_session_id = session_id();
}
session_id(Crypt::randomBytesBase64());
if (isset($old_session_id)) {
$params = session_get_cookie_params();
$expire = $params['lifetime'] ? REQUEST_TIME + $params['lifetime'] : 0;
setcookie(session_name(), session_id(), $expire, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
$fields = array('sid' => Crypt::hashBase64(session_id()));
if ($is_https) {
$fields['ssid'] = Crypt::hashBase64(session_id());
// If the "secure pages" setting is enabled, use the newly-created
// insecure session identifier as the regenerated sid.
if (Settings::get('mixed_mode_sessions', FALSE)) {
$fields['sid'] = Crypt::hashBase64($session_id);
}
}
db_update('sessions')
->fields($fields)
->condition($is_https ? 'ssid' : 'sid', Crypt::hashBase64($old_session_id))
->execute();
}
elseif (isset($old_insecure_session_id)) {
// If logging in to the secure site, and there was no active session on the
// secure site but a session was active on the insecure site, update the
// insecure session with the new session identifiers.
db_update('sessions')
->fields(array('sid' => Crypt::hashBase64($session_id), 'ssid' => Crypt::hashBase64(session_id())))
->condition('sid', Crypt::hashBase64($old_insecure_session_id))
->execute();
}
else {
// Start the session when it doesn't exist yet.
// Preserve the logged in user, as it will be reset to anonymous
// by _drupal_session_read.
$account = $user;
drupal_session_start();
$user = $account;
}
date_default_timezone_set(drupal_get_user_timezone());
}
/**
* Ends a specific user's session(s).
*
* @param $uid
* User ID.
*/
function drupal_session_destroy_uid($uid) {
// Nothing to do if we are not allowed to change the session.
if (!drupal_save_session()) {
return;
}
db_delete('sessions')
->condition('uid', $uid)
->execute();
}
/**
* Determines whether to save session data of the current request.
*
* This function allows the caller to temporarily disable writing of
* session data, should the request end while performing potentially
* dangerous operations, such as manipulating the global $user object.
* See http://drupal.org/node/218104 for usage.
*
* @param $status
* Disables writing of session data when FALSE, (re-)enables
* writing when TRUE.
*
* @return
* FALSE if writing session data has been disabled. Otherwise, TRUE.
*/
function drupal_save_session($status = NULL) {
// PHP session ID, session, and cookie handling happens in the global scope.
// This value has to persist across calls to drupal_static_reset(), since a
// potentially wrong or disallowed session would be written otherwise.
static $save_session = TRUE;
if (isset($status)) {
$save_session = $status;
}
return $save_session;
}
...@@ -586,7 +586,7 @@ public static function languageManager() { ...@@ -586,7 +586,7 @@ public static function languageManager() {
* @return \Drupal\Core\Access\CsrfTokenGenerator * @return \Drupal\Core\Access\CsrfTokenGenerator
* The CSRF token manager. * The CSRF token manager.
* *
* @see drupal_session_start() * @see \Drupal\Core\Session\SessionManager::start()
*/ */
public static function csrfToken() { public static function csrfToken() {
return static::$container->get('csrf_token'); return static::$container->get('csrf_token');
......
...@@ -69,7 +69,7 @@ public function setCurrentUser(AccountInterface $current_user = NULL) { ...@@ -69,7 +69,7 @@ public function setCurrentUser(AccountInterface $current_user = NULL) {
* 'drupal_private_key' configuration variable. * 'drupal_private_key' configuration variable.
* *
* @see drupal_get_hash_salt() * @see drupal_get_hash_salt()
* @see drupal_session_start() * @see \Drupal\Core\Session\SessionManager::start()
*/ */
public function get($value = '') { public function get($value = '') {
return Crypt::hmacBase64($value, session_id() . $this->privateKey->get() . drupal_get_hash_salt()); return Crypt::hmacBase64($value, session_id() . $this->privateKey->get() . drupal_get_hash_salt());
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace Drupal\Core\Authentication\Provider; namespace Drupal\Core\Authentication\Provider;
use Drupal\Core\Authentication\AuthenticationProviderInterface; use Drupal\Core\Authentication\AuthenticationProviderInterface;
use Drupal\Core\Session\SessionManagerInterface;
use Drupal\Component\Utility\Settings; use Drupal\Component\Utility\Settings;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
...@@ -17,6 +18,23 @@ ...@@ -17,6 +18,23 @@
*/ */
class Cookie implements AuthenticationProviderInterface { class Cookie implements AuthenticationProviderInterface {
/**
* The session manager.
*
* @var \Drupal\Core\Session\SessionManagerInterface
*/
protected $sessionManager;
/**
* Constructs a new Cookie authentication provider instance.
*
* @param \Drupal\Core\Session\SessionManagerInterface $session_manager
* The session manager.
*/
public function __construct(SessionManagerInterface $session_manager) {
$this->sessionManager = $session_manager;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
...@@ -30,9 +48,7 @@ public function applies(Request $request) { ...@@ -30,9 +48,7 @@ public function applies(Request $request) {
public function authenticate(Request $request) { public function authenticate(Request $request) {
// Global $user is deprecated, but the session system is still based on it. // Global $user is deprecated, but the session system is still based on it.
global $user; global $user;
require_once DRUPAL_ROOT . '/' . Settings::get('session_inc', 'core/includes/session.inc'); if ($this->sessionManager->initialize()->isStarted()) {
drupal_session_initialize();
if (drupal_session_started()) {
return $user; return $user;
} }
return NULL; return NULL;
...@@ -42,7 +58,7 @@ public function authenticate(Request $request) { ...@@ -42,7 +58,7 @@ public function authenticate(Request $request) {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function cleanup(Request $request) { public function cleanup(Request $request) {
drupal_session_commit(); $this->sessionManager->save();
} }
/** /**
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
use Drupal\Core\Queue\QueueFactory; use Drupal\Core\Queue\QueueFactory;
use Drupal\Core\Session\AccountProxyInterface; use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Session\AnonymousUserSession; use Drupal\Core\Session\AnonymousUserSession;
use Drupal\Core\Session\SessionManagerInterface;
/** /**
* The Drupal core Cron service. * The Drupal core Cron service.
...@@ -54,6 +55,13 @@ class Cron implements CronInterface { ...@@ -54,6 +55,13 @@ class Cron implements CronInterface {
*/ */
protected $currentUser; protected $currentUser;
/**
* The session manager.
*
* @var \Drupal\Core\Session\SessionManagerInterface
*/
protected $sessionManager;
/** /**
* Constructs a cron object. * Constructs a cron object.
* *
...@@ -67,13 +75,16 @@ class Cron implements CronInterface { ...@@ -67,13 +75,16 @@ class Cron implements CronInterface {
* The state service. * The state service.
* @param \Drupal\Core\Session\AccountProxyInterface $current_user * @param \Drupal\Core\Session\AccountProxyInterface $current_user
* The current user. * The current user.
* @param \Drupal\Core\Session\SessionManagerInterface $session_manager
* The session manager.
*/ */
public function __construct(ModuleHandlerInterface $module_handler, LockBackendInterface $lock, QueueFactory $queue_factory, StateInterface $state, AccountProxyInterface $current_user) { public function __construct(ModuleHandlerInterface $module_handler, LockBackendInterface $lock, QueueFactory $queue_factory, StateInterface $state, AccountProxyInterface $current_user, SessionManagerInterface $session_manager) {
$this->moduleHandler = $module_handler; $this->moduleHandler = $module_handler;
$this->lock = $lock; $this->lock = $lock;
$this->queueFactory = $queue_factory; $this->queueFactory = $queue_factory;
$this->state = $state; $this->state = $state;
$this->currentUser = $current_user; $this->currentUser = $current_user;
$this->sessionManager = $session_manager;
} }
/** /**
...@@ -84,8 +95,8 @@ public function run() { ...@@ -84,8 +95,8 @@ public function run() {
@ignore_user_abort(TRUE); @ignore_user_abort(TRUE);
// Prevent session information from being saved while cron is running. // Prevent session information from being saved while cron is running.
$original_session_saving = drupal_save_session(); $original_session_saving = $this->sessionManager->isEnabled();
drupal_save_session(FALSE); $this->sessionManager->disable();
// Force the current user to anonymous to ensure consistent permissions on // Force the current user to anonymous to ensure consistent permissions on
// cron runs. // cron runs.
...@@ -157,7 +168,9 @@ public function run() { ...@@ -157,7 +168,9 @@ public function run() {
// Restore the user. // Restore the user.
$this->currentUser->setAccount($original_user); $this->currentUser->setAccount($original_user);
drupal_save_session($original_session_saving); if ($original_session_saving) {
$this->sessionManager->enable();
}
return $return; return $return;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
use Drupal\Component\Utility\Settings; use Drupal\Component\Utility\Settings;
use Drupal\Core\Database\Connection; use Drupal\Core\Database\Connection;
use Drupal\Core\Utility\Error; use Drupal\Core\Utility\Error;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack;
/** /**
* Default session handler. * Default session handler.
...@@ -19,11 +19,18 @@ ...@@ -19,11 +19,18 @@
class SessionHandler implements \SessionHandlerInterface { class SessionHandler implements \SessionHandlerInterface {
/** /**
* The request. * The session manager.
* *
* @var \Symfony\Component\HttpFoundation\Request * @var \Drupal\Core\Session\SessionManagerInterface
*/ */
protected $request; protected $sessionManager;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/** /**
* The database connection. * The database connection.
...@@ -42,13 +49,16 @@ class SessionHandler implements \SessionHandlerInterface {