FOR CLARIFICATION: This plugin works as far as I know. It functions with our LDAP server and will likely work with others. I just labeled it "abandoned" because I don’t think I’ll be able to provide future updates.
This is my first, and possibly last post here. I am a web developer and I’m investigating assorted CMS to figure out what the company I work for would like to use in the future. Unfortunately MODx’s permissions structure doesn’t mesh well with our existing management framework so it looks like I’ll be moving on.
Before I do, however, I’d like like to pass on this extremely simplistic LDAP Authentication plugin I worked up. I don’t know
that much about LDAP so this is written with our server in mind ... I can’t really speak for its universality. Some assumptions I make include:
- Users are uniquely identified by the "uid" field
- You can anonymously bind to the server to look up a user’s complete "dn" field
Here’s the code:
if(!class_exists('LDAPAuthorization')) {
class LDAPAuthorization {
/*
You need to provide some information about your LDAP server. This isn't
completely 100% fire-and-forget. If you don't know these variables then
you need to contact your LDAP administrator to find them out.
*/
// your ldap server
var $LDAP_Server = "ldap.yourdomain.com";
// the tree on which you should be searching for users
var $LDAP_BaseDN = "ou=people, o=yourdomain.com, dc=yourdomain, dc=com";
var $LDAP_Port = 636; // ldaps=636; ldap=389
// LDAPAuth() : use LDAP to verify a username and password
// This function is borrowed from another project, so it returns either an array
// or false.
function LDAPAuth($username, $Password)
{
$attrs = array("dn");
// There are cleaner ways to code this than a giant if/else tree
// but I use this structure so that you can add debug and error
// handling routines more robust than "return false" whenever any
// part of the process goes wrong.
// connect to the LDAP Server
if ($connect_id = @ldap_connect($this->LDAP_Server, $LDAP_Port)) {
// bind anonymously - your server must be able to perform a search anonymously and get a user's dn
// in LDAP lingo, "bind" essentially means "log in"
if (@ldap_bind($connect_id)) {
// use the username porvided to search for a user with the same uid
$search_id = @ldap_search($connect_id, $this->LDAP_BaseDN, "(uid=$username)", $attrs);
// get the results of that search
$result_array = @ldap_get_entries($connect_id, $search_id);
if ($result_array[0]) {
// attempt to bind to the LDAP server with the user's dn and the provided password
if (@ldap_bind($connect_id, $result_array[0]['dn'], $Password)) {
// if successful, return the result array, all other cases return false
@ldap_close($connect_id);
return $result_array;
} else {
@ldap_close($connect_id);
return false;
}
} else {
@ldap_close($connect_id);
return false;
}
} else {
@ldap_close($connect_id);
return false;
}
} else {
return false;
}
}
}
}
global $_lang;
$event_name = $modx->Event->name;
$auth = new LDAPAuthorization;
if($event_name == 'OnManagerAuthentication') {
// if we're doing authentication, check the username/userpassword against the
// LDAP directory. Because of the way MODx authentication works, it will still
// check the password against the MODx internal password when LDAP authentication
// fails. If they match the user
// will still be logged in. I don't know if that represents a security hole or
// not or even what you can do about it in a plugin.
$modx->Event->output(!($auth->LDAPAuth($username, $userpassword)===false));
}
As mentioned above, when LDAP comes back with a login failure, MODx still checks the username/password against its internal password. If you want to stop that behavior, open up
/manager/processors/login.processor.php and change the following line:
if (!$rt||(is_array($rt) && !in_array(TRUE,$rt))) {
to:
if (!$rt||(is_array($rt) && !in_array(TRUE,$rt)) || (is_array($rt) && !in_array(FALSE,$rt))) {