LDAP Hack for Active Directory Authentication
From Cerberus Helpdesk Wiki
This Cerberus-LDAP modification requires a particular (pretty generic) setup on Active Directory to work. This was tested and used on Cerberus 5.3.x, but should work on other versions of Cerb 5.
Also, this modification may only work with Active Directory as the LDAP server, due to a strange way that AD stores group membership information.
Note that this is a serious hack and is not an example of good code. However, it is open and simple enough to allow us to make basic changes to our AD setup and then modify the PHP code to use the change without too much drama. For example, when we needed to start checking multiple LDAP user containers to determine if a person would be allowed to log into Cerberus, it was pretty easy to hack in.
We started out by adding a "Cerberus" security group in Active Directory and putting AD users into it that we want to get into Cerberus.
Then we created the user accounts manually in Cerberus, assigning each of them the same fixed, random password, represented by the SamePasswordForAll string below.
You need to have an "ldapuser" account in Active Directory that will let you make the initial connection to AD. This is the user that will connect and search for whether the person is in one of the allowed groups. In our case, we want only people in Users, Students, or Temp Accounts to be able to connect to Cerberus. This also allows us to get their full BaseDN string, which we can use to attempt a login for them.
Next, we attempt to bind to AD with their BaseDN and password.
If that succeeds, then, we check to make sure that they are in the Cerberus security group.
If so, then we log them into Cerberus, using the password that all users have.
This function authenticate() replaces the existing function in /features/cerberusweb.core/api/login.classes.php. I usually just rename the old function to something else or comment it out.
The items that you have to change in the code for it to work in your environment are, at a minimum:
$ldap_host - Set this to your AD server location.
$ldap_bind_user - Set this to a user that can bind to LDAP and look up information.
$ldap_bind_password - The password for $ldap_bind_user.
$base_dn_users, $base_dn_students, $base_dn_temps - Three places where Cerberus users can live in AD. You could comment out the students and temps variables and code in the script, if all of your users are in Users.
mysql_pconnect and mysql_select_db - Put in the connection info for your MySQL server.
SamePasswordForAll - Put in your common Cerberus password for all accounts here.
Of course, go through this modification with a fine-toothed comb and make sure it is compatible with your AD LDAP situation before trying to use it. This is definitely not a "slap it in and it works" kind of modification, but it has proven very reliable and capable for us.
// RHODES EDIT - allows LDAP authentication to Cerberus 5 - in /features/cerberusweb.core/api/login.classes.php
function authenticate() {
// Pull from $_POST
@$email = DevblocksPlatform::importGPC($_POST['email']);
@$password = DevblocksPlatform::importGPC($_POST['password']);
global $success; global $student_class;
// gets the username away from the full domain.com email address
$p_ldap_user = strstr($email, '@', true);
$ldap_host = "ldap://ldap.domain.com";
$ldap_bind_user = "CN=ldapuser,CN=Users,DC=domain,DC=com";
$ldap_bind_password= "LDAPUserPassword";
// this is the initial connection to see if the person is in CN=Users or OU=Students
$connect = ldap_connect( $ldap_host, $ldap_port) or exit("Could not connect to LDAP server");
if ($connect == "") {
echo "connect string blank";
break;
}
$bind_initial = ldap_bind($connect, $ldap_bind_user, $ldap_bind_password);
// required to search AD, according to note in PHP manual notes
ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($connect, LDAP_OPT_REFERRALS, 0);
$base_dn_users = "CN=Users,DC=domain,DC=com";
$base_dn_students = "OU=Students,DC=domain,DC=com";
$base_dn_temps = "OU=Temp Accounts,DC=domain,DC=com";
$filter = "(CN=$p_ldap_user)";
$ldap_pass = $password;
$read_users = ldap_search($connect, $base_dn_users, $filter) or exit("Unable to search ldap server for read_users");
$info_users = ldap_get_entries($connect, $read_users);
if ($info_users["count"] == "1") { // found them in CN=Users
$ldap_user = "CN=$p_ldap_user,".$base_dn_users;
$base_dn = $base_dn_users;
} else { // look for them in CN=Students
$read_students = ldap_search($connect, $base_dn_students, $filter) or exit("Unable to search ldap server for read_students");
$info_students = ldap_get_entries($connect, $read_students);
if ($info_students["count"] == "1") { // found them in CN=Students
$ldap_user = "CN=$p_ldap_user,".$base_dn_students; $base_dn = $base_dn_students;
} else { // look for them in OU=Temp Accounts
$read_temps = ldap_search($connect, $base_dn_temps, $filter) or exit("Unable to search ldap server for read_temps");
$info_temps = ldap_get_entries($connect, $read_temps);
if ($info_temps["count"] == "1") { // found them in OU=Temp Accounts
$ldap_user = "CN=$p_ldap_user,".$base_dn_temps;
$base_dn = $base_dn_temps;
}
}
}
// By this point, we know what kind of user is trying to authenticate
// Now, try a login as that user to see if you can bind with their password
if ($ldap_user == "") {
echo "ldap_user string blank";
break;
}
if ($ldap_pass == "") {
echo "ldap_pass string blank";
break;
}
// bind to server
$bind = ldap_bind($connect, $ldap_user, $ldap_pass);
$read = ldap_search($connect, $base_dn, $filter) or exit("Your email address or password is not valid. Please <a href='/cerberus/index.php/login'>click here</a> to try again.");
$info = ldap_get_entries($connect, $read);
// at this point, the user has only authenticated their password
// unless they are in the Cerberus security group, they cannot log into Cerberus
$ii=0;
for ($i=0; $ii<$info[$i]["count"]; $ii++){
$data = $info[$i][$ii];
if ($data == "memberof") {
$total_memberof = (count($info[$i][$data]) - 1);
$total = 0;
$total = count($info[$i][$data]);
$jj=0;
for ($j=0; $jj<$total-1; $jj++) {
if ($info[$i][$data][$jj] == "CN=Cerberus,OU=Security Groups,OU=Groups,DC=domain,DC=com") {
$user_type = "VALID";
}
}
}
}
$realname = $info[0][displayname][0];
ldap_unbind($connect);
// if they get this far, authenticate them using the fixed password
if ($user_type != "") {
// let them log into cerberus
mysql_pconnect("localhost", "dbuser", "dbpassword");
mysql_select_db("dbname");
$sql = "SELECT * FROM worker WHERE email='$email'";
$result_sql = mysql_query($sql);
$result_sql_num = mysql_num_rows($result_sql);
if ($result_sql_num != "0") { // they have logged into cerberus before, so do not set their default group
// authenticate the worker
$worker = DAO_Worker::login($email, 'SamePasswordForAll');
} else { // user does not exist in cerberus so set them up as a new user
echo "ERROR: You have been granted access to the Cerberus security group in Active Directory, but your user account has not been created in the Cerberus application.";
exit;
}
} else {
echo "ERROR: You are not authorized to log into Cerberus.";
exit;
}
if(!is_null($worker)) {
$session = DevblocksPlatform::getSessionService();
$visit = new CerberusVisit();
$visit->setWorker($worker);
$session->setVisit($visit);
// [TODO] Only direct to /welcome when tour is enabled return true;
} else {
return false;
}
}
// END RHODES EDIT