【问题标题】:How to validate domain credentials (from native code)?如何验证域凭据(来自本机代码)?
【发布时间】:2012-04-01 04:53:32
【问题描述】:

我想针对域控制器验证一组凭据。例如:

Username: joel
Password: splotchy
Domain:   STACKOVERFLOW

在 .NET 3.5 和更新版本中 you can use PrincipalContext.ValidateCredentials(username, password)

否则你就有麻烦了。

按照 Microsoft 知识库文章 How to validate user credentials on Microsoft operating systems 中的代码,我到达了您调用 AcceptSecurityContext 的地步:

ss = AcceptSecurityContext(
      @pAS._hcred,           //[in]CredHandle structure
      phContext,             //[in,out]CtxtHandle structure
      @InBuffDesc,           //[in]SecBufferDesc structure 
      0,                     //[in]context requirement flags
      SECURITY_NATIVE_DREP,  //[in]target data representation
      @pAS._hctxt,           //[in,out]CtxtHandle strcture
      @OutBuffDesc,          //[in,out]SecBufferDesc structure
      ContextAttributes,     //[out]Context attribute flags
      @Lifetime);            //[out]Timestamp struture

除了函数失败:

SEC_E_NO_AUTHENTICATING_AUTHORITY (0x80090311)

函数失败。无法联系任何机构进行身份验证。这可能是由于以下情况:

  • 认证方域名不正确。
  • 域不可用。
  • 信任关系失败。

这将是一个有用的错误,除了我可以使用 .NET 3.5 验证相同的凭据:

using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domain))
{
    valid = context.ValidateCredentials(username, password);                
}

会发生什么让 .NET 验证一组凭据,而本机代码却不能?


更新LogonUser 也失败了:

LogonUser("joel@stackoverflow.com", null, "splotchy", 
      LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_WINNT50, out token);

1311 - There are currently no logon servers available to service the logon request

更新二:我已经尝试了首选的Negotiate 提供程序,以及 Windows NT4 旧版“NTLM”提供程序

String package = "Negotiate"; //"NTLM"

QuerySecurityPackageInfo(package, [out] packageInfo);
...
AcquireCredentialsHandle(
      null,                 //[in] principle
      package,              //[in] package
      SECPKG_CRED_OUTBOUND, //[in] credential use
      null,                 //[in] LogonID
      pAuthIdentity,        //[in] authData
      null,                 //[in] GetKeyFn, not used and should be null
      null,                 //[in] GetKeyArgument, not used and should be null
      credHandle,           //[out] CredHandle structure
      expires);             //[out] expiration TimeStamp structure

【问题讨论】:

  • 你怎么打电话给InitializeSecurityContext? (特别是哪个 SSP?)您如何设置 CredHandle
  • @EdwardThomson 我尝试了首选的Negotiate 提供程序,以及NTLMCredHandle 是通过调用 AcquireCredentialsHandle 来初始化的。
  • 我似乎记得遇到过类似的问题,尽管这是几年前的事了,而且问题很模糊。如果您使用提升的权限运行,是否有任何变化? (也许是域管理员?)
  • @EdwardThomson 我无法测试。在本地,我可以以管理员身份运行它(Windows XP),但我无法以域管理员身份运行尝试验证凭据的软件。还要提醒一下:.NET 不需要以管理员身份运行。
  • 是的 - 我没有忘记这一点,但我也无法说出它在幕后所做的事情。我只是对消除一些变量感到好奇。

标签: security kerberos ntlm networkcredentials


【解决方案1】:

我认为这是为了解决与您发布的另一个 question 相同的问题。

我有点理解你现在想要做什么。让我回顾一下你在另一篇文章中写的内容。

Username  Password  Domain             Machine on domain?  Validate as
========  ========  =================  ==================  ============== 
iboyd     pass1     .                  No                  Local account 
iboyd     pass1     (empty)            No                  Local account
iboyd     pass1     stackoverflow.com  No                  Domain account
iboyd     pass1     .                  Yes                 Local account
iboyd     pass1     (empty)            Yes                 Domain account
iboyd     pass1     stackoverflow.com  Yes                 Domain account

你想要

  1. 从您的计算机不信任的域中对用户进行身份验证
  2. 从您的机器信任的域中对用户进行身份验证
  3. 验证本地用户

您可以通过与域控制器进行适当的 SSPI 握手来实现前两种情况。您在另一个问题中提到的知识库文章正在执行环回 SSPI 握手。在第一种情况下它不起作用,因为客户端计算机不信任您正在验证的域。这应该是您看到SEC_E_NO_AUTHENTICATING_AUTHORITY 的原因。

简而言之,如果你想做与

完全相同的事情
PrincipalContext.ValidateCredentials(username, password);

您需要以不同于域用户的方式处理本地用户。对于域用户,您需要调用ldap_bind_s 以使用给定的凭据绑定到域控制器。对于本地用户,您需要使用ADsOpenObject 使用给定的凭据绑定到 WinnT://YourComputerName。这就是 PrincipalContext.ValidateCredentials 从我在 Reflector 中看到的内容。

我没有看到任何等效的单个原生 API 为您做同样的事情。

【讨论】:

    猜你喜欢
    • 2010-09-24
    • 2017-11-11
    • 1970-01-01
    • 2022-10-20
    • 1970-01-01
    • 2021-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多