C#中的Active Directory:获取用户域名? [英] C# Active Directory: Get domain name of user?

查看:737
本文介绍了C#中的Active Directory:获取用户域名?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道,这样的问题已经问过,但其他方法都失败我现在。

由于它代表了我们的窗户服务轮询AD,给定一个LDAP(即LDAP://10.32.16.80),并在该AD服务器用户组的列表来搜索。 它检索所有用户的特定组中,递归搜索这些群体更多的群体也是如此。 每个用户然后被添加到另一个应用程序认证的用户列表。

应用程序的这一部分是成功运行。但是,我们需要每一个用户友好的域名(即其登录域/用户名的一部分)

所以,如果有一个用户是测试域,命名为史蒂夫的部分:试验/史蒂夫是他的登录。 我能找到史蒂夫在广告中,但是我还需要测试,以与他的广告信息一起存储。

同样,我可以找到'史蒂夫'细使用目录搜索和LDAP IP我给,但考虑到LDAP IP,我怎么能找到友好的域名?

当我尝试以下code,我给试图访问defaultNamingContext发生错误:

System.Runtime.InteropServices.COMException(0x8007202A):身份验证机制尚不清楚。

下面是code:

 私人字符串SetCurrentDomain(字符串服务器)
    {
        字符串结果=的String.Empty;
        尝试
        {
            logger.Debug('SetCurrentDomain';实例化的RootDSE LDAP);
            的DirectoryEntry ldapRoot =新的DirectoryEntry(服务器+/的RootDSE,用户名,密码);
            logger.Debug('SetCurrentDomain';成功实例化的RootDSE LDAP);

            logger.Debug(试图找回'defaultNamingContext'......);
            字符串域=(字符串)ldapRoot.Properties [defaultNamingContext] [0]; //这是我打的收到COMException
            logger.Debug(检索defaultNamingContext:+域名);
            如果(!domain.IsEmpty())
            {

                logger.Debug('SetCurrentDomain';实例化分区/配置LDAP条目);
                的DirectoryEntry部分=新的DirectoryEntry(服务器+/ CN =分区,CN =配置,+域名,用户名,密码);

                logger.Debug('SetCurrentDomain';成功实例化的分区/配置LDAP条目);
                的foreach(的DirectoryEntry部分parts.Children)
                {
                    如果(part.Properties [NCNAME] = NULL和放大器;!&安培;!(串)part.Properties [NCNAME] [0] = NULL)
                    {
                        logger.Debug('SetCurrentDomain';实测值属性NCNAME);
                        如果((字符串)part.Properties [NCNAME] [0] ==域)
                        {
                            logger.Debug('SetCurrentDomain'; NCNAME匹配defaultnamingcontext);
                            结果=(字符串)part.Properties [NETBIOSNAME] [0];
                            logger.Debug('SetCurrentDomain';发现NETBIOSNAME(友好的域名):+结果);
                            打破;
                        }
                    }
                }
            }
            logger.Debug(完成设置当前域......);
        }
        赶上(例外前)
        {
            logger.Error(错误尝试设置域:+ ex.ToString());
        }
        返回结果;
    }
 

修改

我加为了试图建议这个样本的方法,但我得到一个异常:未指定的错误当我击中了搜索了的FindAll()调用。 传递的字符串是:CN =测试用户,CN =用户​​,DC =坦佩,DC = ktregression,DC = com的

 私人字符串GetUserDomain(字符串DN)
    {
        字符串域=的String.Empty;
        串firstPart = dn.Substring(dn.IndexOf(DC =));
        字符串二部=CN =分区,CN =配置,+ firstPart;
        的DirectoryEntry根=新的DirectoryEntry(二部,textBox2.Text,textBox3.Text);
        DirectorySearcher从搜索=新DirectorySearcher从(根);
        sea​​rcher.SearchScope = SearchScope.Subtree;
        sea​​rcher.ReferralChasing = ReferralChasingOption.All;
        sea​​rcher.Filter =(及(NCNAME =+ firstPart +)(NETBIOSNAME = *));
        尝试
        {
            SearchResultCollection RS = searcher.FindAll();
            如果(RS!= NULL)
            {
                域的getProperty =(RS [0],NETBIOSNAME);
            }
        }
        赶上(例外前)
        {

        }


        返回域;
 

解决方案

这篇文章帮了我很多理解如何与Active Directory协同工作。
HOWTO:(几乎)一切在Active Directory中通过C#

从现在开始,如果你需要进一步assitance,请让我知道在评论正确的问题,我会回答你的问题,尽我的知识。

编辑#1

您已经更好地与这个例子中的过滤器,而不是去。我已经写了一些示例code来说明如何使用工作的System.DirectoryServices 和的 System.DirectoryServices.ActiveDirectory 的命名空间。在 System.DirectoryServices.ActiveDirectory 命名空间用于检索您的森林中域的信息。

 私人的IEnumerable<的DirectoryEntry> GetDomains(){
    ICollection的<字符串>域=新的名单,其中,串>();

    //查询当前森林内的域。
    的foreach(域D在Forest.GetCurrentForest()。域)
        domains.Add(d.Name);

    返回域;
}

私人字符串GetDomainFullName(字符串的friendlyName){
    DirectoryContext上下文=新DirectoryContext(DirectoryContextType.Domain,的friendlyName);
    域domain = Domain.GetDomain(上下文);
    返回domain.Name;
}

私人的IEnumerable<字符串> GetUserDomain(用户名字符串){
    的foreach(字符串d。在GetDomains())
        //从森林获得的领域,我们搜索域树对于给定的用户名。
        使用(的DirectoryEntry域=新的DirectoryEntry(GetDomainFullName(D))){
            使用(DirectorySearcher从搜索=新DirectorySearcher从()){
                sea​​rcher.SearchRoot =域;
                sea​​rcher.SearchScope = SearchScope.Subtree;
                sea​​rcher.PropertiesToLoad.Add(sAMAccountName赋);
                //过滤器是非常重要的,所以它的查询字符串。在对象类参数是必需的。
                //一旦我们指定的对象类,我们要寻找的登录用户
                //登录的用户名。
                sea​​rcher.Filter =的String.Format((及(对象类=用户)(sAMAccountName赋= {0})),用户名);

                尝试 {
                    SearchResultCollection结果= searcher.FindAll();

                    //如果用户无法找到,那么让我们检查下一个域。
                    如果(结果== NULL || results.Count = 0)
                        继续;

                     //这里,我们得到回报,我们希望所有该用户名进行身份验证的域。
                     得到的回报domain.Path;
                } 最后 {
                    sea​​rcher.Dispose();
                    domain.Dispose();
                }
            }
}
 

在这里,我没有测试code和可能有一些小问题来解决。此示例是作为-是为了帮助你。我希望这会有所帮助。

编辑#2

我发现了另一条出路:

  1. 您必须先看看你是否能找到您域内的用户帐号;
  2. 如果找到,则获取域的NetBIOS名称;和
  3. 将它连接到一个反斜杠(****)和发现登录。

下面的例子使用的 NUnit的测试用例的,你可以自己试一试,看看它做你需要什么来。

  [TestCase的(LDAP://fully.qualified.domain.name,TestUser1)
公共无效GetNetBiosName(字符串LDAPURL,串登录)
    字符串NETBIOSNAME = NULL;
    字符串foundLogin = NULL;

    使用(的DirectoryEntry根=新的DirectoryEntry(LDAPURL))
        使用(DirectorySearcher从搜索=新DirectorySearcher从(根){
            sea​​rcher.SearchScope = SearchScope.Subtree;
            sea​​rcher.PropertiesToLoad.Add(sAMAccountName赋);
            sea​​rcher.Filter =的String.Format((及(对象类=用户)(sAMAccountName赋= {0})),登录);

            信息搜索结果的结果= NULL;

            尝试 {
                结果= searcher.FindOne();

                如果(结果== NULL)
                    如果(string.Equals(登录,result.GetDirectoryEntry()。属性(sAMAccountName赋)。值))
                        foundLogin = result.GetDirectoryEntry()。属性(sAMAccountName赋)。值
            } 最后 {
                sea​​rcher.Dispose();
                root.Dispose();
                如果(结果!= NULL)结果= NULL;
            }
        }

    如果(!string.IsNullOrEmpty(foundLogin))
        使用(的DirectoryEntry根=新的DirectoryEntry(ldapUrl.Insert(7,CN =分区,CN =配置,DC =)。更换(。,DC =))
            使用DirectorySearcher从搜索=新DirectorySearcher从(根)
                sea​​rcher.Filter =NETBIOSNAME = *;
                sea​​rcher.PropertiesToLoad.Add(CN);

                SearchResultCollection结果= NULL;

                尝试 {
                    结果= searcher.FindAll();

                    如果(结果= NULL和放大器;!&安培; results.Count> 0安培;&安培;!结果[0] = NULL){
                        ResultPropertyValueCollection值=结果[0]的.properties(CN);
                        NETBIOSNAME = RPVC [0]的ToString();
                } 最后 {
                    sea​​rcher.Dispose();
                    root.Dispose();

                    如果(结果!= NULL){
                        results.Dispose();
                        结果= NULL;
                    }
                }
            }

    Assert.AreEqual(综\ TESTUSER1,string.Concat(NETBIOSNAME,\,foundLogin).ToUpperInvariant())
}
 

这是我自己的灵感来源是:
查找AD域的NetBIOS名称

I know that this type of question has been asked before, but other methods are failing me right now.

As it stands our windows service polls AD, given an LDAP (i.e. LDAP://10.32.16.80) and a list of usergroups within that AD server to search for. It retrieves all users within those given groups, recursively searching those groups for more groups as well. Each user is then added to another applications authenticated users list.

This part of the application is running successfully. However, we're in need of each user's friendly domain name (i.e. the part of their login DOMAIN/username)

So if there is a user that is part of TEST domain, named Steve: TEST/steve is his login. I'm able to find steve in the AD, however I also need "TEST" to be stored along with his AD information.

Again, I can find 'steve' fine by using a directory searcher and the LDAP IP I'm given, but given the LDAP IP, how can I find the friendly domain name?

When I try the following code I'm given an error when attempting to access the 'defaultNamingContext':

System.Runtime.InteropServices.COMException (0x8007202A): The authentication mechanism is unknown.

Here is the code:

    private string SetCurrentDomain(string server)
    {
        string result = string.Empty;
        try
        {
            logger.Debug("'SetCurrentDomain'; Instantiating rootDSE LDAP");
            DirectoryEntry ldapRoot = new DirectoryEntry(server + "/rootDSE", username, password);
            logger.Debug("'SetCurrentDomain'; Successfully instantiated rootDSE LDAP");

            logger.Debug("Attempting to retrieve 'defaultNamingContext'...");
            string domain = (string)ldapRoot.Properties["defaultNamingContext"][0]; //THIS IS WHERE I HIT THE COMEXCEPTION
            logger.Debug("Retrieved 'defaultNamingContext': " + domain);
            if (!domain.IsEmpty())
            {

                logger.Debug("'SetCurrentDomain'; Instantiating partitions/configuration LDAP entry");
                DirectoryEntry parts = new DirectoryEntry(server + "/CN=Partitions,CN=Configuration," + domain, username, password);

                logger.Debug("'SetCurrentDomain'; Successfully instantiated partitions/configuration LDAP entry");
                foreach (DirectoryEntry part in parts.Children)
                {
                    if (part.Properties["nCName"] != null && (string)part.Properties["nCName"][0] != null)
                    {
                        logger.Debug("'SetCurrentDomain'; Found property nCName");
                        if ((string)part.Properties["nCName"][0] == domain)
                        {
                            logger.Debug("'SetCurrentDomain'; nCName matched defaultnamingcontext");
                            result = (string)part.Properties["NetBIOSName"][0];
                            logger.Debug("'SetCurrentDomain'; Found NetBIOSName (friendly domain name): " + result);
                            break;
                        }
                    }
                }
            }
            logger.Debug("finished setting current domain...");
        }
        catch (Exception ex)
        {
            logger.Error("error attempting to set domain:" + ex.ToString());
        }
        return result;
    }

edit

I added this sample method in order to attempt a suggestion but am getting an exception: "Unspecified error" when I hit the "FindAll()" call on the searcher. The string being passed in is: "CN=TEST USER,CN=Users,DC=tempe,DC=ktregression,DC=com"

        private string GetUserDomain(string dn)
    {
        string domain = string.Empty;
        string firstPart = dn.Substring(dn.IndexOf("DC="));
        string secondPart = "CN=Partitions,CN=Configuration," + firstPart;
        DirectoryEntry root = new DirectoryEntry(secondPart, textBox2.Text, textBox3.Text);
        DirectorySearcher searcher = new DirectorySearcher(root);
        searcher.SearchScope = SearchScope.Subtree;
        searcher.ReferralChasing = ReferralChasingOption.All;
        searcher.Filter = "(&(nCName=" + firstPart + ")(nETBIOSName=*))";
        try
        {
            SearchResultCollection rs = searcher.FindAll();
            if (rs != null)
            {
                domain = GetProperty(rs[0], "nETBIOSName");
            }
        }
        catch (Exception ex)
        {

        }


        return domain;

解决方案

This article helped me much to understand how to work with the Active Directory.
Howto: (Almost) Everything In Active Directory via C#

From this point forward, if you require further assitance, please let me know with proper questions in comment, and I shall answer them for you to the best of my knowledge.

EDIT #1

You had better go with this example's filter instead. I have written some sample code to briefly show how to work with the System.DirectoryServices and System.DirectoryServices.ActiveDirectory namespaces. The System.DirectoryServices.ActiveDirectory namespace is used to retrieve information about the domains within your Forest.

private IEnumerable<DirectoryEntry> GetDomains() {
    ICollection<string> domains = new List<string>();

    // Querying the current Forest for the domains within.
    foreach(Domain d in Forest.GetCurrentForest().Domains)
        domains.Add(d.Name);

    return domains;
}

private string GetDomainFullName(string friendlyName) {
    DirectoryContext context = new DirectoryContext(DirectoryContextType.Domain, friendlyName);
    Domain domain = Domain.GetDomain(context);
    return domain.Name;
}

private IEnumerable<string> GetUserDomain(string userName) {
    foreach(string d in GetDomains()) 
        // From the domains obtained from the Forest, we search the domain subtree for the given userName.
        using (DirectoryEntry domain = new DirectoryEntry(GetDomainFullName(d))) {
            using (DirectorySearcher searcher = new DirectorySearcher()){
                searcher.SearchRoot = domain;
                searcher.SearchScope = SearchScope.Subtree;
                searcher.PropertiesToLoad.Add("sAMAccountName");
                // The Filter is very important, so is its query string. The 'objectClass' parameter is mandatory.
                // Once we specified the 'objectClass', we want to look for the user whose login
                // login is userName.
                searcher.Filter = string.Format("(&(objectClass=user)(sAMAccountName={0}))", userName);

                try {
                    SearchResultCollection  results = searcher.FindAll();

                    // If the user cannot be found, then let's check next domain.
                    if (results == null || results.Count = 0)
                        continue;

                     // Here, we yield return for we want all of the domain which this userName is authenticated.
                     yield return domain.Path;
                } finally {
                    searcher.Dispose();
                    domain.Dispose();
                }
            }
}

Here, I didn't test this code and might have some minor issue to fix. This sample is provided as-is for the sake of helping you. I hope this will help.

EDIT #2

I found out another way out:

  1. You have first to look whether you can find the user account within your domain;
  2. If found, then get the domain NetBIOS Name; and
  3. concatenate it to a backslash (****) and the found login.

The example below uses a NUnit TestCase which you can test for yourself and see if it does what you are required to.

[TestCase("LDAP://fully.qualified.domain.name", "TestUser1")] 
public void GetNetBiosName(string ldapUrl, string login)
    string netBiosName = null;
    string foundLogin = null;

    using (DirectoryEntry root = new DirectoryEntry(ldapUrl))
        Using (DirectorySearcher searcher = new DirectorySearcher(root) {
            searcher.SearchScope = SearchScope.Subtree;
            searcher.PropertiesToLoad.Add("sAMAccountName");
            searcher.Filter = string.Format("(&(objectClass=user)(sAMAccountName={0}))", login);

            SearchResult result = null;

            try {
                result = searcher.FindOne();

                if (result == null) 
                    if (string.Equals(login, result.GetDirectoryEntry().Properties("sAMAccountName").Value)) 
                        foundLogin = result.GetDirectoryEntry().Properties("sAMAccountName").Value
            } finally {
                searcher.Dispose();
                root.Dispose();
                if (result != null) result = null;
            }
        }

    if (!string.IsNullOrEmpty(foundLogin)) 
        using (DirectoryEntry root = new DirectoryEntry(ldapUrl.Insert(7, "CN=Partitions,CN=Configuration,DC=").Replace(".", ",DC=")) 
            Using DirectorySearcher searcher = new DirectorySearcher(root)
                searcher.Filter = "nETBIOSName=*";
                searcher.PropertiesToLoad.Add("cn");

                SearchResultCollection results = null;

                try {
                    results = searcher.FindAll();

                    if (results != null && results.Count > 0 && results[0] != null) {
                        ResultPropertyValueCollection values = results[0].Properties("cn");
                        netBiosName = rpvc[0].ToString();
                } finally {
                    searcher.Dispose();
                    root.Dispose();

                    if (results != null) {
                        results.Dispose();
                        results = null;
                    }
                }
            }

    Assert.AreEqual("FULLY\TESTUSER1", string.Concat(netBiosName, "\", foundLogin).ToUpperInvariant())
}

The source from which I inspired myself is:
Find the NetBios Name of a domain in AD

这篇关于C#中的Active Directory:获取用户域名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆