Reputation: 292
those are my prerequisites:
Right now I check and see if a USER is member of a certain group before displaying some data:
if(is_allowed(USER, '(memberof=CN=Repairgroup,OU=Laboratory,OU=Organization,OU=MyBusiness,DC=somedc,DC=local)')):
display some data
endif;
function is_allowed($check, $filter) {
// connect to ldap
$ldapconn = ldap_connect(LDAP_HOST) or die("Could not connect to LDAP server.");
// binding to ldap server
ldap_bind($ldapconn, LDAP_USER, LDAP_PASS) or die("Error trying to bind: " . ldap_error($ldapconn));
// search for $filter
$result = ldap_search($ldapconn, LDAP_TREE, $filter) or die("Error in search query: " . ldap_error($ldapconn));
$data = ldap_get_entries($ldapconn, $result);
// check if user is part of LDAP_TREE
if (!in_multiarray($check, $data)):
// all done? clean up!
ldap_close($ldapconn);
return false;
endif;
// all done? clean up!
ldap_close($ldapconn);
return true;
}
function in_multiarray($elem, $array) {
while (current($array) !== false):
if (current($array) == $elem):
return true;
elseif(is_array(current($array))):
if(in_multiarray($elem, current($array))):
return true;
endif;
endif;
next($array);
endwhile;
return false;
}
Now if I want to assign a User to a ticket for example I run the following:
// connect to ldap
$ldapconn = ldap_connect(LDAP_HOST);
// binding to ldap server
ldap_bind($ldapconn, LDAP_USER, LDAP_PASS);
// search for $filter
$result = ldap_search($ldapconn, LDAP_TREE, LABORATORY);
$data = ldap_get_entries($ldapconn, $result);
utf8_encoder($data);
for ($i=0; $i<$data["count"]; $i++):
echo "<tr><td><label class=\"label\"><input type=\"checkbox\" name=\"user[]\" value=\"".$data[$i]["cn"][0]."\" />".$data[$i]["cn"][0]."</label></td></tr>";
endfor;
ldap_close($ldapconn);
And into the database I just put the name. If I've more users assigned to it I seperate them with ',' like that:
$users = NULL;
foreach($c_post['user'] as $value):
$users = $users.$value.", ";
endforeach;
Result would be something like that in my database: Alex Foo, Peter Bar
And reading from the DB I just use a simple explode to seperate them.
$iduser = explode(", ", $row->iduser);
also in order to get the current user browsing I use this filter:
// User based on Windows-Login (Look up user currently browsing)
define('LDAP_SELF', '(sAMAccountName='.substr($c_server['REMOTE_USER'], 11).')');
Now having this set up like that it is very easy to add user, manage their rights and so on. Even a destinction between Head of department and so on is fairly easy once you grasp on those filter LDAP uses.
But for me it becomes painful to use in my code. Now I want to send messages and get some statistics based on user which would end up with a bind every time to LDAP and look up the users. It is the first time I'm using LDAP / Active Directory and before that I just had my table in MySQL which was filled with users and their ID. It just seemed more easy to store, manage and do actions based on the IDs in my code then it is now.
As an example
I want to edit the User assigned to a ticket. First I select the value from my table, then explode it and list the users. Now I would need to combine them and check before updating my database if those users are still part of the Active Directory and have sufficient rights.
Thank you so much for your time :)
What I ended up with:
To make things easier I have this:
if(!isset($_SESSION["DN"]) && !isset($_SESSION["username"])):
// connect to ldap
$ldapconn = ldap_connect(LDAP_HOST) or die("Could not connect to LDAP server.");
// binding to ldap server
ldap_bind($ldapconn, LDAP_USER, LDAP_PASS) or die("Error trying to bind: " . ldap_error($ldapconn));
// search for $filter
$result = ldap_search($ldapconn, LDAP_TREE, '(sAMAccountName='.USER.')') or die("Error in search query: " . ldap_error($ldapconn));
$data = ldap_get_entries($ldapconn, $result);
utf8_encoder($data);
ldap_close($ldapconn);
$_SESSION["DN"] = $data[0]["dn"];
preg_match('/^CN=(.+?),(?:CN|OU)=.+/', $_SESSION['DN'], $matches);
$_SESSION["username"] = $matches[1];
endif;
If I need to display users I have this:
// connect to ldap
$ldapconn = ldap_connect(LDAP_HOST) or die("Could not connect to LDAP server.");
// binding to ldap server
ldap_bind($ldapconn, LDAP_USER, LDAP_PASS) or die("Error trying to bind: " . ldap_error($ldapconn));
?>
<div id="container">
<form action="#" method="post">
<table>
<tbody>
<?php
echo "<tr><td>Repairgroup</td></tr>";
$result = ldap_read($ldapconn,
"CN=Repairgroup,OU=Laboratory,OU=Organization,OU=MyBusiness,DC=domain,DC=local",
"(objectClass=*)",
["member"]
);
$data = ldap_get_entries($ldapconn, $result);
utf8_encoder($data);
foreach($data[0]["member"] as $k => $v):
if(!is_int($v)):
preg_match('/^CN=(.+?),(?:CN|OU)=.+/', $v, $name);
echo "<tr><td><label class=\"label\"><input type=\"checkbox\" name=\"user[]\" value=\"".$v."\" />".$name[1]."</label></td></tr>\n";
endif;
endforeach;
?>
</tbody>
</table>
</form>
Then I would store one or more DNs in my database seperated with |
and later when I had to display just the name I use this:
preg_match_all('/\bCN=\b(.+?),/', $row->iduser, $name, PREG_SET_ORDER, 0);
echo "<td class=\"worker\"><span>";
for($i = 0; $i < count($name); $i++):
echo "<p>".$name[$i][1]."</p>\n";
endfor;
echo "</span></td>\n";
This is an example of my regex: https://regex101.com/r/s6PbOR/1/
And to check if someone has access:
if(is_allowed($_SESSION["DN"], 'CN=Repairgroup,OU=Laboratory,OU=Organization,OU=MyBusiness,DC=somedc,DC=local')):
display some data
endif;
Thank you Esteban for guiding me towards this! :) Much appreciated
Upvotes: 0
Views: 1481
Reputation: 1815
- Is there anything I can improve in my code or way of using LDAP?
- Am I using LDAP "correctly"? (I know the answer will be based on opinion but as long as I'm not abusing LDAP with my code I'm fine with it I guess)
You use your LDAP directory as a RDBM backend. You should try to use it as it is intended : a hierarchical database.
In your code you :
memberof
set for a groupUSER
is part of this groupBUT : You have the group DN
, LDAP has mechanisms which entrust that a user to be part of a group should exist in the directory.
SO: What I would have done is :
Retrieve the member
attribute of the group :
$result = ldap_read($ldapconn,
"CN=Repairgroup,OU=Laboratory,OU=Organization,OU=MyBusiness,DC=somedc,DC=local",
"(objectClass=*)",
["member"]
)
This saves you the load of searching into the directory because you access directly the entry providing the unique id to read it (the DN)
- How save will it be to bind everytime to LDAP compared to just have the users in my database?
- If unsafe doing it with LDAP should I run once a day some script an populate a table with the users?
LDAP is a protocol which is built to handle a ratio much higher of read/search than write, so as long as the request/search is optimized, there should be no problem to look for a user every time you need it.
- More easy way to perform something like below?
ldap_read
the user entry without having to perform a search to find this information beforehandmember
attribute array returned by the ldap_read
on the LDAP group (as seen previously)member
attribute of the group should exist in the directory, so the list you need to check is only the one present in the database and not in the groupldap_read
the users entry without retrieving any attribute, if the user does not exist you will have a LDAP error : 32 no such object
It will be much more faster and efficient than making multiple searches
If you do it this way, to check if a user is present in a group and is allowed, the code you posted will only be :
// USER would be the DN in this case
if(is_allowed(USER, 'CN=Repairgroup,OU=Laboratory,OU=Organization,OU=MyBusiness,DC=somedc,DC=local')):
display some data
endif;
function is_allowed($check, $dn) {
// connect to ldap
$ldapconn = ldap_connect(LDAP_HOST) or die("Could not connect to LDAP server.");
// binding to ldap server
ldap_bind($ldapconn, LDAP_USER, LDAP_PASS) or die("Error trying to bind: " . ldap_error($ldapconn));
// search for $dn
$result = ldap_read($ldapconn,
$dn,
"(objectClass=*)",
["member"]
) or die("Error in search query: " . ldap_error($ldapconn));
$data = ldap_get_entries($ldapconn, $result);
ldap_close($ldapconn);
return in_array($check, $data[0]['member']);
}
(NOTE: you will need to tweak this a little to handle the error code return by a user deleted from the LDAP directory)
Upvotes: 1