====== External authentication ====== By default, Dotclear 2 stores user names and passwords in its own database. That said, it can be useful to be able to use another data source for authentication. Dotclear 2 allows this pretty easily. ===== Preamble ===== In its configuration, Dotclear 2 can specify a constant parameter to define the name of the class that will be used for the authentication process. We just have to define the DC_AUTH_CLASS constant and give it the name of a class you'll create. ===== A new authentication class ===== At the same level that our configuration file, we'll create a file called **class.auth.php** that will contain the following code: class myDcAuth extends dcAuth { } In Dotclear configuration file, we'll add the following lines to the end of the file: $__autoload['myDcAuth'] = dirname(__FILE__).'/class.auth.php'; define('DC_AUTH_CLASS','myDcAuth'); At this stage, our Dotclear installation should keep working. For the moment we simply changed the authentication class and since our new class does nothing, nothing is changed. The authentication class must inherits from **dcAuth** to be used. ===== Scenario ===== For this tutorial, we'll suppose we have a XML-RPC Webservice that can check the validity of an identifier and its password and retrieve user's information. Here are the specifications of our fake authentication Webservice. Service URL is **%%http://example.com/auth%%** and it only has one method **auth.login**. This method gets two parameters: a **login** string for user's identifier and a **password** string for the password. It returns a **table** including user's information or raises an XML-RPC error if there is an error with username or password. Finally, we'll assume that our installation only contains one blog whom identifier is **default**. ===== Application ===== For our authentication service, the most important method might be **checkUser** (from dcAuth class) since this is where all the magic happens. This method can be called in different ways by Dotclear. It can be called with only the user's identifier. This allows to initialize the information in the class. It can be called with the user's identifier and a password. This allows not only to initialize the user's info but also to check the password. Finally, it can be called with an identifier, a **null** password and a verification key. This allows to check the user's session and to initialize it with a key. Here is what we're going to do: * If the **checkUser** method is called without a password, we forward it to the parent method. * If the **checkUser** method is called with a password, we check the password validity and we create or update the user in the database and finally, we forward it to the parent method without a password. Please note that **the user must exist in the database** for referential integrity reasons. It is very important to be able to associate posts (or other things) to a given user. It is also required to store the user's password in Dotclear database because it is needed by some operations. That said, it is possible to forbid a user to change his password. Here is the commented source code of our new authentication class: class myDcAuth extends dcAuth { # User cannot change his password. protected $allow_pass_change = false; # Password verificatin method. public function checkUser($user_id, $pwd=null, $user_key=null) { # No password, we call the parent method. if ($pwd == '') { return parent::checkUser($user_id,null,$user_key); } # If a password is given, we check it with the # XML-RPC auth.login method. try { # We start a transaction and open a cursor on Dotclear user # table to create or modify the user. $this->con->begin(); $cur = $this->con->openCursor($this->user_table); # We call the password verification method. # In case of error the process stops and raises an exception. $client = new xmlrpcClient('http://example.com/auth'); $info = $client->query('auth.login',$user_id,$pwd); # We define the password, it is inserted in any case. $cur->user_pwd = $pwd; # If the user exists, we'll simply update his password # in Dotclear user table. if ($this->core->userExists($user_id)) { $this->sudo(array($this->core,'updUser'),$user_id,$cur); $this->con->commit(); } # If the user does not exist, we create him. # To allow him to connect, we need to give him at least the # "usage" permission on the "default" blog. else { $cur->user_id = $info['login']; $cur->user_email = $info['email']; $cur->user_name = $info['name']; $cur->user_firstname = $info['firstname']; $cur->user_lang = $info['lang'] ? $info['lang'] : 'en'; $cur->user_tz = 'Europe/Paris'; $cur->user_default_blog = 'default'; $this->sudo(array($this->core,'addUser'),$cur); $this->sudo(array($this->core,'setUserBlogPermissions'), $user_id,'default',array('usage'=>true)); $this->con->commit(); } # The previous operations went smoothly, we can now call the # parent method to initialize the user in $core->auth object. return parent::checkUser($user_id,$pwd); } catch (Exception $e) { # In case of error, we cancel the transaction and return "false". $this->con->rollback(); return false; } } } Note the use of **allow_pass_change** property that forbids the user from changing his password. As you can see, the process is fairly simple to initialize. A few remarks though: * It is mandatory to store the user's password in Dotclear user table because Dotclear might need it for some operations. * It is of course possible to give extra parameters to this piece of code, like the blog and permissions that will be assigned to the user if he doesn't exist yet. * You can create **afterAddUser**, **afterUpdUser** and **afterDelUser** methods in your authentication class. These methods will be called respectively after the creation, the update or the deletion of a user. This simple authentication example shows what it is possible to achieve. You can then authentify a user from any source such as a LDAP server, a forum user table, or anything else taking an identifier and a password. Finally, the dcAuth class can achieve a truly SSO-like unique authentication using these session verification and authentication form change functions.