As I digging into it deeper, I found that in LibreNMS/Authentication/ActiveDirectoryAuthorizer.php at line 108 there is an ldap_search filter, which is contain a 1.2.840.113556.1.4.1941 OID which is refers to LDAP_MATCHING_RULE_IN_CHAIN. It is a Microsoft Active Directory matching rule used to recursively search through nested group memberships. If I change this filter, skip that OID, then our AD is just works fine with the modified code.
I don’t know if this is a strange AD behavior, checked the groups are security groups, but somehow our AD is gets back result with count=1 in the outer, and count=0 in the inner, even if user is not member of that group:
>>> GROUP: LibreNMS-admin, Outer count: 1, Inner count: 0
>>> GROUP: LibreNMS-readonly, Outer count: 1, Inner count: 0
>>> GROUP: LibreNMS-group-RW, Outer count: 0, Inner count: 0
If I change “CN” to “memberOf” in attributes, then inner count is 1 also:
>>> GROUP: LibreNMS-admin, Outer count: 1, Inner count: 1
>>> GROUP: LibreNMS-readonly, Outer count: 1, Inner count: 1
>>> GROUP: LibreNMS-group-RW, Outer count: 0, Inner count: 0
The test_user is member of LibreNMS-admin group and only, not the other two.
The test PHP code:
$groups = array('LibreNMS-admin','LibreNMS-readonly','LibreNMS-group-RW');
foreach ($groups as $group) {
$ldap_filter = "(&(&(samaccountname=test_user)(!(useraccountcontrol:1.2.840.113556.1.4.803:=2))(objectclass=user))(memberOf:1.2.840.113556.1.4.1941:=cn=".$group.",".$group_dn."))";
$attributes = array("DN");
# $attributes = array("memberOf");
$search_result = @ldap_search($ldap_conn, $ldap_base_dn, $ldap_filter, $attributes);
if (!$search_result) { die("LDAP search error: " . ldap_error($ldap_conn)); }
$entries = ldap_get_entries($ldap_conn, $search_result);
if ($entries["count"] > 0) {
$co = $entries["count"];
$ci = $entries["0"]['count'];
echo ">>> GROUP: ".$group.",\tOuter count: ".$co.", Inner count: ".$ci."\n";
} else {
echo ">>> GROUP: ".$group.",\tOuter count: 0, Inner count: 0\n";
}
}
After I change the filter to:
$ldap_filter = "(&(&(samaccountname=test_user)(!(useraccountcontrol:1.2.840.113556.1.4.803:=2))(objectclass=user))(memberOf=cn=".$group.",".$group_dn."))";
and attributes is “DN”, then:
>>> GROUP: LibreNMS-admin, Outer count: 1, Inner count: 0
>>> GROUP: LibreNMS-readonly, Outer count: 0, Inner count: 0
>>> GROUP: LibreNMS-group-RW, Outer count: 0, Inner count: 0
If I change attributes to “memberOf”, then:
>>> GROUP: LibreNMS-admin, Outer count: 1, Inner count: 1
>>> GROUP: LibreNMS-readonly, Outer count: 0, Inner count: 0
>>> GROUP: LibreNMS-group-RW, Outer count: 0, Inner count: 0
As we see, current code could gets back false positive authorization to unauthorized users. Any hints how to fix the code?