C# – Why does DirectoryServicesCOMException occur querying Active Directory from a machine other than the web server

active-directoryasp.netcwindows-authentication

My ASP.NET WebForms app running on IIS 7.5 works fine when the request comes from the web server but throws the following error when the same domain user requests the same page from any other machine on the domain:

TYPE: System.DirectoryServices.AccountManagement.PrincipalOperationException

MSG: An operations error occurred.

at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit()
at System.DirectoryServices.AccountManagement.PrincipalContext.DoDomainInit()
at System.DirectoryServices.AccountManagement.PrincipalContext.Initialize()
at System.DirectoryServices.AccountManagement.PrincipalContext.get_QueryCtx()
at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithTypeHelper(PrincipalContext context, Type principalType, Nullable`1 identityType, String identityValue, DateTime refDate)
at System.DirectoryServices.AccountManagement.Principal.FindByIdentityWithType(PrincipalContext context, Type principalType, String identityValue)
at System.DirectoryServices.AccountManagement.GroupPrincipal.FindByIdentity(PrincipalContext context, String identityValue)
at Ceoimage.Basecamp.ActiveDirectory.SidSource._TryGetGroupPrincipal(PrincipalContext context, String groupName) in c:\Users\David\Documents\VsProjects\CeoTrunk\Ceoimage.Basecamp\Basecamp\ActiveDirectory\SidSource.cs:line 115

— INNER EXCEPTION —

TYPE: System.DirectoryServices.DirectoryServicesCOMException

MSG: An operations error occurred.

at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_SchemaEntry()
at System.DirectoryServices.AccountManagement.ADStoreCtx.IsContainer(DirectoryEntry de)
at System.DirectoryServices.AccountManagement.ADStoreCtx..ctor(DirectoryEntry ctxBase, Boolean ownCtxBase, String username, String password, ContextOptions options)
at System.DirectoryServices.AccountManagement.PrincipalContext.CreateContextFromDirectoryEntry(DirectoryEntry entry)
at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInit()

The application's web.config file specifies <authentication mode="Windows"> and <identity impersonate="true" /> but does not use a membership provider. In IIS, the application pool runs as a domain user and the app's authentication has everything disabled except for ASP.NET Impersonation (set to Authenticated user) and Windows Authentication.

The code that causes the error just tries to get a group's SID to verify the user should access the application:

public string GetGroupSid()
{
    using (var context = new PrincipalContext("Domain", "Test", "CN=Users,DC=Test,DC=local", ContextOptions.Negotiate))
    {
        var group = _TryGetGroupPrincipal(context, "AppGroup");
        return group.Sid.Value;
    }
}
private static GroupPrincipal _TryGetGroupPrincipal(PrincipalContext context, string groupName)
{
    try
    {
        return GroupPrincipal.FindByIdentity(context, groupName);
    }
    catch (Exception e)
    {
        throw _GetUnableToFindGroupException(e, groupName);
    }
}

As I said earlier, the app works fine if the request comes from the web server but throws this error when the same domain user requests the same page from any other machine on the domain. I know about enabling Kerberos, but you can see my code specifies ContextOptions.Negotiate. I'm not an expert in this stuff, but I am expertly baffled.

Best Answer

Configuring the web server for delegation allowed my web app to query the SID of an AD group without error and without changing any code.