2010-03-02 226 views
12

我有一个MVC应用程序,需要登录并根据Active Directory验证用户。我正在使用PrincipalContext.ValidateCredentials方法,但始终得到false的身份验证。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; 
} 

任何人都知道为什么会发生?

回答

7

我看不到你初始化“pwd”变量的位置 也许你应该在这个方法中使用ContextOption来精确指定需要的行为。对不起,太广泛的回应,但没有太多的细节在你的问题

+0

编辑该问题以包含整个方法。将尝试ContextOption建议。谢谢。 – 2010-03-02 14:27:04

+5

B-Rain, ContextOption参考指出我正确的方向。在我对AD和ContextOptions.SimpleBind的验证凭证调用上使用ContextOptions.Negotiate结束。简单的绑定将为我工作,因为该网站将SSL安全。 感谢您的帮助。 – 2010-03-02 15:30:19

+0

Upvoted这个问题和答案,因为这也帮助我在我的情况。在我的情况下,我的开发机器(登录工作时没有指定上下文)位于网络上的安全区域,但Web服务器(登录在没有指定上下文的情况下无法工作)位于DMZ中。我使用与@Billy Logan相同的配置 - 在validate调用上协商AD和SimpleBind的调用。 – arootbeer 2010-10-14 19:52:03

1

看来你正在验证与域\用户名格式的用户。您可能想要从userName解析域名并使用ValidateCredential。

12

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

问题是NT4(AKA“legacy”,又名“down-level name”)格式(DOMAIN\UserName,或更正确的NetBiosName\SamAccountName)不适用于Negotiate。但它与SimpleBind一起工作。

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

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

正如其中一条评论中提到的,您永远不会自己使用SimpleBind(没有SecureSocketLayer),否则您的密码将通过网络以纯文本形式发送。

在野外,我已经看到一些Active Directory系统根本不允许使用简单的绑定,所以您必须使其与Negotiate协同工作。

我发现2种方式来处理这个问题:

1)如果一切都在同一个域发生的事情,你应该能够调用ValidateCredentials只用用户名(SAM帐户名),留出“DOMAIN \”部分。然后,它会在第一次协商时正常工作。 2)如果域部分很重要,因为可能涉及多个域(即Domain1\UserADomain2\UserA是不同的人),那么它会变得更复杂一些。在这种情况下,我最终做的是将NT4名称(DOMAIN \ User)转换为“用户主体名称”格式(例如[email protected])。有几种不同的方式来做到这一点。最简单的可能是使用UserPrincipal.FindByIdentity()的3参数超载,然后抓取结果上UserPrincipalName属性的值。另一种方式是使用DirectorySearcher并且查询LDAP://domain来获得具有匹配的sAMAccountName值的用户的userPrincipalName属性。注意:只有涉及的所有域位于同一个林中时,此解决方案才会起作用。