The algorithm works, but once the password has been converted to hash and saved into the database, it doesn't redirect to the homepage. Instead, it redirects to the login page saying that the login credentials is incorrect. But if I tried logging in, it is ok. What am I doing wrong?
AuthenticatesUsers.php
protected function attemptLogin(Request $request)
{
$check = $this->guard()->attempt(
$this->credentials($request), $request->has('remember')
);
if ($check === false)
{
$user = User::where('username','=',$request->input('username'))->first();
if(isset($user)) {
if($user->password == md5($request->input('password'))) { // If their password is still MD5
$hashed_password = Hash::make($request['password']); // Convert to new format
$user->password = $hashed_password;
$user->save();
return $this->guard()->attempt(
array(
'username'=>$request->input('username'),
'password'=>$hashed_password
), $request->has('remember')
);
} else {
// Redirect to the login page.
return false;
}
}
}
return $check;
}
attempt doesn't take the hashed password, it takes the password you would get from the user (the plain text password). The user doesn't know the hashed version of their password and attempt does a hash check which requires the plain text version.
You also don't need to call attempt that second time if you have already validated the user and their credentials and have a User instance that represents them. Just use login to log them in at that point. You don't have to go through attempt which is just going to requery the database to get the user, then check the hash that you know is correct since you just set it.
To a degree part of the code you have is just recreating what attempt does internally.
Also you don't need to query the database yourself for the User. That first call to attempt will have held onto the 'user' it found from when it queried the database. You can retrieve it from the guard so you don't have to query the database again, $this->guard()->getLastAttempted().
Making these changes will remove the 'bad credentials' issue coming from the second attempt call, since it won't be called any more. This will also cut your queries down from 3 selects and 1 update to 1 select and 1 update. (roughly)
Related
We imported some users from our old script.
But we can't decrypt this users password.
So I defined a default password to this imported users.
I have a imported column on my users table.
So I want to do this:
When a user post the login form I want to check user is imported or not by using user's email.
Like:
if (User::where("email", $email)->first()->imported == 1) {
//change password parameter and then start auth proccess.
} else {
//nothing. just normal auth proccess
}
If it's imported user, I need to change password parameter's value to my default password and make it successfully login. Then I will send a confirmation mail to this user and force change his/her password. If it's not a imported user, nothing gonna happen just make it login in normal way.
Note: We can use same password hash code instead of laravel's hash. But we don't want to do this.
So how can I intervention to login post before start auth control.
I just want to do: this imported users should be login without error. Because this user's password not gonna match with our db records. I defined a custom password like "123456". User will try his old password. But I want to change his old password with "123456" and user can login the system and I can send confirmation mail for change his password.
First, the logic is bad for some security reasons. If I As a guest user or anonymous use happened to know an email then I can log in to the user account with an invalid or random password.
It is better to do it in another way. First, check the user's email, and if found one then email him a reset password link and don't log him in.
If the user owns the email address then he/she can reset his/her password and log in easily.
But if know what you are really doing then you can create your own login or AuthenticationController. and use your logic there. you can sign in the user by id without the default password. You don't need a default password in this case anyway because the end-user is not typing the default password.
Below is an example:
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class AuthencaticationController extends Controller{
public function login(Request $request){
$user = User::where('email', $request->email)->first();
//use might be null so you should first check
// otherwise an error will occure because we cannot use the property of null or non-object
if(is_null($user)) {
// redirect user back with error message
return back()->withErrors(['email => 'Email is incorrect']);
}
// for readbility i prefer to create isImproted() method in User model
// and return whatever to check if user is imported
if($user->imported) {
auth()->loginUsingId($user->id);
$request->session()->regenerate();
return redirect('email confirmation action path');
}
$request->session()->regenerate();
return redirect('redirect not imported users path');
}
}
Laravel documentation
Regenerating the session ID is often done in order to prevent malicious users from exploiting a session fixation attack on your application.
Note that this just a simple way to do that you can refactor it in many ways.
in my application, I have a default password (1234 for example) for all users I create, when the user login for the first time he will be asked to change that password
my goal is when a user login I want to check if his password equal to that default value (1234) if that's true I redirect him to the reset page if not I 'll do nothing
so my question is
how to check that user's password if it's equal or not to a value I have?
I have found an answer on StackOverflow that helped me a lot
You can use it a couple of ways:
Out of the container
$user = User::find($id);
$hasher = app('hash');
if ($hasher->check('passwordToCheck', $user->password))
{
// Success
}
Using the Facade
$user = User::find($id);
if (Hash::check('passwordToCheck', $user->password))
{
// Success
}
Out of interest using the generic php function password_verify also works. However that works because the default hashing algorithm it uses is bcrypt.
if (password_verify('passwordToCheck', $user->password))
{
// Success
}
post url
I understand that the auth functions allows a user to login etc, but I wanted a confirmation on what exactly was happening in the background.
My guess is that it's just a cookie that holds the login details, correct?
Or is it only storing the remember_token and then automatically comparing that with what is stored in the users table?
So if I wanted to create an account edit page. Would I have to do anything like comparing the auth id with the users table id that the e-mail matches up with? Or is it handling all that automatically?
Laravel Auth is nothing but its class where already all authentication methods or functions are written in laravel out of box.so you need not required to write all that function which is relating to user login.for example to check user we simply use
Auth::check();
but in laravel auth class they written like this
public function check()
{
return !is_null($this->user());
}
in the same way for login attempt we are passing parameter to attempt method .Here also laravel built in function is there
public function attempt(array $credentials = [], $remember = false, $login = true)
{
$this->fireAttemptEvent($credentials, $remember, $login);
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
// If an implementation of UserInterface was returned, we'll ask the provider
// to validate the user against the given credentials, and if they are in
// fact valid we'll log the users into the application and return true.
if ($this->hasValidCredentials($user, $credentials)) {
if ($login) {
$this->login($user, $remember);
}
return true;
}
return false;
}
Here you are passing all credentials in array and remember password and all
I'm using Cake 2.1.1 and trying to write an ajax function to reset a users password to a specific format. I have been able to change the password, but unable to make it so that the new password actually works to log the user in.
I have this function in my Users controller:
function ajax_reset_password(){
$this->autoRender=false;
$user = $this->User->find('first',array(
'conditions'=>array('User.email'=>$_GET['email'])
));
$this->User->id = $user['User']['id'];
$pass = $_GET['name'].'2014';
$passHashed= $this->Auth->password($pass);
$this->User->set('password', $pass);
$this->User->set('updated_at',date("Y-m-d H:i:s"));
$this->User->save();
//... code to email user new password
}
And this is my Users Controller beforeSave:
public function beforeSave(){
if (isset($this->data['User']['password'])) {
$this->data['User']['password'] = AuthComponent::password($this->data['User']['password']);
}
return true;
}
If I run this function and check my database, I can see that the value of password has changed literally to "name2014", but I cannot login with that password.
If I set the password to $passHashed and check my database, I see that the value of password has changed to a hashed value, but again, I cannot use the new password to login.
There is also a 'salt' field in my Users table that never changes.
I am guessing that the issue is that the salt needs to update with the password hash in order to properly decyrpt it, but I'm unsure of how to update the salt. Can I get it in my controller and set the value directly, or is this handled some other way with the AuthComponent?
Other posts about this topic seem to work fine with the code I have been using, but I also haven't found any that trying to set the password value directly.
Use what you have in the beforeSave(). (Don't try the route of hashing in the Controller).
If it's not hashing, just do some standard debugging and find out why it's not getting into that part of the code:
debug($this->data);
exit;
if (isset($this->data['User']['password'])) {
// IT'S NOT GETTING HERE
//...
This is one of those where the "answer" is just a nudge toward debugging your code, since it's clear where you can find out exactly what's going on and why by just seeing what's in the data and when.
I am currently working with CakePHP now if my users forgot their password i wish to allow them to reset it. (i.e me sending a mail to them with their new temp password).
But there is a problem. Passwords stored in my Database are hashed by the Auth component which means that if i try to select all from my User model i will get a hashed version of the password. Futher more i don't know how i will be able to save the password HASHED after generating a new one.
Ive been googling aroung for some time to find an answer to this but couldn't seem to find any examples of how this would be done.
Has anyone tried something similar or know how i can be done?
Ok, 2.x definitely gives more control. I only hash the passwords in my User model's beforeSave method just like you do:
public function beforeSave() {
if (isset($this->data['User']['password'])) {
$this->data['User']['password'] = AuthComponent::password($this->data['User']['password']);
}
return true;
}
This allows you to create a password in your Controller's password reset action as plain text, email it to the user, and then you set the password in the User model and persist it (password is hashed before it hits the database). The important thing here is that your password stays plain text until your controller calls the save method.
Generally I always add an unset on the password field in controller actions that will save the User record just to make sure it won't get rehashed. A second option would be to add an afterFind callback to your user model that does the unset each time the User model(s) are loaded.
About the one time reset key.... I have an additional field in my User object that I use in two cases. Email verification and password reset. When the user is created it is set to the SHA1( + + ). A link is emailed to the user that sends them to the User controller's validate action. Once that key is verified, that column gets cleared out in the database.
Same with the password reset. When they request a reset, the value gets generated in the same way and a link to the User controller's reset action gets emailed to the user. They enter their userid and if the key in the link matches the one in their database row, they can change their password. When their password is changed, this value is again cleared.
The biggest issue with sending temporary passwords is that it creates a DoS mechanism (against users, not your site). If I decided to harass someone, I could create a task that keeps resetting their password every hour. They can't get in until they check their email, but then it'll change again. Using a key, they'll get an email with a reset link, but their current password will still work as the presence of a reset code would not keep them from logging in.
I think you cannot convert encrypt password to decrypt.
So, if you want to read out how you can reset password then read out CakeDC plugin of cakephp.
https://github.com/CakeDC/users
this is the standard plugin of cakephp.
try this
function admin_reset($token = null) {
/**
* if logged in, send to home/dashboard page
*/
if (count($this->Session->read("Auth.User"))) {
return $this->redirect('/');
}
$this->set('title_for_layout', 'Reset Password');
$this->layout = 'admin';
$this->User->recursive = -1;
if (!empty($token)) {
$u = $this->User->findBytokenhash($token);
if ($u) {
$this->User->id = $u['User']['id'];
if (!empty($this->data)) {
$this->User->data = $this->data;
$this->User->data['User']['username'] = $u['User']['username'];
$new_hash = sha1($u['User']['username'] . rand(0, 100)); //created token
$this->User->data['User']['tokenhash'] = $new_hash;
if ($this->User->save($this->User->data, false)) {
$this->Session->setFlash(__('Password has been updated.'), 'default', array('class' => 'alert alert-success'));
$this->redirect(array('controller' => 'users', 'action' => 'login'));
}
}
} else {
$this->Session->setFlash(__('Token corrupted. Reset link work only for once, please try again.'), 'default', array('class' => 'alert alert-success'));
}
} else {
//$this->redirect('/');
}
}