Laravel - how to stop remembering users - php

I'm new to laravel and added a userauthentification to my application. Now I don't want authenticated users to be remembered after closing the browser, but this is actually the case. How do I stop this? The remember_token is a nullable varchar(100), an it is set with the first login and then updated everytime the user logs out.
Shouldn't users only be remembered when i pass true as parameter in the auth::attempt()?
Tyvm in advance...
This is part of my model:
$validation = Validator::make($input, $rules, $messages);
if ($validation->fails())
{
$this->response['message'] = $validation->getMessageBag()->first();
}
else
{
$this->response['message'] = $messages['user.missing'];
if (Auth::attempt(array(
'emailadress' => $input['emailadress'],
'password' => $input['password'])))
{
$this->response['valid'] = true;
$this->response['message'] = 'Hey '.Auth::user()->firstname.'!';
$this->response['redirect'] = '/hello';
}
}
return $this->response;

As you said, you are not including the remember parameter in Auth::attempt(), so indeed - your users are not being remembered.
They will be logged in for as long as their session remains active. Browsers don't empty their cookies upon closing unless the user specifically tells it to, and there is certainly no way for you to "detect" their browser closing from the server-side and expire their session from that end.
So, you must either choose a different session lifetime in your PHP settings if you want sessions to expire more quickly, or you can do something like this where you timestamp their activities and log them out if they've been idle for a set time.
If you choose to shorten your session lifetimes, this can be accomplished in php.ini:
ini_set(‘session.gc_maxlifetime’,30);
ini_set(‘session.gc_probability’,1);
ini_set(‘session.gc_divisor’,1);

Related

How to run an UPDATE query on SESSION TIMEOUT

I am working on a project which is built using CakePHP 2.8 . At the time of login I am setting a FLAG to 1 and on logout it is set to 0, so that account can be logged in on single computer at a time. It is working great till this part.
The problem I am facing is at the SESSION TIMEOUT. I am confused that how to set the flag to 0 in database when session timeout. Is there any way to run an update query on session timeout.
I am using the CORE config file to set the SESSION timeout limit as follow:
Configure::write('Session', array(
'defaults' => 'php',
'timeout' => 30, // The session will timeout after 30 minutes of inactivity
'cookieTimeout' => 1440, // The session cookie will live for at most 24 hours, this does not effect session timeouts
'checkAgent' => false,
'autoRegenerate' => true, // causes the session expiration time to reset on each page load
));
And this is my logout function
public function logout() {
$id = $this->Auth->User('id');
$this->User->updateAll(array('WebLoggedIn'=>0), array('User.id'=>$id));
$this->Auth->logout();
// redirect to the home
return $this->redirect('/');
}
That won't work
The idea in the question isn't going to work. The moving parts related to sessions, with the config in the question are:
A file stored on the server with the serialized session data in it, which updates every time the session is written to
A standard php cron job, which deletes session files that have expired (see /etc/cron.d/php5 or equivalent)
A browser cookie, which links the user's browser session to the file on the server
When a user's session time's out - that either means the session id they presented does not correspond to a file on the server, or they simply didn't present a session cookie. There's no "hey this session expired" event at the moment it expires, and there's no guarantee a user would provide the old session id for you to check if it's valid.
Working proposal
A simple (and this also means naïve and possibly easy to bypass) solution is to not store a boolean, and instead store the time their session will expire in the db. I.e. have code similar to this:
// App Controller
public function beforeFilter()
{
$userId = $this->Auth->user('id');
if ($userId) {
$this->User->updateAll(
array('active_session_expires'=> time() + (30 * 60)),
array('User.id'=>$id)
);
}
}
And in the users controller:
public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
if ($this->Auth->user('active_session_expires') > time()) {
$this->Flash->error('You are still logged in somewhere else');
return $this->logout();
}
$this->User->updateAll(
array('active_session_expires'=> time() + (30 * 60)),
array('User.id'=> $this->Auth->user('id'))
);
return $this->redirect($this->Auth->redirectUrl());
}
$this->Flash->error(__('Invalid username or password, try again'));
}
}
public function logout()
{
$id = $this->Auth->User('id');
if ($id) {
$this->User->updateAll(
array('active_session_expires'=> time()),
array('User.id'=>$id)
);
$this->Auth->logout();
}
return $this->redirect('/');
}
I.e. every time they do something - update the db to keep track of their activity. If they try to login before their existing session expires - immediately log them out. Expect to need to test/modify this example code, it is provided to give you an idea, not necessarily a complete and working solution.
This is similar to an answer you've already been linked to.

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.

Laravel authentication without remember me token

I am using Laravel 4.2's authentication mechanism and I am trying to figure out when and how the "remember me" cookie token gets set.
For some reason when I do the following code, even though the second parameter is false, when I close the browser and reopen it I still get logged in automatically without needing to type in the username and password. So practically it is always acting as if the 'Remember Me' is checked, even if it is false.
My authentication code:
//called on POST of login page with credentials
$userdata = array(
'email' => Input::get('email'),
'password' => Input::get('password')
);
// attempt to do the login
if (Auth::attempt($userdata, false))
{
//redirect to main secure page
My check on the login page to check if the user was already authenticated:
//called on GET of login page
if (Auth::check())
{
//user already logged in, redirect to main secure page immediately
Even though Auth::attempt() is being passed false, the Auth::check() still returns true when I close the browser and reopen it, which normally clears any sessions.
When I used to do authentication manually in PHP (not using Laravel's Authentication method), I used to use something like:
//authenticate the user with the DB and get the $user object
$_SESSION['user'] = $user; //set it in the session
And then in my secure pages I would check if the user is logged in by doing:
if (isset($_SESSION['user']))
{
//user already logged in ...
In this case, closing the browser and reopening it cleared the session. (I just verified this again with one of my older webapps and it still behaves that way, so its not some browser issue).
Is there any reason why Laravel is not behaving in this way? If it is retaining the authentication session across browser sessions anyway, what is the point of passing the 'remember me' flag?
Is there a way to disable this behaviour and make it work normally (i.e. when the browser is closed the session is no longer retained)?
OK seems that apart from the config/auth.php configuration there is a more detailed session configuration in config/session.php, and what I want is actually there in that file.
The setting 'expire_on_close' => false in that file is what is causing this behaviour, and changing it to true immediately solves the issue.
Not sure why its false by default. Its not secure if people just close their browser without logging out of the application (since they wouldn't have checked the 'remember me' flag they would think that the application wouldn't remember them and the session would have been destroyed), and someone else opens the browser and would be able to access the secure pages just the same.
Anyway, posted answer in case someone needs it.

Codeigniter - Session expiration and "remember me" feature

I'm building a "Remember Me" feature in Codeigniter, normally I see libraries/projects setting a cookie on the user with a token, this token gets saved in the database and is compared each time the user accesses the website.
In Codeigniter we can set the session expiration time though, this lead me to try a different approach, this is what I did:
I set the session_expiration in config to 0 (infinite session)
If the user leaves "Remember me" unchecked, I set a 2 hour time in the session and session destroy on window close.
So my login code looks like this:
if (!$this->input->post('remember_me')) {
$this->session->sess_expiration = 7200;
$this->session->sess_expire_on_close = TRUE;
}
$this->session->set_userdata($session_data);
And my config file:
$config['sess_expiration'] = 0;
$config['sess_expire_on_close'] = FALSE;
I don't see people using this solution on projects, I have tested this out and it seems to work fine though.
SO, for my question, would you say this a safe practice to do? Any security dangers I should know about? Any input on this solution vs cookie+database token would be great.
The simpliest solution that I have found for this problem is to just modify the cookie created by Codeigniter by this way:
$this->session->set_userdata('user', $user); // a cookie has been created
if($this->input->post('remember_me'))
{
$this->load->helper('cookie');
$cookie = $this->input->cookie('ci_session'); // we get the cookie
$this->input->set_cookie('ci_session', $cookie, '35580000'); // and add one year to it's expiration
}
Also this can be done by editing/extending system Session library.
First: Set regular session expire time in config file.
Second: In user login function add remember me check-
if($remember)
{
$data['new_expiration'] = 60*60*24*30;//30 days
$this->session->sess_expiration = $data['new_expiration'];
}
$this->session->set_userdata($data);
Third: Edit system Session library [I am not sure whether extending Session will work or not]
Go to this line in sess_read() method
if (($session['last_activity'] + $this->sess_expiration) < $this->now)
Before that line add following code
if(isset($session['new_expiration'])){
$this->sess_expiration = $session['new_expiration'];
}
This works fine for me.
I can't say it's not right, but I can tell you my way of doing this:
First I set the session to expires on browser close with a default uptime of 7200.
Then:
The login sets session userdata
The "remember me" sets a separated cookie (I store an encrypted hash containing user's email+password+id ie: md5(pass+email+id))
Every time the user loads a page I control if the remember me cookie exist, if exist I create the user session.
The only thing I know is that session, uses an encryption key, a malicious attacker will take time to decrypt, so the less a session key exist the less time attacker has for decrypt the current key.
I always avoid session to not expire, so the Remember me, is always something not good for security I think, but anyway is the user to choose or not if to use that feature ;)

Categories