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

前端之家收集整理的这篇文章主要介绍了delphi – 如何确定用户帐户是否是AD组的(间接)成员?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
如何确定用户帐户是否是AD组的成员,尤其是当用户不是该组的直接成员时

一个例子:

> user1是group1的成员
> group1是group2的成员
>(虚构)函数调用的结果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(某些字符串/ 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;

猜你在找的Delphi相关文章