Send reset link with Laravel Auth and encrypted user table - php

I have a laravel 5.4 installation and I always used the default Laravel Authentication guard to handle user authentication and, mainly, the password restore process.
Now I had to encrypt the email in the users table using the Elocryptfive library, so I also added email_hash field where the hash of the mail is stored in the db in order to easily retrieve users by their email.
I can easily authenticate users using the hash:
Auth::attempt([
'email_hash' => hash('sha256', $request->get('email')),
'password' => $request->get('password')]
, $remember);
What I can't get working is the password reset process. Is there a class to override in order to retrieve users by email_hash, then access the decrypted email and send the mail, without rewriting the whole password forgotten process?

I found a way to achieve this. I will answer my own question to provide a useful solution if someone else needs some help on the topic:
In your ForgotPasswordController.php, override the sendResetLinkEmail function:
/**
* Send a reset link to the given user.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse
*/
public function sendResetLinkEmail(Request $request)
{
$this->validateEmail($request);
$hashed = hash('sha256', $request->get('email'));
$user = User::where('email_hash', $hashed)->first();
if (!is_null($user)) {
$response = Password::sendResetLink(
['email_hash' => $hashed]
);
} else {
$response = Password::INVALID_USER;
}
return $response == Password::RESET_LINK_SENT
? $this->sendResetLinkResponse($response)
: $this->sendResetLinkFailedResponse($request, $response);
}
In your ResetPasswordController.php, override the credentials function:
/**
* Get the password reset credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(Request $request)
{
return [
'email_hash' => hash('sha256', $request->get('email')),
'password' => $request->get('password'),
'password_confirmation' => $request->get('password_confirmation'),
'token' => $request->get('token')
];
}
Thanks to Mike Rodham for pointing out the right direction, I hope it helps someone.

Related

How to login with Crypt encryption in login controller

I am using Crypt:: for registration and login. My registration is successful but login is not successful. Please check the code and help me.
public function Login(Request $request)
{
$this->validate($request, [
'email' => 'required',
'password' => 'required',
]);
$userdata = array(
'email' => $request->email,
'password' => \Crypt::encrypt($request->password)
);
if (Auth::attempt($userdata) {
echo "success";die();
}
return "Ops! snap! seems like you provide an invalid login credentials";
}
Originial
You need to use Hashing, not Encryption.
Registration
...
$userdata = [
'email' => $request->email
'password' => Hash::make($request->password)
];
...
// User saved..
Login
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials) {
// It work
}
Ref :
https://laravel.com/docs/5.6/authentication
https://laravel.com/docs/5.6/hashing
Update
OP : I need to Crypt::decrypt to decode the password and send on email. Using hash i couldn't decode it. Thats the reason i need Crypt.
I really don't recommend it. That's why we have the "forgot password" feature to create new password.
Is it secure to store passwords with 2 way encryption?
Okay, back to the topic, How to login with Crypt encryption?
You need to add login() method in Auth\LoginController :
/**
* Handle a login request to the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*
* #throws \Illuminate\Validation\ValidationException
*/
public function login(Request $request)
{
$decrypted = $request->input('password');
$user = User::where('email', $request->input('email'))->first();
if ($user) {
if (Crypt::decryptString($user->password) == $decrypted) {
Auth::login($user);
return $this->sendLoginResponse($request);
}
}
return $this->sendFailedLoginResponse($request);
}
WARNING!
All of Laravel's encrypted values are signed using a message authentication code (MAC) so that their underlying value can not be modified once encrypted.
You must have the same key. If you change the key (artisan key:generate), it means you will not be able to login.
I really don't recommend it.
I have this problem before.
I used Crypt Encryption because I need to display the password from encrypted to decrypted in laravel blade input element.
I deeply look at laravel references in projects and found a solution.
In default laravel used HASH for encryption, since I used Crypt to Register and Login.
When I try to Login this returns false.
What I did is edited one laravel function located in
vendor\laravel\framework\src\Illuminate\Auth\EloquentServiceProvider.php
and change this function from these
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
return $this->hasher->check($plain, $user->getAuthPassword());
}
to these
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
return \Crypt::decrypt($user->getAuthPassword());
}

Laravel 5 send password reset and custom input name

I want to have register / login and send password reset on the same page.
I achieve to have register and login on the same page with different input name. But I don't find a way to add password reset input.
I want to call it "reset_email" but on my controller, if I try :
public function sendResetLinkEmail(Request $request)
{
$this->validateEmail($request);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$response = $this->broker()->sendResetLink(
$request->only('email')
);
return $response == Password::RESET_LINK_SENT
? $this->sendResetLinkResponse($response)
: $this->sendResetLinkFailedResponse($request, $response);
}
/**
* Validate the email for the given request.
*
* #param \Illuminate\Http\Request $request
* #return void
*/
protected function validateEmail(Request $request)
{
$this->validate($request, ['reset_email' => 'required|email']);
}
I've got this error :
We can't find a user with that e-mail address.
Any idea how to use reset_email instead of email for my input name ?
Thank for your help.
Update your method like this:
...
$response = $this->broker()->sendResetLink(
['email' => $request->get('reset_email')]
);
...
This will get your input value and will send it to the password broker with key email, so it will look for users by this column.

Laravel Authentication Custom Rule

I'm working with laravel Auth. Trying to add new rule with email and password, if status(field in user model) is = 1 then he cannot login. I cannot find where should i add this. I was looking at middleware, guard.php AuthenticateUsers.php but did not found it..
Edit:
I've solved this by creating new middleware that checks for this field. Also it can be done with Auth::attempt
You can try as:
if (Auth::attempt(['email' => $email, 'password' => $password, 'status' => 1])) {
// The user is active, not suspended, and exists.
}
From the Docs
If you wish, you also may add extra conditions to the authentication query in addition to the user's e-mail and password.
Add this code to your LoginController:
/**
* Attempt to log the user with custom credentials into the application.
*
* #param \Illuminate\Http\Request $request
* #return bool
*/
protected function attemptLogin(Request $request)
{
$credentials = $this->credentials($request);
$credentials['status'] = 1; // Additional field you want to check
return $this->guard()->attempt(
$credentials, $request->filled('remember')
);
}
Here we add the status field as a part of checked credentials. If user has status not equal to 1, authentication will fail.
Works with Laravel5.6

Override Auth Forgot Password in Laravel 5.3

I am using built in laravel auth functionality.Its working fine.I am trying to override following two functionality.
1.send forgot password email using mandrill.
2.send verification email while registering account.
Can any one help me to solve this issue
My aim is to use mandril instead of default email
I can see auth built in methods but i didnt got idea how i can override that
trait ResetsPasswords
{
use RedirectsUsers;
/**
* Display the password reset view for the given token.
*
* If no token is present, display the link request form.
*
* #param \Illuminate\Http\Request $request
* #param string|null $token
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showResetForm(Request $request, $token = null)
{
return view('auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email]
);
}
/**
* Reset the given user's password.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function reset(Request $request)
{
$this->validate($request, $this->rules(), $this->validationErrorMessages());
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
return $response == Password::PASSWORD_RESET
? $this->sendResetResponse($response)
: $this->sendResetFailedResponse($request, $response);
}
As answered by Mahfuzal, Laravel comes with a bunch of mail drivers out of the box. So just update your .env file to use the right driver.
As for sending a verification email when creating an account, you just need to override the postRegister() function inside the Auth/AuthController like so:
public function postRegister(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
$confirmation_code = str_random(30);
$newUser = new User;
$newUser->username = $request->username;
$newUser->email = $request->email;
$newUser->password = bcrypt($request->password);
$newUser->confirmation_code = $confirmation_code;
$newUser->save();
$data = array('confirmation_code' => $confirmation_code, 'username' => $request->username);
Mail::send('emails.verify', $data, function ($message) use ($newUser){
$message->to($newUser->email, $newUser->username);
$message->subject('Please verify your email address');
});
return redirect('/auth/login');
}
This will execute the above code when registering a user rather than what Laravel does default out of the box so just tweak it to your needs.
You then just need to create a function that will check the token and verify their account when they click the link. For that, I use something similar to what is explained here.
Laravel provides drivers for SMTP, Mailgun, Mandrill, Amazon SES,
PHP's mail function, and sendmail, allowing you to quickly get started
sending mail through a local or cloud based service of your choice.
Open your .env file and change following by your Mandrill credentials and then you're good to go.
MAIL_DRIVER=mandrill
MAIL_HOST=
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
You can create your own reset method in the controller that uses the trait to override the method in the trait.

Salting example in Zend Framework

I am pretty new to the Zend framework and looking to build an application with pretty tight password security. I have been trying to follow the user guides in relation to password salting but haven't had any luck so far. I have setup my database and table adapter (As described in the documentation on the Zend Framework site but it didn't seem to finish the example (or I am not following well enough!) I have started with:
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter,
'users',
'username',
'password', "MD5(CONCAT('".Zend_Registry::get('staticSalt')."', ?, password_salt))"
);
But from here, what is done with the password salt? I just need an example and I'll be away! Does anyone have an example or point me in the right direction??
Many thanks!
Excelent example for an secure login with Zend Framework (altough using salts)
Login example with Zend Framework
Authentication method:
/**
* Authenticate user with specified identity and credential
*
* most used case is authenticate user inline in script
*
* #param string $identity
* #param string $credential
* #return Zend_Auth_Result
*/
public function authenticate ($identity, $credential)
{
$auth = Zend_Auth::getInstance();
$adapter = $this->getAdapter();
$adapter->setIdentity($identity)
->setCredential(self::passwordHash($credential));
$config = Singular_Runtime::extract('config');
$isActiveCol = $config->resources->auth->columns->is_active;
$isActiveAllowVal = $config->resources->auth->is_active->allow_value;
/**
* #see APPLICATION_PATH/configs/application.ini -> resources.auth
*/
if (null != $isActiveCol && null != $isActiveAllowVal) {
$adapter->getDbSelect()->where("{$isActiveCol} = ?", $isActiveAllowVal);
}
Singular_Event::dispatch('beforeAuth', array(
'auth' => $auth, 'adapter' => $adapter
));
$result = $auth->authenticate($adapter);
if ($result->isValid()) {
$auth->getStorage()->write($adapter->getResultRowObject());
Singular_Event::dispatch('afterAuth', array(
'auth' => $auth, 'adapter' => $adapter
));
}
return $result;
}
And password hash generation method:
/**
* Password hash generator
*
* #static
* #param string $password
* #return string
*/
public static function passwordHash ($password)
{
$password = strtolower($password);
return md5(
str_repeat(
md5($password) . strrev($password) . sha1($password),
strlen($password)
)
);
}

Categories