PHP LDAP search issue - php

I'm trying for the first time to use LDAP in some PHP code. I want to determine if someone is a member of a particular AD group.
I've cobbled together some code from other examples and this runs without error, but indicates 0 results, when the user is in fact a member of the group.
Here is my code:
$hostname="192.168.1.1";
$conn=ldap_connect($hostname, 389);
ldap_set_option ($conn, LDAP_OPT_REFERRALS, 0) or die('Unable to set LDAP opt referrals');
ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3) or die('Unable to set LDAP protocol version');
if ($conn) {
$dn = "DC=domain,DC=local";
// if (!($ldapc=ldap_bind($conn,'CN=Username,CN=Users,DC=domain,DC=local','P#ssw0rd'))) {
if (!($ldapc=ldap_bind($conn,'username#domain.local','N0tMyP#ssw0rd'))) {
Is the full CN=,DC=, etc or the #domain.local the preferred method here?
Also, I am assuming that all searches performed for membership will be against the user authenticated by the ldap_bind()?
code continues:
echo "<p>Error:" . ldap_error($conn) . "</p>";
echo "<p>Error number:" . ldap_errno($conn) . "</p>";
echo "<p>Error:" . ldap_err2str(ldap_errno($conn)) . "</p>";
die;
}
$attributes = array("memberOf");
$filter = "(memberOf=myGroup,OU=Application Security,DC=domain,DC=local)";
$result = ldap_search($conn, $dn, $filter, $attributes);
echo $result."<BR />";
$info = ldap_get_entries($conn, $result);
echo $info["count"]." entries returned.\n";
for ($i=0; $i < $info["count"]; $i++) {
echo $info[$i]["ou"][0];
}
} else {
echo "<h4>Unable to connect to LDAP server</h4>";
}
ldap_unbind($conn);
EDIT:
After suggestions below, I was able to get this working as expected. Here is the final working code for those who would benefit...
$hostname="192.168.1.1";
$conn=ldap_connect($hostname, 389);
ldap_set_option ($conn, LDAP_OPT_REFERRALS, 0) or die('Unable to set LDAP opt referrals');
ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3) or die('Unable to set LDAP protocol version');
if ($conn) {
$dn = "DC=domain,DC=local";
if (!($ldapc=ldap_bind($conn,'CN=Administrator,CN=Users,DC=domain,DC=local','password'))) {
echo "<p>Error:" . ldap_error($conn) . "</p>";
echo "<p>Error number:" . ldap_errno($conn) . "</p>";
echo "<p>Error:" . ldap_err2str(ldap_errno($conn)) . "</p>";
die;
}
$filter = "(memberOf=cn=Dashboard,OU=Application Security,DC=domain,DC=LOCAL)";
$result = ldap_search($conn, $dn, $filter);
// $attributes = array('samaccountname');
//$result = ldap_search($conn, $dn, $filter, $attributes);
$info = ldap_get_entries($conn, $result);
echo $info["count"]." entries returned.<br />";
for ($i=0; $i < $info["count"]; $i++) {
echo $i . " " . $info[$i]["samaccountname"][0] . "<br />";
}
} else {
echo "<h4>Unable to connect to LDAP server</h4>";
}
ldap_unbind($conn);

Personally I prefer the cn=... way to bind to a directory as it's universal. The username#domain-version only works on AD.
And the user that binds to the directory is NOT the user you are looking up the groups for but the user you are looking up the information with.
So when the user you are binding to the LDAP-Server with doesn't have the right to see the group information you won't have much luck. On the other hand if you'd need to login with the user you are looking the group-memberships for you could only retrieve the group-memberships when you know the password of the user. Taht would be a bit strange, wouldn't it?
And as the user binding to the LDAP-Server only has to have read-permission to the LDAP-Server often it is possible to use an anonymous bind without the need for a real user to bind. You would then simply omit the user and password-fields on the ldap_bind. But that depends on the setup of the Server.
To get the number of results returned by your query you can also use the ldap_count_entries($connectionHandle, $resultHandle)-function but I assume that there is an issue in your search-filter.
The search-filter has to contain a query. In your case you just give a string but you don't tell the LDAP-Server wwhich field to map it against. The filter always looks something ike this: <fieldname>=<querystring>. So in your case that would be memberOf=cn=mygroup,OU=Application Security,DC=domain,DC=local. The difference being that the group is identified by it's complete DN which (I assume here) is cn=mygroup,OU=Application Security,DC=domain,DC=local - You'll have to verify that!
The query will return you all users that are a member of that role. And it will only return you the memberOf-Attribute of those users which you know already. So you should either leave the $attributes empty or use something like ['cn', 'sAMAcountName', 'mail'] to get the CN, the Users ID and the email-address returned.
In a second step you will then have to check whether the user you are looking for actually is in that returned array.
Alternatively you could just search vor the user (filter would be something like mail=<email-address> or sAMAcountName=<user-ID> and get the memberOf value returned. you will then have to look whether the required group is one of the ones in the memberOf-Entry.
Scared? Didn't understand it? Don't worry. Ask!

Related

PHP - LDAP Authentication and Search

I am using an Online LDAP Test Server here: http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/ to test some basic LDAP code.
I need to authenticate a user and retrieve some user information.
If I understand the information about the test server correctly I should be able to bind with users that belong to respective groups. With the code 'AS IS' below I can bind to un-commented $dn, but if I use any other $dn to authenticate, the bind fails.
What am I not understanding?
For example, tesla should belong to 'ou=scientists,dc=example,dc=com' but I am unable to authenticate tesla on that DN and subsequently I can't search for related information.
$dn = 'dc=example,dc=com';
// $dn = 'ou=mathematicians,dc=example,dc=com';
// $dn = 'ou=scientists,dc=example,dc=com';
$username = 'tesla';
$password = 'password';
$filter = "(uid=" . $username . ")";
$ldapDN = 'uid=' . $username . ',' . $dn;
$ldapCONN = ldap_connect("ldap.forumsys.com") or die("Could not connect to LDAP server.");
if ($ldapCONN)
{
ldap_set_option($ldapCONN, LDAP_OPT_PROTOCOL_VERSION, 3);
$ldapBIND = #ldap_bind($ldapCONN, $ldapDN, $password);
if ( $ldapBIND )
{
$result = ldap_search($ldapCONN, $dn, $filter) or die ("Error: ".ldap_error($ldapCONN));
$data = ldap_get_entries($ldapCONN, $result);
echo '<pre>';
print_r($data);
echo '</pre>';
}
else
{
echo "LDAP bind failed...";
}
}
When using LDAP, it is important to visualize how the database is organized.
Basically, all users are in the main folder. Use this folder to authenticate your user with, otherwise it will not work.
In this case the main folder where all users are in, is dc=example,dc=com. However, most LDAP servers use a main folder like cn=users,dc=example,dc=com.
Why are they using folders at all then? Well, that is to make it easier to categorize and search with a filter. For example, if you want to only show the names of scientists, you add the group Scientists to your search filter like $filter = "(ou=Scientists)". A filter for both groups would look like this: $filter = "(&(ou=Scientists)(ou=Mathematicians)". Now the server will take a look into this folder/these folders, and display just these members.
Hope this helps, for gaining further insight in how the server is organized, I can recommend installing Apache Directory Studio. It is free to download from their site, helped me a lot!

PHP ldap_get_entries() return count=zero

I am trying to authenticate users' login against LDAP(Server is Mac El Capitan).
I can successfully connect and bind to the ldap server.
I can search and sort the result.
But when I perform "ldap_get_entries",I received "Zero" entry.
I've tried everything from StackOverFlow to Google's second page.
Any Suggestions or idea why this might be happening?
MY CODE -
<?php
session_start(); // Starting Session
$error=''; // Variable To Store Error Message
if (isset($_POST['submit'])) {
if (empty($_POST['email']) || empty($_POST['password'])) {
$error = "Username or Password is invalid";
}
else
{
$usernameLogin=$_POST['email'];
$passwordLogin=$_POST['password'];
$username = stripslashes($usernameLogin);
$password = stripslashes($passwordLogin);
echo "User name is ".$username;
echo "</br>";
$ldapUser = "uid=xxxxxx,cn=users,dc=dns1,dc=xxxxxxxx,dc=com";
$ldapPass = "xxxxxxxxxxx";
$url = "ldap://dns1.xxxxxxx.com:389";
$ldap = ldap_connect("$url") or die("Could not connect to LDAP server.");
$baseDN = "cn=users,dc=dns1,dc=xxxxxxxxx,dc=com";
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS,0);
$bind = ldap_bind($ldap, $ldapUser, $ldapPass);
if($bind) {
echo "Connected To LDAP";
echo "</br>";
$filter="(sAMAccountName=$username)";
echo "Filter = ".$filter;
echo "</br>";
$result = ldap_search($ldap,$baseDN,$filter) or die("Could not search.");
echo "Result = ".$result;
echo "</br>";
$sort = ldap_sort($ldap,$result,"uid");
echo "Sort = ".$sort;
echo "</br>";
$number = ldap_count_entries($ldap, $result);
echo "Count Entries = ".$number;
echo "</br>";
$info = ldap_get_entries($ldap, $result);
echo "Data for " . $info["count"] . " items returned:<p>";
echo "Info = ".$info;
echo "</br>";
echo '<pre>'; print_r($info); echo '</pre>';
echo "</br>";
$fentry= ldap_first_entry($ldap, $result);
echo "First Entry = ".$fentry;
for ($i=0; $i<$info["count"]; $i++)
{
if($info['count'] > 1)
break;
echo "<p>You are accessing <strong> ". $info[$i]["sn"][0] .", " . $info[$i]["givenname"][0] ."</strong><br /> (" . $info[$i]["samaccountname"][0] .")</p>\n";
echo '<pre>';
var_dump($info);
echo '</pre>';
$userDn = $info[$i]["distinguishedname"][0];
}
ldap_close($ldap);
}
else{
echo "Cannot Connect To LDAP.";
}
}}
?>
I can connect - bind - search But "ldap_get_entries()" returns zero.
First: You can skip the or die "Could not connect to LDAP Server" as that will almost never happen. ldap_connect only checks the parameter for syntactical correctness and does not actually connect to the server. The actual connection happens on the first call to the server which usually is ldap_bind. That's why conncetion issues often surface on ldap_bind and not on ldap_connect.
Second: Where did you get samAccountName from? That's a field that's usually used by ActiveDirectory. In Apples OpenDirectory the user is usually identified by the uid-attribute. So your filter should be sprintf('uid=%s', $username).
Third: I doubt that only Users in the group "Open Directory Administrators" are allowed to bind agains the LDAP. They for sure are the only ones allowed to edit the directory but every other user can bind as well.
Fourth: ldap_sort is deprecated by now. It's not sorting on the server side but on the client side. So only the returned results are sorted. When you have paged results that means that - even though you sorted the result - there still will be entries that would fit right in between your results. I'm currently working on a way to use server-sided sorting but that relies on the feature to be available on the server. So you can use ldap_sort but you can also implement your own sorting on the result set.
So change the filter to uid=$username and you'll get the expected results. The mail attribute might also contain the full email-address and might therefore then fail! You can also adapt the filter to search more than one field. Have a look at this slide for short examples.
Solved it. I used "mail" instead of "sAMAccountName".
Here's the details -
1 ) From
$filter="(sAMAccountName=$username)";
to
$filter="(mail=$username)";
2 ) From
$sort = ldap_sort($ldap,$result,"uid");
to
$sort = ldap_sort($ldap,$result,"mail");
That's it.
Lessons learn from here -
Use "LDAP Admin Tool" or some sort of LDAP Tool to understand the structure of your LDAP environment before jumping into coding. Big lesson learnt.

Issue authenticating with LDAP

I'm trying to use IP.Board LDAP Login Handler; however, although the server connects and the query I perform is correct, I'm unable to login with a LDAP account. It throws the common "unknown username" error. The script connects successfully, because if I use wrong credentials it throws an authentication error in the LDAP settings page; this also happens if I force a ldap_search(): Search: Bad search filter or a ldap_search(): Search: Operations error when messing with the settings and trying to log in with an account in the Login Page. So the problem I believe should be somewhere else...
To test the settings I'm using, I have performed a successfully connection with the following code:
<?php
set_time_limit(30);
error_reporting(E_ALL);
ini_set('error_reporting', E_ALL);
ini_set('display_errors',1);
// config
$ldapserver = 'server ip';
$ldapuser = 'username';
$ldappass = 'password';
$ldaptree = "OU=The,DC=path,DC=to,DC=users";
// connect
$ldapconn = ldap_connect($ldapserver) or die("Could not connect to LDAP server.");
if($ldapconn) {
// binding to ldap server
$ldapbind = ldap_bind($ldapconn, $ldapuser, $ldappass) or die ("Error trying to bind: ".ldap_error($ldapconn));
// verify binding
if ($ldapbind) {
echo "LDAP bind successful...<br /><br />";
$result = ldap_search($ldapconn,$ldaptree, "(cn=*)") or die ("Error in search query: ".ldap_error($ldapconn));
$data = ldap_get_entries($ldapconn, $result);
// SHOW ALL DATA
echo '<h1>Dump all data</h1><pre>';
print_r($data);
echo '</pre>';
// iterate over array and print data for each entry
echo '<h1>Show me the users</h1>';
for ($i=0; $i<$data["count"]; $i++) {
//echo "dn is: ". $data[$i]["dn"] ."<br />";
echo "User: ". $data[$i]["cn"][0] ."<br />";
if(isset($data[$i]["mail"][0])) {
echo "Email: ". $data[$i]["mail"][0] ."<br /><br />";
} else {
echo "Email: None<br /><br />";
}
}
// print number of entries found
echo "Number of entries found: " . ldap_count_entries($ldapconn, $result);
} else {
echo "LDAP bind failed...";
}
}
// all done? clean up
ldap_close($ldapconn);
?>
It renders the array completely, showing me the complete list of users belonging to that path and that should be enough for IPB to validate the information, isn't it?
Since the connection is actually successful but it doesn't locate an user, it doesn't generate any Log record about it.
I already checked the LDAP username's permissions exposed in this thread: https://serverfault.com/questions/167371/what-permissions-are-required-for-enumerating-users-groups-in-active-directory/167401 so the user has administrative rights and also can read those elements.
This is quite frustrating. Any advise?
I found the UID field required by IPB was CNin our LDAP setup. After correcting this small thing, I finally managed to perform the sync

php ldap_search not returning results

I'm establishing a connection to our Active Directory listing of users/employees. I've done this through .NET, but cant get it to work in my PHP app.
I consistantly get a count of 0.
I've tried using samaccountname and sAMaccountname as filters, this does not change the result.
I am successfully connecting, as changing the $ldap will no longer find the server.
I am using valid credentials, as changing $authUser or $authPath provide an authorized error message.
The ldap_bind (i presume) is working, because it does perform the search and outputs a count of 0.
Here is my code:
<?php
try{
$ldap = "vmc-dc.CompanyName.vmc";
$authUser = "vmc\\MyUsername";
$authPass = "MyPassword";
$baseDn = "dc=vmc-dc,dc=CompanyName,dc=com";
$filter="(&(objectClass=user)(samaccountname=*))";
$conn = ldap_connect($ldap, 389) ;
if ($conn) {
ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($conn, LDAP_OPT_REFERRALS, 0);
// binding to ldap server
$ldapbind = ldap_bind($conn, $authUser, $authPass);
// verify binding
if ($ldapbind) {
//$sr=ldap_read($conn, $baseDn, $filter);
$sr=ldap_search($conn, $baseDn, $filter);
$number_returned = ldap_count_entries($conn,$sr);
echo "Count: " . $number_returned . "<br/>";
$entry = ldap_get_entries($conn, $sr);
ldap_close($conn);
echo "value = '" . $entry[0] . "'";
} else {
echo "LDAP conn ok...";
}
}
} catch (Exception $e) {
}
?>
I wonder if your filter is too broad, all user class objects (which includes computers, to Brian Desmond's point) and is returning more than 1000 found objects. In which case AD will error, and return nothing. I would expect you would get a returned error, so this may not be likely. But a more constrained filter, and/or a repetition with a standalone LDAP tool could help validate this idea.

PHP LDAP, adding new entries into LDAP

I am wanting to create a form that I can fill out and once I submit it the form values can be pulled out and that person can be created into LDAP. I am not very experienced with LDAP infact I just worked towards making an LDAP bind work so I am needing some help. How can I add new users into LDAP through this form I can fill out? I know LDAP has an Add commands but I am not particularly sure on how to get started and what information needs to be passed for the person to be created in LDAP. If it helps, below is my code for LDAP bind.
<?php
$name=$_REQUEST['name'];
$x=1;
if($x==1)
{
//LDAP stuff here.
$username = "myusername";
$password = "mypass";
$ds = ldap_connect('ldap://ldap:389');
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
//Can't connect to LDAP.
if( !ds )
{
echo "Error in contacting the LDAP server -- contact ";
echo "technical services! (Debug 1)";
exit;
}
//Connection made -- bind anonymously and get dn for username.
$bind = #ldap_bind($ds);
//Check to make sure we're bound.
if( !bind )
{
echo "Anonymous bind to LDAP FAILED. Contact Tech Services! (Debug 2)";
exit;
}
$search = ldap_search($ds, "ou=People,DC=sde,DC=goliat,DC=com", "uid=$username");
//Make sure only ONE result was returned -- if not, they might've thrown a * into the username. Bad user!
if( ldap_count_entries($ds,$search) != 1 )
{
echo "Error processing username -- please try to login again. (Debug 3)";
redirect(_WEBROOT_ . "/try1b.php");
exit;
}
$info = ldap_get_entries($ds, $search);
//Now, try to rebind with their full dn and password.
$bind = #ldap_bind($ds, $info[0][dn], $password);
if( !$bind || !isset($bind))
{
echo "Login failed -- please try again. (Debug 4)";
redirect(_WEBROOT_ . "/try1b.php");
exit;
}
//Now verify the previous search using their credentials.
$search = ldap_search($ds, "ou=People,DC=sde,DC=goliat,DC=com", "cn=$name");
$info = ldap_get_entries($ds, $search);
if( $username == "myusername" )
{
/*
very useful set of information to view the LDAP tree info from an array
echo $username;
echo "<pre>".print_r($info[0],true)."</pre><br />";
*/
echo $info[0][cn][0];
echo ",";
echo $info[0][mail][0];
echo ",";
echo $info[0][telephonenumber][0];
exit;
}
else
{
echo "Error. Access Denied";
redirect(_WEBROOT_ . "/try1b.php");
exit;
}
ldap_close($ds);
exit;
}
?>
I would recommend a newUser.php (or whatever) file that checks to make sure that all of your required information is present, then send that info to the file you have started above.
Your $bind should take three variables...
$bind = ldap_bind($ds, 'cn=root,dc=example,dc=com', secretPassword);
For a pretty good guide to adding people to your LDAP server via PHP go to http://www.php2python.com/wiki/function.ldap-add/
Good luck
An add request requires the distinguished name to be added and the attribute that are to be part of the entry, and optional request controls.
On another subject, your search has subtree scope and may return more than one entry that matches user name. There is no reason why there could not be multiple entries with the same RDN in different branches underneath the base object specified in the code - unless your directory server vendor has implemented an attribute uniqueness constraint.

Categories