0
votes

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 = '[email protected]';
$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*))";

1

1 Answers

1
votes

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:

  1. If you have a user called neil, and another called oneil, then whenever neil logs in, you will find both accounts in that search.
  2. 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.