Authenticate against Microsoft Directory (LDAP)
Posted: 2018-05-31 09:39
This is my contribution on how I authenticate against AD in my organisation
Note that this solution could be dependent on how AD has been setup in your organisation but the principals should be the same. I know that there are probably better ways and better coding to this but I am sharing with the hope that it could save fellow Appgini user some time.
First make sure that the php LDAP library is installed and available on your system. You can check this with phpinfo() Make a note of the were the php.ini file is located. If not activated or installed install it first install it.
In Centos do: yum install php-ldap
Add or uncomment in php.ini: extention=ldap.so
Restart your apache/http service: service httpd restart
Before you change code in Appgini run a test authentication program to ensure you have everything setup correctly.
For example:
<?php
$link = ldap_connect('FDC-DC01.FDC.LOCAL'); // Your domain or domain server
if(! $link) {
echo "Could not connect to server - handle error appropriately";
}
else {
echo 'Bind was successful</br>';
}
$ldap_username ='your login name';
$ldap_password = 'your password';
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, 3); // Recommended for AD
// Now try to authenticate with credentials provided by user
if (ldap_bind($link, $ldap_username, $ldap_password)) {
echo 'User LDAP Authentication was successful<br>';
}
else{
echo 'Invalid credentials! Handle error appropriately</br>';
}
$unbind = ldap_unbind($link);
if ($unbind){
echo 'Unbind was successful !!</br>';
}
else {
echo 'unbind problem found</br>';
}
?>
Make sure that you have an admin user created in the Appgini user DB that also exist on the AD structure. If you do not do this you will not be able to login as an administrator on you Appgini system. The idea is that we will be creating a user in Appgini whose user name will be on AD and on the Appgini DB. The active directory password will not be stored in Appgini. The password and username supplied by the user will be used to authenticate against AD and if true we will check to see if the user exist in the Appgini DB.
The custom code changes will made in the IncCommon.php generated code. Look for the function logInMember().
I did not change the Appgini variable $username and $password but rather defined new ones for usage with LDAP
The $link variable is used to set the domain name and will be dependent on your environment
If the link to the domain was successful I check the user credential entered against the AD credentials. If it was successful the $ldap_authorized variable is set to true.
I encapsulated the rest of the Appgini code with an if statement. This means that if a user has valid AD credentials the “if (sqlValue…†will be done. Note that I removed the $password from the select statement as I do not have the AD password in the Appgini DB only the login name.
Changes made Incommon.php LoginMember()
#########################################################
// Set custom code in this function take out password selction form sql value
// test password entered against active directory
function logInMember(){
$redir = 'index.php';
if($_POST['signIn'] != ''){
if($_POST['username'] != '' && $_POST['password'] != ''){
$username = makeSafe(strtolower($_POST['username']));
$password = md5($_POST['password']);
$ldap_username = 'FDC\\'.$_POST['username']; //FDC\ is needed for the FDC ad depends on your ad setup
$ldap_password = $_POST['password'];
$link = ldap_connect('FDC-DC01.FDC.LOCAL'); // Your domain or domain server
if ($link){ // The bind to domain was sucessfull
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, 3); // Recommended for AD
if (ldap_bind($link, $ldap_username, $ldap_password)) { // Now try to authenticate with credentials provided by user
$ldap_authorized = true;
$_POST['rememberMe']=0; // do not want to keep ad info in cookies
}
}
if ($ldap_authorized) { //if ldap_authorized carry on to see if registered in the program
//if(sqlValue("select count(1) from membership_users where lcase(memberID)='$username' and passMD5='$password' and isApproved=1 and isBanned=0")==1){
if(sqlValue("select count(1) from membership_users where lcase(memberID)='$username' and isApproved=1 and isBanned=0")==1){
$_SESSION['memberID']=$username;
$_SESSION['memberGroupID']=sqlValue("select groupID from membership_users where lcase(memberID)='$username'");
if($_POST['rememberMe']==1){
@setcookie('helpdesk_rememberMe', md5($username.$password), time()+86400*30);
}else{
@setcookie('helpdesk_rememberMe', '', time()-86400*30);
}
// hook: login_ok
if(function_exists('login_ok')){
$args=array();
if(!$redir=login_ok(getMemberInfo(), $args)){
$redir='index.php';
}
}
redirect($redir);
exit;
}
} //authorized ldap
}
// hook: login_failed
if(function_exists('login_failed')){
$args=array();
login_failed(array(
'username' => $_POST['username'],
'password' => $_POST['password'],
'IP' => $_SERVER['REMOTE_ADDR']
), $args);
}
if(!headers_sent()) header('HTTP/1.0 403 Forbidden');
redirect("index.php?loginFailed=1");
exit;
}elseif((!$_SESSION['memberID'] || $_SESSION['memberID']==$adminConfig['anonymousMember']) && $_COOKIE['helpdesk_rememberMe']!=''){
$chk=makeSafe($_COOKIE['helpdesk_rememberMe']);
if($username=sqlValue("select memberID from membership_users where convert(md5(concat(memberID, passMD5)), char)='$chk' and isBanned=0")){
$_SESSION['memberID']=$username;
$_SESSION['memberGroupID']=sqlValue("select groupID from membership_users where lcase(memberID)='$username'");
}
}
}
#########################################################
To summarize the steps, I followed:
Create a user in Appgini with the same username as in AD (password does not have to be the same as in AD)
Make custom changes to the function LogInMember()
Test the connection to AD
Test the login credential supplied against AD
If successful test if user exist in Appgini DB
If successful allow access to Appgini system
Note that this solution could be dependent on how AD has been setup in your organisation but the principals should be the same. I know that there are probably better ways and better coding to this but I am sharing with the hope that it could save fellow Appgini user some time.
First make sure that the php LDAP library is installed and available on your system. You can check this with phpinfo() Make a note of the were the php.ini file is located. If not activated or installed install it first install it.
In Centos do: yum install php-ldap
Add or uncomment in php.ini: extention=ldap.so
Restart your apache/http service: service httpd restart
Before you change code in Appgini run a test authentication program to ensure you have everything setup correctly.
For example:
<?php
$link = ldap_connect('FDC-DC01.FDC.LOCAL'); // Your domain or domain server
if(! $link) {
echo "Could not connect to server - handle error appropriately";
}
else {
echo 'Bind was successful</br>';
}
$ldap_username ='your login name';
$ldap_password = 'your password';
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, 3); // Recommended for AD
// Now try to authenticate with credentials provided by user
if (ldap_bind($link, $ldap_username, $ldap_password)) {
echo 'User LDAP Authentication was successful<br>';
}
else{
echo 'Invalid credentials! Handle error appropriately</br>';
}
$unbind = ldap_unbind($link);
if ($unbind){
echo 'Unbind was successful !!</br>';
}
else {
echo 'unbind problem found</br>';
}
?>
Make sure that you have an admin user created in the Appgini user DB that also exist on the AD structure. If you do not do this you will not be able to login as an administrator on you Appgini system. The idea is that we will be creating a user in Appgini whose user name will be on AD and on the Appgini DB. The active directory password will not be stored in Appgini. The password and username supplied by the user will be used to authenticate against AD and if true we will check to see if the user exist in the Appgini DB.
The custom code changes will made in the IncCommon.php generated code. Look for the function logInMember().
I did not change the Appgini variable $username and $password but rather defined new ones for usage with LDAP
The $link variable is used to set the domain name and will be dependent on your environment
If the link to the domain was successful I check the user credential entered against the AD credentials. If it was successful the $ldap_authorized variable is set to true.
I encapsulated the rest of the Appgini code with an if statement. This means that if a user has valid AD credentials the “if (sqlValue…†will be done. Note that I removed the $password from the select statement as I do not have the AD password in the Appgini DB only the login name.
Changes made Incommon.php LoginMember()
#########################################################
// Set custom code in this function take out password selction form sql value
// test password entered against active directory
function logInMember(){
$redir = 'index.php';
if($_POST['signIn'] != ''){
if($_POST['username'] != '' && $_POST['password'] != ''){
$username = makeSafe(strtolower($_POST['username']));
$password = md5($_POST['password']);
$ldap_username = 'FDC\\'.$_POST['username']; //FDC\ is needed for the FDC ad depends on your ad setup
$ldap_password = $_POST['password'];
$link = ldap_connect('FDC-DC01.FDC.LOCAL'); // Your domain or domain server
if ($link){ // The bind to domain was sucessfull
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, 3); // Recommended for AD
if (ldap_bind($link, $ldap_username, $ldap_password)) { // Now try to authenticate with credentials provided by user
$ldap_authorized = true;
$_POST['rememberMe']=0; // do not want to keep ad info in cookies
}
}
if ($ldap_authorized) { //if ldap_authorized carry on to see if registered in the program
//if(sqlValue("select count(1) from membership_users where lcase(memberID)='$username' and passMD5='$password' and isApproved=1 and isBanned=0")==1){
if(sqlValue("select count(1) from membership_users where lcase(memberID)='$username' and isApproved=1 and isBanned=0")==1){
$_SESSION['memberID']=$username;
$_SESSION['memberGroupID']=sqlValue("select groupID from membership_users where lcase(memberID)='$username'");
if($_POST['rememberMe']==1){
@setcookie('helpdesk_rememberMe', md5($username.$password), time()+86400*30);
}else{
@setcookie('helpdesk_rememberMe', '', time()-86400*30);
}
// hook: login_ok
if(function_exists('login_ok')){
$args=array();
if(!$redir=login_ok(getMemberInfo(), $args)){
$redir='index.php';
}
}
redirect($redir);
exit;
}
} //authorized ldap
}
// hook: login_failed
if(function_exists('login_failed')){
$args=array();
login_failed(array(
'username' => $_POST['username'],
'password' => $_POST['password'],
'IP' => $_SERVER['REMOTE_ADDR']
), $args);
}
if(!headers_sent()) header('HTTP/1.0 403 Forbidden');
redirect("index.php?loginFailed=1");
exit;
}elseif((!$_SESSION['memberID'] || $_SESSION['memberID']==$adminConfig['anonymousMember']) && $_COOKIE['helpdesk_rememberMe']!=''){
$chk=makeSafe($_COOKIE['helpdesk_rememberMe']);
if($username=sqlValue("select memberID from membership_users where convert(md5(concat(memberID, passMD5)), char)='$chk' and isBanned=0")){
$_SESSION['memberID']=$username;
$_SESSION['memberGroupID']=sqlValue("select groupID from membership_users where lcase(memberID)='$username'");
}
}
}
#########################################################
To summarize the steps, I followed:
Create a user in Appgini with the same username as in AD (password does not have to be the same as in AD)
Make custom changes to the function LogInMember()
Test the connection to AD
Test the login credential supplied against AD
If successful test if user exist in Appgini DB
If successful allow access to Appgini system