I have an app integrated with saml2 on azure, on my system I always check to see if the user is logged in using:
$as = new \SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth();
however when I log out the user from azure the requireAuth returns that the user is still logged in, only when I close the browser and enter it again it sends the user to log in again.
Using PHP sessions in SimpleSAMLphp will close any existing session when invoked for the first time, and its own session will prevail afterwards.
If you want to restore your own session after calling SimpleSAMLphp, you can cleaning up the session by using following steps:
$session = \SimpleSAML\Session::getSessionFromRequest();
$session->cleanup();
If you don't want to cleanup SimpleSAMLphp's session and try to use $_SESSION afterwards, you won't be using your own session and all your data is likely to get lost or inaccessible.
Note that if your application uses a custom session handler. You can lead to problems because SimpleSAMLphp's stand-alone web UI uses the default PHP session handlers. So, you need to unset the custom handler before making any calls to SimpleSAMLphp:
// use custom save handler
session_set_save_handler($handler);
session_start();
// close session and restore default handler
session_write_close();
session_set_save_handler(new SessionHandler(), true);
// use SimpleSAML\Session
$session = \SimpleSAML\Session::getSessionFromRequest();
$session->cleanup();
session_write_close();
// back to custom save handler
session_set_save_handler($handler);
session_start();
Refer Doc & SO thread for usage of session
Related
Code example:
<?php
require_once(DRUPAL_ROOT . '/simplesaml/lib/_autoload.php');
session_write_close();
session_set_save_handler(new SessionHandler(), true);
$as = new \SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth();
$attributes = $as->getAttributes();
$samlSession = \SimpleSAML\Session::getSessionFromRequest();
$samlSession->cleanup();
$_SESSION['saml'] = $attributes; // <-- this does not work, since altering $_SESSION at this point is useless. reading out $_SESSION on a another page does not have anything saved after calling the SimpleSAMLphp functions
We are using SimpleSAMLphp on our website as SP to use with a Shibboleth IDP. The server cant run the apache modules or memcache so we need to use PHP sessions. On the simplesamlphp documentation it says:
If we are using PHP sessions in SimpleSAMLphp and in the application
we are protecting, SimpleSAMLphp will close any existing session when
invoked for the first time, and its own session will prevail
afterwards. If you want to restore your own session after calling
SimpleSAMLphp, you can do so by cleaning up the session like this:
$session = \SimpleSAML\Session::getSessionFromRequest();
$session->cleanup();
If you don't cleanup SimpleSAMLphp's session and try to use $_SESSION
afterwards, you won't be using your own session and all your data is
likely to get lost or inaccessible.
The problem is, that is exactly the issue we are facing. Whatever I write into $_SESSION after loading the SSP files is lost at the new page request.
Now, we are using Drupal 7. I dont know how to implement the documentation code in a Drupal environment:
// use custom save handler
session_set_save_handler($handler); // what is this? what is $handler?
session_start();
// close session and restore default handler
session_write_close();
session_set_save_handler(new SessionHandler(), true);
// use SimpleSAML\Session
$session = \SimpleSAML\Session::getSessionFromRequest();
$session->cleanup();
session_write_close();
// back to custom save handler
session_set_save_handler($handler); // how do i get the Drupal handler?
session_start();
So how do I implement the session swapping in a Drupal 7 environment? Or generally, how do I get a session handler/ reference?
Drupal itself does this at some point in session.inc:
session_set_save_handler('_drupal_session_open', '_drupal_session_close', '_drupal_session_read', '_drupal_session_write', '_drupal_session_destroy', '_drupal_session_garbage_collection');
But calling any Drupal session function didnt work, $_SESSION was always unwritable (or rather didnt actually save) after using SimpleSAMLphp.
Edited:
If you are not using SimpleSAMLphp's stand-alone web UI, this might work:
require_once(DRUPAL_ROOT . '/simplesaml/lib/_autoload.php');
$as = new \SimpleSAML\Auth\Simple('default-sp');
$as->requireAuth();
$attributes = $as->getAttributes();
$samlSession = \SimpleSAML\Session::getSessionFromRequest();
$samlSession->cleanup();
$_SESSION['saml'] = $attributes;
It should keep your original session handler (which would also be used by SSP), then reload the old session ID by restoring previous session id and name.
Original answer:
Looking at the SimpleSAMLphp session handler's code it should already recover the previous session - If there are any active in the moment of invoking SimpleSAMLphp.
I would say that what happens here is that you manually closed the session by using session_write_close(); before SimpleSAMLPhp started theirs, so when you closed SimpleSAMLphp's session, the previous one could not be restored.
I would try to do as follows (I assumed it is the code you are using):
// If I recall well, Drupal already starts session for you,
// but if it's not the case in your configuration, go ahead and uncomment following lines
// session_set_save_handler($handler);
// session_start();
// use SimpleSAML\Session
$session = \SimpleSAML\Session::getSessionFromRequest();
$session->cleanup();
// Just resume your $_SESSION use
$_SESSION['myAttribute'] = 'myValue';
I'm using a flash based message class to give the user messages.
In a particular page called Backup, the user can restore a backup and it will do the restore and then the following (the custom functions are rather self explanatory):
ASSession::destroySession();
ASSession::startSession();
$mg = new Messages();
$mg->add('s', $prepend);
redirect("login.php");
The issue as I saw it was that when we destroy the session we have to start a new one so that messages (which uses session variables to store the messages) will be displayed. However, once the user gets to the login page after the redirect the page calls a master 'framework' file that also calls ASSession::startSession(). So I figured I'd first check if we had a session id in the startSession() function, as we should have started the session before the redirect so there is no need to start a new session when we reach login as that would also remove the message before the user gets to view it.
So I made this change:
public static function startSession()
{
if (!session_id()) {
ini_set('session.use_only_cookies', SESSION_USE_ONLY_COOKIES);
$cookieParams = session_get_cookie_params();
session_set_cookie_params($cookieParams["lifetime"], $cookieParams["path"], $cookieParams["domain"], SESSION_SECURE, SESSION_HTTP_ONLY);
session_start();
//session_regenerate_id(SESSION_REGENERATE_ID);
}
}
To no avail. I ran an entire site-wide find for session_start() to see if it was starting somewhere else without checking if it had already started and that came up negative. So my question is: why is my session restarting after I started it, if the only function that deals with starting the session checks if the session is currently running? Because my messages are not being displayed :(
Side note: I am trying to avoid the dreaded ?success='It worked' and echo $_GET['success'];
I am tracking the login history of a user in my website, and for that I need to display if there is any other session open in another browser or device. Plus, I need to provide a functionality wherein a user can logout a session that is open in a different browser/device from the current session. I am using redis-server. The things which I have done so far are as follows.
In the .env file, I have updated the CACHE_DRIVER and SESSION_DRIVER to redis.
In session.php and cache.php, I have set driver to redis.
Next, at the time of login, I connect to the redis server and store the session id for a specific user.
$redis = Redis::connection();
$redis->sadd('user:sessions:'. Auth::user()->id, $session_id);
Once this is done, I can see the multiple session id's per user using redis-cli command.
> SMEMBERS user:sessions:1
> "95008658737a7f937c614bccbb748443a649c515"
> "f1f14db9b1760254a4072fe9b440f9acbacc8974"
> GET laravel:95008658737a7f937c614bccbb748443a649c515
> "s:332:\"a:5:{s:6:\"_token\";s:40:\"HAuA200irzF63fgFw4vCVkrsZNuqTk6o2XLkHzlu\";s:9:\"_previous\";a:1:{s:3:\"url\";s:33:\"http://localhost:8000/security\";}s:5:\"flash\";a:2:{s:3:\"old\";a:0:{}s:3:\"new\";a:0:{}}s:50:\"login_web_59ba36addc2b2f9401580f014c7f58ea4e30989d\";i:1;s:9:\"_sf2_meta\";a:3:{s:1:\"u\";i:1464957596;s:1:\"c\";i:1464957416;s:1:\"l\";s:1:\"0\";}}\";"
This output makes me assume that the redis option for storing sessions in laravel is working fine.
Next, for logging out a user from a specific session, I am using the following set of instructions:
public function logoutSession($session_id) {
$redis = Redis::connection();
$redis->del('laravel:' . $session_id);
$redis->srem('user:sessions:' . Auth::user()->id, $session_id);
}
Once this function is called, the corresponding session id is successfully deleted.
Running the SMEMBERS and GET commands again in redis-cli proves it.
So the scenario is, I try to delete a session opened in say, Firefox from another browser say, Chrome. Cliking on the logout link (for Firefox session from Chrome session) deletes the Firefox session from redis-server successfully, but if I try to refresh the Firefox browser, I am still logged in.
Just an image displaying the functionality I am trying to achieve
I cannot understand where I am going wrong exactly. Any sort of help will be highly appreciated.
Thanks
NOTE: I am already using the 'auth' middleware, so that cannot be the problem. Plus, if I try to debug the code, I am seeing different session_ids in $_COOKIE variable and http request variable. Is this normal?
I had a similar issue once myself. I was frustrating myself with cache invalidation etc... and then after going through the "log in" process again I had forgotten to check for the "remember me" cookie.
https://laravel.com/docs/master/authentication#remembering-users
Turns out I had cleared the Cache successfully, but needed to call:
Auth::logout();
In order to remove the "remember_token" from the database. Otherwise, Laravel sees this as a valid way to reboot the Auth system, logging the user back in and setting a new session cookie.
Using your code:
public function logoutSession($session_id) {
$redis = Redis::connection();
$redis->del('laravel:' . $session_id);
$redis->srem('user:sessions:' . Auth::user()->id, $session_id);
Auth::logout();
}
But this logs out from ALL sessions, including the one you're working with.
For your problem, I propose using the Auth::viaRemember() method to determine if the client creating the request along with the cookie is the one you're currently operating with. It differentiates between your current session cookie and a "remember me" cookie:
if (Auth::viaRemember())
{
// Check Redis for session info
// Do something if not found, otherwise just proceed
}
**EDIT**: I found this after posting my answer: Laravel Auth::logout not removing remember me cookie
So to recap:
if (Auth::viaRemember())
{
if (!Redis::get($key))
{
// Get remember_me cookie name
$rememberMeCookie = Auth::getRecallerName();
// Tell Laravel to forget this cookie
$cookie = Cookie::forget($rememberMeCookie);
return Redirect::to('/')->withCookie($cookie);
}
}
I've visited my website for the first time and I see the session cookie set by server. I'm reloading the page and I see that only my browser sends the session identifier to server, while server doesn't return session cookie. I'm using Kohana framework. I'm wondering whether this is native PHP behavior to not send session cookie if the request already has it and it's not expired or this is handled by the framework?
I've found the following piece of code which presumable does the magic:
protected function _read($id = NULL)
{
// Sync up the session cookie with Cookie parameters
session_set_cookie_params($this->_lifetime, Cookie::$path, Cookie::$domain, Cookie::$secure, Cookie::$httponly);
// Do not allow PHP to send Cache-Control headers
session_cache_limiter(FALSE);
// Set the session cookie name
session_name($this->_name);
if ($id)
{
// Set the session id
session_id($id);
}
// Start the session
session_start();
// Use the $_SESSION global for storing data
$this->_data =& $_SESSION;
return NULL;
}
Is it what I'm looking for?
Official manual says:
When session_start() is called or when a session auto starts, PHP will
call the open and read session save handlers. These will either be a
built-in save handler provided by default or by PHP extensions (such
as SQLite or Memcached); or can be custom handler as defined by
session_set_save_handler().
The read callback will retrieve any existing session data (stored in a
special serialized format) and will be unserialized and used to
automatically populate the $_SESSION superglobal when the read
callback returns the saved session data back to PHP session handling.
So the answer should sound like this: This is native PHP behavior unless you defined custom save handler by session_set_save_handler().
I am having problems with a custom start session.For security reasons I decide to look for a method that is safe when starting a session and I came across this tutorial and implemented the method related to start session.
The problem is that whenever I am initiating a new session variable and redirect to another page which is expecting the value from the initialized session, all my session variable that I initialed earlier on get destroyed forcing the user to logout.Below is my function I am using to start sessions:
function sec_session_start(){
$session_name = 'sec_session_id';//set a custom session Name
$secure = false;//true if are using https
$httponly = true; //this stops javascript from accessing session id
ini_set('session.use_only_cookies', 1);//FORCES session to only use cookies
$cookie_params = session_get_cookie_params();//Get current cookie params
session_set_cookie_params($cookie_params['lifetime'],$cookie_params['path'],$cookie_params['domain']
,$secure,$httponly);
session_name($session_name);//set the session name to the one set above
if (!isset($_SESSION)){session_start();}//start the php session
session_regenerate_id();//regenerate new session id and delete the old one THIS IS TO PREVENT SESSION HIJACK
}
I have searched for an answer to my problem with no luck, Please help me on this.
N.B - when I use the default session_start
everything works perfect.
You should start session, not when $_SESSION is not set.
if (!isset($_SESSION)){session_start();}//start the php session
session_regenerate_id();//regenerate new session id and delete the old one THIS IS TO PREVENT SESSION HIJACK
should be
session_start();//Start new or resume existing session
session_regenerate_id();//regenerate new session id and delete the old one THIS IS TO PREVENT SESSION HIJACK
Reference: session_regenerate_id
Try to put session_start() at top of your php code, as first instruction.