SimpleSAMLphp overwrites PHP (Zend) session, doesn't happen with older SimpleSAMLphp version - php

I had to update simplesamlphp on an old PHP server, the old version of the library was from 2010. Simplesamlphp is used as a Service Provider (SP) in a SP initiated enviroment.
I replaced it with the 09/'20 release and configured it the same. It's all working except one thing.
Simplesamlphp uses the PHPSESSION to store the session, by feature it replaces the php session with his and should set the old one again once the cleanup() method is called (on the session instance), after the authentication's complete.
This is not working, but I was fine with it because it didn't matter for the user.
Now I have to implement a button to test the SAML integration on a protected page.
By protected I mean it requires to be authenticated (through Zend Auth) to view the page, otherwise it automatically redirects (server side) the user to the homepage.
This is the code of the Action of this button (to test the SAML integration), that is inside this protected controller:
require_once('simplesaml/lib/_autoload.php');
$as = new SimpleSAML_Auth_Simple('cie');
$as->requireAuth(array(
'saml:idp' => $idp,
));
// --- user is redirected to the IDP and proceeds authenticating)...
$attributes = $as->getAttributes();
$session = \SimpleSAML\Session::getSessionFromRequest();
if($session){
$session->cleanup();
}
What happens is:
requireAuth() is called, my current session is put away and replaced with SimpleSAML's one.
user is redirected to the IDP and authenticates
IDP redirects the user back to my page
Zend does its things before my code is run (everything after requireAuth() is never run) and before the cleanup() method is called, so the old PHP session isn't restored
Zend checks the user isn't authenticated (because it's still using SimpleSAML's session) and redirects the user back to the homepage.
Said so, this doesn't happen with the old library from 2010, the old PHP session is never lost, I have no idea why. I checked everything my colleagues changed in the old library back in the day, but there isn't anything that deals with this.
Do anyone have any idea or tip I could follow?
Any workaround / idea to fix this issue?
I've been desperately googling stuff for weeks, but it's so hard to find something specific.
Thank you very much, just for reading this long question.

I managed to fix this issue very easily after many many hours, I'll write down what I did in case it may help someone else.
My problems were:
simplesamlphp using the same name for the session cookie as my application (I previously already tried changing this setting, but because of the second reason below it never worked)
not properly cleaning simplesamlphp session in my code
So, first all of, I added a call to the cleanup method because it was missing on the real page, the code posted on my question is the test page, this is the real page where it was missing a call to cleanup.
$as->requireAuth(array(
'saml:idp' => $idp,
));
$attributes = $as->getAttributes();
$session = \SimpleSAML\Session::getSessionFromRequest();
if($session){
$session->cleanup();
}
Without calling cleanup() any value I put on the property session.phpsession.cookiename besides NULL ( =use PHP's setting) caused the session to completely break.
So after adding cleanup() I can now specify a value for the property session.phpsession.cookiename (\config\config.php).
I specified a value different (because this was the problem) from the name used by PHP, that is the default value PHPSESSID.
'session.phpsession.cookiename' => 'hSAMLses'
And now it's all working peacefully, hope this answer helps someone because I really struggled too much.

Related

How to find out why/where Symfony sets PHPSESSID cookie?

I am running a Symfony 2.8 based webpage which is separated into a public and a private part (login required).
Due to the "new" GDPR regulation in Europe I have checked which cookies my page actually use. Since I do not use any analytics or tracking tools are related stuff, the public part of the web page does actually need any cookies. However, when inspecting the page with Firefox Webmaster Tools I see that the PHPSESSID Cookie is set when visiting the public pages.
My code of the public pages does not actively uses the session (at least not that I am aware of). Sure the session needs to be queried to check if the user is logged in, is this enough to create a session if it does not exists? I suspect that some third party code/bundle might query the session and thus set the cookie.
Is there a way to find out where and why the cookie is set by symfony?
Usually, php starts session when session_start() happens but it depends on php.ini settings. Symfony starts session dynamically when you first time try to do something with it.
I had the same problem few days ago. In my case symfony starts session when tries to get user token from session.
What I recommend to do: check what session handler you are using, then make a breakpoint inside it and debug.
By default (and in my case) session starts at NativeSessionStorage start method.

Laravel 5 forms && expired sessions - are there alternatives to laravel-caffeine?

So from my experience even in laravel 5.2 the following happens:
in the browser a page with a (ajax) form is shown
the user does something else (e.g. goes home)
when the user returns some time later and the session is expired, he gets an error message that the vrsf token is invalid (VerifyCsrfToken.php)
the user is confused
So far I did not find any build-in solutions for this problem. I am using https://github.com/GeneaLabs/laravel-caffeine but it feels a bit strange that I have to use a 3rd party lib to solve this basic issue. Maybe I missed something?
You don't have to use a 3rd party package for that. All it does is it add some JavaScript at the end of your page that pings the server via Ajax within a given interval in order to keep the session alive.
The CSRF-Token is part of a common security concept. But if you're sure you don't need that for your task, you can tell specific routes not to bother with it. In /app/Http/Middleware/VerifyCsrfToken.php you have an array where you can add the routes you want to exclude from CSRF verification:
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
//
];
But this might not be the best idea, because you're working around a security concept.
And this only prevents from the TokenMismatchException to be thrown. If the controller you're posting to still relies on an active Session, e. g. if it needs the logged in user or something, this won't help you either.
So, there are several solutions to this:
Turn off CSRF-verification for that route. Do this if you know what you're doing and if the session doesn't matter anyway
Hook into the \Illuminate\Session\TokenMismatchException and return a nicely formatted message to the user that their session has expired and ask them to reload the page (I guess that would be the recommended way)
Extend the session lifetime - as #TheFallen already stated, obviously not the best idea
Use that 3rd party package or just add that little piece of JavaScript on your own.
You can increase the time of the expiration of the session. Open config/session.php and change 'lifetime' to the time you wish to allow the session to be valid.
Alternatively in Exceptions/Handler.php listen for VerifyCsrfToken exception and show the user that he needs to refresh the page, login again, etc., which I think would be the better option, because increasing the session lifetime will increase the security risk.

laravel and multi-sessions from the same browser

In our web app, If I use a single browser, login to our application as user A, open another tab and login as user B - User A loses his session data. I assume this is due to a shared cookie made out with the user-agent. Is there a way to concat its name with a username? so that sessions can co-exist between concurrent logged in users using the same browser on the same machine?
We use Laravel 5. Is there any way around it?
Laravel Session Background
Sessions
Skip this section for a quick easy solution
In Laravel, session cookies are created via the Illuminate\Session\SessionManager class, namely through the buildSession method:
SessionManager::buildSession
protected function buildSession($handler)
{
if ($this->app['config']['session.encrypt']) {
return new EncryptedStore(
$this->app['config']['session.cookie'], $handler, $this->app['encrypter']
);
} else {
return new Store($this->app['config']['session.cookie'], $handler);
}
}
In this method we can clearly see that the name of the session comes from our config\session.php, looking in particular this line:
session.php
'cookie' => 'laravel_session', # ~~ ln 121 at time of writing
Ok, but that doesn't help a lot, changing this, changes it everywhere, as noted by the comment proceeding it in the config.
The name specified here will get used every time a new session cookie
is created by the framework for every driver.
And even if we could pass it some dynamic value, something like:
'cookie' => 'laravel_session' . user()->id,
This creates a paradoxical, time ending, universe imploding outcome because you are requesting the id from the user which is accessed via the session looked up by the cookie name laravel_session.. (mindblown)
Let's leave SessionManager and it's session.php configuration alone. We can see from above that regardless of how we approach this, all our session info will be fall under that single laravel_session key.
Guard
Maybe Guard will have some more information.
Guard is your key to auth into your app, and one of the many things that makes Laravel awesome for quickly creating applications.
The method to look at is Guard::user().
One of the first things Guard::user() does after some initial cache and logged out checking, is a session check.
Guard::user()
$id = $this->session->get($this->getName());
So here, Laravel is fetching the session values that match the result of getName() - awesome - all we need to do is mod getName() to return a value, let's take a took at that method:
Guard::getName()
public function getName()
{
return 'login_'.md5(get_class($this));
}
That's pretty straight forward. $this refers to the Guard class, so the md5 will effectively always be the same (if anyone knows the 'why' behind md5'ing the class name which would be the same each time, leave a comment).
There are a few places where this should be updated, such as getRecallerName.
So from here, you can extend the core Guard class and splice in your getName and getRecallerName methods.
You will probably want to wrap some service provider around this, write some unit tests, possibly even overwrite the original auth manager.
"Geez, that seems like a lot of work"
"It sure is Billy, it sure is"
https://www.youtube.com/watch?v=dTxQ9yhGnAg
See the next part
The quick "I just need an answer" answer
Ollie Read has already created a solution, found here:
https://github.com/ollieread/multiauth
I encourage you to have a look, especially the custom Guard class which extends core Guard with custom getName methods.
Any major browser will only store one session cookie for a site, but the site developer gets to choose what's in that cookie. It seems like your site is storing user information in the session cookie, which is then getting overwritten when the other tab stores different information in the same cookie.
You don't provide much detail about how your specific site operates, but here are a few general ways of approaching this problem.
1) Use different browsers for different users. Different browsers don't share cookies between them. If your goal is simply to test your site with multiple users, this is the way. You can also use Incognito/Private mode to log in a separate user, as this mode doesn't share cookies either.
2) Don't use session cookies to store user information. This is a non-starter on most websites, but if this is an internal site or strictly controlled environment, you may be able to pass user identification via the URL, POST data, or some other hidden identifier in the request.
3) Store data in the session cookie for all currently logged in users. Depending on the web framework, it may be possible to create a map of user -> cookieData and look up the correct one based on which user is making the request. This is an advanced technique, and I don't actually know if Laravel exposes this level of control.
Multi userlogin with same browser like google add account. for that you need follow some steps and re-write auth library which provided by the Laravel,
Steps
Tack backup of your Auth file.
Change all session store functionality to store it first in array and then store that array to session
Now you need to create the new session variable which will store the current user instance id like user 0 1 2 ...
Now you need to change all the function from you will get the values from the session you need to check if the session object is empty then user is logout else you need to get data of the user base on the user instance.
You need to change your instance when user want to switch from one account to another.
The easiest is just a URL based sessionID which could be a security issue depending on how your application is designed, especially when sharing urls with non-expired sessions.
Since L5 doesn't support php native sessions anymore, you'll have to use a custom provider like below:
This will use sessionID in the url for laravel V5:
https://github.com/iMi-digital/laravel-transsid
Basically the session is URL based, so you can just login in a different tab and get a new sessionID, and that person can easily do a "open page in new tab" to have two pages of the same user if needed as well.
The library above locks the session to the IP and User Agent so link sharing won't accidentally leak a session.
tl;dr: Yagni
Consider a person (http client in your case) with 2 identities: Dr Jekyll and Mr Hyde.
He visits his new friend Sir RM1970 (http server in your case): "How do you do, RM1970!".
Here is the problem. Poor RM1970 need to welcome back the monster, and there are few options:
fall deep into this rabbit hole: "How do you do both Dr Jekyll and Mr Hyde!", which incredibly complicates further conversation (your ACl, for example, will need to operate with list of identities, and make a decision about priorities if they conflict realtime)
make a decision on your own: "How do you do Dr Jekyll!" and pray you made the right choice (randomly pick user's identity and bring your users some fun with unpredictable responses)
be sly and shift this responsibility back to him: "Pardon me? Who are you? Name yourself!" (require single identity per request)
The later is how it actually works. The browser provides the latest confirmed identity.
You've been asked to change this, but do you really want it? Hold the line and don't accept this responsibility.
If you are not going with first 2 dead-end options, you will need to ask user on which behalf he sends the request. The best option here is to make your frontend stateful, maintain list of opened sessions, and provide a UI for user to pick one. It is almost the 3rd Ryan Bemrose's option, but store this data on client side, and send only the chosen one. No changes in laravel backend required.
The problem here is switching tabs will not automatically switch user, and will be rather confusing, providing very little difference with logout/login path, which is already implemented.
Some browsers support multiple profiles (example), which may be an acceptable alternative. Basically it is the same as 1st Ryan Bemrose's option, but does not require multiple browsers installed, and can benefit from permanent cookies, aka 'remember-me'.
I don't exactly know what do you need this for, but as a developer I sometimes have to log into an application with multiple users. To do that I usually use incognito mode or if its more than 2 users I had some luck using this extension in chrome.
I know its not an answer to your question but it just might be what your looking for.
Different seesions coexist between concurrent logged in users cannot just only implemented by session cookie,because cookie is stored by browser. So the logged
in user's seesion must be stored by Server.
As all we know, Once session_start is called,SessionID is created and then temp file is created in server's temporary
directory.
Diffent user has different SessionID and after session_destory called then all SessionIDs stored in Server and Cookies are recovered. You can rewrite this behavior by implementing SessionHandlerInterface. Of cause many web framework support this,Laravel has not exception.
Here is the document:
custom-session-drivers
I don't know how complicate it is to code it into laravel but this could be one solution:
You use a different session name, has to be a string, and code it into the url every time so the application knows which user made a request. So you can call the session variables by a normal name.
<?php
if(isset($_GET['id']) && !empty($_GET['id']))
session_name($_GET['id']);
session_start();
if(isset($_GET['user'])) {
$_SESSION['user'] = $_GET['user'];
}
if(!empty($_SESSION['user']))
echo "Hello ".$_SESSION['user'];

Yii always starts a session when I touch CWebUser

I'm developing a RESTful API server which require on some of its API methods a valid session, indicated in the form of a cookie with a session ID.
I'm using Yii v1.1.15 with stock PHP session handler (probably 'files').
Thing is that on every call to CWebUser it creates a session and I don't want this. A session should exists only when I explicitly create it, meaning on login (or register which auto-logins the users). For example, if in a certain API method I check if the user is guest using a construct which involves:
Yii::app()->user->isGuest
it automatically creates a session since this code is given in CWebUser.init().
Now, I'm not in a hurry to change CWebUser (in fact, to change this in the already extending class which altered it slightly, in other aspects) since I'm afraid this will have un-anticipated impact on the system.
Can anyone enlight me on this?
What would you do?
Thanks!
Environment:
// Yii v1.1.15
// session component configuration: (but believe me, I've tried every
// combination - its not really related. Check CWebUser.init()...)
'session' => array(
'class' => 'CHttpSession',
'autoStart' => false,
'sessionName' => 'MY_COOKIE_NAME',
'cookieMode' => 'allow',
'cookieParams' => ['lifetime' => 1000],
'gcProbability' => 33,
'timeout' => 1000,
'savePath' => '/tmp/',
),
// Web User's _allowAutoLogin_ is set on 'false'
So you need to check if a user is logged in (This is why you use isGuest) but you don't want to use a session?
The method isGuest uses a session variable to check if an user is logged in. The session is opened when the CWebUser is created. (in the init method like you said.) The isGuest is part of the CWebUser class. If you want to call this method it will always create a session. Unless you overwrite it.
I think you can go 2 ways at this:
Open a session, check if a user is logged in (isGuest) and then close it only if the user is not logged in. You will need to overwrite the isGuest method. Overwrite any other methods to open a session when you need it. (login/register)
Let the client send its login data on every request so you dont have to check the session and thus don't have to open it.
In both cases you will need to overwrite the CWebUser.init() so it won't open a session whenever the CWebUser is created.
So basically this was all a need that came from the following requirement set:
Yii will be used (also) as a RESTful API server.
The RESTful server will establish session only after successful login.
The above last point implies that there is no session cookie for guest users but rather it exists only for an authenticated user session.
The advantages of the above? mostly the 'free' management of login sessions by the stock PHP session including timeouts, garbage collection etc.
Despite the initial appealing of this design, the drawback overcame the advantages:
Indeed, isGuest is a property of CWebUser that when tested, already implied a session generated for the request.
Trying to change the above behavior introduced lots of issues and bugs, and god knows what lurked ahead. In essence, trying to change this behavior on Yii v1.1.x was too problematic as lots of built in features and behaviors (in the abstract meaning...) of Yii based app are implicitly using an established session.
So, I reverted to the following design:
Yii's session management was reverted to stock - yes please! open a session for everything going on! (just do it well as you normally do).
The RESTful server sends an explicit session token on successful login calls.
The client needs to save this token and send it explicitly with every API method that requires an authenticated session.
Server side saves the session token in the "freely managed" (PHP) session and thus is able to verify on each distinct request that the token for the user with this PHP session is indeed his, and is valid.

CodeignitEr Session not working with AJAX

The issue here is I am trying to login into my system via ajax. Let me explain it to your first.
when my user puts in his login details it will be send to the server via Ajax request and then once it gets verified i create an entry into a session and save the information like userid and logged_in flag.
And then i return those value through Json back to user which is processed by a piece of javascript and redirect the user to dashboard.
If the user is not authenticated it shows an error.
But now whats happening here is. When i create a session variable and when the user is redirected to the dashboard. Sometimes it does not create the session variables and thats why i cant show logout button?
any help will be appreciated.
If you’ve used AJAX-heavy web apps built on a CI backend, you might have noticed premature session expiration, even if you’re expiration was set to never expire ($config['sess_expiration'] = 0; in application/config/config.php)
This was apparently due to AJAX requests not regenerating sessions, and apparent collisions. Long story short, last month there was a patch introduced without much fanfare, which (so far) seems to be working for me.
Replace your system/libraries/Session.php file with the one found here (CI’s git):
https://raw.github.com/EllisLab/CodeIgniter/b211adee89f5fd2192051e9c0826146bd150f469/system/libraries/Session.php

Categories