Getting a valid user from Drupal 7 for an external application or website.

While recently working on some projects I got to thinking about how I am using various “bridging” modules for a Drupal 7 website to other applications and websites that are linked to it, for example the Drupal -> MediaWiki Auth Bridge, which links an installation of MediaWiki to an Installation of Drupal for a “single sign-on” experience.  If you have a Drupal account and an active session, you are logged into the Wiki, and based on privileges in Drupal, you may or may not have editing privileges on the wiki.

There are many other examples of this and things like OAuth that intergrate logins between varous sites and services.  Generally there are 3 methods of handling this authorization:

  1. Session checking: This is a method in which you are required to login to the Drupal website before accessing another service. The service checks your browser cookies for valid drupal sessions and you can compare against valid active tokens. This method is not without flaws, session spoofing being one of them.
  2. Checking the drupal user database directly. Your other site/service could query the MySQL (or Postgres) database that Drupal is running on with the user/pass combo, the crypto methods are published and open source, so you could write a script that would check a user/pass combo against the encrypted password in the DB.  Flaws of this method obviously, making calls directly to the database, however if you’re comfortable writing that and knowing how to avoid SQL injection, and handling password encryption that is actually well documented, then this isn’t a bad option. In fact there are several cut and paste versions of this method available that work really well.
  3. Using a drupal module: There are many modules to extend Drupal beyond Drupal, like Oauth and social media hooks, bridges from drupal to other popular sites/services.. these are easy to install and configure even for beginning developers as it is all handled right within the Drupal CMS.

However none of these options were going to work for me. I am working on a node.js client->server application that requires a connection to a Drupal 7 user.  Session checking isn’t going to work out because the connecting application may not be from a browser that can be logged into the drupal site.  I also don’t have much experience connecting a node.js application up to a Postgres database, so option 2 was out.  Option 3 just didn’t fit my needs either as this is a very custom application, and modules generally service existing sites, services and protocols.

So I opted to just ask my Drupal 7 installation. I figured if you can send your user/pass to your drupal login page then, it has a mechanism to authenticate you (by ultimately querying the database and then handing you a session token).  So it seems just logical to me that you could ask drupal and get a response from an external application or service if the user/pass was valid.  A bit of research and tinkering together some scripts I found online got me this:

<?php
/* 
 * SAMPLE Drupal 7 User/Pass Check PHP Script
 * Place this script in your drupal website anywhere like mysite.com/auth/checkauth.php
 */

// CONFIGURE THIS: the DRUPAL ROOT to the full directory of your drupal installation
define('DRUPAL_ROOT','/home/user/public_html/');

// CONFIGURE THIS: relative to the location of this script, where is the includes/bootstrap.inc file
require_once '../includes/bootstrap.inc';

drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
global $user;

// Get POST data
$user = $_POST["user"];
$pass = $_POST["pass"];

if (isset($_POST["user"]) && !empty($_POST["user"])) {
    $account = user_load_by_name($user);
    if(!$account) {
        // bad username
        echo "false";
    }
    else if(!user_authenticate($user, $pass)){
        // bad password 
        echo "false";
    }
    else {
        // instead of echo true/false we could send headers like accepted/rejected
        echo "true";
    }
}
else {
    // the user field post data was not sent, let's return a 404 
    header("Status: 404 Not Found");
}
?>

 

This bit of PHP will take a POST request with post data of user and pass. It includes the drupal bootstrap and uses the functions “user_load_by_name” and “user_authenticate” to simply spit back whether or not the user is valid.  This is just an example, it might be more appropriate and technically safe to simply return headers. You might consider leveraging some flood control to keep people from using this to brute force a user/pass combo.

Once you’ve confirmed a user/pass is valid you can then do your own session handling and your application can leverage a drupal user account for it’s validation method without requiring a login to the actual site or directly querying the database.

 

Leave a Reply

Your email address will not be published. Required fields are marked *