Table of Contents

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.

Important:

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:

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:

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:

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.