Auth Controllers

The Auth controllers allow you to perform basic authentification with:
  • login with an account

  • account creation

  • logout

  • controllers with required authentication

Creation

In the admin interface (web-tools), activate the Controllers part, and choose create Auth controller:

../_images/speControllerBtn.png
Then fill in the form:
  • Enter the controller name (BaseAuthController in this case)

../_images/createAuthForm1.png

The generated controller:

app/controllers/BaseAuthController.php
 1 /**
 2 * Auth Controller BaseAuthController
 3 **/
 4class BaseAuthController extends \Ubiquity\controllers\auth\AuthController{
 5
 6     protected function onConnect($connected) {
 7             $urlParts=$this->getOriginalURL();
 8             USession::set($this->_getUserSessionKey(), $connected);
 9             if(isset($urlParts)){
10                     Startup::forward(implode("/",$urlParts));
11             }else{
12                     //TODO
13                     //Forwarding to the default controller/action
14             }
15     }
16
17     protected function _connect() {
18             if(URequest::isPost()){
19                     $email=URequest::post($this->_getLoginInputName());
20                     $password=URequest::post($this->_getPasswordInputName());
21                     //TODO
22                     //Loading from the database the user corresponding to the parameters
23                     //Checking user creditentials
24                     //Returning the user
25             }
26             return;
27     }
28
29     /**
30      * {@inheritDoc}
31      * @see \Ubiquity\controllers\auth\AuthController::isValidUser()
32      */
33     public function _isValidUser($action=null): bool {
34             return USession::exists($this->_getUserSessionKey());
35     }
36
37     public function _getBaseRoute(): string {
38             return 'BaseAuthController';
39     }
40}

Implementation of the authentification

Example of implementation with the administration interface : We will add an authentication check on the admin interface.

Authentication is based on verification of the email/password pair of a model User:

../_images/model-user.png

BaseAuthController modification

app/controllers/BaseAuthController.php
 1 /**
 2 * Auth Controller BaseAuthController
 3 **/
 4class BaseAuthController extends \Ubiquity\controllers\auth\AuthController{
 5
 6     protected function onConnect($connected) {
 7             $urlParts=$this->getOriginalURL();
 8             USession::set($this->_getUserSessionKey(), $connected);
 9             if(isset($urlParts)){
10                     Startup::forward(implode("/",$urlParts));
11             }else{
12                     Startup::forward("admin");
13             }
14     }
15
16     protected function _connect() {
17             if(URequest::isPost()){
18                     $email=URequest::post($this->_getLoginInputName());
19                     $password=URequest::post($this->_getPasswordInputName());
20                     return DAO::uGetOne(User::class, "email=? and password= ?",false,[$email,$password]);
21             }
22             return;
23     }
24
25     /**
26      * {@inheritDoc}
27      * @see \Ubiquity\controllers\auth\AuthController::isValidUser()
28      */
29     public function _isValidUser($action=null): bool {
30             return USession::exists($this->_getUserSessionKey());
31     }
32
33     public function _getBaseRoute(): string {
34             return 'BaseAuthController';
35     }
36     /**
37      * {@inheritDoc}
38      * @see \Ubiquity\controllers\auth\AuthController::_getLoginInputName()
39      */
40     public function _getLoginInputName(): string {
41             return "email";
42     }
43}

Admin controller modification

Modify the Admin Controller to use BaseAuthController:

app/controllers/Admin.php
1class Admin extends UbiquityMyAdminBaseController{
2     use WithAuthTrait;
3     protected function getAuthController(): AuthController {
4             return $this->_auth ??= new BaseAuthController($this);
5     }
6}

Test the administration interface at /admin:

../_images/adminForbidden.png

After clicking on login:

../_images/formLogin.png

If the authentication data entered is invalid:

../_images/invalidCreditentials.png

If the authentication data entered is valid:

../_images/adminWithAuth.png

Attaching the zone info-user

Modify the BaseAuthController controller:

app/controllers/BaseAuthController.php
1 /**
2 * Auth Controller BaseAuthController
3 **/
4class BaseAuthController extends \Ubiquity\controllers\auth\AuthController{
5...
6     public function _displayInfoAsString(): bool {
7             return true;
8     }
9}

The _userInfo area is now present on every page of the administration:

../_images/infoUserZone.png

It can be displayed in any twig template:

{{ _userInfo | raw }}

Description of the features

Customizing templates

index.html template

The index.html template manages the connection:

../_images/template_authIndex.png

Example with the _userInfo area:

Create a new AuthController named PersoAuthController:

../_images/createAuthForm2.png

Edit the template app/views/PersoAuthController/info.html

app/views/PersoAuthController/info.html
 1{% extends "@framework/auth/info.html" %}
 2{% block _before %}
 3     <div class="ui tertiary inverted red segment">
 4{% endblock %}
 5{% block _userInfo %}
 6     {{ parent() }}
 7{% endblock %}
 8{% block _logoutButton %}
 9     {{ parent() }}
10{% endblock %}
11{% block _logoutCaption %}
12     {{ parent() }}
13{% endblock %}
14{% block _loginButton %}
15     {{ parent() }}
16{% endblock %}
17{% block _loginCaption %}
18     {{ parent() }}
19{% endblock %}
20{% block _after %}
21             </div>
22{% endblock %}

Change the AuthController Admin controller:

app/controllers/Admin.php
1class Admin extends UbiquityMyAdminBaseController{
2     use WithAuthTrait;
3     protected function getAuthController(): AuthController {
4             return $this->_auth ??= new PersoAuthController($this);
5     }
6}
../_images/adminWithAuth2.png

Customizing messages

app/controllers/PersoAuthController.php
 1class PersoAuthController extends \controllers\BaseAuth{
 2...
 3 /**
 4  * {@inheritDoc}
 5  * @see \Ubiquity\controllers\auth\AuthController::badLoginMessage()
 6  */
 7 protected function badLoginMessage(\Ubiquity\utils\flash\FlashMessage $fMessage) {
 8     $fMessage->setTitle("Erreur d'authentification");
 9     $fMessage->setContent("Login ou mot de passe incorrects !");
10     $this->_setLoginCaption("Essayer à nouveau");
11
12 }
13...
14}

Self-check connection

app/controllers/PersoAuthController.php
 1class PersoAuthController extends \controllers\BaseAuth{
 2...
 3 /**
 4  * {@inheritDoc}
 5  * @see \Ubiquity\controllers\auth\AuthController::_checkConnectionTimeout()
 6  */
 7 public function _checkConnectionTimeout() {
 8     return 10000;
 9 }
10...
11}

Limitation of connection attempts

app/controllers/PersoAuthController.php
 1class PersoAuthController extends \controllers\BaseAuth{
 2...
 3 /**
 4  * {@inheritDoc}
 5  * @see \Ubiquity\controllers\auth\AuthController::attemptsNumber()
 6  */
 7 protected function attemptsNumber(): int {
 8     return 3;
 9 }
10...
11}

Account recovery

account recovery is used to reset the account password.
A password reset email is sent, to an email address corresponding to an active account.

../_images/recoveryInit.png
app/controllers/PersoAuthController.php
 1class PersoAuthController extends \controllers\BaseAuth{
 2...
 3 protected function hasAccountRecovery():bool{
 4     return true;
 5 }
 6
 7 protected function _sendEmailAccountRecovery(string $email,string $validationURL,string $expire):bool {
 8     MailerManager::start();
 9     $mail=new AuthAccountRecoveryMail();
10     $mail->to($connected->getEmail());
11     $mail->setUrl($validationURL);
12     $mail->setExpire($expire);
13     return MailerManager::send($mail);
14 }
15
16 protected function passwordResetAction(string $email,string $newPasswordHash):bool {
17     //To implement for modifying the user password
18 }
19
20 protected function isValidEmailForRecovery(string $email):bool {
21     //To implement: return true if a valid account match with this email
22 }
23}
../_images/recoveryForm.png

Nota

By default, the link can only be used on the same machine, within a predetermined period of time (which can be modified by overriding the accountRecoveryDuration method).

Activation of MFA/2FA

Multi-factor authentication can be enabled conditionally, based on the pre-logged-in user’s information.

Nota

Phase 2 of the authentication is done in the example below by sending a random code by email. The AuthMailerClass class is available in the Ubiquity-mailer package.

app/controllers/PersoAuthController.php
 1class PersoAuthController extends \controllers\BaseAuth{
 2...
 3 /**
 4  * {@inheritDoc}
 5  * @see \Ubiquity\controllers\auth\AuthController::has2FA()
 6  */
 7 protected function has2FA($accountValue=null):bool{
 8     return true;
 9 }
10
11 protected function _send2FACode(string $code, $connected):void {
12     MailerManager::start();
13     $mail=new AuthMailerClass();
14     $mail->to($connected->getEmail());
15     $mail->setCode($code);
16     MailerManager::send($mail);
17 }
18...
19}
../_images/2fa-code.png

Nota

It is possible to customize the creation of the generated code, as well as the prefix used. The sample below is implemented with robthree/twofactorauth library.

protected function generate2FACode():string{
        $tfa=new TwoFactorAuth();
        return $tfa->createSecret();
}

protected function towFACodePrefix():string{
        return 'U-';
}

Account creation

The activation of the account creation is also optional:

../_images/account-creation-available.png
app/controllers/PersoAuthController.php
1class PersoAuthController extends \controllers\BaseAuth{
2...
3 protected function hasAccountCreation():bool{
4     return true;
5 }
6...
7}
../_images/account-creation.png

In this case, the _create method must be overridden in order to create the account:

protected function _create(string $login, string $password): ?bool {
        if(!DAO::exists(User::class,'login= ?',[$login])){
                $user=new User();
                $user->setLogin($login);
                $user->setPassword($password);
                URequest::setValuesToObject($user);//for the others params in the POST.
                return DAO::insert($user);
        }
        return false;
}

You can check the validity/availability of the login before validating the account creation form:

protected function newAccountCreationRule(string $accountName): ?bool {
        return !DAO::exists(User::class,'login= ?',[$accountName]);
}
../_images/account-creation-error.png

A confirmation action (email verification) may be requested from the user:

protected function hasEmailValidation(): bool {
        return true;
}

protected function _sendEmailValidation(string $email,string $validationURL,string $expire):void {
        MailerManager::start();
        $mail=new AuthEmailValidationMail();
        $mail->to($connected->getEmail());
        $mail->setUrl($validationURL);
        $mail->setExpire($expire);
        MailerManager::send($mail);
}

Nota

It is possible to customize these parts by overriding the associated methods, or by modifying the interfaces in the concerned templates.