如何为DirectoryEntry.Exists提供凭据?

13

今天早上我发现了一个不错的方法(DirectoryEntry.Exists),它可以检查服务器上是否存在Active Directory对象。所以我尝试用一个简单的命令:

if (DirectoryEntry.Exists(path)) {}

当然,它缺少任何重载来提供凭据。因为如果没有提供凭据,我会收到这个异常:

登录失败:未知的用户名或错误的密码。(System.DirectoryServices.DirectoryServicesCOMException)

是否有其他选项可以让我在AD服务器上验证我的代码?或检查对象的存在性?

6个回答

18

在这种情况下,你不能像你所说的那样使用静态方法Exists:

DirectoryEntry directoryEntry = new DirectoryEntry(path);
directoryEntry.Username = "username";
directoryEntry.Password = "password";

bool exists = false;
// Validate with Guid
try
{
    var tmp = directoryEntry.Guid;
    exists = true;
}
catch (COMException)
{
   exists = false; 
}

那将是我的首选解决方案,但这个属性对我来说似乎不是静态的,请看:http://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.username.aspx - Herman Cordes
哦,我明白了,没事。是的,你需要实例化一个新的DirectoryEntry。已编辑。 - JoeBilly
感谢提供这个漂亮的代码示例。显然那是唯一的方法。遗憾的是,使用默认的 .net 方法不可能实现,但至少一个漂亮的解决方法可以胜任工作! - Herman Cordes
这个方法大部分情况下都能正常工作,但在无法验证实际不存在的情况下(网络错误、未知域等),会返回 false。我刚刚发布了一个答案,借用了DirectoryEntry.Exists的源代码,只有在已知不存在时才返回 false,并重新抛出任何其他异常。 - Gabriel Luci

5

我知道这是一个老问题,但源代码现在已经公开,所以你可以轻松地窃取和修改™来创建一个接受凭证的版本:

public static bool Exists(string path, string username, string password)
{
    DirectoryEntry entry = new DirectoryEntry(path, username, password);
    try
    {
        _ = entry.NativeObject;       // throws exceptions (possibly can break applications)
        return true;
    }
    catch (System.Runtime.InteropServices.COMException e)
    {
        if (e.ErrorCode == unchecked((int)0x80072030) ||
             e.ErrorCode == unchecked((int)0x80070003) ||   // ERROR_DS_NO_SUCH_OBJECT and path not found (not found in strict sense)
             e.ErrorCode == unchecked((int)0x800708AC))     // Group name could not be found
            return false;
        throw;
    }
    finally
    {
        entry.Dispose();
    }
}

您需要做的一个更改是修改使用的Bind方法,因为它是一个internal方法,普通人无法使用。相反,我只获取NativeObject属性,它会为我们调用Bind()方法。
您可以像这样使用它:
var ouExists = Exists("LDAP://hadoop.com/OU=Students,DC=hadoop,DC=com", "username", "password");

2


1

所以回答这个问题:不可能。

最后编写一个自己的方法,通过指定凭据获取Distinguished Name的DirectoryEntry。在存在/不存在的两种情况下,我都得到了DirectoryEntry的实例。为了检查它是否是一个有效的返回对象,我做了一个简单的try...catch来查看它是否会导致异常。如果是,那么它就是无效的。

这是一个恶心的检查,但它确实起作用。太糟糕了,默认的.net方法DirectoryEntry.Exists没有提供重载来提供凭据,就像DirectoryEntry构造函数一样...


0

如果运行该进程的用户没有调用DirectoryEntry.Exists的权限,则可以使用模拟身份。

这可能会有所帮助(讨论了AD上下文中的模拟身份):http://www.codeproject.com/KB/system/everythingInAD.aspx

顺便说一句,如果您已经拥有具有访问所需所有内容的用户的凭据,为什么不使用该用户运行进程(例如/runas)?


谢谢。我也发现了类似的东西,但是没有为我的问题提供一个合适的解决方案。在我的当前项目中,Runas真的不是一个选项...模拟也不行,但到目前为止似乎是最好的选择。 - Herman Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接