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

时间:2011-12-21 14:56:09

标签: winapi active-directory

如何通过用户名获取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

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

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

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

我可以

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

2 个答案:

答案 0 :(得分:2)

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

因此,您应该只关注MSDN中的the code。首先,您获得IDirectorySearch defaultNamingContext的AD容器的"LDAP://rootDSE"界面。

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,您可以使用仅LPOLESTR组成的L"distinguishedName"数组(请参阅代码示例中的pszNonVerboseList并查看FindUsers的代码如果bIsVerboseFALSE)。

您应该获得第一个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;
}          

答案 1 :(得分:0)

以下是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中找到更多信息。