I tried the above via the router aswell as described in the link before making the work-around, but it remained empty. I'll read it again maybe i missed something.
I'm running into another weird issue though. I'm checking the csrf token the same way I'm doing it in other actions where it works, but in the resetAction its empty. Also when i var_dump($this->request->getPost()) it appears empty.
In the HTML code the the hidden crsf field appears as it should be though:
<input type="hidden" id="csrf" name="csrf" value="K1RTMld3cVkwRS9rRzQyL2RVV0hiQT09">
This is my controller
<?php
use Phalcon\Mvc\Controller;
use PhalconTime\Forms\LoginForm;
use PhalconTime\Forms\RequestResetForm;
use PhalconTime\Forms\ResetPasswordForm;
use PhalconTime\Models\User;
use Phalcon\Security;
use Phalcon\Security\Random;
use Phalcon\Mvc\Url;
class AuthController extends Controller
{
/**
* The start action, it shows the login form
*/
public function indexAction()
{
$this->view->setVar('form', new LoginForm(null, ['edit' => false]));
}
/**
* The login action, validates user
*/
public function loginAction()
{
$username = $this->request->getPost('username');
$password = $this->request->getPost('password');
$csrf = $this->request->getPost('csrf');
$user = User::findFirstByName($username);
if($user) {
if($this->security->checkToken($csrf, $this->security->getSessionToken()) && $this->security->checkHash($password, $user->password)) {
$this->session->set('auth-identity', [
'id' => $user->id,
'username' => $user->name,
'image' => $user->image
]);
return $this->dispatcher->forward(["controller" => "project", "action" => "index"]);
}
else {
$this->flash->error('User/Password combination incorrect');
return $this->dispatcher->forward(["controller" => "auth", "action" => "index"]);
}
}
else {
$this->flash->error('User not found');
return $this->dispatcher->forward(["controller" => "auth", "action" => "index"]);
}
}
/**
* The logout action, remove user session
*/
public function logoutAction()
{
$this->session->remove('auth-identity');
return $this->dispatcher->forward([
"controller" => "auth",
"action" => "index"
]);
}
/**
* The password forgotten action
*/
public function requestResetAction()
{
$this->view->setVar('form', new RequestResetForm(null, ['edit' => false]));
}
/**
* the create token action
*/
public function createTokenAction()
{
if (!$this->request->isPost()) {
return $this->dispatcher->forward(["controller" => "auth", "action" => "requestreset"]);
}
$csrf = $this->request->getPost('csrf');
$email = $this->request->getPost("email", "string");
$user = User::findFirstByEmail($email);
if($this->security->checkToken($csrf, $this->security->getSessionToken())) {
if (!$user) {
$this->flash->error('User not found');
return $this->dispatcher->forward(["controller" => "auth", "action" => "requestreset" ]);
}
$random = new Random();
$uuid = $random->uuid();
$user->token = $uuid;
if($user->save()) {
$headers = "From: ".$_SERVER['SERVER_NAME']."\n";
$headers .= "X-Mailer: PHP/" . phpversion() . "\n";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: text/html; charset=utf-8\n";
$headers .= "Content-Transfer-Encoding: 8bit\n";
$subject = 'Reset password for '.$_SERVER['SERVER_NAME'];
$content = $this->view->getRender('emails', 'reset-password', ['token' => $uuid, 'url' => $this->config->application->domainUri]);
if(mail($email, $subject, $content, $headers)) {
$this->flash->success('An e-mail with instruction to reset the password has been send');
return $this->dispatcher->forward(["controller" => "auth", "action" => "index" ]);
}
$this->flash->error('Could not send e-mail');
return $this->dispatcher->forward(["controller" => "auth", "action" => "requestreset" ]);
}
}
$this->flash->error('Something went wrong');
return $this->dispatcher->forward(["controller" => "auth", "action" => "requestreset" ]);
}
/**
* The password reset action
*/
public function resetAction($token)
{
if($this->request->isPost()) {
$token = $this->request->getPost('token');
$csrf = $this->request->getPost('csrf'); // is empty
// @TODO csrf is empty on POST
//if($this->security->checkToken($csrf, $this->security->getSessionToken())) {
$user = User::findFirstByToken($token);
if (!$user) {
$this->flash->error('Token is not valid, request a new token');
return $this->dispatcher->forward(["controller" => "auth", "action" => "requestreset" ]);
}
// @TODO check if form is valid
$password = $this->request->getPost("password");
$user->password = $this->security->hash($password);
$user->token = NULL;
if ($user->save() == false) {
foreach ($user->getMessages() as $message) {
$this->flash->error($message);
}
$this->flash->error('Something went wrong, request a new token');
return $this->dispatcher->forward(["controller" => "auth", "action" => "requestreset"]);
}
$this->flash->success('Password changed');
return $this->dispatcher->forward(["controller" => "auth", "action" => "index" ]);
//}
}
if(!$token) {
$this->flash->error('Request a reset token first');
return $this->dispatcher->forward(["controller" => "auth", "action" => "requestreset" ]);
}
$this->view->setVar('form', new ResetPasswordForm(null, ['edit' => false, 'usertoken' => $token]));
}
}
And the form object
<?php
namespace PhalconTime\Forms;
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Element\Hidden;
use Phalcon\Forms\Element\Password;
use Phalcon\Validation\Validator\File as FileValidator;
use Phalcon\Validation\Validator\PresenceOf;
use Phalcon\Validation\Validator\Identical;
use Phalcon\Validation\Validator\StringLength;
use Phalcon\Validation\Validator\Confirmation;
class ResetPasswordForm extends Form
{
/**
* Initialize the reset password form
*
* @param mixed $entity
* @param array $options
*/
public function initialize($entity = null, $options = [])
{
$token = new Hidden(
"token", [
"class" => "hidden",
"value" => $options["usertoken"]
]
);
$this->add($token);
// Password
$password = new Password(
"password",
[
"placeholder" => "Password",
"class" => "form-control",
]
);
$password->setLabel("Password");
$password->setFilters(
[
"striptags",
"string",
]
);
$password->addValidators(
[
new PresenceOf(
[
"message" => "Password is required",
]
),
new StringLength(
[
'min' => 8,
'messageMinimum' => 'Password is too short. Minimum 8 characters'
]
),
new Confirmation(
[
'message' => 'Password doesn\'t match confirmation',
'with' => 'passwordRepeat'
]
)
]
);
$this->add($password);
// Password repeat
$passwordRepeat = new Password(
"passwordRepeat",
[
"placeholder" => "Password repeat",
"class" => "form-control",
]
);
$passwordRepeat->setLabel("Password repeat");
$passwordRepeat->setFilters(
[
"striptags",
"string",
]
);
$passwordRepeat->addValidators(
[
new PresenceOf(
[
"message" => "Password repeat is required",
]
)
]
);
$this->add($passwordRepeat);
// CSRF
$csrf = new Hidden('csrf');
$csrf->addValidator(new Identical(
[
'value' => $this->security->getSessionToken(),
'message' => 'CSRF validation failed'
])
);
$csrf->clear();
$this->add($csrf);
}
}