Laravel: check if two users are simultaneously logged in - php

I want to validate the use of coupons in my app by checking if both the business' owner and the final client are the ones redeeming the coupon. This would be the process:
Client shows his QR code
Owner scans it
Coupon is redeemed if both of them are logged in (this would happen when the Owner's device makes a post request and uses CouponController)
I know I can use auth() to validate the owner's status (he wouldn't be able to access the Redeem view when logged out anyway), but is there any way to check if the Client is also logged in without modifying the User row in the database? Right now, I use the following:
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use App\Http\Controllers\Controller;
class LoginController extends Controller
{
...
public function store()
{
if( !auth()->attempt(request(['email','password'])) ){
return back()->withErrors([
'message' => 'Please check your credentials and try again.'
]);
}
$user = User::find(auth()->id());
$user->active = 1;
$user->save();
return redirect()->home();
}

Let's first clarify on how PHP scripts work and how that impacts your path to know if a user is online or not.
Under your Laravel application, for the very reasons on how PHP processes HTTP requests, you can only identify hits (requests), that you can interpret like heartbeats. So, you cannot (at least with bare PHP) see the user online all the time, but you can assume the user is there if the page hit was recently.
That said, it will be up-to-you what will be the acceptable time window to interpret if the user is online or not, once given a page hit/http request.
If you only record that the user is active (as a boolean/int flag like $user->active = 1) upon login, you will think the user is active even long after the user is gone from the application, as the user session may perfectly remain still active (open) but the user is actually inactive.
There are many ways to go around this.
One possible approach is to remember the last time a user hit your page, so you consider him online after the next -say- 5 minutes (this value is up to you). This approach is fair enough for what you are willing to achieve. Keeping this track can be achieved with middlewares, so your controllers are kept clean.
On how exactly implement this, well, that would be an entire and opinionated git project to post here and it's probably outside the scope of this answer. Long story short, think of keeping record of timestamps of the events you will consider relevant as user activity, instead of a flag with no timing information.
If you are willing to implement this as a usable feature with external packages, here are a few options:
https://github.com/highideas/laravel-users-online
https://github.com/thomastkim/laravel-online-users
https://github.com/joshrainwater/active-users
Even if you are not willing to pull in a third party package, feel free to dig in their sources (start on the Traits) to get some ideas on how to go around this.
You will also notice that some of them use Cache to keep track of disposable data without the need of storing this into your business ERD in database.
Hope this helps as a starting point.

Related

How to log out an admin user (employee) from back office in Prestashop 1.7?

I am developing a module for PrestaShop and I need to log out a user (employee) from the back office. I see in the back end code that they do it by using
// Find employee
$this->context->employee = new Employee();
$this->context->employee->getByEmail($email, $passwd);
$this->context->employee->logout();
But I can't use it in my module scope since I would need to intercept the credentials from back office login form to create a proper link to the employee, but I can't find a way how. Are there any ways to get these credentials or to log out the user in another way?
P.S. Intercepting user credentials before he logs in and blocking him from logging in until certain point would also satisfy my needs, but it sounds much more complicated and I also can't find a way to do this.
This code is enough to disconnect an employee:
$this->context->employee->logout();
But, as you can see it's in the context, which mean the code should be executed from the employee you want to disconnect because the session is saved in the local cookie of the employee, in other words, you can't disconnect remotely to an employee, but you can use the hook displayBackOfficeHeader which is called in every browsing page and then disconnect the employee, eg:
public function hookDisplayBackOfficeHeader()
{
// My validation to disconnect the employee I want
if ($id_employee == 1) {
$this->context->employee->logout();
Tools::redirectAdmin('index.php');
}
}

How to check other user login in symfony 3

I'm trying to study FOSUserBundle in Symfony. I searched on google "how to check if other users are logged into their account", but I failed to do it. I want to add a green coloured mark if a specific user is logged in, the way Facebook does it.
I don't know if FOSUserBundle has a code that will check whether a user is logged in. I found this (other question on SOF) but it only checks if the current user is logged in.
I don't know it's a good idea to add this property in my entity
/**
*
* #ORM\Column(name="log_status", type="boolean", nullable=true)
*/
protected $logStatus;
This will set the status of a user (logged in or not) and I'll add a column to the fos_user table to save it to the database.
To tackle this issue, you would first need to define what logged in really means in your case.
Because your code is normally only called once per request, the user can be gone 5 seconds after that, or he can have the page opened for an hour, but in both cases the user might still be logged in in the session.
So what you probably want to do is checking if the user is currently active. There are multiple ways to do this, and depending on how real-time the information has to be, you have to choose the best option for you.
Easiest (imho) would be to ping every X seconds to the server with an AJAX call (Polling or Long-Polling), and than make a ruling on how long before the status will change to offline. There should be some rome for the AJAX call to fail.
Other options, which will give you a more real-time overview would be to use either WebSockets, or Server Sent Events.
There might be other options, like using a service like PubNub to handle the connections, and use their API to determine if a user gets inactive. But that you would need to figure out for yourself.
adding that field it's good know you can just go a query to find user that status its true
but the probleme its how to keep update this data you can't do that by symfony
for me i use a ping evry X min like Heartbeat to see if user its Active you can use Socket.io

login form how to give access only to one device

For learning reason, trying to give login access only for one device
so I added new row inside user table in database called ip which stored registered user ip then for example I did something like that
if($user->ip == $myip){ echo 'success'; }
the problem here that ip changing so the form can't let me access or logged in,
So my question is there anyway to logged in from only by using one device without using ip ?
Fixing the IP address might not be possible. There are a number of other ways to achieve your goal, ranging from cheap and simple to very complicated and expensive. Here are a couple.
Use a USB key (such as this one) that enters a strong password on the push of a button.
Use two way SSL (see question), safe but complicated
The easiest of these options (and my recommendation) is to set a long living cookie (using a browser developer toolbar or extension) and check in PHP for the existence of the cookie in the $_COOKIE array
Good luck!
You must use a cookie, and if the cookie is set, you must not allow a new login.
The following experts and accepted solutions agree:
how to identify remote machine uniquely in php?'
Accepted solution: uniquely identify the computer via cookie
Uniquely identify one computer
Accepted solution: set a cookie that must be present on future logins
How to uniquely identify a computer?
Accepted solution: the solution discusses Evercookie but the point seems to be you need a cookie
So, in summary, however you identify this user, if the user has a cookie, let them in. If they don't, I don't know what you're going to do, but maybe that's part of what you are mysteriously trying to learn here.
Not the best solution:
Public IP's are dynamic, meaning when a router is restarted - they obtain a new IP address. Yes, you could never restart the router but you cannot protected against physical things like electricity meaning check-ups, power outs, etc..
The best idea here is to make this Software un-accessible from outside the node you want to be able to interact with. Meaning, use Apache and MySQL (like XAMPP) and run it only on that node.
If you're looking for a long-term solutions to be able to add IP's, used a shared network. Or implement security conventions like Authentication (login).
However, if you want to consist in building it from your point of view: use the $_SERVER super variable to access the current IP and you'd need to know it before they visit (so find it out by going to something like what is my ip.
if($_SERVER['SERVER_ADDR'] == $somePreknownIp) {
// authorised
}
I would recommend using a cookie instead. First add the following code:
If ($user -> me) {
setcookie("HeyItsMe", 'SomeReallyHardToGuessValue', time()+3600*24*365); /* this would expire in 1 year */
}
This will set the cookie for just you since you're logged in. Then, you can get rid of the the code and add the following in your login screen:
if (isset($_COOKIE['HeyItsMe']) && $_COOKIE['HeyItsMe']== 'SomeReallyHardToGuessValue') {
/**show them the login screen **/
} else {
exit;
}
If your have dynamic IP then you can not do it using IP address. Therefor I suggest you to use sessions.
To do that you have to create another PHP file in your root folder(project folder). And do not share that file name with others. (I named that file as loginHandler.php)
loginHandler.php file has following content.
<?php
session_start();
// assign value to loginHandler.
$_SESSION['loginHandler'] = "99";
// redirect to login page
header('Location: login.php');
?>
On your login page (login.php), you have to start session top of the page. And if $_SESSION['loginHandler'] set, Then it will display your login form. Otherwise it will display only rest of the content.
<?php session_start(); ?>
<p>Page Content</p>
<?php if(isset($_SESSION['loginHandler'])): ?>
<div id="loginBlock">
<form method="post" action="">
<p>Your Login Form</p>
</form>
</div>
<?php endif ?>
<p>Page Content</p>
If you want to login. Then first you have to access loginHandler.php file. Then you will be redirected to login.php page. And you can access login form.
But others do not know about loginHandler.php, Therefor they try to access login form directly. Then that login form will not display for them.
Edit:
Upon re-reading the question I see that I've misunderstood what the OP was really asking for. Leaving my original reply underneath, in case someone else finds it useful.
The proper answer to this questions is: Why care about who gets to see the login form? Just use a properly strong password, and the correct techniques for preventing brute-force attempts (throttle limiting).
Any secret key, or similar, you add to this script is just another password after all. Any other information derived from your connection, browser or whatever, can be sniffed and spoofed by an attacker (or even changed from underneath you, for any reason).
Limiting to a single (or range of) IP(s) is only really useful if you have a static IP, and want to make it a bit more difficult for any potential hacker to break your password.It is not a replacement for a good password.
Original answer:
This is actually a rather common problem, and solved quite a few times. While it takes a bit of work to implement the solution, it is quite straight forward.
First off you need to create a table to keep track of the sessions for each user. This table needs only two (or three) fields:
user id
session id
(timestamp)
The timestamp can be omitted as it's not essential, but it might be nice to have for debugging/logging purposes.
Once you have that you need to re-write your login script a bit. So that it first checks if the user has any active sessions already, if they don't then simply create a new session and store its ID in the abovementioned table.
However, if the user does have a session active already, then you need to do one of two things:
If you want to disallow any further logins, simply return an error explaining that they are already logged in.
Or, delete the old sessions and then log them in on the new device.
Of these two approaches I'd prefer the latter one, as the first one can lead to a user accidentally locking himself out of the system. Until you, as the administrator, go in and manually delete the old session.
The second approach will require a bit more work, in order to delete/invalidate the old sessions, but is generally more robust. It will also give the users the least amount of surprise, as they expect to be logged in when attempting to do so. Instead of having to go chase down whatever unit they think they logged in with last.
Another thing you could do, if you decide on approach 1, is to log the timestamp and then use this in conjunction with the max session lifetime. If time_now - max_session_lifetime > timestamp then you know the session is old, and can be deleted automatically. Ensuring that the user will, eventually, be able to log in without having to rely upon finding/getting the old unit, or you manually deleting it.
I won't post any code on this, for two reasons:
You haven't posted the code in which you handle the logins, making it impossible for me to suggest any specific changes.
The changes needs to be done in quite a few places, and requires a redesign of your logic.
However, follow my logic and set up a pseudo code/flowchart diagram and it should be quite easy to implement.
one thing goes into my mind.
If you know his phone number, send him SMS with token to log in.
Of course there is technical issue about sending SMS message, that i'm as newbie are unable to solve...
You can use Mobile-Detect php library and get the device information of particular device and can add device details in db then you can put a check for that particular device.
Official documentation for library is here - Mobile-Detect
And for usage go here - Usage example
There is one for Client side also - mobile-detect.js
Hope this will help you some way (y).
You can combine 2 approaches into one. You have a list with 3 IP-addresses. For example:
$whitelist = [
'192.168.1.2',
'192.168.1.3',
'192.168.1.4',
];
Then you should check address or cookie:
$accessCode = 'Xvj482Sfjfi2Ghj23PoqT'; //some random string
$cookieExpireValue = time() + 3600 * 24 * 365 * 3; //3 years
$isIpValid = ($_SERVER['REMOTE_ADDR'] && in_array($_SERVER['REMOTE_ADDR'], $whitelist, true));
$isCookieSet = (isset($_COOKIES['access_code']) && $_COOKIES['access_code'] === $accessCode);
if ($isIpValid || $isCookieSet) {
setcookie("access_code", $accessCode, $cookieExpireValue);
echo 'success';
}
Pros:
It restricts access
If IP-address changes, user has access for 3 years
You can change $accessCode and $whitelsit to block users which already got access
It simple
Cons:
If some user gets whitelisted IP, he will get access
If a user loses the cookie (OS reinstall, browser clean, etc) with new IP-address, he will lost access (just change the $whitelist)
In case, you have different user's records for every device and you restrict access after form's submitting, you can save a new IP-address for that user if the user has a valid cookie:
if ($isIpValid || $isCookieSet) {
setcookie("access_code", $accessCode, $cookieExpireValue);
$user->ip = $_SERVER['REMOTE_ADDR'];
$user->save();
echo 'success';
}
and change the validation:
$isIpValid = ($_SERVER['REMOTE_ADDR'] && (in_array($_SERVER['REMOTE_ADDR'], $whitelist, true) || $user->ip === $_SERVER['REMOTE_ADDR']));
In this case you can get rid of the whitelist of addresses, just set ip for every whitelisted user.

User permission and software security

I am developing an application in php codeigniter. Now I am worrried abt the permission.
I need page wise permission, page may be add records page, edit page, delete page and print report etc. There will be many users as well, and applicaiton will grow with passage of time.
If I implement ACL that will better for me or not
what can be ideal for me any suggestion.
First, let's clear up some terms: I personally use the security term for things like preventing SQL injection, XSS attacks, where we have to validate input, filter/sanitize values, take care of the dynamically generated SQL commands, take care of properly escaping output (for JSON or HTML text or HTML attributes), etc. This is not about what you are asking, if I understood well.
The access control or permissions system is where you give or deny access to a function for a user. It can be secure or not. I understand that to deny a user which does not have permission the access to a function may sound like "security", but I wouldn't use this specific word in this context, to avoid confusion.
Now, the answer:
I strongly recommend you create a few base controller classes to your needs. Read the following blog post carefully (it is short and useful): http://philsturgeon.co.uk/blog/2010/02/CodeIgniter-base-Classes-Keeping-it-DRY
A code to check if the user is properly authenticated (logged in) is essential. If the user is not logged in, redirect to home page or login page.
For fine-grained control, you could create your ACL in the database using the users table, plus an actions table, plus an acl table...
The users table would contain the users data (id, name, login, password, etc)
The actions table would contain the id field and at least one more field containing what suits best for your application: it can be only the controller class name (the first part of the URL, for example: "products"), granting access to the whole "products" controller or not. Or you may want to include both the controller class AND the method name (the first and second parts of the URL, for example: "products/add" and "products/delete"), and so on.
To decide about the actions table is the most decisive step. Think very well about it, balance your needs (your "true" needs)... I developed a system where each and every action has its entry. It is good, but it needs work to be maintained.
A very useful column for the actions table is a human-readable description of the action.
The acl then would be nothing more than a column for the user id and another column for the action id.
A "master" grant/deny access field in the users table is useful too, in case you want to temporarily deny access from a specific user, without having to delete all his permissions and maybe having to restore it later.
With the database tables and your "controller/method" or "actions" strategy well defined, you can easily code in your base controller class a function which checks if the user have permission to execute the requested action.
This is the basic. In my system, I have the users administration interface, where I can grant/deny the actions for each user (I use an ExtJS tree with checkboxes). One of these actions is the own user management. I have gone one step further, where the user who can access the user management may "delegate" (grant/deny) to other users only the actions he himself has access to.
The system has several modules, and functions. The interface does not show anything the user does not have access. So, I have users who can see only a single or a couple of modules, and they don't even imagine the existence of the other modules.
It requires more work to manage all this, but the result worths.
I also log each granted access, so it is possible to track who did what, and when. This log feature is very very easy to add, since you have this base controller "master function" allowing or disallowing the users to perform the actions.
I hope I have helped. I've just shared a bit of what worked (and works) for me...

Magento - How to Login with “Secondary Email” customer attribute?

How would a customer be able to login with both their primary email address they signed up with as well as a Secondary email address customer attribute field? (I’ve created a customer attribute text field secondary_email).
Assuming it has something to do with customerEntity and would be similair to what people have been doing to get usernames to work: http://www.magentocommerce.com/magento-connect/Sylvain_Raye/extension/7928/diglin_username
or
http://www.magentocommerce.com/boards/viewthread/195573/P15/
I just need for customers to have 1 single password, but be able to use an alternate email address specified within their account if they want.
Thank you!
Magento is no different from almost all other PHP-based frameworks in that it has a serial flow of execution. Thinking from a request flow standpoint, an entry point to suss out your requirement would be the class which handles the login form POST. You can see this in the rendered source in your browser: action="https://demo.magentocommerce.com/customer/account/loginPost/".
The above URI resolves to the method Mage_Customer_AccountController::loginPostAction(). In there one finds typical login logic for a login controller action: is user logged in? is the user posting in login data? is the the login data valid? and so forth. This quickly points to the customer session model, Mage_Customer_Model_Session, particularly to the authenticate() method. In this method is a call to Mage_Customer_Model_Customer->loadByEmail(), which gets us to Mage_Customer_Model_Entity_Model->loadByEmail()`.
At this point, we know that we can rewrite the resource model and change its loadByEmail() to handle lookup of a secondary email method (messy & obtrusive). We could also rewrite and change Mage_Customer_Model_Session->authenticate(), providing some pre-processing to first load the customer record by secondary email, then extract the main email and allow things to proceed as normal.
//rewritten authenticate method
public function authenticate($username,$password) {
$customer = Mage::getResourceModel('customer/customer_collection')
->addAttributeToFilter('secondary_email',$username)
->getFirstItem();
//check we found customer record by secondary email
if ($customer->getId()) {
parent::authenticate($login,$customer->getEmail());
}
else {
parent::authenticate($username,$password)
}
}
I've not really looked into the above snippet, nor would I vouch for its security, but hopefully this demonstrates the process by which one can answer these types of questions using awareness of the framework. This may not be a bad starting point; with something similar in the configured class rewrite plus a setup script to add the secondary_email attribute, this should be quick to implement.
A note worth mentioning:
It's also possible to accomplish this by observing the runtime-constructed controller_action_predispatch_customer_account_loginpost event (see Mage_Core_Controller_Varien_Action::preDispatch()). While it is generally advisable to use the event observe system to effect functional rewrites when possible, this would be quite unintuitive and the messiest option of all.

Categories