2009-10-15 7 views
8

Firma Microsoft opublikowała ogólny artykuł KB (Q316748) opisujący sposób uwierzytelniania w usłudze Active Directory przy użyciu obiektu DirectoryEntry. W ich przykład wytwarzają wartość nazwa_użytkownika przez złączenie nazwy domeny i nazwy użytkownika w standardowym formacie NetBIOS („domena \ nazwa_użytkownika”) i mimochodem, że jako parametr do konstruktora pozycji katalogu:Czy System.DirectoryServices.DirectoryEntry zawiera konstruktor, który faktycznie używa "domena nazwa użytkownika" z Ldap?

string domainAndUsername = domain + @"\" + username; 
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd); 

Niedawno przyszedł do nasza uwaga, że ​​część domeny nazwa użytkownika została całkowicie zignorowana iw wielu środowiskach potwierdziłem to zachowanie. Nazwa użytkownika i hasło są w rzeczywistości używane, ponieważ uwierzytelnianie kończy się niepowodzeniem, gdy są nieprawidłowe, ale można podać dowolną dowolną wartość dla nazwy domeny i przepustek uwierzytelniających. Na pierwszy rzut oka teoretycznie ten format działa dla dostępu do katalogu opartego na WinNT, ale część domeny jest ignorowana dla LDAP.

Kontrola w Google pokazuje wiele przykładów LDAP przekazujących wartość "domain \ username" do obiektu DirectoryEntry, więc albo zawiodłem coś w mojej konfiguracji, albo jest wielu ludzi zdezorientowanych przez artykuł KB. Czy ktoś może potwierdzić, że to oczekiwane zachowanie lub zalecić akceptację wartości "domain \ username" i uwierzytelnić się w Active Directory?

Dzięki,

Odpowiedz

18

Krótka odpowiedź: Gdy parametr konstruktora DirectoryEntrypath zawiera nieprawidłową nazwę domeny przedmiotem DirectoryEntry będzie (po nieudanym poszukiwaniu nieprawidłowych domeny w las) próbować spadek z powrotem przez upuszczenie część domeny Parametr username próbuje nawiązać połączenie przy użyciu zwykłej nazwy użytkownika (sAMAccountName).

The długiej odpowiedzi: Jeśli nazwa domeny określona w parametrze username jest nieważny, ale istnieje użytkownik w domenie określonej przez parametr path użytkownik zostanie uwierzytelniony (dzięki zastosowaniu zastępczą). Jeśli jednak użytkownik istnieje w innej domenie niż w lesie, to uwierzytelnienie parametru zakończy się sukcesem tylko wtedy, gdy część domeny parametru username jest dołączona i poprawna.

Istnieją cztery różne sposoby określania parametru nazwę użytkownika w kontaktach z DirectoryEntry-obiektów:

  • Distinguished Name (CN = Nazwa użytkownika, CN = Users, DC = domena, DC = local)
  • NT Nazwa konta (DOMENA \ Nazwa użytkownika)
  • Plain konto Nazwa/samAccountName (nazwa użytkownika)
  • User Principal Name (ogólnie [email protected])

Pozwól mi zilustrować na przykładzie:

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

using System.DirectoryServices; 

namespace DirectoryTest 
{ 
    class Program 
    { 

    private static Int32 counter = 1; 

    static void Main(string[] args) 
    { 
     TestConnection(); 
    } 

    private static void TestConnection() 
    { 
     String domainOne = "LDAP://DC=domain,DC=one"; 
     String domainOneName = "DOMAINONE"; 
     String domainOneUser = "onetest"; 
     String domainOnePass = "testingONE!"; 

     String domainTwo = "LDAP://DC=domain,DC=two"; 
     String domainTwoName = "DOMAINTWO"; 
     String domainTwoUser = "twotest"; 
     String domainTwoPass = "testingTWO!"; 

     String invalidDomain = "INVALIDDOMAIN"; 

     // 1) This works because it's the correct NT Account Name in the same domain: 
     Connect(domainOne, domainOneName + "\\" + domainOneUser, domainOnePass); 

     // 2) This works because username can be supplied without the domain part 
     // (plain username = sAMAccountName): 
     Connect(domainOne, domainOneUser, domainOnePass); 

     // 3) This works because there's a fall back in DirectoryEntry to drop the domain part 
     // and attempt connection using the plain username (sAMAccountName) in (in this case) 
     // the forrest root domain: 
     Connect(domainOne, invalidDomain + "\\" + domainOneUser, domainOnePass); 

     // 4) This works because the forrest is searched for a domain matching domainTwoName: 
     Connect(domainOne, domainTwoName + "\\" + domainTwoUser, domainTwoPass); 

     // 5) This fails because domainTwoUser is not in the forrest root (domainOne) 
     // and because no domain was specified other domains are not searched: 
     Connect(domainOne, domainTwoUser, domainTwoPass); 

     // 6) This fails as well because the fallback of dropping the domain name and using 
     // the plain username fails (there's no domainTwoUser in domainOne): 
     Connect(domainOne, invalidDomain + "\\" + domainTwoUser, domainTwoPass); 

     // 7) This fails because there's no domainTwoUser in domainOneName: 
     Connect(domainOne, domainOneName + "\\" + domainTwoUser, domainTwoPass); 

     // 8) This works because there's a domainTwoUser in domainTwoName: 
     Connect(domainTwo, domainTwoName + "\\" + domainTwoUser, domainTwoPass); 

     // 9) This works because of the fallback to using plain username when connecting 
     // to domainTwo with an invalid domain name but using domainTwoUser/Pass: 
     Connect(domainTwo, invalidDomain + "\\" + domainTwoUser, domainTwoPass); 
    } 

    private static void Connect(String path, String username, String password) 
    { 
     Console.WriteLine(
     "{0}) Path: {1} User: {2} Pass: {3}", 
     counter, path, username, password); 
     DirectoryEntry de = new DirectoryEntry(path, username, password); 
     try 
     { 
     de.RefreshCache(); 
     Console.WriteLine("{0} = {1}", username, "Autenticated"); 
     } 
     catch (Exception ex) 
     { 
     Console.WriteLine("{0} ({1})", ex.Message, username); 
     } 
     Console.WriteLine(); 
     counter++; 
    } 
    } 
} 

W powyższym przykładzie domain.one jest domena główna Forrest i domain.two jest w tym samym Forrest jako domain.one (ale innego drzewa naturalnie).

więc odpowiedzieć na pytanie: Authentication zawsze zakończy się niepowodzeniem, jeśli użytkownik w nie w domenie, że łączysz się i brak lub nieprawidłowa nazwa domeny jest określony w parametrze username.

+0

Dzięki stary, to jest niezwykle szczegółowa odpowiedź i doceniam czystość –

+0

wspomniałeś o sprawie "Nazwisko użytkownika głównego" ([email protected] jak format), ale nie ma na to przypadku testowego. czy zachowałoby się to w ten sam sposób, więc "domena.local", gdyby była nieważna, spowodowałaby awarię w przypadkach 3) i 9)? – dlatikay

0

Mam dwie aplikacje, które wykorzystuje DirectoryEntry(_path, domainAndUsername, pwd); konstruktora i nie mam żadnego problemu uwierzytelniania. Każda aplikacja jest instalowana na innym kliencie, zarówno z bardzo (bardzo) dużymi strukturami domenowymi.

+0

Hmm, a część nazwy referencyjnej domeny jest używana i łączysz się przez LDAP? Nie mam dokładnie problemów z uwierzytelnianiem, ponieważ z powodzeniem uwierzytelnia się we wszystkich przypadkach, ale ignoruje część nazwy domeny. Jeśli przedrostek z nieprawidłową domeną jest autoryzowany? –

+0

Nie mogę przetestować go teraz, ale zrobię to jutro i opublikuję wyniki tutaj –