DRUPAL

Drupal 6 external database authentication with roles

Derrick Bowen's picture

I talked to Kyle in class the other day about having drupal do user authentication through an external server. All the online tutorials about it show how to do it in Drupal 5, but they changed the APIs to be “more flexible” in Drupal 6, so it is totally different. I’ve got it mostly working now, but I’m run into a little snag and though I’d ask the island for input.

Basically I am making a user guide to accompany our main site. Our site is highly configurable, so we want to not only authenticate the users, but also get their roles from our other website. That way we will only show the pages that apply to them. I’ve got the authentication working great, but roles are doing something weird. I am placing them in the global $user object, and if I do a var_dump on it right away, I see them there, right how they should be. But if I do a var_dump on it later, they have all disappeared except for “authenticated user”. I imported the roles from our server separately, adding 1000 to the role ids to avoid conflicts.

This is my first time coding a drupal module, so any help you could give me would be appreciated. I’ll post the important parts of my code below. If you notice any other glaring problems be sure to share :)

<?php
function cblogin_form_alter(&$form, &$form_state, $form_id) {
  if (
$form_id == 'user_login' || $form_id == 'user_login_block') {
    
// Call cblogin_login_validate() to validate the submission ( 'user_login_name_validate'  & 'user_login_final_validate' are the drupal standard validators.)
     
$form['#validate'] = array('user_login_name_validate','cblogin_login_validate','user_login_final_validate');
  }
}


/**
* Login form _validate hook
*/
function cblogin_login_validate($form, &$form_state) {
  global
$user;

 
// Get username and password from form
 
$username = $form_state['values']['name'];
 
$pass = $form_state['values']['pass'];
 
$form_values = $form_state['values'];

// Name and pass keys are required.
// The user is about to be logged in, so make sure no error was previously
// encountered in the validation process.
 
if (!form_get_errors() && !empty($username) && !empty($pass)) {

    
// Does username exist in our clients database?
     
$cbconn= pg_connect("dbname=db user=u password=p host=h port=5432");
    if (!
$cbconn) {
        exit;
    }
   
$username = pg_escape_string($username);
   
$pass = pg_escape_string($pass);

         
// make a select statement that gets the right columns from the external db and make them look like drupal ones.
     
$cbresult = pg_query($cbconn, "SELECT personid + 30 as uid, username as name, statustypeid as status from userinformation WHERE username = '$username' AND password = '$pass' AND statustypeid = 1");
    
// process results
   
if ($row = pg_fetch_object($cbresult)) {

        global
$cblogin_authenticated;
       
$cblogin_authenticated = TRUE;

       
$user = cbuser_load($row, $cbconn);
   
//var_dump($user);
       
cblogin_userinsert($user->uid,$username);
       
user_authenticate_finalize($form_values);

        return
$user;
    } else {
    
// if external validation fails then it will do the normal drupal thing
    
return user_login_authenticate_validate($form, &$form_state);
    }
  }
}

?>

/**
* replacement for user_load
*/
function cbuser_load($row, $cbconn) {

    global $user;
    $user = drupal_unpack($row);

    $user->roles = array();
    if ($user->uid) {
      $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
    }
    else {
      $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
    }
    // gets roles for the user from the external db, translates them and then puts them in the user object
    $result = pg_query($cbconn, "SELECT r.roleid +1000 as rid, r.rolename as name from role r INNER JOIN userrole ur ON ur.roleid = r.roleid WHERE ur.personid = $user->uid -30;");

    while ($role = db_fetch_object($result)) {
      $user->roles[$role->rid] = $role->name;
    }

  return $user;
}

/**
* Adds the user to the drupal db
*/
function cblogin_userinsert($uid,$username) {
//INSERT INTO {users} (uid,name) VALUES (%d,'%s');
// a new user is being added; check if we did authentication,
    global $cblogin_authenticated;
    if ($cblogin_authenticated) {
      // We use postgres, so I manually added a INSERT or UPDATE function (called user_merge) to make this work best.
      $result = db_query("SELECT user_merge(%d,'%s')", $uid, $username);
    }
}

5 comments

Also for the external users it is setting the "home" page as the: "Welcome to your new Drupal website! Please follow these steps to set up and start using your website: Configure your website..." page. This may be related, or it may be a session/user variable that I haven't been setting.
On the second issue -- have you set the default front page at "admin/settings/site-information"? On the first issue -- the user object is loaded on each page load -- no global objects in php. So on subsequent page loads, drupal isn't loading your special stuff, just what's in the Drupal users table. So you need to use hook_user to load your roles from the other database (http://api.drupal.org/api/function/hook_user). -- Kyle Mathews
Here's some sample code for implementing hook_user as how Drupal hooks + $op work may or may not be obvious on first blush. <?php/** * Implementation of hook_user(). */function your_module_user($op, &$edit, &$user) {  if ($op == 'load') {    // Move code for loading roles here. The $user object is already loaded by the core user_load function so you just need to add your roles.  }}?> -- Kyle Mathews
I thought they would save the user in a session variable or something. Okay. I got the start up page working now, but the roles still aren't loading even after I implemented the hook. I think for now I'll just have it add roles for the user into drupal's native database when the user logs in, but that seems like a suboptimal solution. I put in the cblogin_user function like you suggested, and if I do a "var_dump($user);" at the end of that function, then at the top of the page I see all the roles loaded like they should be. I created a php page/node that does the same thing, however, and only the authenticated user role shows up. And I can't view any of the pages for those roles. any other suggestions? Oh and thanks so much, you're the best. -Derrick
I had it delete from the users_roles table for that user, and then insert the current permissions, and it's working. This works for our uses since we only need 3 users that are drupal unique, but it probably wouldn't work for other people.
Please register or login to post a comment.
Syndicate content