web-dev-qa-db-fra.com

Requête LDAP Active Directory par sAMAccountName et domaine

Comment faire une requête sur un magasin LDAP par sAMAccountName et Domain? Quelle est la propriété "domaine" nommée dans les termes Active Directory ou LDAP?

C'est ce que j'ai jusqu'à présent pour le filtre. J'aimerais pouvoir ajouter dans le domaine:

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

Tout d'abord, modifiez votre filtre de recherche pour rechercher uniquement les utilisateurs et non les contacts:

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

Vous pouvez énumérer tous les domaines d'une forêt en vous connectant à la partition de configuration et en énumérant toutes les entrées du conteneur de partitions. Désolé, je n'ai pas de code C # pour le moment, mais voici un code vbscript que j'ai utilisé dans le passé:

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

De là, vous pouvez récupérer le nom et le dnsRoot de chaque partition:

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

Vous pouvez utiliser les requêtes suivantes

Utilisateurs dont le nom de connexion (avant Windows 2000) est égal à John

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

Tous les utilisateurs

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

Utilisateurs autorisés

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

Utilisateurs handicapés

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

Utilisateurs verrouillés

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

La meilleure façon de rechercher les utilisateurs est (sAMAccountType=805306368).

Ou pour les utilisateurs handicapés:

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

Ou pour les utilisateurs actifs:

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

Je trouve que LDAP n'est pas si léger qu'il était censé l'être.

Ressource également pour requêtes LDAP courantes - en essayant de les trouver vous-même et vous gagnerez un temps précieux et vous ferez certainement des erreurs.

Concernant les domaines: cela n'est pas possible dans une seule requête car le domaine fait partie de l'utilisateur distinguisedName (DN) qui, sur Microsoft AD, n'est pas consultable par correspondance partielle.

8
sorin

"Domaine" n'est pas une propriété d'un objet LDAP. Cela ressemble plus au nom de la base de données dans laquelle l'objet est stocké.

Vous devez donc vous connecter à la bonne base de données (en termes LDAP: "se lier au serveur de domaine/annuaire") afin d'effectuer une recherche dans cette base de données.

Une fois que vous avez lié avec succès, votre requête dans sa forme actuelle est tout ce dont vous avez besoin.

BTW: Choisir "ObjectCategory=Person" plus de "ObjectClass=user" était une bonne décision. En AD, le premier est une "propriété indexée" avec d'excellentes performances, le second n'est pas indexé et un peu plus lent.

5
Tomalak

Vous devez effectuer votre recherche dans le domaine:

http://msdn.Microsoft.com/en-us/library/ms677934 (VS.85) .aspx Donc, fondamentalement, vous devez vous lier à un domaine afin de rechercher à l'intérieur de ce domaine.

3
lkurts

Si vous utilisez .NET, utilisez la classe DirectorySearcher . Vous pouvez passer votre domaine sous forme de chaîne dans le constructeur.

// 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

J'ai écrit une classe C # incorporant

  • l'algorithme de Dscoduc,
  • l'optimisation des requêtes de sorin,
  • un cache pour le mappage du domaine au serveur, et
  • une méthode pour rechercher un nom de compte au format DOMAIN\sAMAccountName.

Cependant, il n'est pas compatible avec le site.

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