delphi – 如何确定用户帐户是否是AD组的(间接)成员?
发布时间:2020-12-15 04:19:33 所属栏目:大数据 来源:网络整理
导读:如何确定用户帐户是否是AD组的成员,尤其是当用户不是该组的直接成员时 一个例子: user1是group1的成员 group1是group2的成员 (虚构)函数调用的结果IsUserMemberOf(‘user1′,’group2’)应为TRUE 对于.NET,有一个解决方案: static bool IsUserMemberOf(str
|
如何确定用户帐户是否是AD组的成员,尤其是当用户不是该组的直接成员时
一个例子: > user1是group1的成员 对于.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(某些字符串/ 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,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,PChar(Computer));
nts := LsaOpenPolicy(@lusSystemName,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,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),1);
Attributes[0] := 'tokenGroups';
hr := DirObject.GetObjectAttributes(@Attributes[0],PADS_ATTR_INFO(AdAttrInfo),Names[i].Name.Length div SizeOf(Char));
CopyMemory(@s[1],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;
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
