I have an ASP.NET application which relies heavily on AD authentication. We recently broke out a service which used to live in the same solution as the application into its own solution, so that we could maintain them seperately and not impact users who rely on the service when, say, we needed to make code changes which only impacted the UI side of the application.
This has lead to an interesting issue for me though. When I debug, I have my local copy of the application pointing to a remote instance of the service, which is also used by the environment copy of the application. When I attempt to authenticate user membership using the local app -> remote service call, it fails with the following exception:
System.Runtime.InteropServices.COMException (0x8007200A): The specified directory service attribute or value does not exist.
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.DoLDAPDirectoryInitNoContainer() 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.UserPrincipal.FindByIdentity(PrincipalContext context, String identityValue) at ******************.******************.******************.IsUserMemberOfGroup(String userName, String groupName)
When I attempt to authenticate the same user in the same group, but using a web browser to hit the app on the remote box which then hits the remote service, it's happy as a clam.
The code I'm using seems trivially simple. It must be something to do with how my machine is calling out, but I'll be dipped if I can work it out.
public static bool IsUserMemberOfGroup(string userName, string groupName)
{
try
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "XXX");
var user = GetUser(userName, ctx);
if (user == null)
{
Log4NetLogManager.LogError("Unable to find user " + userName);
return false;
}
// find the group in question
groupName = groupName.Replace("XXX\\", string.Empty);
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, groupName);
if (group != null) return user.IsMemberOf(group);
Log4NetLogManager.LogError("Unable to find group " + groupName);
return false;
}
catch (Exception ex)
{
if (!ex.Message.Contains("Unknown error"))
{
Log4NetLogManager.LogException(string.Format("Error while checking if {0} is a member of {1}", userName, groupName), ex);
}
return false;
}
}
private static UserPrincipal GetUser(string userName, PrincipalContext ctx)
{
UserPrincipal user = null;
userName = userName.Replace("XXX\\", string.Empty);
try
{
user = UserPrincipal.FindByIdentity(ctx, userName);
}
catch
{
}
return user ?? UserPrincipal.FindByIdentity(ctx, userName);
}