Using an external data source for Drupal user authentication and login

You can use any database table to validate users for your Drupal site. In this case I'm validating users against a database of clients. This client database is maintained outside of Drupal. It's a simple two step process, and just needs a couple of PHP functions in a custom module:

Step One: hook_auth() puts our own authentication code into the Drupal authentication process, we return true to validate a user, or false if the credentials don't match. If we have successfully authenticated someone then we also set a global variable that we can check in the next step.

Step Two: hook_user() allows us to put our own code into the user creation process. When a new user is authenticated Drupal will create a local user object for them. We hook into this process to fill in their details.

<?php
/**
* Implementation of hook_auth()
*/
function modulename_auth($username, $pass, $server) {
 
// Does username exist in our clients database?
 
$results = db_query("SELECT login, password FROM clients WHERE login = '%s' AND password = '%s'",$username,$pass);
 
$row1 = db_fetch_array($results);
  if (
$row1) {
     global
$modulename_authenticated;
    
$modulename_authenticated = TRUE;
     return
TRUE;
  }
  else {
     return
FALSE;
  }
}

/**
* Implementation of hook_user()
*/
function modulename_user($op, &$edit, &$account, $category = NULL) {
  switch(
$op) {
     case
'insert':
       
// a new user is being added; check if we did authentication,
       
global $modulename_authenticated;
        if (
$modulename_authenticated) {
         
$result = db_result(db_query("SELECT email FROM clients WHERE login = '%s'",$account->name));
         
// Set email address in the user table for this user
          // You might want to set up some other parts of the user record here too
         
db_query("UPDATE {users} SET mail = '%s', name = '%s' WHERE uid = %d", $result, $account->name, $account->uid);
        }
  }
}
?>

I am a total Drupal noob. Where can I add this code without going the module path?

So it just overwrites those two methods.

I did a external authentication against our MS SQL user table with something like this and it actually worked. But after login there showed several warning messages, as discussed in drupal.org/node/208908.

Any suggestions? Thanks a lot.

The warning messages were gone once Drupal was upgraded to the 5.8 release.

Again, thanks for the posting.

Dan

I'm looking to do something very similar to what you're explaining here, thank you very much! I have a few questions though. I don't see how you pick a server and a database in the code. I see that the input for the function modulename_auth contains $server, but I don't see where I pick the database I want to look into. I don't understand how it works with choosing the server either...
I installed and enabled the module you're describing, changing the SQL query but the users are still picked from the old location. Do I change the whole 'user' module too?
Thank you for your time and response.

Vitek

I have made this (Drupal 5.7) but wanted to point out that in my case Drupal didn't add the username in the users table as it should after I return true in the hook_auth. Instead it get an error in core user-module user_access() where it tries to implode an empty array of roles. As far as I can see it might be a Drupal-bug as there are no roles because the user is not loaded, and it is not loaded because thats why it is being added in the first place...
Let me know if someelse have run in to the same issue.

I'm looking to do this on one of my drupal sites. I've been using drupal for years now, but am only now getting into module development. Could you please further detail how to make a custom module of this to implement?

Thanks =)

Ryan

To create this as a module, you need two files:

modulename.info
modulename.module

You save these files in a folder called modulename somewhere within the Drupal module include path. For example in /sites/all/modules/modulename

The first of these files contains the basic module information. This can be as basic as this...

name = modulename
description = what your module does
package = Other

You then put the PHP code for the hooks you wish to implement into the *.module file. Hooks are documented on api.drupal.org. All your hooks start with the module name, as per the config file, and your filenames. For this example the content of the modulename.module file would be as follows:

<?php
/**
* Implementation of hook_auth()
*/
function modulename_auth($username, $pass, $server) {
 
// Does username exist in our clients database?
 
$results = db_query("SELECT login, password FROM clients WHERE login = '%s' AND password = '%s'",$username,$pass);
 
$row1 = db_fetch_array($results);
  if (
$row1) {
     global
$modulename_authenticated;
    
$modulename_authenticated = TRUE;
     return
TRUE;
  }
  else {
     return
FALSE;
  }
}

/**
* Implementation of hook_user()
*/
function modulename_user($op, &$edit, &$account, $category = NULL) {
  switch(
$op) {
     case
'insert':
       
// a new user is being added; check if we did authentication,
       
global $modulename_authenticated;
        if (
$modulename_authenticated) {
         
$result = db_result(db_query("SELECT email FROM clients WHERE login = '%s'",$account->name));
         
// Set email address in the user table for this user
          // You might want to set up some other parts of the user record here too
         
db_query("UPDATE {users} SET mail = '%s', name = '%s' WHERE uid = %d", $result, $account->name, $account->uid);
        }
  }
}
?>

You will need to adapt the actual authentication code to match your requirements.

Does that make sense?

just wondering, since the $user object doesnt have alot of things for this users session when signing in for the first time, like user's email which also might be in the old database, how/where do you prefill it? maybe an array to global in auth() or in insert $op in user(). but like what should be put into the $user array if so

also are there any cercumstances where pretend auth() might just authenticate user based on something other than user/pass. like IP address, then does anything get inserted into the user database automatically? cause it seems like it does, and then insert $op you can add onto it.

just curious for wierd authentication schemes like by ip address.

I tried this, but had no luck.

Does this force the normal login form to use your custom authentication? Or do you need to make your own form?

The normal login process will call your custom authentication when the built in login process fails.

The process is as follows:

  1. user submits login information
  2. drupal checks if user is blocked, if so message is displayed and login fails
  3. drupal then attempts to load the user locally
    • if this is successful then the user object is loaded and drupal fires the load and login hooks. the user is then directed towards the 'user' page.
    • if user is not found locally then drupal will call external authentication

External authentication involves firing the auth hook, and on success either validating an existing user or creating a new user object. When a user is created this way a record is stored in the authmap table that confirms which module validates this user login.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options