'how to bind user cookie with user agent in drupal 8
i am using drupal 8 with mysql database. but using cookie editor i am able to get user cookie and reuse them. this also provides other users access, looked at drupal community for resolution but not found drupal 8 fix of this. i want to bind user cookie with browser user agent to make it more secure even user get cookie they will not be able to get user session access.
here is my sessionmanager.php
<?php
namespace Drupal\Core\Session;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Database\Connection;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
class SessionManager extends NativeSessionStorage implements SessionManagerInterface {
use DependencySerializationTrait;
protected $requestStack;
protected $connection;
protected $sessionConfiguration;
protected $startedLazy;
protected $writeSafeHandler;
public function __construct(RequestStack $request_stack, Connection $connection, MetadataBag $metadata_bag, SessionConfigurationInterface $session_configuration, $handler = NULL) {
$options = [];
$this->sessionConfiguration = $session_configuration;
$this->requestStack = $request_stack;
$this->connection = $connection;
parent::__construct($options, $handler, $metadata_bag);
$this->bags = [];
}
/**
* {@inheritdoc}
*/
public function start() {
if (($this->started || $this->startedLazy) && !$this->closed) {
return $this->started;
}
$request = $this->requestStack->getCurrentRequest();
$this->setOptions($this->sessionConfiguration->getOptions($request));
if ($this->sessionConfiguration->hasSession($request)) {
// If a session cookie exists, initialize the session. Otherwise the
// session is only started on demand in save(), making
// anonymous users not use a session cookie unless something is stored in
// $_SESSION. This allows HTTP proxies to cache anonymous pageviews.
$result = $this->startNow();
}
if (empty($result)) {
// Randomly generate a session identifier for this request. This is
// necessary because \Drupal\Core\TempStore\SharedTempStoreFactory::get()
// wants to know the future session ID of a lazily started session in
// advance.
//
// @todo: With current versions of PHP there is little reason to generate
// the session id from within application code. Consider using the
// default php session id instead of generating a custom one:
// https://www.drupal.org/node/2238561
$this->setId(Crypt::randomBytesBase64());
// Initialize the session global and attach the Symfony session bags.
$_SESSION = [];
$this->loadSession();
// NativeSessionStorage::loadSession() sets started to TRUE, reset it to
// FALSE here.
$this->started = FALSE;
$this->startedLazy = TRUE;
$result = FALSE;
}
return $result;
}
/**
* Forcibly start a PHP session.
*
* @return bool
* TRUE if the session is started.
*/
protected function startNow() {
if ($this->isCli()) {
return FALSE;
}
if ($this->startedLazy) {
// Save current session data before starting it, as PHP will destroy it.
$session_data = $_SESSION;
}
$result = parent::start();
// Restore session data.
if ($this->startedLazy) {
$_SESSION = $session_data;
$this->loadSession();
}
return $result;
}
/**
* {@inheritdoc}
*/
public function save() {
if ($this->isCli()) {
// We don't have anything to do if we are not allowed to save the session.
return;
}
if ($this->isSessionObsolete()) {
// There is no session data to store, destroy the session if it was
// previously started.
if ($this->getSaveHandler()->isActive()) {
$this->destroy();
}
}
else {
// There is session data to store. Start the session if it is not already
// started.
if (!$this->getSaveHandler()->isActive()) {
$this->startNow();
}
// Write the session data.
parent::save();
}
$this->startedLazy = FALSE;
}
/**
* {@inheritdoc}
*/
public function regenerate($destroy = FALSE, $lifetime = NULL) {
// Nothing to do if we are not allowed to change the session.
if ($this->isCli()) {
return;
}
// We do not support the optional $destroy and $lifetime parameters as long
// as #2238561 remains open.
if ($destroy || isset($lifetime)) {
throw new \InvalidArgumentException('The optional parameters $destroy and $lifetime of SessionManager::regenerate() are not supported currently');
}
if ($this->isStarted()) {
$old_session_id = $this->getId();
// Save and close the old session. Call the parent method to avoid issue
// with session destruction due to the session being considered obsolete.
parent::save();
// Ensure the session is reloaded correctly.
$this->startedLazy = TRUE;
}
session_id(Crypt::randomBytesBase64());
// We set token seed immediately to avoid race condition between two
// simultaneous requests without a seed.
$this->getMetadataBag()->setCsrfTokenSeed(Crypt::randomBytesBase64());
if (isset($old_session_id)) {
$params = session_get_cookie_params();
$expire = $params['lifetime'] ? REQUEST_TIME + $params['lifetime'] : 0;
setcookie($this->getName(), $this->getId(), $expire, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
$this->migrateStoredSession($old_session_id);
}
$this->startNow();
}
/**
* {@inheritdoc}
*/
public function delete($uid) {
// Nothing to do if we are not allowed to change the session.
if (!$this->writeSafeHandler->isSessionWritable() || $this->isCli()) {
return;
}
$this->connection->delete('sessions')
->condition('uid', $uid)
->execute();
}
/**
* {@inheritdoc}
*/
public function destroy() {
session_destroy();
// Unset the session cookies.
$session_name = $this->getName();
$cookies = $this->requestStack->getCurrentRequest()->cookies;
// setcookie() can only be called when headers are not yet sent.
if ($cookies->has($session_name) && !headers_sent()) {
$params = session_get_cookie_params();
setcookie($session_name, '', REQUEST_TIME - 3600, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
$cookies->remove($session_name);
}
}
/**
* {@inheritdoc}
*/
public function setWriteSafeHandler(WriteSafeSessionHandlerInterface $handler) {
$this->writeSafeHandler = $handler;
}
/**
* Returns whether the current PHP process runs on CLI.
*
* Command line clients do not support cookies nor sessions.
*
* @return bool
*/
protected function isCli() {
return PHP_SAPI === 'cli';
}
/**
* Determines whether the session contains user data.
*
* @return bool
* TRUE when the session does not contain any values and therefore can be
* destroyed.
*/
protected function isSessionObsolete() {
$used_session_keys = array_filter($this->getSessionDataMask());
return empty($used_session_keys);
}
/**
* Returns a map specifying which session key is containing user data.
*
* @return array
* An array where keys correspond to the session keys and the values are
* booleans specifying whether the corresponding session key contains any
* user data.
*/
protected function getSessionDataMask() {
if (empty($_SESSION)) {
return [];
}
// Start out with a completely filled mask.
$mask = array_fill_keys(array_keys($_SESSION), TRUE);
// Ignore the metadata bag, it does not contain any user data.
$mask[$this->metadataBag->getStorageKey()] = FALSE;
// Ignore attribute bags when they do not contain any data.
foreach ($this->bags as $bag) {
$key = $bag->getStorageKey();
$mask[$key] = !empty($_SESSION[$key]);
}
return array_intersect_key($mask, $_SESSION);
}
/**
* Migrates the current session to a new session id.
*
* @param string $old_session_id
* The old session ID. The new session ID is $this->getId().
*/
protected function migrateStoredSession($old_session_id) {
$fields = ['sid' => Crypt::hashBase64($this->getId())];
$this->connection->update('sessions')
->fields($fields)
->condition('sid', Crypt::hashBase64($old_session_id))
->execute();
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
