codeigniter4 / shield

Authentication and Authorization for CodeIgniter 4
https://shield.codeigniter.com
MIT License
351 stars 123 forks source link

Bug: Setting password from a JSON request return a type error when using strong_password validation rule #1142

Closed seunex17 closed 2 weeks ago

seunex17 commented 2 weeks ago

PHP Version

8.3.6

CodeIgniter4 Version

4.5.3

Shield Version

1.1.0

Which operating systems have you tested for this bug?

macOS

Which server did you use?

cli-server (PHP built-in webserver)

Database

MySQL

Did you customize Shield?

No

What happened?

When i get a request via a standard POST like $request = $this->request->getPost(); this strong_password validation work fine.

But on another case am am build a web app with svelte and and sending a fetch to my CI4 backend with json data like $request = (array) $this->request->getJSON();. This method then return an error message titled: TypeError: CodeIgniter\Shield\Entities\User::setEmail(): Argument #1 ($email) must be of type string, null given, called in

It works when using getPost but fail to work when using getJSON. I can only bypass this error is i remove strong_password validation rule.

Steps to Reproduce

Retrive a json data in array form

$request = (array) $this->request->getJSON();

Try to validation this incoming request

$rules = $this->getValidationRules();
if (! $this->validateData($request, $rules, [], config('Auth')->DBGroup)) {
            $errors = $this->validator->getErrors();
            return $this->failValidationErrors(array_shift($errors));
        }

Try to save validation data to you db (Remember to enable strong_password validation rule)

new User($request);

Expected Output

This should create a new user account on my database.

Anything else?

No response

kenjis commented 2 weeks ago

Please show all error message, backtrace, not only one line when you show errors.

CodeIgniter\Shield\Entities\User::setEmail(): Argument #1 ($email) must be of type string, null given, called in
kenjis commented 2 weeks ago

Please show a sample data to reproduce the error. Otherwise we cannot reproduce.

$request = (array) $this->request->getJSON();

In "Steps to Reproduce", write a minimum sample code that reproduce the error. Your code does not work at all.

seunex17 commented 2 weeks ago

I am sending a JOSN data form my frontend to the backend to create new user account. Here is my Controller that extends ShieldRegister

    public function register(): ResponseInterface
    {
        $request = (array) $this->request->getJSON();
        $rules   = $this->getValidationRules();

        if (! $this->validateData($request, $rules, [], config('Auth')->DBGroup)) {
            $errors = $this->validator->getErrors();

            return $this->failValidationErrors(array_shift($errors));
        }

        $this->accountModel->save(new User([
            'username' => $request['username'],
            'email'    => $request['email'],
            'password' => $request['password'],
            'active'   => false,
            'status'   => 0,
            'uuid'     => service('uuid')
                ->uuid4()
                ->toString(),
        ]));

        // Send verification key
        $code = generate_rand_keys(10);

        $this->emailVerifyKeyModel->save(new EmailVerifyKey([
            'email' => xss_clean($request['email']),
            'code'  => $code,
        ]));

        // Send email to Mentor
        $email = xss_clean($request['email']);
        $data  = [
            'code'     => $code,
            'username' => xss_clean($request['username']),
            'link'     => "https://witvafrica.com/verify-email?email={$email}&code={$code}",
        ];

        $mailData = [
            'subject' => 'Verify Your Email',
            'to'      => xss_clean($request['email']),
        ];
        Utility::sendEmail($data, $mailData, 'verify-email');

        return $this->respond([
            'message' => 'Registration successful please check your email',
        ]);
    }

Thie work when i remove strong_password validation rule but fail when added.

Error Output:

INFO - 2024-07-10 06:46:29 --> Session: Class initialized using 'CodeIgniter\Session\Handlers\FileHandler' driver.
CRITICAL - 2024-07-10 06:46:29 --> TypeError: CodeIgniter\Shield\Entities\User::setEmail(): Argument #1 ($email) must be of type string, null given, called in /Users/zubdev/Workspace/clients/wiafrica/witv_backend/vendor/codeigniter4/framework/system/Entity/Entity.php on line 450
[Method: POST, Route: app/register]
in VENDORPATH/codeigniter4/shield/src/Entities/User.php on line 242.
 1 SYSTEMPATH/Entity/Entity.php(450): CodeIgniter\Shield\Entities\User->setEmail(null)
 2 SYSTEMPATH/Entity/Entity.php(165): CodeIgniter\Entity\Entity->__set('email', null)
 3 SYSTEMPATH/Entity/Entity.php(146): CodeIgniter\Entity\Entity->fill([...])
 4 VENDORPATH/codeigniter4/shield/src/Authentication/Passwords/ValidationRules.php(92): CodeIgniter\Entity\Entity->__construct([...])
 5 VENDORPATH/codeigniter4/shield/src/Authentication/Passwords/ValidationRules.php(52): CodeIgniter\Shield\Authentication\Passwords\ValidationRules->buildUserFromRequest()
 6 SYSTEMPATH/Validation/Validation.php(335): CodeIgniter\Shield\Authentication\Passwords\ValidationRules->strong_password('Pa$$w0rd!', null)
 7 SYSTEMPATH/Validation/Validation.php(201): CodeIgniter\Validation\Validation->processRules('password', 'Password', 'Pa$$w0rd!', [...], [...], 'password')
 8 SYSTEMPATH/Controller.php(152): CodeIgniter\Validation\Validation->run([...], null, null)
 9 APPPATH/Controllers/App/Auth/RegisterController.php(58): CodeIgniter\Controller->validateData([...], [...], [], null)
10 SYSTEMPATH/CodeIgniter.php(933): App\Controllers\App\Auth\RegisterController->register()
11 SYSTEMPATH/CodeIgniter.php(509): CodeIgniter\CodeIgniter->runController(Object(App\Controllers\App\Auth\RegisterController))
12 SYSTEMPATH/CodeIgniter.php(355): CodeIgniter\CodeIgniter->handleRequest(null, Object(Config\Cache), false)
13 SYSTEMPATH/Boot.php(325): CodeIgniter\CodeIgniter->run()
14 SYSTEMPATH/Boot.php(67): CodeIgniter\Boot::runCodeIgniter(Object(CodeIgniter\CodeIgniter))
15 FCPATH/index.php(56): CodeIgniter\Boot::bootWeb(Object(Config\Paths))
16 SYSTEMPATH/rewrite.php(44): require_once('/Users/zubdev/Workspace/clients/wiafrica/witv_backend/public/index.php')
seunex17 commented 2 weeks ago

Please note if request is send as a standard post data it will work with strong_password validation rule added or note.

kenjis commented 2 weeks ago

Compare the data, the standard post data and the json data. If there is something missing in json data, that is the cause of the error.

kenjis commented 2 weeks ago

We use GitHub issues to track BUGS and to track approved DEVELOPMENT work packages. We use our forum to provide SUPPORT and to discuss FEATURE REQUESTS.

seunex17 commented 2 weeks ago

The data was logged in a log file to debug and bothe data (Post and Json) are the same.

$postData = $this->request->getPost();
$jsonData = $this-request->getJSON();

I have to remove strong_password validation rule for this to work. Thanks.

kenjis commented 2 weeks ago

Try to set strong_password[].

seunex17 commented 2 weeks ago

@kenjis wow thank you! it works.