PrincipalContext.ValidateCredentials始终返回FALSE

时间:2010-03-02 14:08:08

标签: c# asp.net-mvc active-directory activedirectorymembership

我有一个MVC应用程序需要登录并验证用户对抗Active Directory。我使用的是PrincipalContext.ValidateCredentials方法,但总是获得false的身份验证。

连接服务器很好。问题似乎发生在ValidateCredentials

这是我的代码:

public static bool IsAuthenticated(string domain, string username, string pwd) {
    bool IsAuthenticated = false;

    try {
        PrincipalContext insPrincipalContext = 
            new PrincipalContext(ContextType.Domain, domain, "DC=c1w,DC=com");

        username = "c1w\\" + username;

        IsAuthenticated = insPrincipalContext.ValidateCredentials(username, pwd);
    }
    catch (Exception ex)
    {
        // Rethrow this exception
        ExceptionPolicy.HandleException(ex, "Exception Policy");
    }

    return IsAuthenticated;
}

任何人都知道为什么会发生这种情况?

3 个答案:

答案 0 :(得分:13)

以下是ValidateCredentials(string, string)的工作原理:首先,它尝试使用NegotiateSigningSealing上下文选项进行身份验证。如果失败,则会再次尝试使用SimpleBindSecureSocketLayer

问题是NT4(AKA“遗留”,AKA“低级别名称”)格式(DOMAIN\UserName,或更正确,NetBiosName\SamAccountName)不适用于谈判。但它确实适用于SimpleBind。

那么在调用2参数ValidateCredentials()方法时可能发生的事情是它首先使用Negotiate失败,因为它不喜欢NT4格式,然后在使用简单绑定时再次失败。

在我自己的测试中,我发现即使在回归使用简单绑定之后它失败的原因是它不仅使用SimpleBind。它使用SimpleBindSecureSocketLayer。这意味着如果未正确设置Active Directory服务器以使用SSL(测试环境的常见方案),它仍将失败。

正如其中一条评论中所提到的那样,您永远不要单独使用SimpleBind(不使用SecureSocketLayer),否则您的密码将以纯文本形式通过网络发送。

在野外,我已经看到一些Active Directory系统根本不允许使用简单的绑定,所以你必须让它与Negotiate一起使用。

我找到了两种方法来处理这个问题:

1)如果所有内容都发生在同一个域中,您应该只能使用用户名(SAM帐户名称)来呼叫ValidateCredentials,而忽略“DOMAIN”部分。然后,第一次与Negotiate一起正常工作。

2)如果域部分很重要,因为可能涉及多个域(即Domain1\UserADomain2\UserA是不同的人),那么它会变得有点复杂。在这种情况下,我最终做的是将NT4名称(DOMAIN \ User)转换为“用户主要名称”格式(例如LogonName@domain.com)。有几种不同的方法可以做到这一点。最简单的可能是使用UserPrincipal.FindByIdentity()的3参数重载,然后在结果上获取UserPrincipalName属性的值。另一种方法是使用DirectorySearcher和查询LDAP://domain来查找具有匹配userPrincipalName值的用户的sAMAccountName属性。注意:只有涉及的所有域都在同一个林中时,此解决方案才有效。

答案 1 :(得分:9)

我没看到你在哪里初始化“pwd”变量 也许您应该在此方法中使用ContextOption来准确指定所需的行为。很抱歉,答案过于广泛,但您的问题中没有太多详细信息

答案 2 :(得分:1)

您似乎正在使用domain \ userName格式验证用户。您可能希望从userName解析域名并使用ValidateCredential。