I want to authenticate a custom FrontendUser via my REST-API in a Controller. I tried to hash the password with SaltedPasswordsUtility using this guide.
I get every request a different hash from the same password. I assume this is because the salt is not consistent.
How can I compare the plain text password to the password hash in the database or is there an entirely other way to achieve the same?
My code so far is:
/**
* action check
*
* #param string $username
* #param string $password
* #return string
*/
public function checkAction(string $username, string $password)
{
$user = $this->userRepository->findOneByUsername($username);
$saltedPassword = '';
if (\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::isUsageEnabled('FE')) {
$objSalt = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(NULL);
if (is_object($objSalt)) {
$saltedPassword = $objSalt->getHashedPassword($password);
}
}
echo $saltedPassword;
echo "<br>";
$saltedPassword = $user->getPassword();
// keeps status if plain-text password matches given salted user password hash
$success = FALSE;
if (\TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::isUsageEnabled('FE')) {
$objSalt = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($saltedPassword);
if (is_object($objSalt)) {
$success = $objSalt->checkPassword($password, $saltedPassword);
}
}
echo $saltedPassword;
return "";
}
The code is woking. I messed up setting a faulty password for the test user in the backend.
Related
I'm a begginer in Symfony 4 and I'm developing an API Rest. I want to create a PUT resource that can handle many update cases.
In my case, I have a user with many properties but I will take an example with 3 properties to keep things simple :
User {
username,
email,
password
}
My PUT resource can be called in order to update Username, update Email or update Password. For example, to update Username, the user of my API will send a PUT request with only username :
{
username: "New username"
}
Same for email and password, he will only send the property he wants to change.
My problem is in my Controller, I have to do things like this :
/**
* #Rest\Put("/user/{id}")
* #param Request $request
* #return View
*/
public function putUserRequest(Request $request)
{
$userId = $request->get('id');
$user = $this->doctrine->getRepository(User::class)->findOneBy('id' => $userId);
$userFromRequest = $this->serializer->deserialize($request->getContent(), User::class, 'json');
if ($userFromRequest->getUsername() != NULL) {
$user->setUsername($userFromRequest->getUsername())
}
if ($userFromRequest->getEmail() != NULL) {
$user->setEmail($userFromRequest->getEmail())
}
if ($userFromRequest->getPassword() != NULL) {
$user->setPassword($userFromRequest->getPassword())
}
// ...
}
In my example I have only 3 properties, but imagine when I have 30 properties.
With Symfony 3 I used forms to validate / save my datas :
$form->submit($request->request->all(), $clearMissing);
Where $clearMissing is false to keep datas not provided by the user of my API. I can't find a way to do it with serializer but I guess I'm doing things wrong.
Thanks.
If I understand correctly, You can use the validator Component like this :
/**
* #Rest\Put("/user/{id}")
* #param Request $request
* #return View
*/
public function putUserRequest(User $user, Request $request, ValidatorInterface $validator)
{
$data = $request->getContent();
$this->serializer->deserialize($data, User::class, 'json', ['object_to_populate' => $user]);
//At this moment, the data you sent is merged with your user entity
/** #var ConstraintViolationList $errors */
$errors = $validator->validate($user, null ,['groups' => 'user_update']);
if (count($errors) > 0) {
//return json reponse with formated errors;
}
//if ok $entityManager->flush() and Response Json with serialization group;
...
}
In your user class :
class User implements UserInterface
{
/**
* #Assert\Email(groups={"user_create", "user_update"})
*/
private $email;
/**
* #Assert\NotBlank(groups={"user_create", "user_update"})
* #Assert\Length(min=7, groups={"user_create", "user_update"})
*/
private $password;
/**
* #Assert\Length(min=2, groups={"user_create", "user_update"} )
*/
private $username;
}
Related Validator component documentation : https://symfony.com/doc/current/validation/groups.html
You can also check this project : https://github.com/attineos/relation-deserializer
Save crypt hash security:
$usuario = new User();
$usuario->password = $this->security->hash($this->request->getPost("pass"));
if (!$usuario->save()) {
foreach ($usuario->getMessages() as $message) {
$this->flash->error($message);
}
$this->dispatcher->forward([
'controller' => "usuario",
'action' => 'new'
]);
return;
}
now, How to decrypt hash security to send my form:
$usuario = User::findFirstByid($iduser);
$this->tag->setDefault("pass", $this->encryption->decrypt($usuario->password));
I having this: Notice: Access to undefined property encryption in ...
As #Juri said Hashes are only one way. You can however use encryptBase64() which is two way and you can decode it back. Do not use it for passwords, use it for some data you need to pass to someone and read it back, like api token etc..
Here is how to set it up:
$di->setShared('crypt', function () use ($config) {
$crypt = new \Phalcon\Crypt();
$crypt->setKey('i$4^&/:%2#k50ROQ<#{(e=*!<7u|rI~0');
return $crypt;
});
Helper functions I created, but you can use it directly:
...
...
private static $cryptKey = 'i$4^&/:%2#k50ROQ<#{(e=*!<7u|rI~0';
/**
* Generate url safe encoded string
*
* #param string $string string to be encoded
* #return encoded string
*/
public static function encodeString($string)
{
$crypt = new \Phalcon\Crypt();
return $crypt->encryptBase64($string, self::$cryptKey, true);
}
/**
* Decode string generated with Common::encodeString()
*
* #param string $string Encoded string
* #return decoded string
*/
public static function decodeString($string)
{
$crypt = new \Phalcon\Crypt();
return $crypt->decryptBase64($string, self::$cryptKey, true);
}
We are currently using auto auth and we have the method below to log in the user automatically using there email, the problem is when the email has a plus sign it will not login automatically.
/**
* #param $email Clients Email Address to Login
* #param string $goto is a url endpoint where you want to redirect the user
*/
public static function autoLoginUser( $email, $goto = 'index.php?m=dashboard' )
{
global $CONFIG;
/**
* Define WHMCS url and AuthKey from confguration.php
*/
$whmcsurl = $CONFIG['SystemURL'] . "/dologin.php";
$autoauthkey = "Our auth key is here"; //$autoauthkey from configuration.php
$timestamp = time(); //Get current timestamp
$hash = sha1($email . $timestamp . $autoauthkey); //Generate Hash
/**
* Generate AutoAuth URL & Redirect
*/
$url = $whmcsurl . "?email=$email×tamp=$timestamp&hash=$hash&goto=" . urlencode($goto);
header("Location: $url");
exit;
}
Does anyone have tried this before? Having a normal email address works perfectly but on email that contains plus sign it won't log the user automatically.
I don't know why it was not documented in whmcs but the work around we manage to have is encode the email like the following code
/**
* #param $email Clients Email Address to Login
* #param string $goto is a url endpoint where you want to redirect the user
*/
public static function autoLoginUser( $email, $goto = 'index.php?m=dashboard' )
{
global $CONFIG;
/**
* Define WHMCS url and AuthKey from confguration.php
*/
$whmcsurl = $CONFIG['SystemURL'] . "/dologin.php";
$autoauthkey = "Our auth key is here"; //$autoauthkey from configuration.php
$timestamp = time(); //Get current timestamp
$hash = sha1($email . $timestamp . $autoauthkey); //Generate Hash
$email =
/**
* Generate AutoAuth URL & Redirect
*/
$url = $whmcsurl . "?email=".urlencode($email)."×tamp=$timestamp&hash=$hash&goto=" . urlencode($goto);
header("Location: $url");
exit;
}
I'm using Laravel 5.1 to build back-end system with RESTFUl resources which will be consumed by some mobile applications.
Forgot Password Story
if someone forgot password then the server has to send an email with the temporary password to his registered email. From the next time on words server has to authenticate the user either with temp password or with the password
Can someone guide me how to do this
You can modify your PasswordController located in app\http\controllers\auth
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
use App\Models\User; //yours is probably App\User;
use Mail, Hash;
class PasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Create a new password controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest');
}
public function postEmail(Request $request)
{
$this->validate($request, ['email' => 'required|email']);
$email = $request->get('email');
if(!$user = User::where('email', $email)->first()) return redirect()->back()->with('error', 'Email does not exists');
//create temporal password
$temp_password = str_random(8); //generates random 8 characters long string
//hash password and save in database
//I assume you have `temp_password` in your users column
$user->temp_password = Hash::make($temp_password);
$user->save();
//data to be used in mail
$data['subject'] = 'Password Reminder'; //$this->getEmailSubject();
$data['email'] = $email;
$data['temp_password'] = $temp_password;
//send mail to user
Mail::send('emails.password_reminder', $data, function($message) use ($data)
{
$message->from('no-reply#site.com', $data['subject']);
$message->subject($data['subject']);
$message->to($data['email']);
});
}
}
Then in resource/views/emails create password_reminder.blade.php
Your temporal password is {{$temp_password}}
NB:Someone requested a password reminder, if you are not the one kindly ignore
For User Authentication
try - (not tested)
$email = \Request::get('email');
$password = \Request::get('password');
if (Auth::attempt(['email' =>$email, 'password' => $password])){
return true;
}elseif(Auth::attempt(['email' =>$email, 'temp_password' => $password])){
return true;
}else{
return false;
}
or try this
$email = \Request::get('email');
$password = \Request::get('password');
$user = User::where('email',$email)->first();
if(!$user) return false;
if (Auth::attempt(['email' =>$email, 'password' => $password])){
return true;
}elseif(\Hash::check($password, $user->temp_password)){
Auth::loginUsingId($user->id); return true;
}else{
return false;
}
I am trying to use Laravel's built in authentication, but it is not working. If I hash a password at the registration process, it does not match the hash in the login process, because Laravel's auth generates a totally different hash than Hash:make().
I made a test route and function, to make everything clear
(I tried to use the Auth::attempt() function with Hash::make() and without Hash::make() too, If I pass the Hashed password, it generates a totally different one, If I pass the raw password the Auth doesn't even bother to hash it):
Route::get('/test', function() {
$email = rand(1, 1000) . "test#mail.com";
$password = $email;
$now = new DateTime();
Felhasznalo::create(array(
'teljesnev' => 'valami',
'email' => $email,
'jelszo' => Hash::make($password),
'FelFelhasznaloiSzint_id' => 2,
'created_at' => $now->getTimestamp(),
'aktiv' => 1
));
if (Auth::attempt(array(
'email' => $email,
'jelszo' => Hash:make($password)
))) {
echo 'Working';
} else {
echo 'Not working';
}
});
The first part generates this row to my mysql server:
39test#mail.com, $2y$10$gkzQ2BEuDWN05RQ/OyBH8u4aKRqdL5zSIthUO4BUyEKcscgzRwZzG, valami ....etc
I intentionally mistyped the password field's name to jelszo1 (means password1 in english), when attempting login, to get an sql error.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'jelszo1' in 'where clause' (SQL: select * from `Felhasznalo` where `email` = 39test#mail.com and `jelszo1` = y$XAnnnGNKrOQOxBiX2BnEPOq86Y9mh5h./xwUlfCTPpzW.jzzt3YiO limit 1)
First part (in mysql):
$2y$10$gkzQ2BEuDWN05RQ/OyBH8u4aKRqdL5zSIthUO4BUyEKcscgzRwZzG
Second part (when attempting login):
y$XAnnnGNKrOQOxBiX2BnEPOq86Y9mh5h./xwUlfCTPpzW.jzzt3YiO
and the User model (named as Felhasznalo)
<?php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class Felhasznalo extends \Eloquent implements UserInterface, RemindableInterface {
use UserTrait,
RemindableTrait;
protected $fillable = [
'id', 'email', 'jelszo', 'teljesnev', 'jelszoreset',
'hash', 'aktiv', 'ban', 'FelFelhasznaloiSzint_id',
'remember_token'
];
protected $guarded = [
];
protected $hidden = [
'jelszo', 'jelszoreset', 'hash'
];
protected $table = 'Felhasznalo';
public $timestamps = true;
protected $softDelete = true;
//----------------------------
//----------------------------
// RELATIONSHIP FUNCTIONS
//----------------------------
//----------------------------
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier() {
return $this->getKey();
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword() {
return $this->jelszo;
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail() {
return $this->email;
}
public function getRememberToken() {
return $this->remember_token;
}
public function setRememberToken($value) {
$this->remember_token = $value;
}
public function getRememberTokenName() {
return 'remember_token';
}
}
The auth config.:
'model' => 'Felhasznalo',
'table' => 'Felhasznalo',
SQL Error error when using raw password in attempt():
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'jelszo1' in 'where clause' (SQL: select * from `Felhasznalo` where `email` = 832test#mail.com and `jelszo1` = 832test#mail.com limit 1)
The answer to Your question from the post's title (Which Hash function laravel's Auth is using?) can be found on mnshankar.wordpress.com - Laravel Hash::make() explained.
Here is the first sentence from the "How?" section of the linked blog post:
Internally, Hash::make() encrypts using the bcrypt function and Blowfish algorithm.
Also, You can see on the Laravel 5.4 docs - Hashing page that they say:
The Laravel Hash facade provides secure Bcrypt hashing for storing user passwords.
I just checked the Auth code, your password column MUST be called password. You cannot use jelszo
Also - yourr login code is incorrect. You just do this:
if (Auth::attempt(array(
'email' => $email,
'password' => $password
))) {
echo 'Working';
} else {
echo 'Not working';
}
Auth::attempt() will do the hashing for you.