Joh*_*win 8 c# directoryservices ldap active-directory
Microsoft有一篇通用知识库文章(Q316748),描述了如何使用该DirectoryEntry对象对Active Directory进行身份验证.在他们的示例中,他们通过将域名和用户名连接到标准NetBIOS格式("domain\username")并将其作为参数传递给目录条目构造函数来生成用户名值:
string domainAndUsername = domain + @"\" + username;
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
Run Code Online (Sandbox Code Playgroud)
它最近引起了我们的注意,用户名的域名部分被完全忽略,在多个环境中我已经确认了这种行为.实际上正在使用用户名和密码,因为身份验证在无效时失败,但可以为域名和身份验证传递提供任意值.我一眼就认为这种格式适用于基于WinNT的目录访问,但LDAP的域部分被忽略.
谷歌检查显示许多LDAP示例将"域\用户名"值传递给DirectoryEntry对象,所以我要么在我的配置中弄乱了一些东西,或者很多人对KB文章感到困惑.任何人都可以确认这是预期的行为或建议一种方法来接受"域\用户名"值并与他们对Active Directory进行身份验证?
谢谢,
Per*_*alt 18
简答:当构造函数的path参数DirectoryEntry包含无效域名时,DirectoryEntry对象将(在forrest中搜索无效域失败后)尝试通过删除username参数的域部分并使用纯用户名尝试连接来回退(sAMAccountName赋).
答案很长:如果username参数中指定的域名无效,但用户存在于path参数中指定的域中,则将对用户进行身份验证(通过使用回退).但是,如果用户存在于forrest中的另一个域中,那么path参数身份验证中指定的用户只有在包含参数的域部分username并且正确时才会成功.
在处理DirectoryEntry-objects时,有四种不同的方法来指定username参数:
让我用一个例子来说明:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices;
namespace DirectoryTest
{
class Program
{
private static Int32 counter = 1;
static void Main(string[] args)
{
TestConnection();
}
private static void TestConnection()
{
String domainOne = "LDAP://DC=domain,DC=one";
String domainOneName = "DOMAINONE";
String domainOneUser = "onetest";
String domainOnePass = "testingONE!";
String domainTwo = "LDAP://DC=domain,DC=two";
String domainTwoName = "DOMAINTWO";
String domainTwoUser = "twotest";
String domainTwoPass = "testingTWO!";
String invalidDomain = "INVALIDDOMAIN";
// 1) This works because it's the correct NT Account Name in the same domain:
Connect(domainOne, domainOneName + "\\" + domainOneUser, domainOnePass);
// 2) This works because username can be supplied without the domain part
// (plain username = sAMAccountName):
Connect(domainOne, domainOneUser, domainOnePass);
// 3) This works because there's a fall back in DirectoryEntry to drop the domain part
// and attempt connection using the plain username (sAMAccountName) in (in this case)
// the forrest root domain:
Connect(domainOne, invalidDomain + "\\" + domainOneUser, domainOnePass);
// 4) This works because the forrest is searched for a domain matching domainTwoName:
Connect(domainOne, domainTwoName + "\\" + domainTwoUser, domainTwoPass);
// 5) This fails because domainTwoUser is not in the forrest root (domainOne)
// and because no domain was specified other domains are not searched:
Connect(domainOne, domainTwoUser, domainTwoPass);
// 6) This fails as well because the fallback of dropping the domain name and using
// the plain username fails (there's no domainTwoUser in domainOne):
Connect(domainOne, invalidDomain + "\\" + domainTwoUser, domainTwoPass);
// 7) This fails because there's no domainTwoUser in domainOneName:
Connect(domainOne, domainOneName + "\\" + domainTwoUser, domainTwoPass);
// 8) This works because there's a domainTwoUser in domainTwoName:
Connect(domainTwo, domainTwoName + "\\" + domainTwoUser, domainTwoPass);
// 9) This works because of the fallback to using plain username when connecting
// to domainTwo with an invalid domain name but using domainTwoUser/Pass:
Connect(domainTwo, invalidDomain + "\\" + domainTwoUser, domainTwoPass);
}
private static void Connect(String path, String username, String password)
{
Console.WriteLine(
"{0}) Path: {1} User: {2} Pass: {3}",
counter, path, username, password);
DirectoryEntry de = new DirectoryEntry(path, username, password);
try
{
de.RefreshCache();
Console.WriteLine("{0} = {1}", username, "Autenticated");
}
catch (Exception ex)
{
Console.WriteLine("{0} ({1})", ex.Message, username);
}
Console.WriteLine();
counter++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,domain.one是forrest根域,domain.two与domain.one在同一个forrest中(但自然是一个不同的树).
因此,要回答您的问题:如果用户不在我们要连接的域中且在username参数中未指定或者无效的域名,则身份验证将始终失败.
| 归档时间: |
|
| 查看次数: |
12081 次 |
| 最近记录: |