I created a user with encrypted password.(bcrypt(password))
In rest api I am getting md5(password) [from app]
How to validate both the password?
\Hash::check($request->password, $user->password)
NOT WORKING
There is no direct way to compare the actual password in Laravel. Laravel never store your password as plain text but a hashed version + salt, so you can check the plain version of the password against the hashed stored version using the Hash::check method:
// original password
$password = 'my-password';
// hashed password
$hashed_password = bcrypt($password);
// something like: "$2y$10$XFs6ocWUaiiB99QvLwTuhOuABIq71D13LmpFdeISh7RsC.SsAthHG";
The hashed version is the one stored.
If you want to check if the validation of a password:
use Illuminate\Support\Facades\Hash;
// ...
$passed = Hash::check($password , $hashed_password); // true
You can not compare passwords encrypted by different ways. You need the plain password. I guess you are trying to make a seamless access for users in your platform in order to avoid the user do two times login (in your system and the api provider system) Am I correct?
In that case, probably you need to think in other way to approach it.
In Laravel 9 i make like this,
first import
use Illuminate\Support\Facades\Hash;
in rules() function
return [
'password' => ['required', function ($attr, $value, $fail) {
$user = User::where('email', $this->request->get('email'))->first();
if ($user && !(Hash::check($value, $user->password))) {
$fail('The ' . $attr . ' is invalid.');
}
}],
];
Related
Just want to be sure if that's the "right way" and most importantly if it's "secure way". I'm making simple form for someone who want's to reset password (not logged in). I don't want to use Laravel way (no dedicated database for that). Simply I'm sending crypted link, link is valid for 10 minutes.
public function sendConfirmationLink(Request $request)
{
$validatedData = $request->validate([
'email' => 'required|email|exists:users',
]);
$user = User::where('email', $request->get('email'))->firstOrFail();
$parameters = [
'user_id' => $user->id,
'date' => Carbon::now(),
'type' => 'password_reset',
];
$passwordResetLink = Crypt::encrypt($parameters);
SendPasswordResetLink::dispatch($user, $passwordResetLink)->onQueue('high');
}
Later on, I'm decrypting that hash and I'm making password change.
public function resetPassword(Request $request)
{
$validatedData = $request->validate([
'hash' => 'required',
'new_password' => 'required|string|min:6|confirmed',
]);
try {
$decrypted = Crypt::decrypt($request->get('hash'));
$password = Hash::make($request->get('new_password'));
$user = User::where('id', $decrypted['user_id'])->firstOrFail();
$user->password = $password;
$user->save();
} catch (DecryptException $e) {
abort(404);
}
}
If I'm right... that "link" will be extremely difficult to crack and it's valid for only 10 minutes. Is it in any way less secure then native Laravel version with similar code stored in database?
Yes I know that Laravel Auth can do it for me. I want use my method in more then password reset so I'm looking for answear if it's secure this way.
The Crypt library from Laravel uses a combination of OpenSSL and AES-256-CBC with a MAC signing. I think for a 10 min period, that should be safe enough.
A more serious problem is, that you can't "disable" a link after usage. So theoretically everyone with the link can change the account password infinite times (in a 10 min period).
A solution for that problem could be, that you add the current password hash into your link-hash and then compare that. In that case the password change would only work one-time per link.
My problem is that I'm using CodeIgniter. I created an Administrator Panel which I use to create users and passwords. I use password_hash before sending them to database (in fact, in the database I can see the hashed password).
The problem is... When I try to log in, it doesn't. I can only access with administrator account, which I created before I started using CodeIgniter.
I can log in with admin account, but not with the accounts created with the admin panel.
I tried to use a very simple php file (outside CI) to copy and paste the hash to one of the user's fields in my database and it worked. I don't understand why this doesn't work within CodeIgniter.
Here's the part of my code:
public function insert_user($username, $passw, $perm){
$hashed_pass = password_hash($passw, PASSWORD_DEFAULT);
$data = array(
"username" => $username,
"passw" => $hashed_pass,
"perms" => $perm
);
$this->db->insert('usuarios', $datos);
}
The function above inserts correctly data in the database. I can see the password hashed, but when I try to log in with created users from admin panel, it just doesn't work (but it does with admin account, and they all are using the same function to log in).
public function login($username, $password){
$query = $this->db->query("select passw, perms from users where username = '".$username."'");
$result = $query->row();
$p_hashed = $result->passw;
$perms= $result->perms;
if(password_verify($password, $p_hashed)){
$info= array(
"is_valid" => true,
"username" => $username,
"perms" => $perms
);
return $info;
}
else {
$info= array(
"is_valid" => false,
"username" => ""
);
return $info;
}
}
I checked database and CI charset, all is utf8. I don't understand why is not working... I would appreciate any help.
P.S.: if the name of variables are no correlated or are not the same is because I translated it to English (I'm not native English speaker, so I'm not using English in this project).
Thank you.
EDIT
I've changed the code to use md5 instead of password_hash and I'm having the same issue.
EDIT 2
I detected the problem: I was comparing the 2 password (the first one and the confirm password). After that comparison, I passed the data to the model... But the variable of the password I was sending to model was a new variable with no data. I was hashing a not initialized variable.
There doesn't seem to be any problem in the code you show. As I commented, the likely problem is that the passw column in the table is truncating the data being inserted.
Check the documentation for password_hash to find what the return data size is for the various algorithms and adjust your table structure accordingly. For PASSWORD_DEFAULT the suggested size is 255 characters.
The code below isn't an answer, but I have time and thought you might find a refactored version of login() interesting.
It is assumed that you have properly validated and sanitized the values being passed to the login() method.
public function login($username, $password)
{
//use query binding so values are automatically escaped, producing a safer query
$query = $this->db->query("select username, perms, passw
from users where username = ?", [$username]);
// make sure query worked and found a record
if($query && $query->num_rows() > 0)
{
// get an row array so you don't need to make an array
$row = $query->row_array();
if(password_verify($password, $row['passw']))
{
unset($row['passw']); // remove passw from array
$row['is_valid'] = true;
return $row;
}
}
return array( "is_valid" => false, "username" => "");
}
I am building a testing routine in Laravel 5.1 to run through the login process I have just created. I am wanting, as part of the testing, to test the password reset and change process.
The issue is that the password reset process generates and row in a table with a timestamp and uuid. The link remains valid for 1 hour for the reset to work.
The flow is:
1- Reset password by entering email address
2- System generates email with uuid link and sends to the user (currently it appears in the Laravel log).
3- User clicks on link from email, and if within one hour since it was generated, the user is presented with a password change screen. The link is also deleted from the table.
So now for my test code:
public function testSendPasswordLink()
{
$this->visit('/login')
->click('Forgot Your Password?')
->seePageIs('/forgot-password')
->type('test#test.com','email')
->press('Send Password Reset Link')
->seePageIs('/login')
->see('A password reset link was sent to the email address supplied.')
->seeInDatabase('password_resets', ['email' => 'test#test.com']);
}
I would like to:
->getFromDatabase('password_resets', 'uuid')
->visit('/reset-password/'.$uuid)
->see(....
Is there a way of doing the above? I know how to see in the table but not how to get from the table in the test.
Alternatively is there a way to accomplish this via a different set of steps?
Thanks!
Wow, insanity setting in... well, I am new at this so I will not execute myself as yet...! The answer was rather obvious (after sleeping on it!)
All I had to do is query the table and retrieve the token to perform the password reset test... below is the finished code:
Add Eloquent to the test php file
use Illuminate\Database\Eloquent\Model;
Below is the complete function:
public function testChangePassword()
$this->visit('/login')
->click('Forgot Your Password?')
->seePageIs('/forgot-password')
->type('test#test.com','email')
->press('Send Password Reset Link')
->seePageIs('/login')
->see('A password reset link was sent to the email address supplied.')
->seeInDatabase('password_resets', ['email' => 'test#test.com']);
$uuid = DB::table('password_resets')
->where('email', '=', 'test#test.com')
->value('token');
$this->visit('/reset-password/' . $uuid)
->type('bbbbbbbb','password')
->type('bbbbbbbb','password_confirmation')
->press('Change Password')
->see('Your password was reset.')
->seePageIs('/login')
->type('test#test.com','email')
->type('bbbbbbbb','password')
->press('Sign In')
->seePageIs('/welcome')
->click('Logout')
->seePageIs('/login');
// Change password back
$this->visit('/login')
->click('Forgot Your Password?')
->seePageIs('/forgot-password')
->type('test#test.com','email')
->press('Send Password Reset Link')
->seePageIs('/login')
->see('A password reset link was sent to the email address supplied.')
->seeInDatabase('password_resets', ['email' => 'test#test.com']);
$uuid = DB::table('password_resets')
->where('email', '=', 'test#test.com')
->value('token');
$this->visit('/reset-password/' . $uuid)
->type('abcd1234','password')
->type('abcd1234','password_confirmation')
->press('Change Password')
->see('Your password was reset.')
->seePageIs('/login')
->type('test#test.com','email')
->type('abcd1234','password')
->press('Sign In')
->seePageIs('/welcome')
->click('Logout')
->seePageIs('/login');
By the way, I cannot seem to format the code with the {} brackets, so apologies.
My case is for change password option. I already have current password in object $pass. I want to validate this $pass against textbox form input current_password to proceed to create a new password for the user. How to validate with same validator. Sorry I'm new to laravel.
$rules = array('password_current' => "required|same:$pass");
doesn't work.
since same: used to ensure that the value of current field is the same as another field defined by the rule parameter (not object). so you can't use this function take a look this example code below.
$data = Input::all();
$rules = array(
'email' => 'required|same:old_email',
);
the above code will check if current email field is same as old_email field.
so i think you can you simple if else
in your handle controller function assume
public function handleCheck(){
$current_password = Input::get('current_password');
$pass = //your object pass;
if($current_password == $pass){
// password correct , show change password form
}else{
// password incorrect , show error
}
}
let me know if it works. see Laravel Validation same
If you have password stored in $pass already just inject $pass in the request and use its field instead for e.g.
$request->request->add(['password_old' => $pass]);
Then, you can validate it like
$rules = array('password_current' => "required|same:password_old");
I need to do some extra checks on a user, I would like to get the user by username and password.
Firstly:
Is there a built in function that gets a user by username and password without authenticating them?
Secondly:
If the above is no, then how do I correctly hash the password, because if I use Hash::make( $password ) and then compare to the database, it is not the same... You would usually use Hash::check but I need to actually get the user by username and password.
In Laravel 5.2
You can use Auth::once($credentials) to validate credentials and thereafter Auth::getUser(); to get the user.
$credentials = Request::only('username', 'password');
if(!Auth::once($credentials)) {
// Invalid user credentials; throw Exception.
}
$user = Auth::getUser();
First:
If you want to check if user data to authentication is correct you can use:
if (Auth::validate($credentials))
{
//
}
But if you want to get user from database with user and password, you can use:
$user = User::whereName($username)->wherePassword(Hash::make($password))->first();
Second
To store password in database you should use Hash::make($password) as you showed and it works without any problems. Using Auth::validate should solve the issue.
Yes, there is a built in function you should use. I recommend you to read the docs. But here's a good example, it's pretty self-evident:
$input = array(
'username' => Input::get('username'),
'password' => Input::get('password'),
);
$remember = (boolean)Input::get('remember'); //'Remember me' checkbox
if (Auth::attempt($input, $remember)) {
return Redirect::intended('dashboard')->with("success", "You're logged in!"); //Redirect the user to the page intended to go to, with the dashboard page as default
}
Registering a user looks something like this:
$input = array(
'username' => Input::get('username'),
'email' => Input::get('email'),
'password' => Hash::make(Input::get('password')) //Encrypt password
);
$user = User::create($input);
I also recommend you to read about input validation. I hope this helps, good luck.
Edit: I didn't read the "without authenticating them" part. You should use Auth::validate($input) as Marcin already explained.
Laravel 5.7
To check a users credentials without logging them in, I had to do this:
$user = User::whereEmail($request->email)->first();
$user = password_verify($request->password, optional($user)->getAuthPassword()) ? $user : false;
Laravel auth validation makes use of https://www.php.net/manual/en/function.password-verify.php