Hi,

I have an existing non-Drupal web app, with its own user repository and login process. I now need to deploy a Drupal site, for use by the same users, that will be automatically accessible to any users who have already logged-in to their original web app account.

The original web app provides a SOAP API, and some PHP includes which allow me to ask the main web app "is the current user logged in". This function will either return an array of the user details (username, real name, email etc) if the user is logged-in, or will redirect to the original web app login page otherwise.

I've been instructed to invoke the "is the current user logged in" function at the point that any page is requested from my Drupal app. Which hook should this call be placed in to ensure it is invoked for every page requested, before any content is sent back to the HTTP stream?

The other fundamental question is how I 'fake' the login to Drupal once the original web app has authenticated the user and returned the array of user details? I just can't work out how to take the user ID returned by the "is the current user logged in" function, and use it to log the user in to the Drupal app... as a cookie surely needs to be set, as it would be if logging in normally via the Drupal login page? Or do I just need to override something that deals with checking the request for the cookie - and just replace this check with the call to "is the current user logged in"?

Any help very very gratefully received!

Cheers,
Steve

Comments

minutes2memories’s picture

hey steve,

i have a similar application scenario. to solve the second part of your question (first!), i just log my users into my remote application and then post to the drupal login with the users' details. just using the form parameters i grabbed from the login screen. so that's easy enough, altho the new registration part is harder but follows the same principle. this then logs them properly into drupal and all is good (unless i'm misunderstanding your question...)

the first part of your question, regarding redirecting to a remote login page upon serving each and every info page has got me stuck too. my drupal site has some restricted content which, if i try to access it without being logged in, just gives me a link to the drupal login (index.php?q=user). what i want is to modify this behaviour so that instead of showing the 'You need to be logged in to view this item" message and the link to drupal login, it redirects to my external login page instead.

i have read some stuff on using the error 403 redirect and have tried that but it would appear that this is a different category as i still get the same message back and can't seem to invoke the error 403 behaviour.

anyway, if anyone has any ideas, they'd be appreciated, otherwise i'll keep looking and report back shortly.

cheers.

wonza’s picture

How did you "post to the drupal login with the users' details." ?

Thanks! :)

Hannu’s picture

I would be interested in learning that, too. Thanks.

olafke’s picture

I did the same thing using the user_authenticate function which takes the $user->uid and the password as parameters. Because the user is already authenticated my my LDAP at this point I check whether the user exists in my Drupal DB, if yes I use the user_authenticate with a dummy password. If the user is not in the Drupal DB I create him (again with a dummy password) and then do a user_authenticate

speakaboos’s picture

I am in a similar situation and would like to automatically log-in my users to a drupal site. I also want the users to log in through the main application and not through drupal. Would love to hear if you have any solutions.

Thanks.

motoservo’s picture

I wish someone could post a really detailed explanation on how to add Drupal into a site that already has its own user registration and login application.

dc-bob’s picture

I have the same problem, and would really appreciate an answer.

I have a system where users are automatically logged in by the framework where my web application is, so I get e.g. the user id automatically and I don't have to worry about sessions management or user management.

What I'd like to have from Drupal is that there'd be a way to programmatically "log in" from my web application. The goal is that users would transparently use Drupal without even knowing it's there.

rola_51’s picture

I've finally found a way to do that, after a question posted in http://drupal.org/node/264906. I replicated the user table in Drupal with data from the other app, and wrote a script to be ran with cron to keep things in sync. Not very clean, but it works.

This is the code I used, installed in the root drupal directory test script (but a module with this will probably be the rest of the solution):

include_once './includes/bootstrap.inc';
global $user;
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);  //  not sure if this is the bootstrap phase required

// the following variables are from the "other" non-drupal database
$name = 'aUserName';
$pass = ('aPassword');

$user=user_authenticate($name, $pass);
if ($user)
    header  ("Location: http://mydrupalsite/?q=user/".$user->uid);   // goes straight into Drupal, fully logged.

Really simple in fact.

However, I have another concern: The code above works because I know the original password, but in my "other" database I have it md5 encoded. Any suggestion anyone so I can use the encoded password?

flexvixon’s picture

Could this be used from a sub domain, or at least, could the script be run from a directory other than drupal root?

drupalexpert_amit’s picture

This is quite an interesting topic. Many developers come across issues with multiple drupal versions in dealing with external authentication.

The following code works well in almost all implementations:

<?php
require_once 'includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
global $user;

$userName = $_REQUEST["user"];
$password = $_REQUEST["passwd"];
$account = user_load(array('name' => $userName, 'pass' => $password, 'status' => 1));
$user = $account;

if($user->uid > 0)
echo 'login successfull';
else
echo 'login failed';


?>

Regards,
Amit
Email: drupalexpertamit@gmail.com

sportsmaniac’s picture

Sorry, I am a drupal greenhorn ;) Where do I have to put this code?

Regards,
Martin

drupalexpert_amit’s picture

Put the above code in a php file in your drupal directory. e.g. testlogin.php

Then you can call this file by giving it user input variables as : "user" and "passwd" using either GET or POST variables.
e.g. http://www.domain.com/testlogin.php?user=testusername&passwd=testpass

If the above user/pass exists then you will get a "success" message.

Additionally you can invoke any of the drupal's modules or fetch any user specific info once you have logged in a user sucessfully.

Hope that helps...

Regards,
Amit
Email: drupalexpertamit@gmail.com

EvanDonovan’s picture

Thanks for the code, Amit. Looks like it could be very useful. Unfortunately, in our case, we have a JSP-based website which we want users to be able to log in from. Are there any solutions which would work in that case?

Would it be possible to add this page to the Drupal site and then have the JSP site POST these items , then redirect back to the homepage of the JSP site?

Online Publications Editor,
UrbanMinistry.org
http://www.urbanministry.org/user/evandonovan

Nonprofit / EdTech Mentor
http://drupal.org/user/168664

tejuspratap’s picture

Hi I am using drupal 6. I am using the following code for remote login in a file called remotelogin.php. The user has to send His "username" via a POST form submit.
After authentication the user is redirected to the drupal front page.
The problem i am having is that after login (after clearing all cookies in browser) the first redirect to the front page shows that the user has not lgged in. But if I try the second time without clearing the cookies then the user is shown as logged in. The code that I am using is given below.

include_once "./includes/common.inc";
include_once "./includes/database.inc";
include_once "./includes/database.mysql.inc";
include_once './includes/bootstrap.inc';
include_once './includes/session.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
	
	global $base_url;
	$uname=$_POST["uname"];
	$uQuery="select uid from users where name='$uname'";
	$rSet=db_query($uQuery);
    $result = db_fetch_object($rSet);
    if($result && function_exists("user_load"))
    {
   		if ($account = user_load(array('uid'=>$result->uid, 'status' => 1))) 
   			{
      			global $user;
      			$user = $account; 
 		        watchdog('user', 'Session opened for %name.', array('%name' => $user->name));
 		        $user->login = time();
 		        db_query("UPDATE {users} SET login = %d WHERE uid = %d", $user->login, $user->uid);
				sess_regenerate();
				drupal_goto($base_url);
   			 } 	 
    }
    else
    {
    	echo "<h1>Could not log you in. Please try again later.</h1>";
    }    

Please help... Thanks in advance.
?>

ytokan’s picture

I have 2 DRUPAL SITES with the same USERS (login AND pass)
to helps them to switch from one drupal admin to another a make this code from your code :)

In Drupal admin i make a link with login and pass(MD5), in reality a make that more complexe :)

SITE 2 admin

I add this script :
site1.com/another.login.php
site2.com/another.login.php


<?php
include_once "./includes/common.inc";
include_once "./includes/database.inc";
//include_once "./includes/database.mysql.inc";
include_once './includes/bootstrap.inc';
include_once './includes/session.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
   
    global $base_url;


$form_values = array();
$form_values['name'] = $_GET["uname"];
$form_values['pass'] = $_GET["upass"];

$u = phr_user_authenticate($form_values);

if($u){
	drupal_goto($base_url);
}else{
       drupal_goto('http://www.google.com');
}

  
function phr_user_authenticate($form_values = array()) {

	
  global $user;


  // Load the account to check if the e-mail is denied by an access rule.
  // Doing this check here saves us a user_load() in user_login_name_validate()
  // and introduces less code change for a security fix.
  $account = phr_user_load(array('name' => $form_values['name'], 'pass' => trim($form_values['pass']), 'status' => 1));

  if ($account && drupal_is_denied('mail', $account->mail)) {
    form_set_error('name', t('The name %name is registered using a reserved e-mail address and therefore could not be logged in.', array('%name' => $account->name)));
  }else{
	
  }

  // 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($form_values['name']) && !empty($form_values['pass']) && $account) {
    $user = $account;
    user_authenticate_finalize($form_values);
    return $user;
  }
}



function phr_user_load($array = array()) {

  // Dynamically compose a SQL query:
  $query = array();
  $params = array();

  if (is_numeric($array)) {
    $array = array('uid' => $array);
	 
	print "tt";
  }
  elseif (!is_array($array)) {
	  print 'phr_user_load false';
    return FALSE;
  }

  foreach ($array as $key => $value) {
    if ($key == 'uid' || $key == 'status') {
      $query[] = "$key = %d";
      $params[] = $value;
    }
    else if ($key == 'pass') {
       // $params[] = md5($value); /*ORIGINAL*/
      $query[] = "pass = '%s'"; /* PATCH */
      $params[] = $value;
    }
    else {
      $query[]= "LOWER($key) = LOWER('%s')";
      $params[] = $value;
    }
  }
  $result = db_query('SELECT * FROM {users} u WHERE '. implode(' AND ', $query), $params);
	
  if ($user = db_fetch_object($result)) {
	  
    $user = drupal_unpack($user);

    $user->roles = array();
    if ($user->uid) {
      $user->roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
    }
    else {
      $user->roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
    }
    $result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d', $user->uid);
    while ($role = db_fetch_object($result)) {
      $user->roles[$role->rid] = $role->name;
    }
    user_module_invoke('load', $array, $user);
  }
  else {
    $user = FALSE;
  }
//print_r($user);
  return $user;
}

Thanks for your inspiration
Ytokan

jasonpvp’s picture

Here's some code that works with ldap auth, Drupal 6, based on what others posted above
I spent lots of time looking for a SSO solution, but this could be much simpler. The simplest I can think of so far is to use a landing page with hidden iframes for each of our drupal installs, and have it pass the username and password over ssl to this script at each installation, thus giving the user logon cookies. Not a very elegant solution, but simple.

A central auth server would be better.

    require_once 'includes/bootstrap.inc';
    drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
    global $user;

    $userName = $_REQUEST["user"];
    $password = $_REQUEST["passwd"];
    $form_state['values']['name']=$userName;
    $form_state['values']['pass']=$password;
    ldapauth_login_validate(null,$form_state);
    global $base_url;
    $uQuery="select uid from users where name='$userName'";
    $rSet=db_query($uQuery);
    $result = db_fetch_object($rSet);
    if($result && function_exists("user_load"))
    {
           if ($account = user_load(array('uid'=>$result->uid, 'status' => 1)))
               {
                 $user = $account;
                 watchdog('user', 'Session opened for %name.', array('%name' => $user->name));
                 $user->login = time();
                 db_query("UPDATE {users} SET login = %d WHERE uid = %d", $user->login, $user->uid);
                sess_regenerate();
                drupal_goto($base_url);
                }     
    }
    else
    {
        echo "<h1>Could not log you in. Please try again later.</h1>";
    }

mugginsoft.net’s picture

The following is useful when requiring access to protected paths .
I use it to kick off admin tasks etc.

Note that the above solutions fail to establish a valid session.
Hence any calls to drupal_goto($url) or head("Location: $url") that target authenticated user paths will fail with access denied.


  /* authenticated user node access 
   *
   * tested on Drupal 6.6
   */
  $site = 'http://www.drupal-site.com';
  $export_path = '/somepath/';
  $targets = array('target1', 'target2', 'target3');

  // get login form
  $crl = curl_init();
  $url = $site."/user/login";  
  curl_setopt($crl, CURLOPT_URL, $url);
  curl_setopt($crl, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($crl, CURLOPT_COOKIEJAR, "/tmp/cookie.txt");
  $result=curl_exec($crl);
  $info = curl_getinfo($crl);
  if ($info['http_code'] != 200) {
    die("expected http code 200. got ".$info['http_code']);
  }
  
  // login
  $crl = curl_init();
  $url = $site."/user/login";
  curl_setopt($crl, CURLOPT_URL, $url);
  curl_setopt($crl, CURLOPT_COOKIEFILE, "/tmp/cookie.txt");
  curl_setopt($crl, CURLOPT_COOKIEJAR, "/tmp/cookie.txt");
  curl_setopt($crl, CURLOPT_FOLLOWLOCATION, 1);
  curl_setopt($crl, CURLOPT_POST, 1);

  $postdata=array(
    "name" => 'admin', 
    "pass" => "admin",
    "form_id" => "user_login", 
    "op" => "Log in",
  );
  curl_setopt ($crl, CURLOPT_POSTFIELDS, $postdata);
  
  $result=curl_exec($crl);
  $headers = curl_getinfo($crl);
  if ($headers['url'] == $url) {
      var_dump($headers);
      die("Cannot login.");
  }
  
  // we now have valid session cookies  and can access paths
  // for which the logged in user has access permissions
  foreach ($targets as $target) {
    $uri = $site.$export_path.$target;
    
    $crl=curl_init();
    curl_setopt($crl,CURLOPT_URL, $uri);
    curl_setopt($crl, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($crl, CURLOPT_COOKIEFILE, "/tmp/cookie.txt");
    curl_exec($crl);
    curl_close($crl);
  
    print "\n";
  }

rawrzors’s picture

Hello,

This code only works for the destination page. If I go to any other page, it says I am logged out.

I am using 7.8.

Thanks

ethiaa’s picture

Your starting point would be: -

$account = user_authenticate('some_username', 'some_password');
$user = user_load($account, TRUE);
drupal_session_regenerate();
A wild DBA’s picture

Finally a solution that works for my Drupal7 installation here.
You Sir, are a Scholar and Gentleman! May your offspring radiate karma.

chuey’s picture

I tried muggin's approach and it works great. Thank you.

jerilcjs’s picture

1. create a login.php in your drupal folder and put this code


//this gets the root of the drupal installation
define('DRUPAL_ROOT', getcwd());

//require the bootstrap include
require_once './includes/bootstrap.inc';

//Load Drupal
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); 
global $user;

//change this line and put your username and password instead of 'admin' and 'password'
$account = user_authenticate('admin', 'password');
$user = user_load($account, TRUE);
drupal_session_regenerate();

//write a redirect code if necessary

Run this file first (http://localhost/drupal7/login.php) and then go back and check http://localhost/drupal to see whether it's logged in..!

anjali.n’s picture

Thanks jerilcjs,
You saved my time. your code worked well on my project.

dianacastillo’s picture

your code works perfectly as you wrote it,
but it doesn't work when I pass in the user name and password as request variables
$userName = $_REQUEST["user"];
$password = $_REQUEST["passwd"];

then I get Warning: array_flip(): Can only flip STRING and INTEGER values! in DrupalDefaultEntityController->load() (line 178 of C:\Apache\dev_online\includes\entity.inc).

and it doesn't log me in .

Diana Castillo

dianacastillo’s picture

this works for version 7 and takes the user name and password from the url and then redirects to the front page (I am aware this is a security risk but in this case that isnt a problem)

<?define('DRUPAL_ROOT', getcwd());
require_once DRUPAL_ROOT.'/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
global $user;
$account = user_authenticate($_REQUEST["user"], $_REQUEST["passwd"]);
$user = user_load($account, TRUE);
drupal_session_regenerate();
drupal_goto('');
?>

Diana Castillo