Failure of PHP AD LDAP script ONLY when passed variables - php

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); ?>

Related

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.

How can i manage an ldap_search() Operations error?

I'm trying to use an LDAP query to get my AD groups of one of my divisions, I've written this for the moment:
<?php
session_start();
//::::::::DEBUG::::::::\\
//echo $_SESSION['login_session'];
//echo "<br>";
//echo $_SESSION['password_session'];
//echo "<br>";
//echo $_SESSION['AD_session'];
//$_SESSION['AD_session']=ldap_conect(XXX.XXX.XXX,389) but i apparently cannot conserve this function in a $_SESSION var...
//echo "<br>";
//echo $_SESSION['DN_SESSION'];
//"OU=XXX,DC=XXX,DC=XXX"
//echo "<br>";
//::::::::DEBUG::::::::\\
//----------------------------------------------------------------------------------------------------
//::::::::SECURITY FUNCTION::::::::\\
if (NULL!==($_SESSION['login_session']&&$_SESSION['password_session'])){
//::::::::SECURITY FUNCTION::::::::\\
//----------------------------------------------------------------------------------------------------
//::::::::VARIABLES::::::::\\
$filter = "(CN=*)";
$attr = array("OU","CN","DC");
//::::::::VARIABLES::::::::\\
//----------------------------------------------------------------------------------------------------
//::::::::LDAP's setting::::::::\\
ldap_set_option(ldap_connect("XXX.XXX.XXX",389), LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option(ldap_connect("XXX.XXX.XXX",389), LDAP_OPT_REFERRALS, 0);
//::::::::LDAP's setting::::::::\\
//----------------------------------------------------------------------------------------------------
//::::::::LDAP BIND::::::::\\
ldap_bind(ldap_connect("XXX.XXX.XXX",389),"CN=".$_SESSION['login_session'].",OU=XXX,OU=XXX,DC=XXX,DC=XXX", $_SESSION['password_session']);
//::::::::LDAP BIND::::::::\\
//----------------------------------------------------------------------------------------------------
//::::::::REQUESTS VARIABLES::::::::\\
$result = ldap_search(ldap_connect("XXX.XXX.XXX",389),$_SESSION['DN_SESSION'], $filter, $attr);
$rescount = ldap_count_entries(ldap_connect("XXX.XXX.XXX",389),$result);
$data = ldap_get_entries(ldap_connect("XXX.XXX.XXX",389),$result);
//::::::::REQUESTS VARIABLES::::::::\\
//----------------------------------------------------------------------------------------------------
//::::::::RESULTS DISPLAY::::::::\\
echo '<pre>';
foreach($data as $row) {
print_r($row);
}
//::::::::RESULTS DISPLAY::::::::\\
//----------------------------------------------------------------------------------------------------
?>
The binding function is working well and I'm using a valid user to query my AD groups. But I get an "ldap_search(): Search: Operations error" message on my ldap_search query. I've searched for a moment on different forums and I saw some solutions: setting the protocol and referral of the AD, which I've done in my LDAP's setting part, I also saw that some people get this error because they were using DN instead of DC in the distinguished name that they wanted to reach but it is not my case...
Is someone have an idea of what's the problem in my code ? Thanks a lot.
Operations Error means there is an error in the sequencing of operations.
LDAP is a connected protocol, which means that you first connect to it, and then you issue multiple operations on that connection, the first one being a Bind to authenticate the user.
In your code, you are creating a new connection for each operation with ldap_connect("XXX.XXX.XXX",389). Do this once, pass the connection to all other calls as a variable, and things should work.

PHP login script using bind_result in subsequent query mysqli

I'm trying to build a relatively simple PHP login script to connect to MySQL database running on my home server. I know the connection works as I've gotten some data returned as I would expect. However, I am having trouble getting the full script to work.
Essentially, I'm taking in a username/password from the user, and I first do a lookup to get the user_id from the users table. I then want to use that user_id value to do a comparison from user_pswd table (i'm storing usernames and passwords in separate database tables). At one point, I was able to echo the correct user_id based on the username input. But I haven't been able to get all the issues worked out, as I'm pretty new to PHP and don't really know where to see errors since I load this onto my server from a remote desktop. Can anyone offer some advice/corrections to my code?
The end result is I want to send the user to another page, but the echo "test" is just to see if I can get this much working. Thanks so much for the help!
<?php
ob_start();
$con = new mysqli("localhost","username","password","database");
// check connection
if (mysqli_connect_errno()) {
trigger_error('Database connection failed: ' . $con->connect_error, E_USER_ERROR);
}
$users_name = $_POST['user'];
$users_pass = $_POST['pass'];
$user_esc = $con->real_escape_string($users_name);
$pass_esc = $con->real_escape_string($users_pass);
$query1 = "SELECT user_id FROM users WHERE username = ?;";
if ($result1 = $con->prepare($query1)) {
$result1->bind_param("s",$user_esc);
$result1->execute();
$result1->bind_result($userid);
$result1->fetch();
$query2 = "SELECT user_pswd_id FROM user_pswd WHERE active = 1 AND user_id = ? AND user_pswd = ?;";
if ($result2 = $con->prepare($query2)) {
$result2->bind_param("is",$userid,$pass_esc);
$result2->execute();
$result2->bind_result($userpswd);
$result2->fetch();
echo "test", $userpswd;
$result2->free_result();
$result2->close();
} else {
echo "failed password";
}
$result1->free_result();
$result1->close();
}
$con->close();
ob_end_clean();
?>

Add password user using LDAP PHP

I searched every days for my problem, I tried many solutions and I didn't find... :(
I want to create an user using ldap_add with PHP. Working fine without enable account and without password. You find the code below.
Can you help me, please?
Config :
PHP 5.6
Windows Server 2012 R2 with AD
I can enable an account when I use $info["useraccountcontrol"]=544; but the account isn't with a password... User must loggon without password and type his new password at the first connection. *
I tried to add a password with $info['userPassword'] and chand useraccountontrol at 512 and I get this error :
ldap_add(): Add: Server is unwilling to perform
Here is my code :
<?php
$name = htmlspecialchars($_POST["name_build"]);
$lastname = htmlspecialchars($_POST["lastname_build"]);
$department = utf8_encode(htmlspecialchars($_POST["department_build"]));
$title = utf8_encode(htmlspecialchars($_POST["title_build"]));
$dn="CN=$name OU=Users, o=Domocom, c=net";
$ds = ldap_connect("192.168.1.1",389);
if ($ds) {
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); // IMPORTANT
ldap_bind($ds, "administrateur#domocom.net", "password");
// Prépareles données
$cn = $info["cn"] = "$lastname $name";
$info["sn"]="$name";
$info["givenname"]="$lastname";
$info["displayname"]="$lastname $name";
$info["name"]="$lastname $name";
$info["userprincipalname"]= "$lastname.$name#domocom.net";
$info["samaccountname"]= "$lastname.$name";
$info["title"]="$title";
$info["department"]="$department";
$info["mail"]="$lastname.$name#domocom.fr";
$info["postalcode"]="69009";
$info["objectClass"][0]="user";
//$info['userPassword'] = "password";
//$info["useraccountcontrol"]=544;
$r = ldap_add($ds,"CN=$cn,OU=Users,OU=Direction,OU=Domocom-SP,DC=domocom,DC=net", $info);
ldap_close($ds);
} else {
echo "unable to connect to ldap server";
}
?>
Thanks a lot.
PS : it's fake society for my school. :p
If it's an AD you might need to use a secure LDAP-Connection.
For that you'll need to call ldap_connect('ldaps://192.168.1.1:<port of the AD>');. Calling ldap_connect with two parameters is deprecated and should be avoided. Use it with an LDAP-URI!
You can also omit the if…else around the ldap_connect as it will return true in almost all cases. And a true return-value does not mean that a connection to the server actually as established. A connection is first established on the first ldap_-command that needs a connection which is typically ldap_bind.
And then you might want to have a look at Change AD password using PHP, Issue updating AD password using PHP and Change AD Password using PHP/COM/ADSI/LDAP

ldap_mod_replace() [function.ldap-mod-replace]: Modify: Server is unwilling to perform

Getting an error:
Server is unwilling to perform
while changing unicodePwd in AD through PHP. However, I'm able to search, add, remove and modify any attributes of the users.
Using Administrator account to bind and admin has full rights to change passwords of any users.
Here's the code I'm using:
<?php
$dn = "CN=Vishal Makwana,OU=Address Book,DC=example,DC=com";
$ad = ldap_connect("ldap://example.com")
or die("Couldn't connect to AD!");
ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3);
$bd = ldap_bind($ad,"admin#example.com","admin1");
if($bd) {
echo "AD bind successfully";
}
else {
echo "Couldn't bind AD";;
}
$user["unicodePwd"] = "asdf1234";
$result = ldap_mod_replace($ad, $dn, $user);
if ($result) echo "User modified!"; else
echo "There was a problem!";
ldap_unbind($ad);
?>
There are a number of things you need to get exactly right to set a password in AD via LDAP.
you need to use an SSL connection (ldaps://)
the password needs to be enclosed in quotes
the (quoted) password needs to be encoded in 16-bit unicode (UTF-16LE)
Assuming the password you're trying to set is ordinary ascii characters, the unicode conversion can be accomplished by adding a \000 byte after each byte of the ascii string, as shown in this code sample.
So your example would instead look like:
$newpassword = "asdf1234";
$newpassword = "\"" . $newpassword . "\"";
$len = strlen($newpassword);
for ($i = 0; $i < $len; $i++) $newpass .= "{$newpassword{$i}}\000";
$user["unicodePwd"] = $newpass;
After searching a lot and spending a lot of time, I am finally able to modify the active directory user password from PHP code using LDAP library.
We need the LDAP's connection with the active directory server from the PHP code; and that you have to modify the unicodePwd field.
ldap_connect(ldaps://IP, 636);
ldap_connect(ldaps://IP, 389);

Categories