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
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 /**
 * Auth Controller BaseAuthController
 **/
class BaseAuthController extends \Ubiquity\controllers\auth\AuthController{

     protected function onConnect($connected) {
             $urlParts=$this->getOriginalURL();
             USession::set($this->_getUserSessionKey(), $connected);
             if(isset($urlParts)){
                     Startup::forward(implode("/",$urlParts));
             }else{
                     //TODO
                     //Forwarding to the default controller/action
             }
     }

     protected function _connect() {
             if(URequest::isPost()){
                     $email=URequest::post($this->_getLoginInputName());
                     $password=URequest::post($this->_getPasswordInputName());
                     //TODO
                     //Loading from the database the user corresponding to the parameters
                     //Checking user creditentials
                     //Returning the user
             }
             return;
     }

     /**
      * {@inheritDoc}
      * @see \Ubiquity\controllers\auth\AuthController::isValidUser()
      */
     public function _isValidUser($action=null): bool {
             return USession::exists($this->_getUserSessionKey());
     }

     public function _getBaseRoute(): string {
             return 'BaseAuthController';
     }
}

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
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 /**
 * Auth Controller BaseAuthController
 **/
class BaseAuthController extends \Ubiquity\controllers\auth\AuthController{

     protected function onConnect($connected) {
             $urlParts=$this->getOriginalURL();
             USession::set($this->_getUserSessionKey(), $connected);
             if(isset($urlParts)){
                     Startup::forward(implode("/",$urlParts));
             }else{
                     Startup::forward("admin");
             }
     }

     protected function _connect() {
             if(URequest::isPost()){
                     $email=URequest::post($this->_getLoginInputName());
                     $password=URequest::post($this->_getPasswordInputName());
                     return DAO::uGetOne(User::class, "email=? and password= ?",false,[$email,$password]);
             }
             return;
     }

     /**
      * {@inheritDoc}
      * @see \Ubiquity\controllers\auth\AuthController::isValidUser()
      */
     public function _isValidUser($action=null): bool {
             return USession::exists($this->_getUserSessionKey());
     }

     public function _getBaseRoute(): string {
             return 'BaseAuthController';
     }
     /**
      * {@inheritDoc}
      * @see \Ubiquity\controllers\auth\AuthController::_getLoginInputName()
      */
     public function _getLoginInputName(): string {
             return "email";
     }
}

Admin controller modification

Modify the Admin Controller to use BaseAuthController:

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

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
3
4
5
6
7
8
9
 /**
 * Auth Controller BaseAuthController
 **/
class BaseAuthController extends \Ubiquity\controllers\auth\AuthController{
...
     public function _displayInfoAsString(): bool {
             return true;
     }
}

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

Change the AuthController Admin controller:

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

Customizing messages

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

 }
...
}

Self-check connection

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

Limitation of connection attempts

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

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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class PersoAuthController extends \controllers\BaseAuth{
...
 protected function hasAccountRecovery():bool{
     return true;
 }

 protected function _sendEmailAccountRecovery(string $email,string $validationURL,string $expire):bool {
     MailerManager::start();
     $mail=new AuthAccountRecoveryMail();
     $mail->to($connected->getEmail());
     $mail->setUrl($validationURL);
     $mail->setExpire($expire);
     return MailerManager::send($mail);
 }

 protected function passwordResetAction(string $email,string $newPasswordHash):bool {
     //To implement for modifying the user password
 }

 protected function isValidEmailForRecovery(string $email):bool {
     //To implement: return true if a valid account match with this email
 }
}
../_images/recoveryForm.png

Note

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.

Note

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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class PersoAuthController extends \controllers\BaseAuth{
...
 /**
  * {@inheritDoc}
  * @see \Ubiquity\controllers\auth\AuthController::has2FA()
  */
 protected function has2FA($accountValue=null):bool{
     return true;
 }

 protected function _send2FACode(string $code, $connected):void {
     MailerManager::start();
     $mail=new AuthMailerClass();
     $mail->to($connected->getEmail());
     $mail->setCode($code);
     MailerManager::send($mail);
 }
...
}
../_images/2fa-code.png

Note

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
1
2
3
4
5
6
7
class PersoAuthController extends \controllers\BaseAuth{
...
 protected function hasAccountCreation():bool{
     return true;
 }
...
}
../_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);
}

Note

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