I am trying to change the password of a user for this i need to check that old password of that user does match with the value i am getting from html "oldpass" text box. If the existing password value and "oldpass" value matches the new password will be updated in database.The password value i am getting from the database is encrypted.
$userpass = User::where('id', '=', Session::get('userid'))->get(array('password'));
The problem is that $userpass returns a null value .
Here is the code:
$oldpass = Hash::make(Input::get('oldpass'));//Getting password from html form
$userpass = User::where('id', '=', Session::get('userid'))->get(array('password'));//Getting password value from database Users table
if ($oldpass === $userpass) {
User::where('id', '=', Session::get('userid'))
->update(array(
'password' => Hash::make(Input::get('newpass'))
));
} else {
Return View::make('changepass.changepass')
->with('errormessage', 'Password does not match');
}
There are two main problems here.
On one hand, $userpass is returning null because get() is not the appropiate function to fecth a column. You can use pluck for that (see the query builder docs)
Anyway you can just call the attribute once you fetch the user like:
$userpass = User::find(Session::get('userid'))->password;
You are trying to compare a hashed password with a plain password. Laravel uses Guard
by default to manage user Authentication and Guard uses Hash::make to store it. You should compare hashes with:
Hash::check($oldpass, $userpass)
You could also just check with Guard the user credentials are correct with Auth::validate($credentials) (see Laravel Security) and then change the password like:
if(Auth::validate('id' => Session::get('userid'), 'password' => Input::get('oldpass'))){
//Assuming user was authenticated before. If not use Auth::attempt instead of validate
Auth::user()->password = Hash::make(Input::get('newpass'));
} else {
Return View::make('changepass.changepass')
->with('errormessage', 'Password does not match');
}
Related
Trying to check if the user 'email' or 'number' exists when the user is tring to change password if forgotten. Below is the form enter code here:
Email or Cellphone
Already have an Account.?
User exist function check:
public function checkUserExits($field){
$userExists = User::where('email', $field)->orWhere('cellphone',$field)->first();
return $userExists;
}
when running on local server getting an error message "Triying to get property "email"
of non-object." the problem is that when i remove check to see if just email exist the same code works.
dd($field) and check what result you are getting.
from below one of the query should work
$userExists = User::where('email', $field->email)->orWhere('cellphone',$field->cellphone)->first();
$userExists = User::where('email',$field['email'])->orWhere('cellphone',$field['cellphone'])->first();
I'm trying to hash passwords using the CodeIgniter 3 library "Community Auth", and I think I've found that only certain special characters will work. I just can't tell why, or really what's happening to them.
Here's an example password that works: KA83**8!d#
Here's an example password that does NOT work: 1aA!##%^&*()-_=+{};:,<.>
Edit: I should clarify that the passwords save to the DB, but trying to login is what doesn't work.
If I pull the below methods out to a single function that does hash_passwd and password_verify, then a comparison do work for both passwords.
Should I be using preg_quote on the string so that it saves correctly to the database? I tried, but it didn't seem to affect anything.
Here are the two methods that I use to change a password, and then the third to check for login.
Model = application\models\User_model.php
Method = change_password
$this->db->where('user_id', $user_data->user_id)
->update(
$this->db_table('user_table'), [
'passwd' => $this->authentication->hash_passwd($password),
'passwd_recovery_code' => NULL,
'passwd_recovery_date' => NULL
]
);
Model = application\third_party\community_auth\libraries\Authentication.php
Method = hash_passwd
public function hash_passwd($password) {
return password_hash($password, PASSWORD_BCRYPT, ['cost' => 11]);
}
Model = application\third_party\community_auth\libraries\Authentication.php
Method = check_passwd
public function check_passwd($hash, $password) {
if (password_verify($password, $hash)) {
return TRUE;
}
return FALSE;
}
I figured it out. The change_password method is escaping the password, but the login method was not. Updated to escape both, and now it works.
I've been searching the internet and have yet to find a solution to the following problem...
We currently have a website developed using Laravel which the user table is a remote Microsoft SQL database. The driver in config/auth.php has been set to "database". All is working fine except for the password reset functionality, which we get the following error:
UnexpectedValueException in PasswordBroker.php line 238: User must implement CanResetPassword interface.
From my limited understanding of Laravel (this is my first experiance with Laravel), the Eloquent driver has support for the CanResetPassword functionality, however, this has not been implemented in the Database User Provider by Laravel, hence the error.
So my question is thus, has anyone had a configuration where they have the driver to “Database” and implemented a reset password functionality? All the examples I have seen to date relate to using the Eloquent model, which from my understanding of Laravel is not an option since during the initial development we had to change the driver from Eloquent to database to get the remote Microsoft SQL server working in the first place. Moving the Microsoft SQL database to a local database is not an option I’m afraid.
Alternatively, if anyone has implemented another method of a user resetting their password using an email address I would be open to suggestions.
To write your own password reset logic, you can still use the default migration that comes out of the box or simply create yours. The most important part is the token. Because you are making your own password reset, you have a couple of decisions to make:
Will the token expire?
Can a user use the same token multiple times?
You will need 2 pages, 4 different routes and 4 different functions in the same controller. The 'I forgot my password' page and the 'Reset password' page. In the first page, display a form where you take the user email. And post to the following controller.
//to be added on top as use statements
use DB;
use Auth;
use Hash;
use Carbon;
use App\User;
public function sendPasswordResetToken(Request $request)
{
$user = User::where ('email', $request->email)-first();
if ( !$user ) return redirect()->back()->withErrors(['error' => '404']);
//create a new token to be sent to the user.
DB::table('password_resets')->insert([
'email' => $request->email,
'token' => str_random(60), //change 60 to any length you want
'created_at' => Carbon::now()
]);
$tokenData = DB::table('password_resets')
->where('email', $request->email)->first();
$token = $tokenData->token;
$email = $request->email; // or $email = $tokenData->email;
/**
* Send email to the email above with a link to your password reset
* something like url('password-reset/' . $token)
* Sending email varies according to your Laravel version. Very easy to implement
*/
}
Second part, when the user clicks on the link
/**
* Assuming the URL looks like this
* http://localhost/password-reset/random-string-here
* You check if the user and the token exist and display a page
*/
public function showPasswordResetForm($token)
{
$tokenData = DB::table('password_resets')
->where('token', $token)->first();
if ( !$tokenData ) return redirect()->to('home'); //redirect them anywhere you want if the token does not exist.
return view('passwords.show');
}
Display a page with a form containing 2 inputs
- New password password or whateveer you want
- New password confirmation password_confirm or whatever you want
The form should post to the same URL mapped to the following controller. Why? because we still need to use the token to find the actual user.
public function resetPassword(Request $request, $token)
{
//some validation
...
$password = $request->password;
$tokenData = DB::table('password_resets')
->where('token', $token)->first();
$user = User::where('email', $tokenData->email)->first();
if ( !$user ) return redirect()->to('home'); //or wherever you want
$user->password = Hash::make($password);
$user->update(); //or $user->save();
//do we log the user directly or let them login and try their password for the first time ? if yes
Auth::login($user);
// If the user shouldn't reuse the token later, delete the token
DB::table('password_resets')->where('email', $user->email')->delete();
//redirect where we want according to whether they are logged in or not.
}
Don't forget to add routes
Route::get('password-reset', 'PasswordController#showForm'); //I did not create this controller. it simply displays a view with a form to take the email
Route::post('password-reset', 'PasswordController#sendPasswordResetToken');
Route::get('reset-password/{token}', 'PasswordController#showPasswordResetForm');
Route::post('reset-password/{token}', 'PasswordController#resetPassword');
Note: There might be typos or syntax errors because I did not test this and wrote it here directly from the top of my head. If you see an error/exception, don't panick, read the error and search google.
Just to add to what #eddythedove said.
Instead of str_random(60) I used the Laravel way of creating a token:
private function generateToken()
{
// This is set in the .env file
$key = config('app.key');
// Illuminate\Support\Str;
if (Str::startsWith($key, 'base64:')) {
$key = base64_decode(substr($key, 7));
}
return hash_hmac('sha256', Str::random(40), $key);
}
If you find an error in str_random, make sure you import the module first:
use Illuminate\Support\Str;
Then call with Str::random (60).
$key = config('app.key');
if (Str::startsWith($key, 'base64:')) {
$key = base64_decode(substr($key, 7));
}
$token = hash_hmac('sha256', Str::random(40), $key);
$dbToken = app(Hasher::class)->make($token);
DB::insert('password_resets', [
'email' => 'email#mail.com',
'token' => $dbToken,
]);
This should work in Laravel 8
The default way Laravel handles the Reset Password has a few security issues.
No track record reset password attempts (Delete the token in the table after success attempt is not acceptable)
No expiry date
No token used time
We always better keep track of these security functions.
I have altered the default table like this on my db migration:
public function up()
{
Schema::table('password_resets', function (Blueprint $table) {
$table->bigIncrements('id');
$table->enum('is_used', ['t', 'f'])->default('f');
$table->dateTime('updated_at')->nullable();
});
}
Instead of deleting the record I simply update the table 'is_used' to 't' and updated_at column.
I use following query to filter is_used = 'f' and created on the same day to gather with token.
$data = PasswordReset::where('token', $token)->where('is_used', 'f')
->whereDate('created_at', '>=', Carbon::today()->toDateString())->first();
i try some code after that i get some solution that will work in laravel 8+.
$key = config('app.key');
if (Str::startsWith($key, 'base64:')) {
$key = base64_decode(substr($key, 7));
}
$token = hash_hmac('sha256', Str::random(40), $key);
$dbToken =Hash::make($token);
Within my project, I have given the administrator role the privilege to add users to the site. For security reasons, I hash a random string, to store as the temporary password, I then want to send the user an email with the standard Laravel reset password template.
I have the following:
$user = new User();
$user->name = Input::get('name');
$user->email = Input::get('email');
$user->password = Hash::make(str_random(8));
$user->save();
$response = Password::sendResetLink(Input::get('email'), function (Message $message) {
$message->subject('Password Reset');
});
The error I'm getting is
Argument 1 passed to
Illuminate\Auth\Passwords\PasswordBroker::sendResetLink() must be of
the type array, string given
How can I trigger this function within Laravel, so the user is sent a password reset email? Thank you.
The problem here is that you are sending string email, and you should send array (this is what error says).
You should in this case use:
Request::only('email')
instead of
Input::get('email')
When I'm updating my model-bound form with
$user->update(Input::all())
My password field is re-hashed, even when it's empty. I have set my User.php class to automatically hash that field, but shouldn't it be skipped since the field is empty?
You could use in this case:
Input::except('password')
so in your controller you could do it this way:
if (trim(Input::get('password')) == '') {
$data = Input::except('password');
}
else {
$data = Input::all();
}
$user->update($data);
However you should consider other possible issues for that. In this case if user send input with id name (and anyone can do it even if you don't have such field in your form) he could change easily other users passwords/accounts and destroy your whole data.
You should use in your User model at least:
protected $guarded = array('id');
to protect user id from being changed during mass assignment but maybe there are also some other fields you would like to protect (you should list them in $guarded array.
For me much better option in this case is using standard user updating:
$user = User::find($id);
if (trim(Input::get('password')) != '') {
$user->password = Hash::make(trim(Input::get('password')));
}
$user->name = Input::get('name');
// and so on - this way you know what you are changing and you won't change something you don't want to change
$user->save();
Just as Tom Bird commented, here's some code for an example.
If you use a mutator like setPasswordAttribute() method in your model then you can do this:
public function setPasswordAttribute($password)
{
if (!empty($password))
{
$this->attributes['password'] = bcrypt($password);
}
}
This will prevent a new password from being hashed. This setPasswordAttribute() method is called a "mutator" and became available in Laravel 4.2 from what I see. http://laravel.com/docs/4.2/eloquent
Because you have sent all of the input to the user model it assumes you want to update all fields including the password even though it is an empty string, it is possible to hash an empty string.
You need to check if the password is empty and if it is use Input::except('password')
The simple method you can use for this is array_filter. Array_filter filter excludes any empty field. so if you password field is empty then it will not be included in the user update model and when the password field is not included it will not be hashed since mutators and accessors only work when the model has the given attribute. When you filter it out the fields, the model does not receive the field and thus will not hash. You use it in following way...
$user->update(array_filter(Input::all()));
or
$user->update(array_filter($request->all()));
The only problem with this is it will not only exclude password but also all the field that were set empty.
public function update($id)
{
$register = Register::findOrFail($id);
if (empty(Request::get('password'))) {
$data = Request::except('password');
} else {
$data = Request::all();
}
$register->update($data);
return redirect('register');
}