【问题标题】:How to get the IADs interface of an active directory user?如何获取活动目录用户的 IADs 接口?
【发布时间】: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=stackoverflow,dc=com")
   AdsGetObject("LDAP://rootDSE", IADs, ref ads);
   String dn = ads.Get("defaultNamingContext"); //"dc=stackoverflow,dc=com"

   String path;

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

   return ads;       
}

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

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

编辑

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

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

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

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

这来自我之前的笔记:

注意:

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

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

public IADs GetUserObject(string samAccountName)
{
   //TODO: ask stackoverflow
}

更新 2:

注意

更新 3

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

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

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

我可以

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

【问题讨论】:

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

标签: winapi active-directory


【解决方案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=stackoverflow,dc=com")
   AdsGetObject("LDAP://rootDSE", IADs, ref ads);
   String dn = ads.Get("defaultNamingContext"); //"dc=stackoverflow,dc=com"

   //Get the the object of the current domain (e.g. LDAP://dc=stackoverflow,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 获取用户的distinguishedName
  • distinguishedName 获取 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=stackoverflow,dc=com")
   IADs ads = GetObject("LDAP://rootDSE");
   String dn = ads.Get("defaultNamingContext"); //"dc=stackoverflow,dc=com"

   //Get the the object of the current domain (e.g. LDAP://dc=stackoverflow,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。 (即我只知道帐户名称)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-12
    • 2011-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多