Quick links: Content - sections - sub sections
EN FR
The page corresponding to the latest stable release can be seen in the Jelix 1.8 Manual
Jelix 1.9.0-dev

Chapter: jAuth : authentication system

« jUrl: automatic urls ^ Jelix components jAcl2 : rights management »
Switch to language: FR

The Jelix authentication system handles only one thing: logins, passwords, and users.

Relying on drivers to access user data, you can use a database, a LDAP directory, or any other way to access data. As for now, there is a database driver, an LDAP directory based driver, and a driver for an external class.

The authentication system relies on several things :

  • a plugin for the jelix coordinator, auth, verifying if authentication is done for the actions when it is necessary
  • a jAuth class, allowing to do different operations on authentication and logins handling. This class implements a driver system.
  • a jauth module offering a controller and some default templates. It is not mandatory and you can define your own authentication module.
  • an object stored in the session, containing information about the user. It is provided by the driver. This can be a DAO object, a simple class, and so on.

To use the authentication system, you must install at least the plugin for the jelix coordinator, and configure it.

The role of the Auth plugin:

  • Check authentication
  • Control session timeout (optional)
  • Control authentication persistance (optional)
  • Specify which driver to use
  • Specify parameters for the driver (dao for jAuthDb, cn/sn/uid for ldap driver etc)
  • Indicates what to do if not authenticated

Plugin installation

To activate it, if you want to use ressources of the module jauth (controllers, zones...), install the module, else install the plugin by hand.

By installing the module jauth

Use the command module:configure of jelix to install the module:


$ php dev.php module:configure jauth

It will activate the module, and create a new file var/config/index/auth.coord.ini.php, which is the configuration of the plugin auth.

Then launch php install/installer.php.

By hand

Copy the file lib/jelix-modules/jauth/install/var/config/auth.coord.ini.php into the configuration directory of your entry point, for instance app/system/index/auth.coord.ini.php.

You should then add this line into the coordplugins section of your application configuration file:


[coordplugins]
auth = "index/auth.coord.ini.php"
  • *Note on the plugin declaration**: if you use several coordinator plugins, the order of declaration in the configuration is important. So if the plugin "auth" is in first, then other plugins won't be called if it asks a redirection. So you should declare the "auth" plugin after plugins that don't need authentication.

You can learn more about plugins here.

Authentication core configuration

To configure the authentication system, edit the file auth.coord.ini.php.

Selecting a driver

You must assign the driver option with a driver name and fill a section containing the driver parameters.


driver=Db

It is possible to indicate the driver into the main configuration (mainconfig.ini.php, localconfig.ini.php or the configuration file of an entry point), into the section coordplugin_auth.


[coordplugin_auth]
driver=Db

Read the jAuth drivers documentation to know which driver you can use and how to activate it.

Function to hash password

Since Jelix 1.4.1 (and 1.3.4, 1.2.10), there are two hashing system to hash your password in the storage. Jelix 1.4.1 and higher provide indeed a more secured method, using the new password API of PHP 5.5.

Old deprecated hashing system

By default, the function to hash password is sha1, (in jelix 1.1 and lower, it was md5) but it's possible to use an other function which accepts a string in parameter, and returns the corresponding hashed string.

Note that nowadays, sha1 and md5 are not considered secured because of the power of computers. If possible use better hashing methods like provided by the new hashing system of Jelix 1.4.1.

To indicate the hash function, indicates its name into the password_crypt_function option, in the section of the driver.

The function could accepts other parameters, like a salt value. To indicates that the function accepts other parameters, you should precede the function name by a number and a ":":

  • "1:functionname": the function accepts a salt value as first parameter, and the string to encrypt as second parameter. The salt value should be filled into the password_salt option
  • "2:functionname": the function name accepts an array containing all options of the driver section, and the string to encrypt as second parameter. So the function can deal with any options stored in the configuration.

To create your own function, you can write it into its own php file, and include it into the application.init.php file of your application.

Here is an example to use the sha1 php function with a salt value. Here is the function (this function is already available in jelix and declared with the plugin):


function sha1WithSalt($salt, $password) {
    return sha1($salt.':'.$password);
}

In the configuration of the plugin:


 driver=Db
   
 [Db]
 dao = "mon_dao"
 password_crypt_function = "1:sha1WithSalt"
 password_salt = "here_your_salt_value"

New hashing system

This system is provided since Jelix 1.2.10/1.3.4/1.4.1 and use a new PHP 5.5 API. It uses by default the bcrypt method.

The configuration is simple. You should have to parameters in the global section of the jauth configuration (so outside sections like [Db]):

  • password_hash_method : indicates the hash method to use. Only one is possible for the moment, BCRYPT. You should then set it to "1". It the value is "0" or empty, the new hashing system is not used.
  • password_hash_options : a string containing a list of "key=value;". These are options depends of the hash method. For BCRYPT, you have a "salt" and a "cost" option (But it is recommended to use default values, so to leave password_hash_options empty).

The new hashing system always generates a random salt for each stored password (unless you indicate one in password_hash_options, but it is less secure). And the salt is stored with the password, this is why you need a bigger password field in your database, than the old hashing system.

Migration

If you want to upgrade an existing application that is using the old hash system, and you would like to use the new hashing system (which is highly recommended!), you should:

  • enlarge the password field (password) in your database, to 120 characters
  • modify the corresponding DAO (if you don't use jelixuser of jauthdb module), to indicate this new size.
  • set the configuration with password_hash_method=1

Each user who will authenticate itself, the hash generated with the old hashing system will be replaced by a new hash. This is why you should keep the values of password_crypt_function and password_salt, else users couldn't authenticate themselves.

  • *Warning: Do not do this migration with a shared database**, used by several application in which the migration has not been done. Users could not be authenticated, since new hash password are not compatible with the old hashing system (and vice-versa). And you could not return to the old hashing system, unless you made database backup.
  • *Do a backup of the user table before the migration**.

Timeout

timeout option indicates inactivity duration to invalid authentication. Its unit is minutes. If you set it to 0, there is no timeout. And the authentication session will live throughout the browser session, or the php session (configured into the php.ini file).

Control authentication in each action

Each action can declare if it needs an authentication. It is done through authentication plugin api. If all actions needs an authentication then just set auth_required to on in auth.config.ini.php file. Whereas an off specifies the contrary.


auth_required=on

In any case, you'll certainly have to deal with exceptions. Imagine you have an home page which doesn't need authentication but every other page requires one. Those exceptions are declared in controllers using auth plugin parameters.

Example:


class xxxCtrl extends jController {

    public $pluginParams = array( ... );

}

Here the auth plugin is configured to check for authentication in every action of this controller (* rule) except for index action (possibly your home page).

On the contrary, you can tell auth plugin to check for authentication only for some actions such as index and secret. See below:


class xxxCtrl extends jController {

    public $pluginParams = array(
        '*'=>array('auth.required'=>false),
        'index'=>array('auth.required'=>true),
        'secret'=>array('auth.required'=>true),
     );
}

See coordinator plugins documentation for an in-depth view of $pluginParams usage (remember that auth plugin is a coordinator plugin).

Application behavior if authentication does not succeed

If authentication does not succeed and current action needs it, auth plugin reacts regarding to on_error option value.

If on_error=1, auth plugin will generate an error message configured by error_message option.

If on_error=2, auth plugin will execute action selected by on_error_action option. It can be a controller action of auth module (default case) or any action of any other module. Basically this action will ask for login/password couple but you can imagine other scenario.

Authentication persistence

jAuth offers a way to create authentication persistence. In other words, a user will authenticate once and on every other visits, he will be automatically authenticated. This is done by a cookie which stores some user information that are encrypted.

To configure persistence use the parameters below:

  • persistant_enable: set it to on to activate authentication persistence
  • persistant_crypt_key: this one is mandatory. Since 1.6.8 it is filled automatically by the installer, with a random key, and is stored into the section coordplugin_auth of the localconfig.ini.php file or in the liveconfig.ini.php file (1.6.18+). It will be used as an encrypt key for cookie datas. If you change key value, be aware that all users will have to re-authenticate to benefit of persistence.

Other less important parameters:

  • persistant_cookie_name: cookie name. Default : "jelixAuthentificationCookie".
  • persistant_duration: validity time (in days) of persistence. Default is one day.
  • persistant_cookie_path: cookie path. Default empty : cookie will be stored with basePath general config value.

jAuth module: default controllers

The jAuth module implements generic controllers. You can use them to control login, logout step. Alternatively, jAuth module offers also zones and templates. The latter is useful if you need to add login/logout option to one or more of your own controllers.

If you want other features, like registering and clearing account forms, changing passwords or lost password forms, you may use the jcommunity module. See the jCommunity website.

Classic configuration

When using the jAuth module, one can add/modify options to suit his neeeds. An example of auth.plugin.ini.php file:


  on_error_action = "jauth~login:out"
  after_login = "myapp~default:index"
  after_logout = "jauth~login:form"
  on_error_sleep = 3

The parameter on_error_sleep defines defines a duration. This is the amount of time in seconds, where authentication form is inactivated if user has not succeeded it. However it is not recommended to activate it, as it may facilitate a DDOS attack.

For after_login and after_logout, watch below.

Templates of the module jAuth can be easily customized if you overload them. Just copy and edit them in var/themes/default/jauth/. More about themes here.

Redirection options

Auth plugin defines some config options to specify redirections on login/logout steps, used by the jauth module.

Parameters after_login and after_logout must content some selectors to actions, to which a redirection will be made, if login succeeds for the first one, and if the logout succeeds for the second one. There are required. (else you will have some errors on a bad redirection).

In a authentication form or a logout url, you can add a parameter indicating to which page jelix should go after a login or a logout. This parameter should be named auth_url_return and should contain the url of this page. If you want to use it, you should activate enable_after_login_override and/or enable_after_logout_override (set them to on or off).

Setup of URLS significants

jauth module provides some urls mapping, to declare into your app/system/urls.xml file. Add the line:


<url pathinfo="/auth"     module="jauth" include="urls.xml"/>

Using your own controller

Authentication can be done using your own controllers of course. You'll have to dive in jAuth API et call its static methods to check users login/password, and connect or disconnect them.

In this case, of course, you may not install the jauth module...

jAuth class

jAuth is the main class for authentication. All its methods are static. It manages users, connect or disconnect them. Its methods must be called to authenticate either by jAuth module or in your own controllers. Read its reference description.

Some methods needs a user object as an argument. jAuth itself provides it to you. It contains user datas and has no defined class. Its type depends on the driver used. (In a Db driver, users object and datas will certainly be structured by a DAO). The only requirement on this user object is that it must have a login and a password field.

jAuth shouldn't be derived from. Its driver based system should cover all authentication formats.

Connecting / Disconnecting a user

To login/logout a user, you should call the methods login() and logout():


   // login
   $ok = jAuth::login('the_login', 'the_password');
   
   // logout
   jAuth::logout();

You can also use the jAuth::setUserSession($login) method to set the user without verifying the password. It is useful to implements a stateless web API with JWT for example.

After calling login() and if this is a success, jAuth stores some informations about the user in the session. These informations are in an object, that you can retrieve with getUserSession():


  $user = jAuth::getUserSession();

The class of this object depends of the driver. For the "db" driver, this will be a DAO record, from the DAO indicated in the configuration of jAuth.

You can know if a user is connected with the method isConnected():


  if (jAuth::isConnected()) {
      // ok, a user is connected
  }

To login the user in a persistant manner (he will be recognized automatically when he go on your application, even if his session has been destroyed), you have to add the true value as third parameter, when calling the login() method.

You can also just verify a login/password, without "connecting" a user :


  $ok = jAuth::verifyPassword('the_login', 'the_password');

Read the reference documentation of jAuth to know about other methods.

Creating a user

To manage user, you have to call jAuth too. To create a user, you need to retrieve an object for the new user, to fill it with some informations if needed, then to ask jAuth to save it.


   // retrieve a new object for the new user
   $newUser = jAuth::createUserObject ('the_login', 'the_password');
   
   //add some information, for example the birthday date.
   $newUser->birthday = '1980-01-01';
   
   // let's register the new user
   $ok = jAuth:saveNewUser($newUser);

Modifying a user

To modify informations of a user, you have to retrieve the object corresponding to the user, to modify it, then to ask jAuth to save it.


   $user = jAuth::getUserSession()
   // or
   $user = jAuth::getUser('his_login');

   // modification example
   $user->birthday = '1980-01-02';

   // save
   jAuth::updateUser($user);

Notice: if the modified user is the current connected user, then informations in sessions are also updated.

Don't use this process to modify the password! Because you don't really know how the password is encrypted, or how it is stored. It depends of the jAuth configuration and of the driver. So, to change the password, use the method canChangePassword() and changePassword(). The first one allow to know if the password can be changed. Some authentication protocol, like SAML, oAuth etc, may not allow to change the password, as it is not accessible to the application.


if (jAuth::canChangePassword($login)) {
   jAuth::changePassword($login, 'the_new_password');
}
else {
    $reasonMessage =  jAuth::getReasonToForbiddenPasswordChange();
}

Calling getReasonToForbiddenPasswordChange when canChangePassword() fails, allows to display the reason to the user (method existing since Jelix 1.7.11).

You can use the method jAuth::getRandomPassword() to generate a random password.

Other methods

To delete a user, use jAuth::removeUser() :


   jAuth::removeUser('his_login');

To retrieve a list of users, use jAuth::getUserList():


   $list = jAuth::getUserList();

The result is an iterator over a list of objects, each objects representing a user (like the object you retrieve with getUser()).

Events

About every jAuth methods emit events. As a result, modules can be aware of authentication status and do some specific action related to user.

  • AuthNewUser : a new user has been created
  • AuthCanRemoveUser : ask if deletion of a user is allowed
  • AuthRemoveUser : a user has been removed
  • AuthUpdateUser : current user has been updated
  • AuthCanLogin : ask if user can connect
  • AuthLogin : a user has logged in
  • AuthLogout : a user has logged out
  • AuthErrorLogin : a user authentication has failed
  • AuthBeforeLogin : apply some process before a user authentication
  • AuthChangePassword (since Jelix 1.6.17): the password of a user has changed.

In response to some of these events, you can set some data:

  • for AuthCanRemoveUser, set canremove to true or false
  • for AuthCanLogin : set canlogin to true or false
  • for AuthBeforeLogin : set processlogin to true or false (false to cancel the login)

Exemple of an event handler on "AuthCanRemoveUser":


function onAuthCanRemoveUser  ($event)
{
    $login = $event->getParam('login');
    if($login == 'admin)
      $ok = false;
    else
      $ok = true;
    $event->Add(array('canremove'=>$ok));
}

See the chapter about events to know more.