如何获取活动目录用户的 IADs 接口?

Posted

技术标签:

【中文标题】如何获取活动目录用户的 IADs 接口?【英文标题】:How to get the IADs interface of an active directory user? 【发布时间】:2011-12-21 14:56:08 【问题描述】:

如何通过 用户名 获得 Active Directory 用户的IADs 界面?

注意:本机代码


我正在尝试编写可以在 Active Directory 中获取 用户IADs 接口的函数。

到目前为止,我有以下“伪代码”:

public IADs GetUserObject(string samAccountName)

   IADs ads;

   //Get the current domain's distinguished name ("dc=***,dc=com")
   AdsGetObject("LDAP://rootDSE", IADs, ref ads);
   String dn = ads.Get("defaultNamingContext"); //"dc=***,dc=com"

   String path;

   //Attempt #1 to bind to a user by username
   path = "LDAP://sSAMAccountName="+samAccountName+",dc=***,dc=com"
   AdsGetObject(path, IADs, ref ads); //invalid syntax

   return ads;       

我想不通的诀窍是如何通过用户的帐户名绑定到用户。以下变体不起作用:

LDAP://sSAMAccountName=ian,dc=***,dc=com LDAP://dc=***,dc=com;(&(objectCategory=user)(sAMAccountName=ian)) <LDAP://dc=***,dc=com>;(&(objectCategory=user)(sAMAccountName=ian))

编辑

确实有效但没有回答我的问题的版本是:

LDAP://cn=Ian Boyd,ou=Avatar Users,dc=***,dc=com

它没有回答我的问题有两个原因:

我不知道用户的 CN(通用名)(例如 Ian Boyd),只知道他们的 sAMAccountName(例如 ian) 不适用于不在头像用户单位部门的用户;而且我不知道用户的 OU

这来自我之前的笔记:

注意:

我不知道域名的名称(不过没关系,我可以在运行时获取) 我不知道任何活动目录服务器的名称 我不知道用户所在的文件夹

tl;dr:你会如何编写实用函数:

public IADs GetUserObject(string samAccountName)

   //TODO: ask ***

更新 2:

注意

我已经知道如何查询用户信息using .NET's DirectorySearcher 我已经知道如何查询有关用户 using the Active Directory Services OLEDB provider with ADO 的信息(使用 SQL 语法,但不是本机语法) 我现在正在寻找代码来查询有关用户 using Active Directory Services COM objects 的信息(因此是关于为用户获取 IADs 的问题)

更新 3

当然可能需要我应用“过滤器”,但我不知道在哪里。唯一提到 Filter 的 ActiveDs 界面是 IADSContainer,但我不知道从哪里获得。

我随机尝试从根IADs接口获取IADsContainer接口,但是“rootDSE”不支持IADsContainer

IADs ads = AdsGetObject("LDAP://rootDSE");
IADsContainer container = (IADsContainer)ads; //interface not supported exception

我可以

请教如何获取AD根的IADsContainer 所以我可以问如何递归搜索活动目录 所以我可以询问如何使用IADsContainer 进行过滤 so i can figure out how to get the IADs object of a user so i an figure out how to query AD for user properties

但是跟踪所有这些问题很困难。

【问题讨论】:

为什么不尝试使用轻量级目录访问协议 Microsoft API(如 RFC 1823 中所述) @JPBlanc 这将需要 另一个 *** 问题,“如何使用 RFC1823 的轻量级直接访问协议获得IADs 接口?” 【参考方案1】:

如果您知道sAMAccountName 的值并需要获取您需要的用户的IADs,您首先需要在Active Directory 中通过sAMAccountName 找到用户并获取distinguishedName 的属性用户。您已经知道如何通过distinguishedName 获取IADs

因此,例如,您应该关注 MSDN 中的 the code。首先得到"LDAP://rootDSE"defaultNamingContext的AD容器的IDirectorySearch接口。

IADs domain;
ADsGetObject("LDAP://rootDSE", IADs, domain);

然后您使用IDirectorySearch::ExecuteSearch 使用过滤字符串应用搜索:

(&(objectClass=user)(objectCategory=person)(sAMAccountName=theName))

注意:搜索过滤器语法描述为here。

IDirectorySearch directorySearch = domain as IDirectorySearch;
ADS_SEARCH_HANDLE searchHandle;

directorySearch.ExecuteSearch(
      "(&(objectClass=user)(objectCategory=person)(sAMAccountName=ian))",
      attributeNames, numberOfAttributes,
      out searchHandle);

您使用sAMAccountName 的已知值而不是theName

对于pAttributeNames,您可以使用仅由L"distinguishedName" 组成的LPOLESTR 数组(请参阅代码示例中的pszNonVerboseList,并在bIsVerbose 的情况下查看FindUsers 的代码为@987654345 @)。

你应该得到distinguishedName 属性的第一个(如果有的话)找到的项目。拥有distinguishedName 属性,您可以使用AdsGetObject 来获取用户的IADs

或者你可以获取用户的objectGUID属性而不是distinguishedName属性并使用binding by GUID语法,但是distinguishedName的用法我个人觉得更清晰易懂。


public IADs GetUserObject(string samAccountName)

   IADs ads;

   //Get the current domain's distinguished name (e.g. "dc=***,dc=com")
   AdsGetObject("LDAP://rootDSE", IADs, ref ads);
   String dn = ads.Get("defaultNamingContext"); //"dc=***,dc=com"

   //Get the the object of the current domain (e.g. LDAP://dc=***,dc=com)
   AdsGetObject("LDAP://"+dn, IADs, ref ads);

   //Now we're going to search for the "distinguishedName" of this user

   //setup the search filter for the user we want
   String filter = "(&(objectClass=user)(objectCategory=person)(sAMAccountName="+samAccountName+"))";

   //specify that we only need to return one attribute, distinguishedNamem, 
   //otherwise it returns all attributes and is a waste of resources
   String[] searchAttributes =  "distinguishedName" ;

   //run the search
   IDirectorySearch ds = ads as IDirectorySearch;
   ADS_SEARCH_HANDLE searchHandle;
   ds.ExecuteSearch(filter, searchAttributes, 1, out searchHandle);
   ds.GetFirstRow(searchHandle);

   //Now get the details of the "distinguishedName" column
   ADS_SEARCH_COLUMN column;
   ds.GetColumn(searchHandle, "distinguishedName", ref column);

   //Get the user's distinguishedName
   String dn = column.pADsValues.DNString;


   //Now that we have the user's distinguishedName, we can do what we really wanted:
   AdsGetObject("LDAP://"+dn, IADs, ads);

   return ads;

这意味着在概念上它可以分为两个步骤:

从用户的samAccountName 获取用户的distinguishedNamedistinguishedName 获取 IADs

并拆分代码:

public IADs GetUserObject(string samAccountName)

   String userDistinguishedName = GetUserDistinguishedName(samAccountName);

   return GetObject("LDAP://"+userDistingishedName);


public String GetUserDistinguishedName(string samAccountName)

   //Get the current domain's distinguished name (e.g. "dc=***,dc=com")
   IADs ads = GetObject("LDAP://rootDSE");
   String dn = ads.Get("defaultNamingContext"); //"dc=***,dc=com"

   //Get the the object of the current domain (e.g. LDAP://dc=***,dc=com)
   ads := GetObject("LDAP://"+dn);

   //Now we're going to search for the "distinguishedName" of this user

   //setup the search filter for the user we want
   String filter = '(&(objectClass=user)(objectCategory=person)(sAMAccountName='+samAccountName+'))';

   //specify that we only need to return one attribute, distinguishedNamem, 
   //otherwise it returns all attributes and is a waste of resources
   String[] searchAttributes =  "distinguishedName" ;

   //run the search
   IDirectorySearch ds = ads as IDirectorySearch;
   ADS_SEARCH_HANDLE searchHandle;
   ds.ExecuteSearch(filter, searchAttributes, 1, out searchHandle);
   ds.GetFirstRow(searchHandle);

   //Now get the details of the "distinguishedName" column
   ADS_SEARCH_COLUMN column;
   ds.GetColumn(searchHandle, "distinguishedName", ref column);

   //Get the user's distinguishedName
   return column.pADsValues.DNString;
          

【讨论】:

【参考方案2】:

这是一个 C++ 示例

IADs *pObject;
HRESULT hr;

// Initialize COM.
CoInitialize(NULL);

hr = ADsGetObject(L"LDAP://CN=JPB,OU=MonOU,DC=societe,DC=fr", 
        IID_IADs,
        (void**) &pObject);

if(SUCCEEDED(hr))

    // Use the object.

    // Release the object.
    pObject->Release()


// Uninitialize COM.
CoUninitialize();

您可以在Binding to Active Directory Domain Services找到更多信息。

【讨论】:

当我用 LDAP://cn=ian,dc=avatopia,dc=com 调用 AdsGetObject 时,我得到了 hresult $80072030(“服务器上没有这样的对象”)。大概是因为ian 不是Common-Name (CN),而是sAMAccountName。 (即我只知道帐户名称)。

以上是关于如何获取活动目录用户的 IADs 接口?的主要内容,如果未能解决你的问题,请参考以下文章

活动目录 - 获取密码即将到期的用户列表

查找当前用户活动目录组 C++

在 ios 应用程序中使用活动目录用户验证 Web 服务?

使用过滤器从活动目录中获取所有用户

powershell 从活动目录中获取Windows用户所属的广告组

powershell Powershell脚本获取OU的所有活动目录用户并生成计数