【问题标题】:Find Domain Name in Active Directory在 Active Directory 中查找域名
【发布时间】:2011-06-07 17:55:10
【问题描述】:

我正在运行一个 ASP.NET 4.0 应用程序,它使用用户名(即 HttpContext.Current.Request.LogonUserIdentity.Name.ToString())来管理对各种组件的访问。

返回的用户名格式为“abc\jsmith”,其中“abc”是域名,“jsmith”是用户的登录名。

此应用的部分安全模块会访问用户所属的 Active Directory 组(例如,“Accounting”、“AccountsPayable”、“AdminDepartment”)。我可以使用 DirectoryEntry.Properties (即 System.DirectoryServices.PropertyCollection") "sAMAccountName".Value 从 Active Directory 获取用户名。

到目前为止,一切都很好,但我希望能够跨多个域扩展应用程序,这意味着我需要能够在 Active Directory 中找到域名以及用户的登录名。我可以从 PrincipalContext 获得一个“域”值,但它返回的是“abcdc”,而不是“abc”。我可以假设这个属性总是在每个域的末尾返回“dc”(如“域控制器”)(在这种情况下我可以使用属性的子字符串),还是在其他地方我可以得到用户的当前域名?

【问题讨论】:

    标签: active-directory dns


    【解决方案1】:

    我不清楚的一件事是您关于在域控制器中检索给定目录条目的域名的问题。我假设您有一台可以查看多个受信任域的服务器,并且用户可以从其中任何一个域登录您的应用程序,这样您就不知道需要针对哪个域来测试角色成员资格。

    要通过 ADGroup 成员资格控制对功能的访问,您可以使用

    HttpContext.Current.User.IsInRole("appdomain\groupname") 
    

    其中 User.Identity.Name=="userdomain\user"。我不熟悉域信任问题,但这假设您可以将受信任域中的用户添加到您控制的域组中,因此您无需担心组域位置。

    如果你不能,或者如果你在每个不同的域中都有相同的组名,那么你可以做这样的事情吗?

    HttpContext.Current.User.IsInRole(userDomainname + "\groupname")
    

    几点:

    1. 除非您已经建立了庞大的 AD 代码库,否则我建议您使用 System.DirectoryServices.AccountManagement 命名空间中的对象。
    2. 我强烈推荐来自 Sysinternals 的 ADExplorer 实用程序,以获得您的域的更多 LDAP 视图,这通常有助于 LDAP 连接字符串和目录编程。
    3. 如果您对互操作感到满意,并且需要执行任何 LDAP 连接字符串解析,请查看此site
    4. System.DirectoryServices.AccountManagement.PrincipalContext.Container 和 System.DirectoryServices.DirectoryEntry.Path 属性返回带有域末尾的 LDAP 连接字符串字符串(即 DC=mycompany,DC=com)
    5. 不要忘记值得信赖的旧 Environment.UserDomainName 和 Environment.UserName(它从当前执行的线程中获取 WindowsPrincipal;请参阅 表 1:线程公开 CurrentPrincipal 对象@http://msdn.microsoft.com/en-us/library/Aa480475.aspx有关当前用户在 asp.net 运行时中的内容的表。)

    ** 2011 年 6 月 8 日下午 2:15 更新**

    如果我对 AD 的理解正确,用户的域是 AD 返回的用户对象的一个​​组成部分。扩展您的“Bob Newaccountant”示例...

    因此,鉴于以下 2 个域之间存在信任:

    1. "abcdc.com"
        CN=Users
            CN="Bob NewAccountant"
    2. "abc.com"
        CN=Users
            CN="Local User1"
        OU=Applications
            OU=MyApplication
                CN=ReportReaders (Members: abcdc\BNewAccountant, abc\luser1)
    

    您应该通过以下查询获取用户信息:

    //name parameter = domain
    //container parameter = distinguished name
    using(var ctx = new PrincipalContext(
                         ContextType.Domain,
                         name: "abc.com",
                         container: "OU=MyApplication,OU=Applications,DC=abc,DC=com",
                         "abc\serviceaccountname",
                         "Password1"))
    {
        var officeGroup = GroupPrincipal.FindByIdentity(ctx,
                                         IdentityType.SamAccountName,
                                         "ReportReaders");
    
        foreach(Principal prin in officeGroup.GetMembers(recursive: true))
        {
            Console.WriteLine("DistinguishedName: " + prin.DistinguishedName 
                + " UPN: " + prin.UserPrincipalName);
        }
        //Should result in
        //  DistinguishedName: CN=luser1,CN=Users,DC=abc,DC=com UPN: luser1@abc.com
        //  DistinguishedName: CN=BNewAccountant,CN=Users,DC=abcdc,DC=com UPN: BNewAccountant@abcdc.com
    }
    

    因此,您应该能够通过活动目录的 distinguishedNameuserPrincipalName 属性获取用户的域。 (注意:我手头没有双域设置,所以我现在无法测试上面的代码。)是不是越来越近了?

    【讨论】:

    • Environment.UserDomainName 对于查找用户当前登录的计算机的域非常有用。但是,我需要能够让我的安全管理员能够添加和管理用户.我可以使用“sAMAccountName”从 Active Directory 获取用户“登录名”。但是我怎样才能得到域名呢?这才是真正的问题。而且,顺便说一句,DC=myCompany 不是我要找的。这就是给我“abcdc”的原因。我需要的是“abc”。 -- 非常感谢您的意见。它给了我更多考虑的途径。 -- 獾
    • 嗯......也许这更像是我错过的基本事物。因为我相信将存储在域控制器中的唯一用户可以来自该域。让我修改我的答案以表明我的意思。
    • 也许如果我给出安全管理员 (SA) 用户的场景:公司雇用新会计; SA 用户登录到应用程序,该应用程序搜索 Active Directory 并返回用户列表; SA 然后可以选择用户(例如,“Bob Newaccountant”)并授予他使用适当功能(例如,报告)的权限。我们希望设置应用程序,以便 SA 不仅可以查看我们 AD 中的所有用户,还可以查看他们所在的域。这样是否更清楚?再次感谢您的输入。獾
    • 这看起来更接近了。有没有办法在不知道用户密码的情况下获取 ctx 数据?当我们通过 Active Directory(以及其中的组)工作时,我可以将其视为“foreach”循环,但我无法访问每个用户的密码。再次感谢。我认为我们走在正确的轨道上!!
    • 太棒了!是的,您不需要用户密码。我们有一种不使用模拟的情况,因此我们有一个特殊的服务帐户设置,用于连接到活动目录(这就是用户名和密码的用途)。对于不需要用户名和密码的用户,请参阅 PrincipalContext 的构造函数重载:msdn.microsoft.com/en-us/library/…
    【解决方案2】:

    这是找到它的 WMI 方法。我给你写 PowerShell,但你可以很容易地将它转换为 VBScript 或 C#

    PS C:\> (Get-WmiObject Win32_NTDomain).DomainName
    

    请注意,“pre windows 2000 域”的域部分可能与用于登录 Active-Directory 的用户主体名称 (user@domain) 完全不同。 DOMAIN 是 Primary Domain Controleur 名称或 Netbios 域名。 DOMAIN 是在域创建期间创建的,默认情况下它是 DNS 名称的一部分,但可以在域创建期间完全更改。

    您可以通过 nETBIOSName 属性找到它:

    ldifde -f netbios.ldf -d "CN=Partitions,CN=Configuration,DC=your-DNS-Name" -r "(netbiosname=*)" 
    

    编辑

    这是 CSharp 代码

    ManagementObjectSearcher domainInfos1 = new ManagementObjectSearcher("select * from WIN32_NTDomain");
    
    foreach (ManagementObject domainInfo in domainInfos1.Get())
    {
      Console.WriteLine("Name : {0}", domainInfo.GetPropertyValue("Name"));
      Console.WriteLine("Computer/domain : {0}", domainInfo.GetPropertyValue("Caption"));
      Console.WriteLine("Domain name : {0}", domainInfo.GetPropertyValue("DomainName"));
      Console.WriteLine("Status : {0}", domainInfo.GetPropertyValue("Status"));
    }
    

    【讨论】:

    • 尝试在命令窗口中运行“ldifde”。出现“'ldifde' 未被识别为内部或外部命令、可运行程序或批处理文件”的错误。 -- 幸运的是,我的网络上没有 2000 之前的域。 -- 我会考虑将您的 PowerShell 命令翻译成 C#,以使其更容易集成到应用程序的其余部分。 - 感谢您的输入。獾
    • Ldifde 出现在域控制器上。
    • 啊,但我需要能够让我的安全管理员访问此信息,以便管理用户对应用程序各个部分的访问。 -- 再次感谢
    • 我编辑了答案。 LDIFDE.EXE 只是一个可以从 W2K 或 W2K3 机器复制的 exe 文件。
    • 这在获取我所在系统的域名方面非常有效。它正确显示“域名:abc”。但是,我需要能够遍历 Active Directory 并检查每个名称和域名。否则,我将查看“用户 'NewHire' 的域名是什么”?有任何想法吗??感谢你的帮助。我认为我们正在接近我所需要的!
    【解决方案3】:

    DC 代表域组件。使用 Active Directory 进行编程的一个看似不错的概要是 here。那里有很多东西可以在这里做一个像样的复制和粘贴,但我确实找到了following 这可能会对你有所帮助:

    domainname=inputbox("Enter DNS Domain Name" & vbcrlf & "(Leave blank for current domain):")
    username=inputbox("Enter username:")
    
    
    IF domainname = "" THEN
        SET objRoot = GETOBJECT("LDAP://RootDSE")
        domainname = objRoot.GET("defaultNamingContext")
    END IF
    
    IF username <> "" THEN
        wscript.echo finduser(username,domainname)
    END IF
    
    
    FUNCTION FindUser(BYVAL UserName, BYVAL Domain) 
        ON ERROR RESUME NEXT
    
        SET cn = CREATEOBJECT("ADODB.Connection")
        SET cmd = CREATEOBJECT("ADODB.Command")
        SET rs = CREATEOBJECT("ADODB.Recordset")
    
        cn.open "Provider=ADsDSOObject;"
    
        cmd.activeconnection=cn
        cmd.commandtext="SELECT ADsPath FROM 'LDAP://" & Domain & _
                 "' WHERE sAMAccountName = '" & UserName & "'"
    
        SET rs = cmd.EXECUTE
    
        IF err<>0 THEN
            FindUser="Error connecting to Active Directory Database:" & err.description
        ELSE
            IF NOT rs.BOF AND NOT rs.EOF THEN
                    rs.MoveFirst
                    FindUser = rs(0)
            ELSE
                FindUser = "Not Found"
            END IF
        END IF
        cn.close
    END FUNCTION
    

    【讨论】:

    • 其实在这种情况下,我发现“dc”是域名的一部分(“设计中心”),而不是“域组件”。
    • 顺便说一下,在我的研究过程中,这是我第二次看到VB.Net 方法“GetObject”,它在C# 中不起作用。有人有类似的 C# 方法吗?
    【解决方案4】:

    您可以获得用户“userprincipalname”。它看起来像一个电子邮件地址,但实际上是 samaccountname + @ + domain.name。需要注意的一点是,Active Directory 域看起来像一个互联网域名,但 netbios 域名(您的示例中的“abc”)却不是。

    如果你抓住UPN,我相信它总是会包含点状域名。

    【讨论】:

    • 使用 DirectoryEntry.Properties["userPrincipalName"].Value 对此进行了调查。我仍然将“abcdc”作为域名。仍在调查 netBios 的事情。再次感谢您的意见。
    • 我得到“DC=abcdc”。我在访问 UserPrincipalName 时也遇到了一些问题。我已经尝试了“[”UserPrincipalName”].Value”、“[”User-Prinicpal-Name”].Value”,以及我能想到的所有其他内容,但不断提出“null”值。当然,这些来自 DirectoryEntry.Properties PropertyCollection。我在正确的轨道上吗? -- 再次感谢,獾
    猜你喜欢
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2011-06-19
    • 1970-01-01
    • 1970-01-01
    • 2017-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多