![]() |
Active Directory Probleme
Ich spiele gerade etwas mit Active Directory und dem Zugriff darauf von Delphi aus rum. Dazu verwende ich adshlp
Leider renne ich in ein paar Problemchen. 1. Ich scheine den LDAP-Pfad nicht richtig zu bestimmen.
Delphi-Quellcode:
Mit keiner der Varianten wird die CallbackFunction je aufgerufen. Hier zur Referenz ADsEnumerateObjects aus adshlp:
function getADGruppenObjectGUIDs: TList;
var Ergebnis :IAdsContainer; begin //ich habe nun folgende Varianten ausprobiert: ADsGetObject('LDAP://myDom.de', IAdsContainer, Ergebnis); ADsGetObject('LDAP://DC=myDom,DC=de', IAdsContainer, Ergebnis); ADsGetObject('LDAP://myServer/DC=myDom,DC=de', IAdsContainer, Ergebnis); ADsGetObject('LDAP://myServer.myDom.de/DC=myDom,DC=de', IAdsContainer, Ergebnis); Ergebnis.Filter := VarArrayOf(['group']); ADsEnumerateObjects(Ergebnis,MyCallBackFunc); Result := List; end; procedure MyCallBackFunc(Intf: IADs); begin List.Add(Intf.Get('objectguid')); end;
Delphi-Quellcode:
Egal, welche Variante ich versuche, lNumElements ist immer 0.
procedure ADsEnumerateObjects(Container : IADsContainer; Func : TADsEnumCallback);
var e : IEnumVARIANT; varArr : OleVariant; lNumElements : ULong; obj : IADs; hr : integer; begin hr := ADsBuildEnumerator(Container,e); while(Succeeded(Hr)) do begin hr := ADsEnumerateNext(e,1, varArr ,lNumElements); if (lNumElements=0) then break; IDispatch(varArr).QueryInterface(IADs, obj); if obj<>nil then begin Func(obj); end; varArr := NULL; end; end; Ich nehme an, dass dies an einem falsch konfigurierten Pfad liegt. Servername und Domain sind aber korrekt. Verwende ich stattdessen:
Delphi-Quellcode:
geht es.
ADsGetObject('WinNT://myDom.de', IAdsContainer, Ergebnis);
Aaaaaber.... 2. Intf.Get('objectguid') erzeugt Fehler "Die Verzeichniseigenschaft wurden nicht im Cache gefunden" Mit anderen Eigenschaften geht es aber problemlos. Gut, habe nicht alle durchgetestet, aber zumindest Intf.Get('description') gibt korrekt die Beschreibungen der AD-Gruppen zurück. Woran könnte es liegen? |
AW: Active Directory Probleme
Nachtrag zu Punkt 2: Das liegt daran, dass über WinNT nicht alle AD-Eigenschaften abrufbar sind, so wohl auch ObjectGUID.
Noch ein Grund mehr, Problem 1 zu lösen... |
AW: Active Directory Probleme
|
AW: Active Directory Probleme
Die Seite ist informativ, hat mir aber leider nicht weitergeholfen.
Auf einzelne Objekte kann ich mit LDAP auch zugreifen. Es ist also keine Frage des Connection Strings. Wenn ich aber beim ADsGetObject IAdsContainer anstatt IADs spezifiziere, erhalte ich mit ADsEnumerateNext keine Rückgabe. Aber: ADsEnumerateNext gibt als HRESULT 0 (=S_OK) zurück. In diesem Fall dürfte lNumElements eigentlich gar nicht kleiner als die angegebene Anzahl zu fetchender Elemente (in meinem Fall also 1) sein. Was ist da los? |
AW: Active Directory Probleme
Hier ein Beispiel eines alten Programms:
Delphi-Quellcode:
Probiere es mal, wenn es läuft dann hast du CoInitialize(nil); vergessen.
FDomain : String;
FDomainName : String; LRoot : TTreeNode; type PNodeData = ^TNodeData; TNodeData = class(TObject) private FName : String; FClassName: String; FFullPath : String; procedure SetName(Value : String); public property Name : String read FName write SetName; property CName : String read FClassName write FClassName; property FullPath : String read FFullPath; end; procedure TMainForm.FormCreate(Sender: TObject); begin FDomainName := ''; CoInitialize(nil); GetLDAPDomain; end; procedure TMainForm.FormDestroy(Sender: TObject); begin CoUninitialize; end; procedure TMainForm.GetLDAPDomain; var NSContainer : IADsContainer; Enum : IEnumVariant; hr : integer; varArr : OleVariant; lNumElements : ULONG; item : IADs; s : String; RN : TTreeNode; begin tvLDAP.Items.Clear; NSContainer := nil; ADsGetObject( 'LDAP:', IADsContainer, NSContainer); Enum := nil; RN := tvLDAP.Items.Add(nil, 'Active Directory'); RN.ImageIndex := 0; hr := ADsBuildEnumerator(NSContainer,Enum); while SUCCEEDED(hr) do begin hr := ADsEnumerateNext(Enum, 1, varArr, lNumElements); if (lNumElements<=0) then Break; IDispatch(varArr).QueryInterface(IADs, item); s := item.ADsPath; LRoot := tvLDAP.Items.AddChild(RN, s); LRoot.Data := TNodeData.Create; TNodeData(LRoot.Data).Name := Item.ADsPath; TNodeData(LRoot.Data).CName := Item.Class_; LRoot.ImageIndex := 1; LRoot.SelectedIndex := 1; end; end; |
AW: Active Directory Probleme
Danke für den Codeausschnitt :-)
Es funktioniert, wenn ich wie in deinem Fall schreibe:
Delphi-Quellcode:
Angabe eines Filters hat jedoch nicht die gewünschte Wirkung. Zudem sollte ich die die Auswahl schon auf eine Domain einschränken. Dann aber ist lNumElements wieder 0.
ADsGetObject( 'LDAP:', IADsContainer, NSContainer)
Vielleicht versuche ich den IADsContainer in einer Weise zu verwenden, wofür er nicht gedacht ist? Geht es nur so, wie in deinem Beispiel, also einen Connection String ohne Angabe einer Domain? Aber wie verwendet man dann den Filter korrekt? So geht's jedenfalls nicht:
Delphi-Quellcode:
NSContainer := nil;
ADsGetObject( 'LDAP:', IADsContainer, NSContainer); NSContainer.Filter := VarArrayOf(['group']); Enum := nil; hr := ADsBuildEnumerator(NSContainer,Enum); while SUCCEEDED(hr) do begin hr := ADsEnumerateNext(Enum, 1, varArr, lNumElements); if (lNumElements<=0) then Break; IDispatch(varArr).QueryInterface(IADs, item); LadeGruppenDaten(item); end; |
AW: Active Directory Probleme
Hallo,
ist schon sehr lange her:wink:
Delphi-Quellcode:
interface ... type TADsGroupEntry = class Name : String; Group : IAdsGroup; end; ... implementation ... NSContainer := nil; ADsGetObject( 'LDAP:', IADsContainer, NSContainer); NSContainer.Filter := VarArrayOf(['group']); ADsEnumerateObjects(NSContainer, AddToList); // AddToList ist ein Callback ... procedure TADSGroup.AddToList(disp : IADs); var GE : TADSGroupEntry; Ret: HRESULT; begin Ret := 0; GE := TADSGroupEntry.Create; GE.Name := disp.Name; try Ret := AdsGetObject(disp.ADsPath, IADsGroup, GE.Group); except if Ret <> 0 then Exception.Create('AddToList'); end; FGroupList.Add(GE); end; |
AW: Active Directory Probleme
Hallo Alter Mann! Ich habe jetzt eine andere Lösung von dir abgekupfert, die ich in einem alten Thread gefunden habe: IDirectorySearch
Hier der relevante Teil, wie ichs jetzt implementiert habe:
Delphi-Quellcode:
Zwei Problemchen, die noch bestehen: die Suche nach objectClass=Group gibt mehr als 1000 Ergebnisse, was gerade dazu führt, dass die while-Schleife nicht terminiert (bekomme den schönen Fehler "zu wenig Arbeitsspeicher" :wink: ). Daher der manuelle break.
SdsADGruppen.AddField(TStringField,fnADGrpName,fkData,50,false);
SdsADGruppen.AddField(TStringField,fnADGrpDescr,fkData,255,false); SdsADGruppen.AddField(TStringField,fnADGUID,fkData,50,false); SdsADGruppen.AddField(TStringField,'distName',fkData,255,false); SdsADGruppen.CreateDataSet; SdsADGruppen.Edit; if SUCCEEDED(ADsGetObject('LDAP://'+vPath.str, IDirectorySearch, Search)) then begin try opt.dwSearchPref := ADS_SEARCHPREF_SEARCH_SCOPE; opt.vValue.dwType := ADSTYPE_INTEGER; opt.vValue.__MIDL_0010.Integer := ADS_SCOPE_SUBTREE; if not SUCCEEDED(search.SetSearchPreference(opt, 1)) then begin ADsGetLastError(dwErr, @szErr[0], 254, @szName[0], 254); raise Exception.Create(WideCharToString(szErr)); Result := ''; Exit; end; dwCount := Length(Properties); hr := search.ExecuteSearch(StringToOleStr('(objectCategory=' + Category + ')'), @Properties[0], dwCount, ptrResult); if SUCCEEDED(hr) then begin hr := search.GetNextRow(ptrResult); while (hr <> S_ADS_NOMORE_ROWS) do begin SdsADGruppen.Append; for idx := 0 to dwCount -2 do begin if Succeeded(search.GetColumn(ptrResult, Properties[idx], col)) then begin if col.pADsValues <> nil then begin SearchText := col.pAdsValues^.__MIDL_0010.BackLink.ObjectName; case idx of 0 : SdsADGruppen.FieldByName(fnADGrpName).Value := SearchText; 1 : SdsADGruppen.FieldByName(fnADGrpDescr).Value := SearchText; 2 : SdsADGruppen.FieldByName('distName').Value := SearchText; //3 : SdsADGruppen.FieldByName(fnADGUID).Value := SearchText; end; end; search.FreeColumn(col); end; end; SdsADGruppen.FieldByName(fnADGUID).Value := '{Dummy}'; SdsADGruppen.Post; hr := search.GetNextRow(ptrResult); //if SdsADGruppen.RecordCount > 900 then //break; end; end; finally end; end; Aber dazu lese ich mich gerade ins paging beim Directory search ein. Das zweite Problem ist ein Typenkonflikt beim Auslesen der GUID. Das ist auch nicht verwunderlich. Alle anderen Eigenschaften, auf die ich da zugreife, sind letztendlich in einem String-kompatiblen Format. Die objectGUID fährt da mit dem OctetString aber ne eigene Schiene. Kennst du da vielleicht nen Trick, wie man über nen DirectorySearch die GUID der Objektes der Zeile als Zahl oder String auslesen kann? |
AW: Active Directory Probleme
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
der erste Wert von col.pAdsValues^ gibt den Datentyp an. 8 bedeutet ADSTYPE_OCTET_STRING. Die Property wird also gefunden. Wie man aber sieht (rote Umkringelung) ist hinter OctetString kein Wert hinterlegt (ok, klar, ich könnte versuchen auf Adresse 10 zuzugreifen, aber ich glaube wir alle wissen, wohin das führt :-D ) So komme ich an die GUID offenbar nicht heran. Ist es vielleicht möglich, was einem DirectorSearch-Zeile ein Objekt zu erhalten, welches das IADs Interface implementiert? So könnte man dann direkt auf die GUID zugreifen. Oder ich versuche es mit der Lösung, die du als letztes gepostet hast. |
AW: Active Directory Probleme
Hallo,
nicht ganz so einfach. Habe zur Zeit keinen direkten Zugriff auf das LDAP. Ich würde es mit
Delphi-Quellcode:
versuchen.
col.pAdsValues^.__MIDL_0010.OctetString.lpValue^
Es soll ja ein Zitat:
|
AW: Active Directory Probleme
Zitat:
Delphi-Quellcode:
würde versuchen, Adresse $10 auszulesen. Dass das nicht funktioniert, kann man bereits erahnen, und tatsächlich: es fliegen einem sofort fröhlich Zugriffsverletzungen um die Ohren.
col.pAdsValues^.__MIDL_0010.OctetString.lpValue^
Generell halte ich dies für ein Problem bei der Delphi<->ActiveDirectory Anbindung. Die nicht String-kompatiblen Typen scheinen Probleme zu machen. Aber auch generell: eigentlich sollte man den Wert eines Attributs über col.pAdsValues^.__MIDL_0010.TypDesAttributs auslesen, und nicht über den "Umweg" col.pAdsValues^.__MIDL_0010.BackLink.Name. Das dass bei den String-kompatiblen Typen funktioniert ist Glück. Bei Typen wie OctetString für die ObjectGUID ist BackLink.Name eben leer (''). Ich glaube inzwischen, dass sich das, was ich tun will (gefilterte Suche auf alle Objekte einer Domain und Auslesen ua. der objectGUID für jedes Element der Ergebnismenge) derzeit nicht in Delphi möglich ist. Ich versuche jetzt eine externe dll zu in VisualBasic zu schreiben, die die Funktion implementiert, um diese dann von Delphi aus aufzurufen. Habe ich zwar auch alles noch nie gemacht, aber hey, man wächst an seinen Herausforderungen :wink: |
AW: Active Directory Probleme
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo,
ich habe mal eine alte Festplatte durchforstet und zwei Dateien angehängt. Die adsicode.zip sollte dem Original von agnisoft entsprechen. Die adsisample.zip enthält einen Teil meiner alten 'Gehversuche', eventuell findet sich ja da etwas. Um jetzt genauer helfen zu können fehlt mir ein LDAP-Server und Zeit. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:08 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz