gpt4 book ai didi

delphi - 如何确定用户帐户是否是 AD 组的(间接)成员?

转载 作者:行者123 更新时间:2023-12-03 14:53:30 26 4
gpt4 key购买 nike

如何确定用户帐户是否是 AD 组的成员,特别是当用户不是该组的直接成员时

示例:

  • 用户 1 是组 1 的成员
  • 组 1 是组 2 的成员
  • (虚构的)函数调用 IsUserMemberOf('user1', 'group2') 的结果应为 TRUE

对于 .NET 有一个解决方案:

static bool IsUserMemberOf(string userName, string groupName)
{
using (var ctx = new PrincipalContext(ContextType.Domain))
using (var groupPrincipal = GroupPrincipal.FindByIdentity(ctx, groupName))
using (var userPrincipal = UserPrincipal.FindByIdentity(ctx, userName))
{
return userPrincipal.IsMemberOf(groupPrincipal);
}
}

如何使用 Delphi (Delphi-2007) 做到这一点?

解决方案:

我接受Remko的回答,但因为他的代码在Delphi-2007下不起作用(一些String/WideString问题),这是我正在运行的D2007版本:

unit Unit1;

interface

uses // Jedi ApiLib
SysUtils, Classes, Windows, JwaActiveDs, JwaAdsTlb, JwaNative, JwaWinNT, JwaWinBase,
JwaNtSecApi, JwaNtStatus, JwaWinType;

type
// Some Helper Types
TSidArray = array of PSID;
PSidArray = ^TSidArray;

TAdsValueArray = array[0..ANYSIZE_ARRAY-1] of ADSVALUE;
PAdsValueArray = ^TAdsValueArray;

TLsaTranslatedNameArray = array[0..ANYSIZE_ARRAY-1] of LSA_TRANSLATED_NAME;
PLsaTranslatedNameArray = ^TLsaTranslatedNameArray;

function GetPolicyHandle(const Computer: WideString=''): PLSA_HANDLE;
function GetGroupMembership(const AdsPath: WideString; var Groups: TStringList): Boolean;

implementation

function GetPolicyHandle(const Computer: WideString=''): PLSA_HANDLE;
var
ObjectAttributes: LSA_OBJECT_ATTRIBUTES;
lusSystemName: LSA_UNICODE_STRING;
nts: NTSTATUS;
dwError: DWORD;
begin
ZeroMemory(@ObjectAttributes, SizeOf(ObjectAttributes));

RtlInitUnicodeString(@lusSystemName, PWideChar(Computer));

nts := LsaOpenPolicy(@lusSystemName, ObjectAttributes, POLICY_LOOKUP_NAMES,
Pointer(Result));

if nts <> STATUS_SUCCESS then
begin
dwError := LsaNtStatusToWinError(nts);
raise EOSError.Create(SysErrorMessage(dwError));
end;
end;

function GetGroupMembership(const AdsPath: WideString; var Groups: TStringList): Boolean;
const
Username: PChar = 'Administrator';
Password: PChar = 'password';
var
hr: HRESULT;
nts: NTSTATUS;
PolicyHandle: PLSA_HANDLE;
DirObject: IDirectoryObject;
Domains: PLSA_REFERENCED_DOMAIN_LIST;
Names: PLsaTranslatedNameArray;
SidArray: TSidArray;
Attributes: array of PChar;
AdValue: PAdsValueArray;
AdAttrInfo: PADS_ATTR_INFO;
dwNumAttributes: DWORD;
i: Integer;
s: WideString;
begin
Result := False;

Assert(Assigned(Groups));

// Get Lsa Policy Handle
PolicyHandle := GetPolicyHandle;

try
// Open AD object, note that I am using username, password because I am
// connecting from a machine that's not a domain member.
// I am also passing the ADS_SERVER_BIND flag because I am directly
// connecting to a specific Domain Controller
hr := ADsOpenObject(PWideChar(AdsPath), Username, Password,
ADS_SERVER_BIND or ADS_SECURE_AUTHENTICATION, IID_IDirectoryObject,
Pointer(DirObject));
if Failed(hr) then
Exit;

// Attribute array
SetLength(Attributes, 1);
s := 'tokenGroups';
Attributes[0] := @s[1];

hr := DirObject.GetObjectAttributes(@Attributes[0], Length(Attributes), AdAttrInfo, dwNumAttributes);
if Failed(hr) then
Exit;

// Setup an Array for the PSID's
SetLength(SidArray, AdAttrInfo^.dwNumValues);
AdValue := PAdsValueArray(AdAttrInfo^.pADsValues);

for i := 0 to AdAttrInfo^.dwNumValues-1 do
begin
// Copy Pointer to Array
Assert(AdValue^[i].OctetString.dwLength > 0);
SidArray[i] := PSid(AdValue^[i].OctetString.lpValue);
end;

nts := LsaLookupSids(PolicyHandle, Length(SidArray), @SidArray[0], Domains, PLSA_TRANSLATED_NAME(Names));
if nts >= STATUS_SUCCESS then
begin

for i := 0 to AdAttrInfo^.dwNumValues - 1 do
begin
SetLength(s, Names[i].Name.Length div SizeOf(WideChar));
CopyMemory(@s[1], Names[i].Name.Buffer, Names[i].Name.Length);
Groups.Add(s);
end;

// even if nts returns STATUS_NONE_MAPPED or STATUS_SOME_NOT_MAPPED we
// must Free the Mem!
LsaFreeMemory(Names);
LsaFreeMemory(Domains);

Result := True;
end;

FreeAdsMem(AdAttrInfo);

finally
// Close the Lsa Policy Handle
LsaClose(PolicyHandle);
end;
end;

end.

最佳答案

tokenGroups属性包含用户直接或间接成员的所有组的 SID 数组。 LsaLookupSids可用于在一次调用中将一组 SID 转换为名称。

示例代码:

uses  // Jedi ApiLib
JwaActiveDs, JwaAdsTlb, JwaNative, JwaNtSecApi, JwaNtStatus, JwaWinType;

type
// Some Helper Types
TSidArray = array of PSID;
PSidArray = ^TSidArray;

TAdsValueArray = array[0..ANYSIZE_ARRAY-1] of ADSVALUE;
PAdsValueArray = ^TAdsValueArray;

TLsaTranslatedNameArray = array[0..ANYSIZE_ARRAY-1] of LSA_TRANSLATED_NAME;
PLsaTranslatedNameArray = ^TLsaTranslatedNameArray;

function GetPolicyHandle(const Computer: String=''): PLSA_HANDLE;
var
ObjectAttributes: LSA_OBJECT_ATTRIBUTES;
lusSystemName: LSA_UNICODE_STRING;
nts: NTSTATUS;
dwError: DWORD;
begin
ZeroMemory(@ObjectAttributes, SizeOf(ObjectAttributes));

RtlInitUnicodeString(@lusSystemName, PChar(Computer));

nts := LsaOpenPolicy(@lusSystemName, ObjectAttributes, POLICY_LOOKUP_NAMES,
Pointer(Result));

if nts <> STATUS_SUCCESS then
begin
dwError := LsaNtStatusToWinError(nts);
raise EOSError.Create(SysErrorMessage(dwError));
end;
end;

function GetGroupMembership(const AdsPath: String;
var Groups: TStringList): Boolean;
const
Username: PChar = 'Administrator';
Password: PChar = 'password';
var
hr: HRESULT;
nts: NTSTATUS;
PolicyHandle: PLSA_HANDLE;
DirObject: IDirectoryObject;
Domains: PLSA_REFERENCED_DOMAIN_LIST;
Names: PLsaTranslatedNameArray;
SidArray: TSidArray;
Attributes: array of PChar;
AdValue: PAdsValueArray;
AdAttrInfo: PADS_ATTR_INFO;
dwNumAttributes: DWORD;
i: Integer;
s: String;
begin
Result := False;

Assert(Assigned(Groups));

// Get Lsa Policy Handle
PolicyHandle := GetPolicyHandle;

try
// Open AD object, note that I am using username, password because I am
// connecting from a machine that's not a domain member.
// I am also passing the ADS_SERVER_BIND flag because I am directly
// connecting to a specific Domain Controller
hr := ADsOpenObject(PChar(AdsPath), Username, Password,
ADS_SERVER_BIND or ADS_SECURE_AUTHENTICATION, IID_IDirectoryObject,
Pointer(DirObject));
if Failed(hr) then
Exit;

// Attribute array
SetLength(Attributes, 1);
Attributes[0] := 'tokenGroups';

hr := DirObject.GetObjectAttributes(@Attributes[0], Length(Attributes),
PADS_ATTR_INFO(AdAttrInfo), dwNumAttributes);
if Failed(hr) then
Exit;

// Setup an Array for the PSID's
SetLength(SidArray, AdAttrInfo^.dwNumValues);
AdValue := PAdsValueArray(AdAttrInfo^.pADsValues);

for i := 0 to AdAttrInfo^.dwNumValues-1 do
begin
// Copy Pointer to Array
Assert(AdValue^[i].OctetString.dwLength > 0);
SidArray[i] := PSid(AdValue^[i].OctetString.lpValue);
end;

nts := LsaLookupSids(PolicyHandle, Length(SidArray), @SidArray[0], Domains,
PLSA_TRANSLATED_NAME(Names));
if nts >= STATUS_SUCCESS then
begin

for i := 0 to AdAttrInfo^.dwNumValues - 1 do
begin
SetLength(s, Names[i].Name.Length div SizeOf(Char));
CopyMemory(@s[1], Names[i].Name.Buffer, Names[i].Name.Length);
Groups.Add(s);
end;

// even if nts returns STATUS_NONE_MAPPED or STATUS_SOME_NOT_MAPPED we
// must Free the Mem!
LsaFreeMemory(Names);
LsaFreeMemory(Domains);

Result := True;
end;

FreeAdsMem(AdAttrInfo);

finally
// Close the Lsa Policy Handle
LsaClose(PolicyHandle);
end;
end;

使用示例:

procedure TForm4.Button1Click(Sender: TObject);
var
Groups: TStringList;
bRes: Boolean;
i: Integer;
begin
Groups := TStringList.Create;
Groups.Duplicates := dupIgnore;
Groups.Sorted := True;

try
bRes := GetGroupMembership('LDAP://2003DC/CN=Administrator,CN=Users,DC=contoso,DC=com', Groups);

if bRes then
begin
for i := 0 to Groups.Count - 1 do
begin
Memo1.Lines.Add(Groups[i]);
end;
end;

Memo1.Lines.Add(Format('IsMemberOf Administrators: %s',
[BoolToStr(Groups.IndexOf('Administrators') <> -1, True)]));
finally
Groups.Free;
end;
end;

关于delphi - 如何确定用户帐户是否是 AD 组的(间接)成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13935425/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com