gpt4 book ai didi

windows - Win32 : How to validate credentials against Active Directory?

转载 作者:可可西里 更新时间:2023-11-01 12:23:55 25 4
gpt4 key购买 nike

已经asked , 和 answered for .NET ,但现在是时候获得 native Win32 代码的答案了:

我如何验证 Windows 用户名和密码?

asked this question before for managed code .现在是 native 解决方案的时候了。


需要指出一些更常提出的解决方案的陷阱:

无效方法 1。使用模拟查询 Active Directory

很多人suggest querying the Active Directory为了某件事。如果抛出异常,则您知道凭据无效 - 正如 this stackoverflow question 中所建议的那样.

some serious drawbacks to this approach然而:

  • You are not only authenticating a domain account, but you are also doing an implicit authorization check. That is, you are reading properties from the AD using an impersonation token. What if the otherwise valid account has no rights to read from the AD? By default all users have read access, but domain policies can be set to disable access permissions for restricted accounts (and or groups).

  • Binding against the AD has a serious overhead, the AD schema cache has to be loaded at the client (ADSI cache in the ADSI provider used by DirectoryServices). This is both network, and AD server, resource consuming - and is too expensive for a simple operation like authenticating a user account.

  • You're relying on an exception failure for a non-exceptional case, and assuming that means invalid username and password. Other problems (e.g. network failure, AD connectivity failure, memory allocation error, etc) are then mis-intrepreted as authentication failure.

使用DirectoryEntry class is .NET 是验证凭据的不正确方法的示例:

无效方法 1a - .NET

DirectoryEntry entry = new DirectoryEntry("persuis", "iboyd", "Tr0ub4dor&3");
object nativeObject = entry.NativeObject;

无效方法 1b - .NET #2

public static Boolean CheckADUserCredentials(String accountName, String password, String domain)
{
Boolean result;

using (DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, accountName, password))
{
using (DirectorySearcher searcher = new DirectorySearcher(entry))
{
String filter = String.Format("(&(objectCategory=user)(sAMAccountName={0}))", accountName);
searcher.Filter = filter;
try
{
SearchResult adsSearchResult = searcher.FindOne();
result = true;
}
catch (DirectoryServicesCOMException ex)
{
const int SEC_E_LOGON_DENIED = -2146893044; //0x8009030C;
if (ex.ExtendedError == SEC_E_LOGON_DENIED)
{
// Failed to authenticate.
result = false;
}
else
{
throw;
}
}
}
}

以及通过 ADO 连接查询 Active Directory:

无效方法 1c - native 查询

connectionString = "Provider=ADsDSOObject;
User ID=iboyd;Password=Tr0ub4dor&3;
Encrypt Password=True;Mode=Read;
Bind Flags=0;ADSI Flag=-2147483648';"

SELECT userAccountControl
FROM 'LDAP://persuis/DC=stackoverflow,DC=com'
WHERE objectClass='user' and sAMAccountName = 'iboyd'

即使您的凭据有效,但您无权查看您的目录条目,这两种方法都会失败:

enter image description here

无效方法 2.LogonUser Win32 API

Others建议使用 LogonUser() API函数。这听起来不错,但不幸的是,调用用户有时需要通常只授予操作系统本身的权限:

The process calling LogonUser requires the SE_TCB_NAME privilege. If the calling process does not have this privilege, LogonUser fails and GetLastError returns ERROR_PRIVILEGE_NOT_HELD.

In some cases, the process that calls LogonUser must also have the SE_CHANGE_NOTIFY_NAME privilege enabled; otherwise, LogonUser fails and GetLastError returns ERROR_ACCESS_DENIED. This privilege is not required for the local system account or accounts that are members of the administrators group. By default, SE_CHANGE_NOTIFY_NAME is enabled for all users, but some administrators may disable it for everyone.

分发“作为操作系统的一部分”特权不是您愿意随意做的事情 - 正如 Microsoft 在 knowledge base article 中指出的那样:

...the process that is calling LogonUser must have the SE_TCB_NAME privilege (in User Manager, this is the "Act as part of the Operating System" right). The SE_TCB_NAME privilege is very powerful and should not be granted to any arbitrary user just so that they can run an application that needs to validate credentials.

此外,如果指定了空白密码,对 LogonUser() 的调用将失败。


有效的 .NET 3.5 方法 - PrincipalContext

有一种验证方法,仅在 .NET 3.5 和更新版本中可用,允许用户在不执行授权检查的情况下进行身份验证:

// create a "principal context" - e.g. your domain (could be machine, too)
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "stackoverflow.com"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("iboyd", "Tr0ub4dor&3")
}

不幸的是,此代码仅在 .NET 3.5 及更高版本中可用。

是时候找到原生的等价物了。

最佳答案

Here is Microsoft's recommendation .

至于其他答案,我不太确定您为什么要将它们击落。您在尝试验证凭据时提示(相对边缘情况)失败,但如果您实际上要对这些凭据执行某些操作,那么该操作无论如何都会失败。如果您实际上不打算使用这些凭据执行某些操作,那么为什么首先需要验证它们?这看起来有点人为的情况,但显然我不知道你想要完成什么。

关于windows - Win32 : How to validate credentials against Active Directory?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7111618/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com