Multiple users' session in same browser - php

Current app:
The app I'm working on has a single User entity.
Users can be "member" or "manager" using a boolean attribute stored in database (is_manager).
All the users connect trough the same routes (/login) and are redirected depending on the attribute is_manager.
Here is my problem:
The client want to be logged as a "member" in one tab and an other user "manager" in an other tab of the same browser.
Not several "members"/"managers" at the same time in the same browser.
How can I acheive it with Symfony 3.3 ?
Based on my idea the session ID should depend on the attribute is_manager but I'm not really sure of it and don't know how to do it with Symfony.
Any help will be really appreciated!

You could use User switching to almost solve this problem. Instead of logging in as member or manager, they login as a user with the role ROLE_ALLOWED_TO_SWITCH. You can then provide links to the page they want to see with an added attribute ?_switch_user=member_user or ?_switch_user=manager_user. Both those users have to exist and need the correct permissions.
This may not be perfect, for example you have to maintain 3 different users for 1 account and you have to make sure they don't accidentally perform actions after switching the role, but that is the best way I can think of, to support this kind of switching.

You need to tune up your user management system. You can put some vars in your session saying to your system to behave un some way (manger or user) but if it must depend on the open tab, then the best approach that I can think of, is using the url. Put some kind of token (secured one, of course) on the url that tells your system how to deal with that user.
On this approach, if the user closes the tab, it becomes automatically logged out, at least in one of it's roles.
So you can do a standard login process, set the session for the manager role (the more privileged one) and the build and present a link to the user to he non manager versión. That url contains the mentioned token, and if he closes the tab and wants to recover the tab, it should go to the manager versión and follow the link again.

Related

User cannot login when admin is logged in

I have a problem in my project. When admin is logged in, no front end user can login in the same browser, why this happens? But when I destroy the cookies and then tries to login as user it correctly logs in.
How can I solve this?
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.
Harshad is covering all the aspects very well, but I can tell about a little trick a I have used when I wanted to test using different user rights (same browser). In my case, it was Windows Authentication, but it does not matter:
1) define a flag at user level (e.g. SuperUser). It can be 0 (false) or 1 (true).
2) allow "impersonation" - if an administrator has SuperUser flag set, he/she can change its roles/rights and see the site as if he/she is a normal user with that particular rights, but user management section is still accessible, to allow changing rights back.
3) Little changes are required in the user management section to allow SuperUser security implementation (i.e. section is showing if user does not have admin role, but it is marked as SuperUser)
So, you are testing as a single user, no multiple session cookies or other tricks are required. You can have one tab opened with your user profile and other(s) to do the actual testing.
Note: regarding the multiple browser suggestion, it is a quick solution for developers, but in corporate environment, this can be a real problem, as users (e.g. key users that have to test security) do not have access to more than one browser.

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'];

Force user reauthentication on symfony

I'm developping a website with a member area and user levels. admin members can access to an area where they can view, add and change some sensitive data.
To add a protection layer on this group of pages, i'd like to ask users their login and password before accesing the home page of the restricted area even if they are already logged in.
How can i do that ? in the symfony doc, i haven't found anything about a second authentication of the users.
What you're looking for here is IS_AUTHENTICATED_REMEMBERED vs IS_AUTHENTICATED_FULLY. If you have remember me functionality you can set the session to expire after 30 minutes to an hour (or whatever time interval you think is ok) When the session times out, in admin areas, if you check for is authenticated fully they'll be asked to login, if they visit any place with lower bar (e.g. is authenticated remembered) they'll still appear logged in. This is basically what amazon does when you try access your user settings page. Sure you're logged in and can add stuff to your cart, but once you try and access your sensitive data, you must re-login.
I would avoid a second authentication... I is better to work with restriction layers (user roles)... the FOSUserBundle already provides all the needed functionality

Invalidate session for a specific user in Symfony2

I have written a system in which a background PHP process (written using the RabbitMQBundle) processes messages from a message queue. The worker process updates user accounts. This may include a change in the user roles.
The problem is that a user won't notice any changes in his roles while being logged in. The new roles only get applied after logging out and in again. From a security perspective this is not desirable. A user should loose any role as soon as an administrator takes away privileges from that user in the backend system.
The question is: How can a session for a specific user be updated with the new roles? Or when that is not possible, how can the session be invalidated?
Note that in the background process we don't have an active security.context or request that we can use. Code like this therefore doesn't work:
$this->get('security.context')->setToken(null);
$this->get('request')->getSession()->invalidate();
You can solve this in several ways:
1) via security.always_authenticate_before_granting
You can force Symfony to refresh user on each request, effectively reloading all roles with it.
See this SO question/answer:
Change the role of a distant user without having to relog
2) Via EquatableInterface:
You need to implement isEqualsTo(User) which in turn should compare everything with User class, including roles.
See this link: Create a User Class
3) Finally, you can use DBMS to store sessions. Then, it's just matter of find the record and delete it.

How to handle different login credentials for modules in one project?

I am fairly new to PHP programming and I think I might have some security issues with session variables.
I am currently working on a project which has 3 modules which require separate login credentials.
The 3 modules are for students, teachers and administration.
After the user logs in the respective portals, these credentials are stored as session variables. Let's say we have 2 tabs open in the browser, 1 has the student portal open and the other has the admin portal open. If the student logs in the first portal with user id 1 shortly after the admin has loged in with user id 2, then the userid for both the portal appears to be the same(userid 1). The problem is the session variables for both the portals are getting shared in the browser.
Sometimes session variables are also pulled from previous session in a new tab even after closing it.(*tested it using var_dump[$_SESSION]*)
Can somebody please explain to me how to limit the session variables to each portals or provide me with some hints about other ways of security handling in php?
PS: I have logout buttons which clears up the session variables. The problem seems to persist if the tab is closed or a new portal is opened in the new tab.
thanks in advance.
From a browser to a server only one PHP session will be started (apart from private browsing options, but that's off topic) and that is "shared" among all tabs. In contrast to what #fejese's answer suggests, you can solve your situation with using only one PHP session. Your problem probably is that you use the same session variable to indicate that someone is logged in regardless of the access level of that logged in user.
As your 3 separate modules handle authentication, create 3 different session variables that indicate which user is logged in. For e.g. when a student logs in, craete $_SESSION['auth_student_id'] and assign the logged user (student) ID to it. When a teacher logs in, create $_SESSION['auth_teacher_id'], and so forth.
Then, depending on which portal is loaded, ignore the other session variables. So if in tab 1 the student portal is loaded, check for $_SESSION['auth_student_id'] and ignore the others. If that is set, you know the portal should show protected content because the user (student) has authenticated themselves. If in tab 2 the teacher portal loaded do the same with $_SESSION['auth_teacher_id'] and ignore the other 2.
You have some options:
Change "session_name" on a portal basis
If you change the session name, the cookies that identify the session will be different from portal to portal. Note that no session will be shared this way. If the user logged to a portal, he'll need to log again to the others.
Implement session namespaces
You could set an array in the main $_SESSION object, one for each submodule, and use each array as if you are using the session directly. With this approach you can share the sessions (easily implementing SSO between the portals), but raises some security concerns. It's valuable to implement an API to access the session if you go this way.

Categories