web-dev-qa-db-ja.com

sAMAccountNameおよびDomainによるActive Directory LDAPクエリ

SAMAccountNameおよびDomainによるLDAPストアのクエリはどのように行いますか? Active DirectoryまたはLDAPの用語で名前が付けられている「ドメイン」プロパティとは何ですか?

これは私がこれまでのところフィルターに持っているものです。ドメインに追加できるようにしたい:

(&(objectCategory=Person)(sAMAccountName=BTYNDALL))
21
BuddyJoe

まず、連絡先ではなくユーザーのみを検索するように検索フィルターを変更します。

(&(objectCategory=person)(objectClass=user)(sAMAccountName=BTYNDALL))

構成パーティションに接続し、パーティションコンテナー内のすべてのエントリを列挙することにより、フォレストのすべてのドメインを列挙できます。申し訳ありませんが、現在C#コードはありませんが、過去に使用したvbscriptコードを次に示します。

Set objRootDSE = GetObject("LDAP://RootDSE")
AdComm.Properties("Sort on") = "name"
AdComm.CommandText = "<LDAP://cn=Partitions," & _
    objRootDSE.Get("ConfigurationNamingContext") & ">;" & _
        "(&(objectcategory=crossRef)(systemFlags=3));" & _
            "name,nCName,dnsRoot;onelevel"
set AdRs = AdComm.Execute

それから、各パーティションの名前とdnsRootを取得できます。

AdRs.MoveFirst
With AdRs
  While Not .EOF
    dnsRoot = .Fields("dnsRoot")

    Set objOption = Document.createElement("OPTION")
    objOption.Text = dnsRoot(0)
    objOption.Value = "LDAP://" & dnsRoot(0) & "/" & .Fields("nCName").Value
    Domain.Add(objOption)
    .MoveNext 
  Wend 
End With
21
Dscoduc

次のクエリを使用できます

ログオン名(Windows 2000以前)がJohnと等しいユーザー

(&(objectCategory=person)(objectClass=user)(!sAMAccountType=805306370)(sAMAccountName=**John**))

全てのユーザー

(&(objectCategory=person)(objectClass=user)(!sAMAccountType=805306370))

有効なユーザー

(&(objectCategory=person)(objectClass=user)(!sAMAccountType=805306370)(!userAccountControl:1.2.840.113556.1.4.803:=2))

無効なユーザー

(&(objectCategory=person)(objectClass=user)(!sAMAccountType=805306370)(userAccountControl:1.2.840.113556.1.4.803:=2))

ロックアウトされたユーザー

(&(objectCategory=person)(objectClass=user)(!sAMAccountType=805306370)(lockouttime>=1))
14
kombsh

usersを検索するbest way(sAMAccountType=805306368)

または、障害のあるユーザーの場合:

(&(sAMAccountType=805306368)(userAccountControl:1.2.840.113556.1.4.803:=2))

またはアクティブユーザーの場合:

(&(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))

LDAPがそれほど想定されていなかったのではないかと思います。

また、 一般的なLDAPクエリのリソース -それらを自分で見つけようとすると、貴重な時間を費やし、間違いを犯します。

ドメインに関して:ドメインはユーザーdistinguisedNameDN)の一部であるため、単一のクエリでは不可能です。MicrosoftADでは、部分一致では検索できません。

8
sorin

「ドメイン」は、LDAPオブジェクトのプロパティではありません。オブジェクトが保存されているデータベースの名前に似ています。

そのため、そのデータベースで検索を実行するには、適切なデータベース(LDAPの用語で"ドメイン/ディレクトリサーバーにバインド")に接続する必要があります。

バインドに成功すると、現在のシェイプでのクエリが必要になります。

ところで:"ObjectCategory=Person"より_"ObjectClass=user"を選択するのは良い決断でした。 ADでは、前者は優れたパフォーマンスを持つ「インデックス付きプロパティ」であり、後者はインデックス化されておらず、少し遅いです。

5
Tomalak

ドメインで検索を実行する必要があります。

http://msdn.Microsoft.com/en-us/library/ms677934(VS.85).aspx したがって、基本的にこのドメイン内を検索するには、ドメインにバインドする必要があります。

3
lkurts

.NETを使用している場合は、 DirectorySearcher クラスを使用します。ドメインを文字列としてコンストラクターに渡すことができます。

// if you domain is domain.com...
string username = "user"
string domain = "LDAP://DC=domain,DC=com";
DirectorySearcher search = new DirectorySearcher(domain);
search.Filter = "(SAMAccountName=" + username + ")";
3
Aaron Daniels

私は組み込むC#クラスを書きました

  • dscoducのアルゴリズム、
  • sorinからのクエリ最適化、
  • ドメインからサーバーへのマッピングのキャッシュ、および
  • dOMAIN\sAMAccountName形式のアカウント名を検索するメソッド。

ただし、サイトを認識しません。

using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Text;

public static class ADUserFinder
{
    private static Dictionary<string, string> _dictDomain2LDAPPath;

    private static Dictionary<string, string> DictDomain2LDAPPath
    {
        get
        {
            if (null == _dictDomain2LDAPPath)
            {
                string configContainer;
                using (DirectoryEntry rootDSE = new DirectoryEntry("LDAP://RootDSE"))
                    configContainer = rootDSE.Properties["ConfigurationNamingContext"].Value.ToString();

                using (DirectoryEntry partitionsContainer = new DirectoryEntry("LDAP://CN=Partitions," + configContainer))
                using (DirectorySearcher dsPartitions = new DirectorySearcher(
                        partitionsContainer,
                        "(&(objectcategory=crossRef)(systemFlags=3))",
                        new string[] { "name", "nCName", "dnsRoot" },
                        SearchScope.OneLevel
                    ))
                using (SearchResultCollection srcPartitions = dsPartitions.FindAll())
                {
                    _dictDomain2LDAPPath = srcPartitions.OfType<SearchResult>()
                        .ToDictionary(
                        result => result.Properties["name"][0].ToString(), // the DOMAIN part
                        result => $"LDAP://{result.Properties["dnsRoot"][0]}/{result.Properties["nCName"][0]}"
                    );
                }
            }

            return _dictDomain2LDAPPath;
        }
    }

    private static DirectoryEntry FindRootEntry(string domainPart)
    {
        if (DictDomain2LDAPPath.ContainsKey(domainPart))
            return new DirectoryEntry(DictDomain2LDAPPath[domainPart]);
        else
            throw new ArgumentException($"Domain \"{domainPart}\" is unknown in Active Directory");
    }

    public static DirectoryEntry FindUser(string domain, string sAMAccountName)
    {
        using (DirectoryEntry rootEntryForDomain = FindRootEntry(domain))
        using (DirectorySearcher dsUser = new DirectorySearcher(
                rootEntryForDomain,
                $"(&(sAMAccountType=805306368)(sAMAccountName={EscapeLdapSearchFilter(sAMAccountName)}))" // magic number 805306368 means "user objects", it's more efficient than (objectClass=user)
            ))
            return dsUser.FindOne().GetDirectoryEntry();
    }

    public static DirectoryEntry FindUser(string domainBackslashSAMAccountName)
    {
        string[] domainAndsAMAccountName = domainBackslashSAMAccountName.Split('\\');
        if (domainAndsAMAccountName.Length != 2)
            throw new ArgumentException($"User name \"{domainBackslashSAMAccountName}\" is not in correct format DOMAIN\\SAMACCOUNTNAME", "DomainBackslashSAMAccountName");

        string domain = domainAndsAMAccountName[0];
        string sAMAccountName = domainAndsAMAccountName[1];

        return FindUser(domain, sAMAccountName);
    }

    /// <summary>
    /// Escapes the LDAP search filter to prevent LDAP injection attacks.
    /// Copied from https://stackoverflow.com/questions/649149/how-to-escape-a-string-in-c-for-use-in-an-ldap-query
    /// </summary>
    /// <param name="searchFilter">The search filter.</param>
    /// <see cref="https://blogs.Oracle.com/shankar/entry/what_is_ldap_injection" />
    /// <see cref="http://msdn.Microsoft.com/en-us/library/aa746475.aspx" />
    /// <returns>The escaped search filter.</returns>
    private static string EscapeLdapSearchFilter(string searchFilter)
    {
        StringBuilder escape = new StringBuilder();
        for (int i = 0; i < searchFilter.Length; ++i)
        {
            char current = searchFilter[i];
            switch (current)
            {
                case '\\':
                    escape.Append(@"\5c");
                    break;
                case '*':
                    escape.Append(@"\2a");
                    break;
                case '(':
                    escape.Append(@"\28");
                    break;
                case ')':
                    escape.Append(@"\29");
                    break;
                case '\u0000':
                    escape.Append(@"\00");
                    break;
                case '/':
                    escape.Append(@"\2f");
                    break;
                default:
                    escape.Append(current);
                    break;
            }
        }

        return escape.ToString();
    }
}
1
Froggy