Chapter: jAuth : authentication system
« jUrl: automatic urls | ^ Jelix components | jAcl2 : rights management » |
− Table of content
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 leavepassword_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 toon
to activate authentication persistencepersistant_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 sectioncoordplugin_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.