Validating Users in Active Directory Gotcha

time to read 3 min | 457 words

A while ago I asked about doing Active Directory Authentication, after getting some advice, I settled on using the Acitve Directory Membership provider. It worked, but after a while we started to get really bad feedback from the users about the time that it took to login. To give you an idea, I timed it and I have an average of 14 seconds spent just making the "Membership.ValidateUser()" call.

For a while I insisted that it can't be my code, after all, I was explicitly using the Microsoft recommended way of doing it. I am not an Active Directory / LDAP expert by any mean, so I just went with the recommended appraoch. Today the network guys finally hunt me down and show me the sniffer trace logs, which shows my application getting a response packet from the domain controller and spending 12 seconds doing something with it, before responding.

I sat down and wrote the following benchmark.

Validate using MembershipProvider:

private static bool MembershipProvider(string user, string password)
{
    try
    {
        return Membership.ValidateUser(user, password);
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        return false;
    }
}

<system.web>
    <membership defaultProvider="ExtranetADMembershipProvider">
        <providers>
            <add name="ExtranetADMembershipProvider"
                 type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web"
                 connectionStringName="ADConnectionString"
                 attributeMapUsername="SAMAccountName"
                 connectionUsername="MyDomain\Beaker"
                 connectionPassword="Do you get the joke?"/>
        </providers>
    </membership>
</system.web>

Validate directly using System.DirectoryServices:

private static bool DirectLdap(string user, string password)
{
    try
    {
        using (DirectoryEntry de = new DirectoryEntry(ldapPath,
                                              Domain +"\\"+ user, password,
                                               AuthenticationTypes.Secure))
        {
            return de.NativeObject != null;
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        return false;
    }
}

The end result is rather suprising:

LDAP:
        First:                                                                   00:00.4531424
        After first time, validate 1000 times same user: 00:20.9851808
Membership:
        First:                                                                   00:24.7040736
        After first time, validate 1000 times same user: 00:24.3603104

So, for the first request I made, it is 55 times faster to use the direct approach. and it is 16 precent slower on repeating calls. I have run the test a number of times, and the result of 0.4 seconds is actually very close to the high end for the first request.

My actual usage scenario meant that the average login time was actually averaging on 14 seconds or so. I would guess that the issue is some sort of caching that it is doing, but the initial cost is so high, and apperantly there is continous cost associated with it that is visible over long term usage.

I am using it for authenticaton only, so I just dropped the whole thing and use DirectoryServices myself. I am very disappointed about it, but the perf has shot thourgh the roof.