I have just started learning Laravel and I was following the documentation. I got to know that Laravel uses emails.auth.reminder view to be sent as an email to the user with the reset token. In my emails.auth.reminder, I have put the following:
Hello Dear User,<br><br>
We have received a request from your account to reset your password at Larblog. Please use the following link to reset your password.<br><br>
{{ URL::to( 'user/resetpassword/' . Session::get('_token') ) }}<br><br>
If it wasn't you who tried to reset the password, simply ignore this email.<br><br>
Thanks,<br>
- Larblog
Notice that, I am using Session::get('_token') to access the token. Is it the right way that I am doing it? As it's always generating the same token.Z7vKMT5ssfzeXsQcVkrYodoRmYnbjH0prdP83jBk again and again. And when I use this to reset the password, it says: Invalid token received. Also, I have checked in the password_reminders table of my database and it's showing different token. When I use the token stored in the database, it works.
So, what's right way to access the token in the view that is sent via email?
I'm not certain what the method is to access a password reminder token directly, however normally when sending the email it's done via the Password::remind() function, rather than the usual email function. When using this the $token variable is automatically passed into the email view so that you can use it.
An example use of this function is:
Password::remind(Input::only('email'), function ($message)
{
$message->subject('Password Reset');
});
And then accessing it in the view is as simple as:
To reset your password, complete this form: {{ URL::to('reset', array($token)) }}
The _token in the session isn't the password reminder token - it's the CSRF token automatically inserted for security reasons.
Since I don't know what your tables and models look like, it's hard to say exactly how you should get the actual password reminder token, but it's likely something like this:
$user = User::find($someid); // first fetch your user
$token = $user->passwordReminder->token; // now get the token
If your tables and models differ from my assumption, feel free to update your question and I'll be happy to update my answer. :)
Related
I want to get user data
I tried using
$user_data = App\User::where(["username"=>"admin", "password"=>bcrypt("test123")])->get();
But it is not working! I am sure the username and password is correct!
then I tried another one without bcrypt
$user_data = App\User::where(["username"=>"admin", "password"=>"test123"])->get();
And still not working!.
I don't know what is the problem.
I wondering if I can use Auth::attempt just to get the user data (without log-in)
$user_data = Auth::attempt(["username"=>"admin", "password"=>"test123"]);
Auth::attempt will signing you in. But I don't want that. I just want to get the user data only (without sign-in)
I forgot to mention that I'm creating an API...
However, I solved the problem by using Auth::once()
Auth::once(['username'=>'admin', 'password'=>'test123']);
I have a table in my database called (users_system) contains:
user_id
user_pass (plain text)
... some other fields
What I want is to be able to do laravel(5.2) authentication using those two fields considering the (Auth::attempt) only deal with email and hashed password.
So is that possible and if so how to do it?
You can check credentials and login user manually:
$userSystem = UserSystem::where('user_id', $userId)->where('user_pass', $password)->first();
if (!is_null($userSystem)) {
// Manually login user.
$user = User::find($userId);
Auth::login($user);
}
But this is a terrible idea to use plain text passwords. You should never do that in a real app.
I am trying to use the same token(server-side generated - PHP) to auth the user in web(JS) and iOS app(SDK). These are the steps I do to auth a user:
generate a JWT token:
I am using using the recommended lib https://github.com/firebase/firebase-token-generator-php:
$generator = new TokenGenerator($firebaseSecret);
$token = $generator->setOption('expires', strtotime('+1 day'))
->setData(array('uid' => $user->id))
->create();
use the token to auth the user via Javascript:
ref.authWithCustomToken(token, registerHandler);
registerHandler: function(error, authData)
{
if (error) {
console.log("Login Failed!", error);
} else {
console.log("Login Success!");
}
All works correctly, the FIRST time, the user is logged in and ready to roll.(Firebase session set to 1 year)
However:
if I logout and use the same method to login again, with the same token, I get the following error: "INVALID_TOKEN: Failed to validate MAC.". If I use another fresh token all works again.
If I send the token(unused) to the iOS app I am also working with, I get the above error all the time.
Can somebody share some light into this situation ? Any help will be greatly appreciated.
I found the problem myself, in the end. I'll post this here so that future devs avoid the issue I ran into.
Be always careful about where you store your data. My tokens were stored into the DB, in a varchar type column, but they were bigger then 256 chars, so they were not saved properly. After changing the column type everything worked flawlessly.
I'm using laravel's Auth password reset method and not sure i fully understand what part plays the token in all of this.
I'm sending the user an email with Password::remind('email#email.com') , which generates a token in my password_reminders table. The token is fully visible in the url.
The user goes to a url that looks something like: mywebsite.com/remindpass/xxxxxx[token] .
Then he fills out a form with his email and a new password , sending it trough post to a controller - which uses Password::reset('email','password','xxxxxx') .
The question is how is this secure? What does the generated token do to prevent someone just going to mywebsite.com/remindpass/xxxxxx[token] and change the email & password as he likes?
Can someone please clarify the proccess?
I'm sure someone could answer this question better than I could.
Short answer:
The token makes it more difficult for someone to guess the credentials needed to reset the password while making the reset link in the email available.
Long answer:
In the file vendor/laravel/framework/src/Illuminate/Auth/Guard.php, you'll see the method createRememberTokenIfDoesntExist. This method actually references another method right above it called refreshRememberToken to set your token.
It uses the laravel helper function str_random. If you trace this function back to it's source, you'll find it uses the vendor/laravel/framework/src/Illuminate/Support/Str.php class' random method.
public static function random($length = 16)
{
if (function_exists('openssl_random_pseudo_bytes'))
{
$bytes = openssl_random_pseudo_bytes($length * 2);
if ($bytes === false)
{
throw new \RuntimeException('Unable to generate random string.');
}
return substr(str_replace(array('/', '+', '='), '', base64_encode($bytes)), 0, $length);
}
return static::quickRandom($length);
}
Now we finally get down to where the token is built. This method uses the function openssl_random_pseudo_bytesto generate the token. You can read about that function in the PHP manual page for openssl_random_pseudo_bytes, but basically it generates a cryptographically strong random string.
Laravel then takes this string (still in the random method), base 64 encodes it, replaces some characters, and takes a slice of that string based on either the default setting of 16 (seen in the parameter definition $length = 16) or whatever length is passed into the method by the caller.
So, you get a string that is cryptographically strong and then manipulated as your token.
If you look at the file vendor/laravel/framework/src/Illuminate/Auth/DatabaseUserProvider.php and find the method retrieveByToken, you'll see that laravel uses both the user record ID and the token to find the user who's password needs to change.
For someone to guess that string AND the id of you user record that has that token would be incredibly difficult and would require knowledge of your application's business logic.
What does the generated token do to prevent someone just going to mywebsite.com/remindpass/xxxxxx[token] and change the email & password as he likes?
Because only you and the person you sent the email to (i.e. the account holder) know what the token is.
A strong implementation will takes steps to make it hard to guess tokens:
Long (harder to guess) tokens
Time limited tokens
IP based rate limiting for access to /remindpass/*
I'm developing a mobile app which has to access to an external webapp (PHP + Codeigniter) to administrate the actions queried by ajax.
So by this way, there is a problem. If anyone see the urls used, could delete rows, or modify the user's info from the database. So I thought in this system to aboid this:
After a sucessful login I would do this:
// getToken : https://stackoverflow.com/a/13733588/2154101
$this->session->set_userdata('private_token', getToken(50));
$public_token = getToken(50);
$this->session->set_userdata('secure_token', md5("$private_token:$public_token"));
$data['token'] = $public_token;
// some stuff ...
// send $data in JSON
Then the client would the public token in the next query I would do this on the server:
$public_token = $this->input->post('token');
$data['token'] = get_public_token($public_token);
// some stuff ...
// send $data in JSON
Where get_public_token is within a helper with this code:
public get_public_token($public_token) {
$last_secure_token = $this->session->userdata('secure_token');
$private_token = $this->session->userdata('private_token');
$actual_token = md5("$private_token:$public_token");
if ($actual_token === $last_secure_token) {
$public_token = getToken(50);
$this->session->set_data('private_token', getToken(50));
$this->session->set_data('secure_token', md5("$private_token:$public_token"));
return $public_token;
} else { // you are cheating me ...
$this->session->sess_destroy();
redirect('/');
}
}
So only the user of this session could modify the data of the database.
I'm just trying to do the same explained here: https://stackoverflow.com/a/17371101/2154101
The session are encrypted, and I store them in a database too.
Do you think this method will work ok? Am I missing something important?
You should create an API for your mobile application. Create a authentication mechanism.
If your database holds user specific data, then you should create account for each user. So if the user sniffs the network and tries to call the api manually, then he could only change he's own data.
There are some API libraries for php out there, you should look into that.
Actually your solution is doing more than necessary. The only token of interest is the public_token sent back and forth. So you can throw away private_token and secure_token from session data, keeping only public_token for checking. Your current check is something like (X + 5)/2 == (14 + 5)/2 (is [received_token + 5]/2 equal to [14 + 5]/2 ?) when you can simplify to X == 14.
However if someone is sniffing the network, he can get the last token sent to a client and use it to hijack into that session. He can execute anything while the original client doesn't send a request with the outdated token, killing the session.
A better solution would be creating a secure_key after login and keep it at both ends (client and server). Then server would keep sending a new public_token at each response, but the client would send a md5(secure_key + public_token) at requests. This would narrow even more the hijacking window to the exact point where the session started. Without the original key, attackers can't create a valid md5.
However we are talking about minor hacking fans here. Anyone more zealous could hack that anyway. If you are concerned about that, then throw away all that stuff and simply use a HTTPS connection. With a trusted connection your sessions and access control rules are protected.
The better way is create API using SOAP or SAML2.
OAuth can be a very good solution: http://oauth.net/. It takes care of token and has a very secured API! If you wish to support secure authentication of web application + mobile application then it can be a good/proven solution!
On the other hand, it really depends on how complex your current system is and how the system is going to be in future.