PHP LDAP secondary query after obtaining dn - php

Im working on adding authentication to one of my dashboards.
My setup is a little unique I believe. We use a service account to obtain the DN of a user, this query works as expected. We then bind a second time using that new dn instead of the service account. This also works, so technically at this point, the user is properly authenticated.
I'm trying to perform a second ldap_search after succesful bind as the dn I pull from the first query. This is unfortunately giving me the results of the previous ldap_search. This is what I'm not understanding.
if($bind = #ldap_bind($ldap, $ldap_dn, $adminpass)) {
// valid
echo "bound to ldap<BR>\n";
$filter = "(&(objectclass=user)(samaccountname=$user))";
$attr = array("dn, password, samaccountname");
$dn = "DC=CORP,DC=COMPANY,DC=com";
$result = ldap_search($ldap, $dn, $filter, $attr) or exit("Unable to search LDAP server");
$entries = ldap_get_entries($ldap, $result);
// Now build second query to bind and authenticate as user.
$ldap_dn_bind = $entries["0"]["dn"];
echo $ldap_dn_bind;
if($ubind = #ldap_bind($ldap, $ldap_dn_bind, $password)) {
echo "bound as $user - $ldap_dn_bind<BR>\n\n"; // Works
$u_attr = array("description, physicaldeliveryofficename, postaladdress, st, postalcode, title, telephonenumber, mobile, samaccountname, givenname, sn, company, displayname, employeetype, mail, manager, employeeID, KMADescription, terminationdate");
$u_result = ldap_search($ldap, $dn, $filter, $u_attr) or exit("Unable to search LDAP server");
echo "ldap search<BR>\n";
$u_entries = ldap_get_entries($ldap, $u_result);
echo "print u_entries";
print_r($u_entries);
echo "done";
} else {
die("failed to authenticate user");
}
This line:
$u_result = ldap_search($ldap, $dn, $filter, $u_attr) or exit("Unable to search LDAP server");
seems to work as desired and no error about performing the ldap search.
$u_entries however contains the same information as $entries and this is where I'm having a problem. I'm trying to obtain details about the user and insert them into a local db if they're not already present.

I had the same problem before, check if your LDAP server lets external connections in.
Check your $dn variable if you're using emails only enter the stuff after the # sign
Also be sure that your admin credentials
also this link helped me understand it a bit more:
https://github.com/Adldap2/Adldap2-Laravel/issues/224
Note i worked with Laravel

My attributes array was incorrect and by definition ldap_search will ALWAYS return the DN. Problem resolved.

Related

LDAP user authentification works with CN but not sAMAccountName

What I got.
I got a simple HTML login form, where username and password are passed to an ldap.php. I am able to successfully login, as soon as I use cn= instead of sAMAccountName=as a parameter. For Example, the user Mickey Mouse and mmouse as login does not work. Instead I need to login with Mouse \, Mickey. Which is pretty uncomfortable.
Do I need to authenticate, with an privilege account first and perform another bind with the wanted user afterwards?
Whats the problem?
If I replace cn= with sAMAccountName= I run into an ldap_bind error.
<?php
// LDAP Bind parameters
$ldap_dn = "sAMAccountName=".$_POST["username"].",OU=User of myCompany,OU=myCompany,DC=myDomain,DC=com";
$ldap_password = $_POST["password"];
$ldap_connection = ldap_connect("myCompany.com");
// Set LDAP protocol version
ldap_set_option($ldap_connection, LDAP_OPT_PROTOCOL_VERSION, 3);
// Set LDAP returns to 0
ldap_set_option($ldap_connection, LDAP_OPT_REFERRALS, 0);
if (ldap_bind($ldap_connection, $ldap_dn, $ldap_password))
echo "Anmeldung erfolgreich";
else
echo "Anmeldung fehlgeschlagen";
?>

how to filter ldap active directory users information based on IIS windows authentication and display that information in php website?

I'm creating an intranet PHP website without any login requirements. I have an IIS application (based on PHP), authentication is done with Windows Authentication (Anonymous Authentication is disabled). I've successfully managed to set up IIS and windows authentication with some GPO tweaks. My simple PHP page contains $_SERVER['REMOTE_USER']; so active directory user without any login prompts can see DOMAIN\User.Name
In my understanding IIS Windows authentication is very limited and can only display the user's name and domain name. So I enabled LDAP to display more information about the user such as display name or phone number. But I'm stuck here because as far as I know, LDAP uses username and password bind to retrieve information. When I use active directory admin credentials it gives me a table of all user's information but how to filter that table to display only current user information (based on windows authentication).
Code:
<?php
$current_user = get_current_user();
$ldap_password = 'AdminPassword';
$ldap_username = 'Administrator#domain.name';
$ldap_connection = ldap_connect("domain.name");
if (FALSE === $ldap_connection){
echo 'ERROR';
}
ldap_set_option($ldap_connection, LDAP_OPT_PROTOCOL_VERSION, 3) or die('Unable to set LDAP protocol version');
ldap_set_option($ldap_connection, LDAP_OPT_REFERRALS, 0);
if (TRUE === ldap_bind($ldap_connection, $ldap_username, $ldap_password)){
$ldap_base_dn = 'OU=Users,DC=domain,DC=name';
$search_filter = '(|(objectCategory=person)(objectCategory=contact))';
$result = ldap_search($ldap_connection, $ldap_base_dn, $search_filter);
if (FALSE !== $result){
$entries = ldap_get_entries($ldap_connection, $result);
echo '<h2>Result</h2></br>';
echo '<table border = "1"><tr><td>Username</td><td>Last Name</td><td>First Name</td></tr>';
for ($x=0; $x<$entries['count']; $x++){
$LDAP_samaccountname = "";
if (!empty($entries[$x]['samaccountname'][0])) {
$LDAP_samaccountname = $entries[$x]['samaccountname'][0];
if ($LDAP_samaccountname == "NULL"){
$LDAP_samaccountname= "";
}
} else {
$LDAP_uSNCreated = $entries[$x]['usncreated'][0];
$LDAP_samaccountname= "CONTACT_" . $LDAP_uSNCreated;
}
//Last Name
$LDAP_LastName = "";
if (!empty($entries[$x]['sn'][0])) {
$LDAP_LastName = $entries[$x]['sn'][0];
if ($LDAP_LastName == "NULL"){
$LDAP_LastName = "";
}
}
//First Name
$LDAP_FirstName = "";
if (!empty($entries[$x]['givenname'][0])) {
$LDAP_FirstName = $entries[$x]['givenname'][0];
if ($LDAP_FirstName == "NULL"){
$LDAP_FirstName = "";
}
}
echo "<tr><td><strong>" . $LDAP_samaccountname ."</strong></td><td>" .$LDAP_LastName."</td><td>".$LDAP_FirstName."</td></tr>";
}
}
ldap_unbind($ldap_connection);
echo("</table>");
}
?>
EDIT: Managed to filter current user by editing LDAP filter:
$search_filter = "(|(objectCategory=persons)(sAMAccountName=*$current_user*))";
Your query is almost right, but it's working in a roundabout way :)
There is no objectCategory called persons. It's just person (no "s"). So objectCategory=persons is always false for every object on your domain. But it's working because you're using an OR (|).
So the only criteria it's really using is sAMAccountName=*$current_user*. But that's asking for any object where sAMAccountName contains $current_user. That has two unintended consequences:
If you have a user called neil, and another called oneil, then whenever neil logs in, you will find both accounts in that search.
Because your search criteria starts with a wildcard (*), it cannot use the index to find the account. That means that it has to look through every object on your domain to find a match. That might not matter if you have a small domain, but the more objects you have on your domain, the longer it will take.
IIS is giving you the exact username, so there is no need to make a "contains" comparison. So your query can be simplified to:
(sAMAccountName=$current_user)
Since sAMAccountName is an indexed attribute, that will be a super fast query.
You will often see the added criteria of limiting the search to user accounts, like this (notice the &):
(&(objectClass=user)(objectCategory=person)(sAMAccountName=$current_user))
But really, only users can authenticate to IIS, and the sAMAccountName is unique across all object types, so it doesn't really matter.

PHP LDAP Multiple Binds

Quite new to PHP and LDAP here, looking for some assistance with a personal project (trying to teach myself!).
I would like to password protect certain pages on our website using a simple login box.
My login.php page contains a simple login form with username and password inputs. I have managed to get the login process working using the code below. I am able to use my Active Directory username/pass to login via this form and proceed to the desired page, no issues.
However I'm not sure if I am doing it the 'correct' way.
My code;
ldap.php
session_start();
function authenticate($user, $password) {
if(empty($user) || empty($password)) return false;
$ldaphost = "ad.example.com";
$ldap_dn = "DC=ad,DC=example,DC=com";
$ldap_user_group = "Staff";
$ldap_usr_dom = '#ad.example.com';
$ldap = ldap_connect($ldaphost);
if($bind = ldap_bind($ldap, $user.$ldap_usr_dom, $password) or die ("Error: ".ldap_error($ldap))) {
$filter = "(sAMAccountName=".$user.")";
$attr = array("");
$result = ldap_search($ldap, $ldap_dn, $filter) or exit("Unable to search LDAP server") or die ("Error searching: ".ldap_error($ldap));
$entries = ldap_get_entries($ldap, $result);
ldap_unbind($ldap);
}
foreach($entries[0]['memberof'] as $grps) {
if(empty($grps) || empty($ldap_user_group)) return false;
if(strpos($grps, $ldap_user_group)) {
$access = 1;
} else {
}
}
if($access != 0) {
$_SESSION['user'] = $user;
$_SESSION['access'] = $access;
return true;
} else {
return false;
}
}
I've been told (by someone else) that this particular LDAP authentication process should work in two steps, as follows;
A search is made for the entered user name. I would recommend you use a search user DN and password for this – a user that has search permissions. It binds with these credentials before making the search. If the search succeeds it retrieves the DN of the found user and the search attribute which will later be used to look up the member record.
A second bind is then made with the retrieved user DN and the entered password. If this bind succeeds then the user is authenticated.
My questions are;
Is the above statement correct?
Are two 'binds' necessary?
Can't I just bind the LDAP connection with the credentials the user entered?
Any advice is appreciated, I'm struggling to get my head round the authentication process really :s
Short Answers:
yes
yes
no
Long answer:
Currently you can only bind with the users username and email-address. And that only works with AD as backend. So when you want to do an AD-Authenticator that's OK. But you specificslly asked for an LDAP-Authenticator. And an LDAP bind only works witha DN as the "username". As most of your users will not know that it's easier for them to remember an email-address or a username for a login. So you will need to find the DN to the users login-data. So you will need to do a search in the LDAP and for that you have to bind. So to bind as the user you need to bind... To get around that circular dependency you need to bind first as someone that has read access to the Directory and use that session to find the DN of the user. When found you use that DN and the user-provided password to do a second bind to verify the users credentials.
I did a talk about that just two days ago at zendcon. You can find the slides with some examples at https://heiglandreas.github.io/slidedeck/Directory_Authentication_with_LDAP/20161019%20-%20zendcon/index_online.html

Modifying AD LDAP objects with samaccountname

I have a php script which works but I need to change it to use an AD account (samaccountname) instead of CN in this sample;
<?php
$base_dn="CN=Peter Parker,OU=Subcontainer,OU=Subcontainer,OU=Container,
DC=domain,DC=com";
$ldapconn = ldap_connect("host.domain.com") or die("Could not connect to LDAP server.");
if ($ldapconn)
{
$ldapbind = ldap_bind($ldapconn, $ldapusername, $ldappassword);
if ($ldapbind)
{
echo "LDAP bind successful ...";
}
else
{
echo "LDAP bind failed ...";
}
}
$newinfo['ipphone']="555";
ldap_modify($ldapconn,$base_dn,$newinfo);
?>
The intention is to modify the ipphone object for users in AD, but I can't use CN because this input is not unique enough for the task. If the CN in the account's base DN is the descriptive name of the user, am I out of luck?
You have to give ldap_modify the distinguished name (DN) of the account you want to change. There is no way around that.
If you start out only knowing the sAMAccountName, then you can search the domain for the account first, then grab the distinguishedName attribute from the results.
To search, use ldap_search using the filter "(sAMAccountName=username)"

Failure of PHP AD LDAP script ONLY when passed variables

Sample AD LDAP Live Lookup PHP from Helpspot
Okay so I am using the above sample php LDAP script to lookup user info in our ticketing system. I am running into some issues however (these are probably due to my very rudimentary understanding of PHP). I know the script is sort of working because if I hit the URL for the script in my browser it will spit back a list of all users in the domain until it hit the return limit and just stops. I am sure I could get it to spit back more, but that is not really the issue right now. Because I am getting data from my domain I am assuming that my creds and binds are good in the script. We use the credentials, server, etc on all our MFP's for their global address list without issue so I am positive I am good there. The problem arises when you pass anything to it to do a lookup. I receive an error that states:
ldap search failed: Operations error
When I tweak the script to give me a little more info it points me back to this line:
$search = ldap_search($ad, $dn, $filter, $attrs)
or die ("ldap search failed: ".ldap_error($ad));
Which I had suspected given the error I was getting is present in this line. So I am assuming one of those defined variables is the culprit causing me problems. This is where i start to get lost. I am not understanding why asking it to narrow the results returned would break this? Any suggestions? Or is there anything more I need to share?
Thank you #heiglandreas that post helped me immensely. Using the script being run in that section I was able to grab some pieces that allowed my script to function properly. I am not sure exactly why my environment didn't care for my first script, I suspect the change in location in the script of certain steps and the changed formatting of the bind helped. My script now looks like:
<?php
header('Content-type: text/xml');
$hostname="ldap://SERVER IP ADDRESS";
$ds=ldap_connect($hostname, 389);
$user = "domain\username";
$pswd = "PASSWORD";
ldap_set_option ($ds, LDAP_OPT_REFERRALS, 0) or die('Unable to set LDAP opt referrals');
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3) or die('Unable to set LDAP protocol version');
if ($ds)
{
$dn = "DC=DOMAIN,DC=local";
if (!($ldapc=ldap_bind($ds, $user, $pswd))) {
echo "<p>Error:" . ldap_error($ds) . "</p>";
echo "<p>Error number:" . ldap_errno($ds) . "</p>";
echo "<p>Error:" . ldap_err2str(ldap_errno($ds)) . "</p>";
die;
}
$attributes = array('employeeID','givenname','sn','mail','telephoneNumber');
if(!empty($_GET['customer_id'])){ //If an ID is passed in use that to make a direct lookup
$filter = 'employeeID='.$_GET['customer_id'].'*';
}elseif(!empty($_GET['email'])){ //If no ID then try email
$filter = 'mail='.$_GET['email'].'*';
}elseif(!empty($_GET['last_name'])){ //If no ID or email then search on last name
$filter = 'sn='.$_GET['last_name'].'*';
}elseif(!empty($_GET['first_name'])){ //Try first name if no ID,email,last name
$filter = 'givenname='.$_GET['first_name'].'*';
}else{
$filter = 'sn='.'*'; //Return everyone
}
$search = ldap_search($ds, $dn, $filter, $attributes)
or die ("ldap search failed: ".ldap_error($ds));
$entries = ldap_get_entries($ds, $search);
echo '<?xml version="1.0" encoding="utf-8"?>';
}
?>
<livelookup version="1.0" columns="first_name,last_name, email">
<?php for ($i=0; $i < $entries["count"]; $i++) : ?>
<customer>
<customer_id><?php if(isset($entries[$i]['employeeID'][0])){ echo htmlspecialchars($entries[$i]['employeeID'][0]); } ?></customer_id>
<first_name><?php if(isset($entries[$i]['givenname'][0])){ echo htmlspecialchars($entries[$i]['givenname'][0]); } ?></first_name>
<last_name><?php if(isset($entries[$i]['sn'][0])){ echo htmlspecialchars($entries[$i]['sn'][0]); } ?></last_name>
<email><?php if(isset($entries[$i]['mail'][0])){ echo htmlspecialchars($entries[$i]['mail'][0]); } ?></email>
<phone><?php if(isset($entries[$i]['telephonenumber'][0])){ echo htmlspecialchars($entries[$i]['telephonenumber'][0]); } ?></phone>
<!-- Add custom elements here. Simply add them to $attrs above and then output the tag like the others here -->
</customer>
<?php endfor; ?>
</livelookup>
<?php ldap_unbind($ds); ?>

Categories