Skip to content

Commit b81fd1e

Browse files
committed
Separado la implementación con el winapi del client
1 parent ba711a4 commit b81fd1e

File tree

4 files changed

+330
-314
lines changed

4 files changed

+330
-314
lines changed
Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
unit ActiveDirectory.Client.Winapi;
2+
3+
interface
4+
5+
uses
6+
ActiveDirectory.Client.Intf,
7+
ActiveDirectory.Types;
8+
9+
type
10+
{ Class implements Active Directory Client by WinApi }
11+
TActiveDirectoryClientWinapi = class(TInterfacedObject, IActiveDirectoryClient)
12+
private
13+
function GetActiveLDAPDomainName: string;
14+
15+
protected
16+
function GetCurrentUserName: string;
17+
function GetCurrentDomainName(inUserName: string): string;
18+
function GetCurrentLDAPDomainName(inDomainName: string): string;
19+
function GetAllProviders: string; // CSV (LDAP, WinNT, ...)
20+
function GetActiveDirectoryEnabled: Boolean;
21+
22+
function GetUserInfo(inDomainName, inUserName: string; out outUserInfo: TADSIUserInfo): Boolean;
23+
function GetUserActive(inDomainName, inUserName: string): Boolean;
24+
25+
function AuthenticateUser(inDomainName, inUserName, inUserPass: string): Boolean;
26+
27+
public
28+
class function New: IActiveDirectoryClient;
29+
end;
30+
31+
implementation
32+
33+
uses
34+
System.SysUtils,
35+
System.Classes,
36+
Winapi.Windows,
37+
Winapi.ActiveX,
38+
39+
ActiveDirectory.Winapi.DllMapper, // <-- Generate by mapping dlls ADSI
40+
ActiveDirectory.Winapi.TLB; // <-- Generate by "Import Type Library" from "c:\windows\system32\activeds.tlb" (Active DS Type Library)
41+
42+
const
43+
_ProviderAD_LDAP = 'LDAP:';
44+
_ProviderAD_WinNT = 'WinNT:';
45+
_ProviderAD_PathBegin = '//';
46+
_ProviderAD_PathDelim = '/';
47+
_CSV_Sep = ',';
48+
49+
type
50+
{ Class Utilities }
51+
TActiveDirectoryWinapiUtils = class
52+
private
53+
class var FUserInfoEmpty: TADSIUserInfo;
54+
public
55+
class procedure ClearUserInfo(var inUserInfo: TADSIUserInfo);
56+
57+
class function GetPathLDAP(inDomainName: string; inObjName: string = ''): string;
58+
class function GetPathWinNT(inDomainName: string; inObjName: string = ''): string;
59+
end;
60+
61+
{ TActiveDirectoryWinapiUtils }
62+
63+
class procedure TActiveDirectoryWinapiUtils.ClearUserInfo(var inUserInfo: TADSIUserInfo);
64+
begin
65+
inUserInfo := Self.FUserInfoEmpty;
66+
end;
67+
68+
class function TActiveDirectoryWinapiUtils.GetPathLDAP(inDomainName: string; inObjName: string = ''): string;
69+
begin
70+
Result := _ProviderAD_LDAP + _ProviderAD_PathBegin + Trim(inDomainName);
71+
72+
if (Trim(inObjName) <> '') then
73+
Result := Result + _ProviderAD_PathDelim + inObjName
74+
end;
75+
76+
class function TActiveDirectoryWinapiUtils.GetPathWinNT(inDomainName: string; inObjName: string = ''): string;
77+
begin
78+
Result := _ProviderAD_WinNT + _ProviderAD_PathBegin + Trim(inDomainName);
79+
80+
if (Trim(inObjName) <> '') then
81+
Result := Result + _ProviderAD_PathDelim + inObjName
82+
end;
83+
84+
{ TActiveDirectoryClientWinapi }
85+
86+
class function TActiveDirectoryClientWinapi.New: IActiveDirectoryClient;
87+
begin
88+
Result := TActiveDirectoryClientWinapi.Create;
89+
end;
90+
91+
function TActiveDirectoryClientWinapi.GetActiveLDAPDomainName: string;
92+
var
93+
UserName: string;
94+
DomainName: string;
95+
begin
96+
UserName := Self.GetCurrentUserName;
97+
DomainName := Self.GetCurrentDomainName(UserName);
98+
Result := Self.GetCurrentLDAPDomainName(DomainName);
99+
end;
100+
101+
function TActiveDirectoryClientWinapi.GetCurrentUserName: string;
102+
const
103+
cnMaxUserNameLen = 254;
104+
var
105+
UserName: string;
106+
dwUserNameLen: DWord;
107+
begin
108+
dwUserNameLen := cnMaxUserNameLen - 1;
109+
SetLength(UserName, cnMaxUserNameLen);
110+
GetUserName(PChar(UserName), dwUserNameLen);
111+
SetLength(UserName, dwUserNameLen);
112+
Result := UserName;
113+
end;
114+
115+
function TActiveDirectoryClientWinapi.GetCurrentDomainName(inUserName: string): string;
116+
const
117+
DNLEN = 255;
118+
var
119+
SId: PSID;
120+
SIdSize: DWord;
121+
SIdNameUse: DWord;
122+
DomainNameSize: DWord;
123+
DomainName: array [0 .. DNLEN] of char;
124+
begin
125+
Result := '';
126+
127+
SIdSize := 65536;
128+
GetMem(SId, SIdSize);
129+
try
130+
DomainNameSize := DNLEN + 1;
131+
SIdNameUse := SidTypeUser;
132+
133+
if LookupAccountName(nil, PChar(inUserName), SId, SIdSize, DomainName, DomainNameSize, SIdNameUse) then
134+
Result := StrPas(DomainName);
135+
finally
136+
FreeMem(SId);
137+
end;
138+
end;
139+
140+
function TActiveDirectoryClientWinapi.GetCurrentLDAPDomainName(inDomainName: string): string;
141+
var
142+
Path: string;
143+
Resultado: HRESULT;
144+
AD: IADs;
145+
begin
146+
Path := TActiveDirectoryWinapiUtils.GetPathLDAP(inDomainName);
147+
Resultado := ADsGetObject(Path, IADs, AD);
148+
149+
if (Failed(Resultado)) then
150+
begin
151+
Result := '';
152+
Exit;
153+
end;
154+
155+
Result := AD.Get('distinguishedName');
156+
end;
157+
158+
function TActiveDirectoryClientWinapi.GetAllProviders: string;
159+
var
160+
NSContainer: IADsContainer;
161+
Item: IADs;
162+
Enum: IEnumVariant;
163+
Resultado: HRESULT;
164+
varArray: OleVariant;
165+
NumElements: ULONG;
166+
Value: string;
167+
Lista: TStringList;
168+
begin
169+
Lista := TStringList.Create;
170+
try
171+
NSContainer := nil;
172+
ADsGetObject('ADs:', IADsContainer, NSContainer);
173+
174+
Enum := nil;
175+
Resultado := ADsBuildEnumerator(NSContainer, Enum);
176+
177+
while SUCCEEDED(Resultado) do
178+
begin
179+
Resultado := ADsEnumerateNext(Enum, 1, varArray, NumElements);
180+
181+
if (NumElements <= 0) then
182+
Break;
183+
184+
IDispatch(varArray).QueryInterface(IADs, Item);
185+
Value := Item.ADsPath;
186+
187+
// Add
188+
Lista.Add(Value);
189+
end;
190+
191+
Lista.Delimiter := _CSV_Sep;
192+
Result := Lista.DelimitedText;
193+
finally
194+
FreeAndNil(Lista);
195+
end;
196+
end;
197+
198+
function TActiveDirectoryClientWinapi.GetActiveDirectoryEnabled: Boolean;
199+
var
200+
LDAPDomain: string;
201+
Providers: string;
202+
begin
203+
try
204+
LDAPDomain := Self.GetActiveLDAPDomainName;
205+
Providers := Self.GetAllProviders;
206+
207+
if (Trim(LDAPDomain) <> '') and (Pos(_ProviderAD_LDAP, Providers) > -1) then
208+
Result := True
209+
else
210+
Result := False;
211+
except
212+
Result := False;
213+
end;
214+
end;
215+
216+
function TActiveDirectoryClientWinapi.GetUserInfo(inDomainName, inUserName: string; out outUserInfo: TADSIUserInfo): Boolean;
217+
var
218+
Path: string;
219+
Resultado: HRESULT;
220+
User: IAdsUser;
221+
Groups: IAdsMembers;
222+
Group: IAdsGroup;
223+
Enum: IEnumVariant;
224+
varGroup: OleVariant;
225+
UserFlags: Integer;
226+
Temp: LongWord;
227+
begin
228+
Result := False;
229+
TActiveDirectoryWinapiUtils.ClearUserInfo(outUserInfo);
230+
231+
if (Trim(inDomainName) = '') then
232+
Exit;
233+
234+
if (Trim(inUserName) = '') then
235+
Exit;
236+
237+
Path := TActiveDirectoryWinapiUtils.GetPathWinNT(inDomainName, inUserName);
238+
Resultado := ADsGetObject(Path, IAdsUser, User);
239+
240+
if (Failed(Resultado)) or (User = nil) then
241+
Exit;
242+
243+
// Get user info
244+
UserFlags := User.Get('userFlags');
245+
246+
outUserInfo.UID := inUserName;
247+
outUserInfo.UserName := User.FullName;
248+
outUserInfo.Description := User.Description;
249+
outUserInfo.Password.Expired := User.Get('PasswordExpired');
250+
outUserInfo.Password.CannotChange := (UserFlags and ADS_UF_PASSWD_CANT_CHANGE) <> 0;
251+
outUserInfo.Password.NeverExpires := (UserFlags and ADS_UF_DONT_EXPIRE_PASSWD) <> 0;
252+
outUserInfo.Disabled := User.AccountDisabled;
253+
outUserInfo.LockedOut := User.IsAccountLocked;
254+
255+
// Get all groups by user in CSV (group1, group2, ...)
256+
outUserInfo.Groups := '';
257+
258+
Groups := User.Groups;
259+
Enum := (Groups._NewEnum as IEnumVariant);
260+
261+
if (Enum <> nil) then
262+
begin
263+
while (Enum.Next(1, varGroup, Temp) = S_OK) do
264+
begin
265+
Group := (IDispatch(varGroup) as IAdsGroup);
266+
267+
if (outUserInfo.Groups <> '') then
268+
outUserInfo.Groups := outUserInfo.Groups + _CSV_Sep;
269+
270+
outUserInfo.Groups := outUserInfo.Groups + Group.Name;
271+
272+
VariantClear(varGroup);
273+
end;
274+
end;
275+
276+
User := nil;
277+
Result := True;
278+
end;
279+
280+
function TActiveDirectoryClientWinapi.GetUserActive(inDomainName, inUserName: string): Boolean;
281+
var
282+
UserInfo: TADSIUserInfo;
283+
UserFind: Boolean;
284+
begin
285+
Result := False;
286+
287+
UserFind := Self.GetUserInfo(inDomainName, inUserName, UserInfo);
288+
289+
if (not UserFind) then // User not found
290+
Exit;
291+
292+
if (UserInfo.Disabled) then // User disabled
293+
Exit;
294+
295+
if (UserInfo.LockedOut) then // User lockedout
296+
Exit;
297+
298+
Result := True;
299+
end;
300+
301+
function TActiveDirectoryClientWinapi.AuthenticateUser(inDomainName, inUserName, inUserPass: string): Boolean;
302+
var
303+
Path: string;
304+
Resultado: HRESULT;
305+
Obj: IADs;
306+
begin
307+
Result := False;
308+
309+
if (Trim(inDomainName) = '') then
310+
Exit;
311+
312+
if (Trim(inUserName) = '') then
313+
Exit;
314+
315+
Path := TActiveDirectoryWinapiUtils.GetPathLDAP(inDomainName);
316+
Resultado := ADsOpenObject(Path, inUserName, inUserPass, ADS_SECURE_AUTHENTICATION, IADs, Obj);
317+
318+
if (Failed(Resultado)) or (Obj = nil) then
319+
Exit;
320+
321+
Obj := nil;
322+
Result := True;
323+
end;
324+
325+
end.

0 commit comments

Comments
 (0)