codeigniter4 / shield

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

The Example Code Written In The Docs & The Code In The Plugin Gives Out A Solution That Runs You In A Loop #583

Closed Elvis254 closed 1 year ago

Elvis254 commented 1 year ago

PHP Version

8.1.6.0

CodeIgniter4 Version

4.2.11

Shield Version

dev-develop 44bbf2c

Which operating systems have you tested for this bug?

Windows

Which server did you use?

apache

Database

MySQL 5.6

Did you customize Shield?

I customized the Login Controller where I need to create an admin panel and it needs no registration process maybe on another Controller so as to have the super admin create, read, update & delete users as per required. I also copied the code in the Register Controller into another file that runs during software installation. In that when the software is installing a super admin is added to the system without having them fill out forms about their details so their information is hard coded in the software.

What happened?

When I try to login into the system it does nothing but returns me to the login form.

Steps to Reproduce

I have included the codes I used to customize the software below. It doesn't even show the Log Message in the login action method.


namespace App\Controllers;

use CodeIgniter\HTTP\RedirectResponse;

class AuthController extends BaseController
{
    public function loginPage()
    {
        log_message('info', 'AuthController: Login Page Method Executed.');

        if (auth()->loggedIn()) {
            return redirect()->to(config('Auth')->loginRedirect());
        }

        $authenticator = auth('session')->getAuthenticator();

        if ($authenticator->hasAction()) {
            return redirect()->route('auth-action-show');
        }

        return $this->renderView(
            'auth/login', [
                'pageTitle' => esc('Login', 'raw'),
            ]
        );
    }

    public function loginAction(): RedirectResponse
    {
        log_message('info', 'AuthController: Login Action Method Executed.');

        $rules = $this->getValidationRules();

        if ( ! $this->validate($rules)) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        $credentials             = $this->request->getPost(setting('Auth.validFields'));
        $credentials             = array_filter($credentials);
        $credentials['password'] = $this->request->getPost('password');
        $remember                = (bool) $this->request->getPost('remember');

        $authenticator = auth('session')->getAuthenticator();

        $result = $authenticator->remember($remember)->attempt($credentials);
        if ( ! $result->isOK()) {
            return redirect()->route('login')->withInput()->with('error', $result->reason());
        }

        if ($authenticator->hasAction()) {
            return redirect()->route('auth-action-show')->withCookies();
        }

        return redirect()->to(config('Auth')->loginRedirect())->withCookies();
    }

    /**
     * Returns the rules that should be used for validation.
     *
     * @return array<string, array<string, array<string>|string>>
     * @phpstan-return array<string, array<string, string|list<string>>>
     */
    protected function getValidationRules(): array
    {
        return setting('Validation.login') ?? [
            'username' => [
                'label' => 'Username',
                'rules' => config('AuthSession')->usernameValidationRules,
            ],
            // 'email' => [
            //     'label' => 'Auth.email',
            //     'rules' => config('AuthSession')->emailValidationRules,
            // ],
            'password' => [
                'label' => 'Auth.password',
                'rules' => 'required',
            ],
        ];
    }
}

The code I used to add a super admin to the system is shown below.

public function superAdminAction()
    {
        log_message('info', 'InstallController: Super Admin Action Method Executed.');

        $userModel = model(setting('Auth.userProvider'));
        $userInfo = new User();

        $userInfo->username = 'Elvis254';
        $userInfo->email    = 'elvisabwa@gmail.com';
        $userInfo->password = 'elvisM@1992.29';

        try
        {
            $userModel->save($userInfo);
        }
        catch(ValidationException $e)
        {
            throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
        }

        $userInfo = $userModel->findById($userModel->getInsertID());
        $userModel->addToDefaultGroup($userInfo);

        $authenticator = auth('session')->getAuthenticator();
        $authenticator->startLogin($userInfo);
        $authenticator->activateUser($userInfo);
        $authenticator->completeLogin($userInfo);

        return redirect()->to('/');
    }

Expected Output

I expect it to get me logged in and redirect me to the dashboard page of the system.

Anything else?

No response

Elvis254 commented 1 year ago

Oh, I used my own written routes instead of the single line statement specified in the documentation. The code is shown below:

  $routes->group('auth', ['namespace' => 'App\Controllers'], static function ($routes) {

      $routes->get('login', 'AuthController::loginPage');

      $routes->post('login', 'AuthController::loginAction');

  });
kenjis commented 1 year ago

It doesn't even show the Log Message in the login action method.

Check your login form. Does it send a POST request to auth/login?

Elvis254 commented 1 year ago

Yes it does here is the code:

<?= form_open('auth/login') ?>
                <?php if (session('error') !== null) : ?>
                    <div class="alert alert-danger" role="alert"><?= session('error') ?></div>
                <?php elseif (session('errors') !== null) : ?>
                    <div class="alert alert-danger" role="alert">
                        <?php if (is_array(session('errors'))) : ?>
                            <?php foreach (session('errors') as $error) : ?>
                                <?= $error ?>
                                <br>
                            <?php endforeach ?>
                        <?php else : ?>
                            <?= session('errors') ?>
                        <?php endif ?>
                    </div>
                <?php endif ?>
                    <div class="input-group mb-3">
                        <input type="text" name="username" value="<?= old('username') ?>" class="form-control" placeholder="Username" autocomplete="off" required />
                        <div class="input-group-append">
                            <div class="input-group-text">
                                <span class="fas fa-user-circle"></span>
                            </div>
                        </div>
                    </div>
                    <div class="input-group mb-3">
                        <input type="password"name="password" class="form-control" placeholder="Password" autocomplete="off" required />
                        <div class="input-group-append">
                            <div class="input-group-text">
                                <span class="fas fa-lock"></span>
                            </div>
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-8">
                            <div class="form-check icheck-primary">
                                <input id="rememberMe" type="checkbox" name="remember" class="form-check-input" <?php if (old('remember')): ?> checked<?php endif ?> />
                                <label for="rememberMe" class="form-check-label">Remember Me</label>
                            </div>
                        </div>
                        <div class="col-4">
                            <button type="submit" class="btn btn-primary btn-block btn-flat">
                                <span class="fas fa-sign-in-alt mr-1"></span>
                                Login
                            </button>
                        </div>
                    </div>
                <?= form_close() ?>
kenjis commented 1 year ago

If you send a POST request to loginAction(), you see the log message. If you don't see the log message, you don't send a request.

I don't know why a POST request is not sent, but I believe this is not a bug in Shield.

Check the HTTP requests with your browser developer tool. Or run step debugging with your IDE.

Elvis254 commented 1 year ago

Okay. Let me take a closer look into it. Will update you on the proceedings once am done. Thanks anyway. :)

datamweb commented 1 year ago

What @kenjis mentioned, I don't consider this a bug.

The minimum code provided by you was not complete, with a little change, the code works.

demo02

I consider this issue over.

Therefore, I will send the topic to the discussion section.