【问题标题】:How to check if user with [UserName] and [Password] is domain administrator of [DomainName] without impersonation?如何检查具有 [UserName] 和 [Password] 的用户是否是 [DomainName] 的域管理员而不冒充?
【发布时间】:2012-03-13 11:46:47
【问题描述】:

Impersonation example

我可以通过下一行代码检查用户域管理员:

using (Impersonation im = new Impersonation(UserName, Domain, Password))
{
    System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
    bool isDomainAdmin = identity.IsDomainAdmin(Domain, UserName, Password);
    if (!isDomainAdmin)
    {
        //deny access, for example
    }
}

其中 IsDomainAdmin - 是扩展方法

public static bool IsDomainAdmin(this WindowsIdentity identity, string domain, string userName, string password)
{
    Domain d = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain, domain, userName, password));

    using (DirectoryEntry de = d.GetDirectoryEntry())
    {
        byte[] domainSIdArray = (byte[])de.Properties["objectSid"].Value;
        SecurityIdentifier domainSId = new SecurityIdentifier(domainSIdArray, 0);
        SecurityIdentifier domainAdminsSId = new SecurityIdentifier(WellKnownSidType.AccountDomainAdminsSid, domainSId);
        WindowsPrincipal wp = new WindowsPrincipal(identity);
        return wp.IsInRole(domainAdminsSId);
    }
}

但是,当 IsDomainAdmin 方法被调用时,它试图将一些文件写入模拟用户的 %LOCALAPPDATA%,如果程序不是以管理员身份运行,则会引发异常

无法加载文件或程序集'System.DirectoryServices, 版本=4.0.0.0,文化=中性,PublicKeyToken=b03f5f7f11d50a3a' 或 它的依赖项之一。没有达到要求的模拟级别 提供,或提供的模拟级别无效。 (例外 来自 HRESULT:0x80070542)

【问题讨论】:

标签: c# .net active-directory


【解决方案1】:

您当然不需要用户密码来验证用户是否是组的成员。那么为什么不直接使用DirectoryEntryDirectorySearcher 查询AD?如果您还需要验证提供的密码是否正确,您可以使用PrincipalContext.ValidateCredentials 在附加步骤中执行此操作。 (见PrincipalContext.ValidateCredentials Method (String, String))。

static void Main(string[] args) {
    string userDomain = "somedomain";
    string userName = "username";
    string password = "apassword";

    if (IsDomainAdmin(userDomain, userName)) {
        string fullUserName = userDomain + @"\" + userName;
        PrincipalContext context = new PrincipalContext(
            ContextType.Domain, userDomain);
        if (context.ValidateCredentials(fullUserName, password)) {
            Console.WriteLine("Success!");
        }
    }
}

public static bool IsDomainAdmin(string domain, string userName) {
    string adminDn = GetAdminDn(domain);
    SearchResult result = (new DirectorySearcher(
        new DirectoryEntry("LDAP://" + domain),
        "(&(objectCategory=user)(samAccountName=" + userName + "))",
        new[] { "memberOf" })).FindOne();
    return result.Properties["memberOf"].Contains(adminDn);
}

public static string GetAdminDn(string domain) {
    return (string)(new DirectorySearcher(
        new DirectoryEntry("LDAP://" + domain),
        "(&(objectCategory=group)(cn=Domain Admins))")
        .FindOne().Properties["distinguishedname"][0]);
}

【讨论】:

  • 第一部分是正确的 - 我需要验证用户凭据。我对 LDAP 查询知之甚少,但如果我将 "cn=Domain Admins" 更改为 "cn=Domain Users",我总是会出错,但我知道具有提供名称的用户存在。查询中可能有一些错误?
  • AD 用户未明确添加到组Domain Users;这是暗示的。因此域用户组的 dn 不会在 memberOf 列表中。尝试搜索您的用户并枚举memberOf 中的项目以更好地理解。
  • 它的作品!但!我不喜欢硬编码字符串"Domain Admins" 的解决方案。域管理员组可以在某些 AD 结构中使用另一个名称吗?
【解决方案2】:

我们修改了@jmh_gr 的答案,它似乎变得独立于"Domain Admins" 组名。

static string BuildOctetString(SecurityIdentifier sid)
{
    byte[] items = new byte[sid.BinaryLength];
    sid.GetBinaryForm(items, 0);
    StringBuilder sb = new StringBuilder();
    foreach (byte b in items)
    {
        sb.Append(b.ToString("X2"));
    }
    return sb.ToString();
}
public static bool IsDomainAdmin(string domain, string userName)
{
    using (DirectoryEntry domainEntry = new DirectoryEntry(string.Format("LDAP://{0}", domain)))
    {
        byte[] domainSIdArray = (byte[])domainEntry.Properties["objectSid"].Value;

        SecurityIdentifier domainSId = new SecurityIdentifier(domainSIdArray, 0);
        SecurityIdentifier domainAdminsSId = new SecurityIdentifier(WellKnownSidType.AccountDomainAdminsSid, domainSId);

        using (DirectoryEntry groupEntry = new DirectoryEntry(string.Format("LDAP://<SID={0}>", BuildOctetString(domainAdminsSId))))
        {
            string adminDn = groupEntry.Properties["distinguishedname"].Value as string;
            SearchResult result = (new DirectorySearcher(domainEntry, string.Format("(&(objectCategory=user)(samAccountName={0}))", userName), new[] { "memberOf" })).FindOne();
            return result.Properties["memberOf"].Contains(adminDn);
        }
    }
}

无论如何,感谢@jmh_gr 的回答。

【讨论】:

    【解决方案3】:

    @lluisfranco 使用此代码

    using System.DirectoryServices;
    using System.DirectoryServices.ActiveDirectory;
    using System.Net.NetworkInformation;
    using System.Security.Principal;
    
    namespace Alpha.Code
    {
        public static class SecurityExtensions
        {
            public static bool IsDomainAdmin (this WindowsIdentity identity)
            {
                Domain d = Domain.GetDomain(new
                    DirectoryContext(DirectoryContextType.Domain, getDomainName()));
                using (DirectoryEntry de = d.GetDirectoryEntry())
                {
                    byte[] bdomSid = (byte[])de.Properties["objectSid"].Value;
                    string sdomainSid = sIDtoString(bdomSid);
                    WindowsPrincipal wp = new WindowsPrincipal(identity);
                    SecurityIdentifier dsid = new SecurityIdentifier(sdomainSid);
                    SecurityIdentifier dasid = new SecurityIdentifier(
                        WellKnownSidType.AccountDomainAdminsSid, dsid);
                    return wp.IsInRole(dasid);
                }
            }
    
            public static string getDomainName()
            {
                return IPGlobalProperties.GetIPGlobalProperties().DomainName;
            }
    
            public static string sIDtoString(byte[] sidBinary)
            {
                SecurityIdentifier sid = new SecurityIdentifier(sidBinary, 0);
                return sid.ToString();
            }
        }
    }
    

    使用示例:

    if (WindowsIdentity.GetCurrent().IsDomainAdmin())
    {
        //Actions to do if user is domain admin
    }
    

    来源:
    http://geeks.ms/blogs/lfranco/archive/2009/11/25/how-to-191-como-saber-si-el-usuario-actual-es-administrador-del-dominio.aspx

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-02
    • 1970-01-01
    • 1970-01-01
    • 2013-04-29
    • 2018-02-02
    • 2022-10-02
    • 2011-02-26
    • 1970-01-01
    相关资源
    最近更新 更多