I would like to be able to authenticate local users outside of the database. That is, I have an existing userbase and wish to use existing authentication mechanisms for drupal's login.
I've hacked together something which allows me to do this (using IMAP), but I had to make a change to the user module. Attached is my IMAP module. The user module change was in user_authenticate. I'll include my hacked function below, but it's against 4.5. The cvs version of this function isn't much different though.
The change involves saving the full login name ($fullname) in addition to splitting it into name and server. If the standard authentication fails, $fullname is sent to the authentication modules. Previously, the authentication modules were only consulted if there was no $server part (no "@" in the login).
This change allows me to write custom authentication modules without requiring the user to type in a login name with an at-sign. I don't believe this will adversely affect existing authentication modules; at worst, slow ones could merely check $server (which they should be doing anyway).
A quick search of your site for "IMAP" or "LDAP" shows that there are other folks who would also like this sort of behavior. There's even a "webserver_auth" module which allows HTTP auth, although in a kludgy way that could be cleaned up by this change to the user module.
(Even cooler would be if the standard authentication was pluggable--this change would allow such a thing. Then I could *only* let my local users authenticate, which is what I want.)
I place my IMAP authentication code in the public domain and disclaim any ownership rights with the express intent of the Drupal team (or someone else) picking it up and making it a proper package.
Here's the new function:
function user_authenticate($fullname, $pass) {
global $user;
// Try to log in the user locally:
$user = user_load(array('name' => $fullname, 'pass' => $pass, 'status' => 1));
// Strip name and server from ID:
if ($server = strrchr($fullname, '@')) {
$name = substr($name, 0, strlen($fullname) - strlen($server));
$server = substr($server, 1);
} else {
$name = $fullname;
}
// When possible, determine corresponding external auth source. Invoke
// source, and log in user if successful:
if (!$user->uid && $result = user_get_authmaps($fullname)) {
if (module_invoke(key($result), 'auth', $name, $pass, $server)) {
$user = user_external_load($fullname);
watchdog('user', t('External load by %user using module %module.', array('%user' => "<em>$name@$server</em>", '%module' => '<em>'. key($result) .'</em>')));
}
else {
$error = t('Invalid password for %s.', array('%s' => "<em>$fullname</em>"));
}
}
// Try each external authentication source in series. Register user if
// successful.
else if (!$user->uid) {
foreach (module_list() as $module) {
if (module_hook($module, 'auth')) {
if (module_invoke($module, 'auth', $name, $pass, $server)) {
if (variable_get('user_register', 1) == 1) {
$user = user_load(array('name' => $fullname));
if (!$user->uid) { // Register this new user.
$user = user_save('', array('name' => $fullname, 'pass' => user_password(), 'init' => $fullname, 'status' => 1, "authname_$module" => $fullname, 'roles' => array(_user_authenticated_id())));
watchdog('user', t('New external user: %user using module %module.', array('%user' => "<em>$fullname</em>", '%module' => "<em>$module</em>")), l(t('edit'), 'user/'. $user->uid .'/edit'));
break;
}
}
}
}
}
}
return $user;
}
| Comment | File | Size | Author |
|---|---|---|---|
| imap_auth.module | 718 bytes | neale |
Comments
Comment #1
ricabrantes commentedAny activity??
Comment #2
jstollerI like the idea of a plug-in architecture for authentication sources. Personally, I'd like to see a major overhaul of the user access system in Drupal and this would be a great addition.
Before finding Drupal, I was very interested in using PEAR::LiveUser for authentication. One of the things that drew me to it was the ability to have different users authenticate against different databases. So normal users could authenticate against a local MySQL database, while employees might authenticate against our internal Active Directory via LDAP or IMAP. Any number of authentication containers can be specified in LiveUser and there are a number of modules available to plug in for communication with different databases.
If I recall correctly, LiveUser is tied to the PEAR::MDB2 database abstraction layer, so any database that MDB2 can talk to, LiveUser can authenticate against. This seems like a more flexible system than database plug-ins that are specifically tied to the authentication system itself. If Drupal has an application-wide database abstraction layer, and plug-ins are available to allow said DB abstraction layer to communicate with a variety of databases, then it should be a (relatively) simple matter to define a data source (or multiple data sources) for your authentication.
Comment #3
scoutbaker commentedMoving to 7.x.
Comment #4
tstoecklerStill very much a valid feature request.
I just looked into openid.module for the first time and saw that it only works with some considerable form_alters() of the login form. :(
Comment #5
corvus_ch commentedDrupal 8 now ships with a pluggable authentication system that is also capable of dealing with non session based means of authentication. See #1890878: Add modular authentication system, including Http Basic; deprecate global $user.
I consider to be this a duplicate and can therefore be closed.
Comment #6
colanIt's also worth mentioning #1157310: base authentication class to make multiple and external authn methods easier to implement, which is more up-to-date instance of this ticket.