Logging out one browser session from another browser - LARAVEL 5.2 - php

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);
}
}

Related

making user redirect if not logged in using php sessions

I am beginner in web development and i am creating my first project. I am using XAMPP, for my php files. I have basically created app.php, sigin.php. So in order to prevent user from directly access my app.php i am using session variables in php. Hence i added the following PHP code just before my app.php.
<?php
session_start();
if(!isset($_SESSION['loginstatus'])) {
header('location:./login.php');
die();
}
?>
And i am setting my session variables in my signin.php like the following:
if($user['username'] == $username && $user['password'] == $password) {
$_SESSION['username'] = $username;
$_SESSION['loginstatus'] = 'success';
echo "success!";
header('location:../app.php');
}
Now i tried accessing my app.php without login, i am still able to access app.php. To check where is the issue i cleared my browser history and cookies, then i tried accessing app.php, then surprisingly it worked i was actually redirected to login page, but as soon as i do first succesfull login, and logout and again try to access app.php without login, i was again able to access app.php without login.
Now for some reason i feel that my browser is saving session variables too, So to check that i wrote a small piece of code and pasted in my app.php:
<?php
var_dump($_SESSION['loginstatus']);
?>
after first successful login my $_SESSION['loginstatus'] is always set to successful. Now as i said i am a beginner, what i learnt is session are stored in server side. So i am totally confused regarding this.
There is a cookie in your webbrowser "phpsessid" wich stores the id of the Session on the server.
In normal cases you destroy the Session, at logout.
session_unset(); to unset all session variables
session_destroy(); destroys the session
The Session will timeout after time X. You can change it, described here -> Link
So if you have a cookie in your Browser with a valid id of a not-timeouted Session you will always be able to log in.
So basically, going to browser setting > privacy and security > more > pre-load pages for faster browsing and searching
I just disabled this default setting from chrome, and it started working as expected.

Laravel 5.5 Sessions not saving after using Paypal

I have checked several questions already and tried everything but it did not help.
I want to use Laravel Sessions to store some data but they don't persist.
The code is something like this:
public function payment (Request $request)
{
$data = "somedata";
$provider = new Provider();
$request->session()->put("data",$data);
$request->session()->put("provider",$provider);
$response = $provider->setExpressCheckout($data);
return redirect($response['paypal_link']);
}
This happens when I open, let's say www.mypage.com/pay
When I use dd($request->sesion()->all()); here, the session has been saved.
Now the user gets redirected to Paypal, does the check out and it gets redirected somewhere in my application.
public function aferpay(Request $request)
{
dd($request->sesion()->all());
}
When this function gets called, the previous url is fine "url" => "www.mypage.com/pay" even though it comes from Paypal, but the rest of the data is not there anymore.
Any help?
Check your session config for any oversights, especially the session domain.
Make sure the session driver is working, and if you are using file sessions make sure the session directory is writable and there's enough free disk space.
Finally, msure you are not accessing mypage.com/pay without www first, and paypal redirects to www.mypage.com/pay and the session doesn't stick because of that - setting .mypage.com as the session domain will fix this.
If all else fails, please attach the set-cookie response headers of your mypage.com/pay page.

Typo3 - manual login only works with cookie

I'm trying to manually login the user using this snippet (after verifying the login data of course):
public function loginUser($user) {
$userArray = array('uid' => $user->getUid());
$GLOBALS['TSFE']->fe_user->is_permanent = true;
$GLOBALS['TSFE']->fe_user->checkPid = 0;
$GLOBALS['TSFE']->fe_user->createUserSession($userArray);
$GLOBALS['TSFE']->fe_user->user = $GLOBALS['TSFE']->fe_user->fetchUserSession();
$GLOBALS['TSFE']->fe_user->fetchGroupData();
$GLOBALS['TSFE']->loginUser = true;
//this somehow forces a cookie to be set
$GLOBALS['TSFE']->fe_user->setAndSaveSessionData('dummy', TRUE);
}
If I leave out the "setAndSaveSessionData" Part, the login doesn't work at all, after a page redirect the login data are gone and the user is logged out again. But the setAndSaveSessionData stores the session in a cookie and the user will remain logged in even after closing the browser - which is a behaviour I do not want (not without the user's consent). Is there a way to manually login the user without the "setAndSaveSessionData" part? I'm using Typo3 6.2.12 with extbase and felogin
Thank you very much in advance!
In some TYPO3 6.2.x (I don't remember which x exactly) there was a change introduced, which causes that you need to call AbstractUserAuthentication::setSessionCookie() method yourself... Unfortunately it has protected access so the best way to login user is creating some util class extending it:
typo3conf/your_ext/Classes/Utils/FeuserAuthentication.php
<?php
namespace VendorName\YourExt\Utils;
use TYPO3\CMS\Core\Authentication\AbstractUserAuthentication;
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
class FeuserAuthentication extends AbstractUserAuthentication {
function __construct($uid) {
return $this->authByUid($uid);
}
// Authenticates user by uid
public function authByUid($uid) {
/** #var $fe_user FrontendUserAuthentication */
$fe_user = $GLOBALS['TSFE']->fe_user;
$fe_user->createUserSession(array('uid' => $uid));
$fe_user->user = $fe_user->getRawUserByUid($uid);
$fe_user->fetchGroupData();
$GLOBALS['TSFE']->loginUser = true;
$fe_user->setSessionCookie();
return $fe_user->isSetSessionCookie();
}
}
so to login your user by uid you just need to create new object of this class with $uid of fe_user as a constructor's param:
$this->objectManager->get(
'\VendorName\YourExt\Utils\FeuserAuthentication',
$user->getUid()
);
P.S. As you can see this class doesn't check if account exists and/or is enabled, so you need to check it yourself before authentication attempt.
A website is delivered HTTP(S), which is a stateless protocol. This means that something has to be saved on the client computer, because otherwise the server couldn't reliably recognize the user again. There are several ways to do this:
Use a session cookie (The way TYPO3 does it, PHP also does that)
Manually add a session ID to each request on a page, Java-based applications do that sometimes. This breaks if the user leaves the page and comes back later (in the same session, or in another tab without copying a link).
There are probably some more ways, but I can't come up with them right now
So my answer is: Since I believe it is hard to get TYPO3 to switch to another way of setting the session information (would be quite user unfriendly), there is no good way to avoid setting the cookie.
However:
The cookie is a session cookie, which expires when the browser session is ended. So closing the browser and reopening it should end the login, except if the browser restores the previous session when opened. Many modern browsers do this, especially mobile browsers. Ways to get around that:
Use the incognito or private mode of the browser
Set the browser to start a fresh session on each start and make sure the browser terminates when you are finished (again: watch mobile devices).

Set and Check Cookie in the one response - Laravel

I am attempting to set a cookie and then check to see if the cookie has been set.
So in one function, I have it make the cookies:
public function makeCookies(){
Cookie::queue('logged_in', $value, 15);
Cookie::queue('user_id', 2);
//return Response::make()->withCookie(Cookie::make('logged_in', $value, 15))->withCookie(Cookie::forever('user_id', 2));
}
And in the other function, I try to check to see if the cookie has been set:
public function checkCookies(){
$this->makeCookies();
if(Cookie::get('logged_in') && Cookie::get('user_id')){
return 'Logged In!';
}
}
However the only way this works is if I add 'return' before $this->makeCookies(); However, I want to be able to get to the conditional below it. Is there any way I can go about doing this? Any help is greatly appreciated.
To understand the Cookie Creation/Read process:
The user's browser sends a request for a page, along with any cookies that it currently has for the site
The site serves up the page, and any cookies you create become a header in your response.
Subsequent requests to your site will send the cookies created in #2.
What you are asking...to be able to read cookies that you create in step #2 in step #1...not possible.
Now, depending on how the Cookie class is created, you could make it so that when the Cookie::queue() is called, that it creates in-memory data that reflects what the cookie "should be" on the next request, but it doesn't truly know whether or not the user's browser will accept cookies, etc.
This is why many sites, after creating a cookie give the user a redirect to a page with something like ?checkCookie=1. This way, on the subsequent request, they can verify that your browser supports cookies...and if the cookie doesn't exist on the ?checkCookie page, they give you an error saying that their site requires cookie support. However, it does require a second round to the server to read cookies from the browser that were created.
UPDATE 2015-04-24 Per #Scopey, Laravel does support in-memory retrieval of cookies via queued(). So, you should be able to do:
public function checkCookies(){
$this->makeCookies();
$loggedIn = Cookie::get('logged_in') ?: Cookie::queued('logged_in');
$userId = Cookie::get('user_id') ?: Cookie::queued('user_id');
if( $loggedIn && $userId ){
return 'Logged In!';
}
}
SECURITY CONCERNS (NOT DIRECTLY ANSWERING THE QUESTION)
Your question was only about the cookies, so that's all I answered. However, now that I'm looking at your code, I feel I would be remiss not to point this out for anyone that happens to be reading this. This may just be a "how to" for yourself and not production code, but that code could be very dangerous if it ever went public.
Make sure you do NOT TRUST a user_id stored in a cookie to determine what user is coming in via cookies. If you rely on that, and I come to your site, I can modify my cookie to any user_id I want and get into other people's accounts.
General Safety Rules:
A cookie should contain a GUID, or similar random string to identify the session. This random string should be sufficiently long (e.g. 32 characters or greater, IMHO) that it is not easy for someone to brute-force their way to hijacking sessions.
The user_id should be stored in the $_SESSION (or laravel's wrapper for session if applicable) so that the user doesn't have any access to the user_id to be able to modify it.
In plain PHP, this something like this for the login page:
session_start();
if( isValidPassword($_POST['username'], $_POST['password']) ) {
$_SESSION['user_id'] = $user->Id;
}
else {
die('invalid login credentials');
}
The session_start() method automatically generates a cookie for the user with that long, random string (so you don't even have to worry about that part.)
On subsequent pages, you just check the session user_id to know who is logged in:
session_start();
if( empty($_SESSION['user_id']) ) {
die('You are not logged in and cannot access this page');
}
Change as needed per Laravel's documentation, which if they have their own session wrapper, I'm sure is well documented on best practices.
Excellent description by #KevinNelson about cookies but Laravel does support fetching back any cookies you have queued in the current request. Try using
Cookie::queued('logged_in');
The catch is, the cookie will only be "queued" during the request that you queued it. You will have to use get like you are for any other requests.

PHP Session issue on browser close

Here running into problem where I have requirement to clear user session when closing the browser. I have tried all the various option like setting session.cookie_lifetime=0 or session_destroy on browser close using onunload function. But nothing seems to destroy session when I open the browser next time.
I just googled a bit and I saw that in Chrome browser there is setting called ''Allow local data to be set' that has to be changed to 'Keep local data only until I quit my browser', when I do this it does not retain my session.
The real problem is I cannot ask each user to change the settings of the browser and then it would work accordingly, is there a way I can handle it in code using php or javascript. Any option is fine.
Have you tried checking for both cookie and session when your page loads? Something like this:
1) destroy cookie on unload
2) on page load check for both
if(isset($_COOKIE['user'] && $isset($_SESSION['user'] {
//user is logged in
} else {
//your code should fall here after user closes browser
//because the cookie doesn't exist anymore. Maybe you can even destroy the session too
[session_destroy();]
...
...
}

Categories