AD 和 ADSI 入门知识


转自http://www.why100000.com/_articles/show_a_article.asp?autoid=76&tab=tabWindows

    AD简介

    Active Directory(以下简称AD)可以认为是一个大的层次结构数据库,集中存储的内容必须遵循AD当前所定义的Schema。我觉得AD中最重要的内容就是Schema,然后是ADSI。

    Schema定义了数据存储的格式。包括类(classSchema),分为抽象类(Abstract)、附属类(Auxiliary)
    和结构类(Structure)三种;属性(attributeSchema),分为单值和多值属性;以及类和属性之间的关系,分为可选属性和必要属性。AD中的Schema相当于全局的Catalog,在整个AD的forest中是全局唯一的,任何的修改都会被同步。所以有关Schema的修改需要有Schema Administrators的权限。而且Schema的内容只能增加,不能删除,过程是不可逆的,最多只能禁止一些属性或者类,而且还有诸多限制,详见文档。

    在AD中存储的数据被当作一个一个的对象,每一个对象是一个classSchema的实例。都有一个唯一的路径访问。AD中对象的路径由所支持的Provider决定,Windows 2000默认的Provider有四个,安装IIS的话会增加一个IIS的Provider,对IIS进行管理。通常使用比较多的是LDAP,可以通过这个Provider针对域用户以及其他扩展信息进行访问和管理。WinNT是针对NT4的帐号管理,估计是向下兼容。另外两个是对Netware的DN的访问,对我们而言不太会用到,不赘述了。

    ADSI(Active Directory Service Interface)是用来对AD中存储数据的访问接口,我认为他是一个架空的框架,与具体的数据访问无关,只是给上层应用提供一个统一的接口。实际工作的就是Provider,应当是Provider访问数据,然后包装成ADSI要求的形式,这些工作对用用户来说完全透明。
    另一个比较爽的地方是ADSI提供了比较好的扩展的方式,你能够非常容易的增加新的类,或者给已有的类增添新的方法。
    需要解释一下,虽然ADSI和AD经常一起出现,但是AD和ADSI是两码事,ADSI不仅仅能访问AD,还可以访问IIS以及Netware所存储的数据。你只要按照要求提供相应的Provider,ADSI可以干任何事情。

    AD编程
    AD的编程到目前来看涵盖的内容非常多,从最粗糙的使用ADSI对AD中已有的数据访问,到比较高级的扩展AD。我认为扩展AD才是这部分编程中比较重要的内容,因为针对任何具体的应用多绘有自己特定的信息,而应用AD主要是为了利用MS提供的安全性以及分布式存储,如果将这两方面结合起来,就需要为了自身的应用对AD进行扩展。
    如果需要为已有的类(接口类)添加方法,那么需要编写AdsExtension类;如果需要在AD中存储扩展信息,就需要修改Schema,增加新的类(classSchema)或者属性(attributeSchema);更进一步的话,完全可以自己实现一个Provider,实现自己的查询和数据存储的方式,这一部分内容已经不仅仅局限于AD了。
    通过ADSI访问AD
        通过ADSI访问AD比较简单,实际上是应用WinNT和LDAP这两个Provider。除了通用接口IAds、IAdsContainer、IAdsDirectorySearch等以外,Windows默认提供了一些接口类如IAdsUser、IAdsGroup,当安装了一些基于AD的服务之后,又会增加一些专有接口,如安装Exchange 2000之后,会出现Person,同时扩展了User。
        在使用AD的过程中比较重要的一个问题是访问者的权限,如果使用GetObject的方式操作,那么应用程序是以当前登录用户的权限访问AD,很多的写操作是被拒绝的。使用IAdsOpenDSObject-〉OpenDSObject可以指定操作对象的用户,当然这就需要实现得到指定用户的口令。
        第二个需要注意的地方就是AD的Path,有两个最常用的前缀(姑且这么叫吧):CN(Common Name)和DC(Domain Controller)。另外对于LDAP从左到右范围增大,而WinNT从左到右范围是减小,比如访问我的帐号,路径分别为LDAP://CN=mittermeyer,CN=Users,DC=cn,DC=corp,DC=company,DC=com,WinNT://cn.corp.company.com/Users/mittermeyer。另外据说AD是区别大小写的,我看下来他有一种数据类型是区别大小写的字符串,但是路径这里好像无所谓,CN=和cn=都行。
        第三个需要注意的地方就是查询语法。查询的话,一共提供了两种方式,一个是IAdsSearchDirectory接口,IAdsDirectorySearch完成查询过程和处理查询结果的全部工作,我个人认为这种方式不太适合VB的程序;另一种方式是使用ADO。AD针对ADO有一个Provider(ADsDSOObject),使用这种方式返回一个ADO.Recordset,处理结果和关系型数据库的查询完全一致,这种方式VB比较容易上手。ADO的方式查询可以使用SQL的语法,也可以使用LDAP的语法;而IAdsDirectorySearch只能使用到的是LDAP的语法。

        这一部分比较有趣的是扩展接口,就是写一个接口作为已经存在的接口类的扩展。扩展接口本身只是继承IDispatch就可以了,但是如果需要支持后期绑定,那么还需要实现IAdsExtension所要求的一系列方法,看上去是模板,就是一个套路,所以这部分工作还是比较简单的。
        关键是把自己编写的接口和已经存在的接口类关联,嘿嘿!也很简单,只要在注册表里加一项就可以了。(MS想到的方法总是比较容易理解,不过在整体框架那里还是花了很多心思的,所以架子有了扩展就容易了。)例如:以及下就是Exchange加的对User地扩展,它表明Exchange针对User有一个扩展的CoClass--Mailbox,其中包含了两个接口IMailRecipient和IMailboxStore。
    [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/ADs/Providers/LDAP/Extensions/User]
    [HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/ADs/Providers/LDAP/Extensions/User/{25150F21-5734-11D2-A593-00C04F990D8A}]
    “Interfaces“=hex(7):7b,00,32,00,35,00,31,00,35,00,30,00,46,00,34,00,31,00,2d,/
      00,35,00,37,00,33,00,34,00,2d,00,31,00,31,00,44,00,32,00,2d,00,41,00,35,00,/
      39,00,33,00,2d,00,30,00,30,00,43,00,30,00,34,00,46,00,39,00,39,00,30,00,44,/
      00,38,00,41,00,7d,00,00,00,7b,00,32,00,35,00,31,00,35,00,30,00,46,00,34,00,/
      30,00,2d,00,35,00,37,00,33,00,34,00,2d,00,31,00,31,00,44,00,32,00,2d,00,41,/
      00,35,00,39,00,33,00,2d,00,30,00,30,00,43,00,30,00,34,00,46,00,39,00,39,00,/
      30,00,44,00,38,00,41,00,7d,00,00,00,00,00

    扩展Schema
        首先,我们知道attributeSchema和classSchema都存储在同一个层次下,我们可以通过这样的路径访问:LDAP://computername/Schema 之下(另外一种访问路径是CN=Schema,CN=Configuration,〈DC=forestroot〉),所以在这个Container下我们可以枚举到整个AD中所有的attributeSchema和classSchema。但是我发觉有一个有趣的现象,如果不是以域用户的身份去访问,那么不能得到全集,获得的是Abstract Class和相关的属性,无法得到Structure Class,例如:User。
        其次,针对attributeSchema和classSchema都有一些特性:
        OID(governsID),LDAP所需要的对象的唯一表示符,这是一个字符串,但是不同于GUID根据本机信息生成,而是逐级分配的属性结构,最上层由ISO分配,逐级授权,所以很麻烦。MS提供了一个工具OIDGEN.exe,随Windows 2000的Resource Kit发布,我不知道即使是用这样的工具生成的新ID能否运行在实际的扩展系统中,还是必须通过MS的认证。
        schemaIDGUID,用于访问控制目录中控制访问这个类的对象。通过这个ID而不是名称来访问类的对象实例。GUID还是非常好处理的,可以通过Windows自身的API获得。
        其他的就是各类名称(cn,LDAPDisplayName,adminDisplayName),在不同的工具或者场合显示区别类或者属性,这些名字只要保证全局唯一即可。此外classSchema和attributeSchema各有一些特定的必备属性。

        扩展Schema包括以下几部分的工作:新增/禁止attributeSchema,新增/禁止classSchema,修改Property与classSchema的关系。
        新增attributeSchema和classSchema,通过IAdsContainer.Create,在Schema存储的路径下新建子节点,然后给必要的属性赋值,最后提交即可。
        禁止attributeSchema和classSchema,可以通过“废弃”的方式禁止一个现存的类或者属性。即获得这个classSchema或者attributeSchema,将他的isDefunct属性置为True即可;反之只要将isDefunct属性置为False即可恢复。当然这个操作也存在一系列的限制,例如:禁止一个属性,那么将阻止创建所有所有必须包含该属性的类的实例。
        修改Property与classSchema的关系,因为决定每一个classSchema中包含哪些attributeSchema,其实是指定classSchema的“mustContain”和“mayContain”,这两个多值属性(字符串数组)分别表示表示所包含的必要属性和可选属性。反过来,可以通过IAdsClass.MandantoryProperties和IAdsClass.OptionalProperties读取。

    实现Provider
        暂时没有研究。

    实例
    枚举对象。下面这个例子枚举了所有通过RC的接口添加到AD中的用户组和帐号。此例中IAdsContainer.Filter为一个需要筛选的类名数组,如果为空,则表示返回所有类型的对象。
    Public Function EnumGroups() As VBA.Collection
        Dim adDomain As IADsContainer
        Dim adGroup As IADsGroup
        Dim nResult As VBA.Collection

        If m_sAdmin 〈〉 vbNullString Then
            Set adDomain = m_adRoot.OpenDSObject(“LDAP://“ & m_sExchServer & “/CN=Users,“ & m_sDomain, _
                                        m_sAdmin, m_sAdminPwd, ADS_SECURE_AUTHENTICATION)
        Else
            Set adDomain = GetObject(“LDAP://CN=Users,“ & m_sDomain)
        End If
        If adDomain Is Nothing Then Exit Function

        Set nResult = New VBA.Collection
        adDomain.Filter = Array(“group“,“user“”)

        On Error Resume Next
        Dim sName As String
        Dim sType As String
        For Each adGroup In adDomain
            sName = Right(adGroup.Name, Len(adGroup.Name) - 3)  ’ filter “CN=“
            Debug.Print sName
            sType = adGroup.Get(cPropCustomType)
            If Err.Number = 0 And sType = cTypeRC Then
                nResult.Add sName, sName
            End If
            Err.Clear
        Next
        Set EnumGroups = nResult
    End Function

    添加一个用户以及用户相关的邮箱,这是一个相对复杂的利用ADSI的示例,其他类似的操作就不赘述了。这里用到的就是ADSI和Exchange针对ADSI中IAdsUser对象的扩展。斜体的那一段代码颇值得回味,在VB中非常简单的一句话,背后有一套复杂的逻辑。
    添加用户组和组邮箱的操作类似,不同的是组邮箱不是一个物理邮箱,而是一个邮箱列表,通过IMailRecipient.MailboxEnabled使之有效即可。
    ’ add new user to Domain and create mailbox for it
    Public Function AddAccountEx(ByVal sAccount As String, ByVal sFullName As String, ByVal sDesc As String, _
                                ByVal sPassword As String) As Long
        Dim adDomain As IADsContainer
        Dim adNewUser As IADsUser
        Dim oMailStore As CDOEXM.IMailboxStore
        Dim oExchServer As CExchageManager

        If m_sAdmin 〈〉 vbNullString Then
            Set adDomain = m_adRoot.OpenDSObject(“LDAP://CN=Users,“ & m_sDomain, _
                                        m_sAdmin, m_sAdminPwd, ADS_SECURE_AUTHENTICATION)
        Else
            Set adDomain = GetObject(“LDAP://CN=Users,“ & m_sDomain)
        End If

        ’ create a account
        Set adNewUser = adDomain.Create(“user“, “cn=“ & sAccount)
        adNewUser.Put “sAMAccountName“, sAccount
        adNewUser.Put “userPrincipalName“, sAccount & “@“ & Domain
        adNewUser.FullName = sFullName
        adNewUser.Description = sDesc
        adNewUser.SetInfo

        adNewUser.SetPassword sPassword
        adNewUser.AccountDisabled = False
        ’ create mailbox for this account
        Set oExchServer = New CExchageManager
        oExchServer.Connect m_sExchServer    ’ Get Exchange Server’s Information
        Set oMailStore = adNewUser
        Call oMailStore.CreateMailbox(“LDAP://“ & m_sExchServer & “/“ & oExchServer.DefaultMailboxStore)
        adNewUser.SetInfo

        ’ enable immediate-logon for the user
        adNewUser.Put “msExchUserAccountControl“, 2
        adNewUser.SetInfo
    End Function

    查找。通过ADO查询比较简单,只是属性的类型,特别是一些多值属性需要额外注意。
    这个例子是查询所有指定域中所有的组,其中description就是一个多值属性。
    Public Function SearchGroup() As ADODB.Recordset
        Dim oResult As ADODB.Recordset
        Dim oCommand As ADODB.Command
        Dim sConnectionStr As String

        If m_sAdmin = vbNullString Then
            sConnectionStr = “Provider=ADsDSOObject“
        Else
            sConnectionStr = “Provider=ADsDSOObject;UID=“ & m_sAdmin & “;PWD=“ & m_sAdminPwd
        End If

        Set oCommand = New ADODB.Command
        With oCommand
            .ActiveConnection = sConnectionStr
            .CommandTimeout = 15
            .CommandText = “SELECT name,description FROM ’LDAP://“ & m_sDomain _
                            & “’ WHERE objectCategory=’group’“
            Debug.Print .CommandText
            .Properties(“searchscope“) = ADS_SCOPE_SUBTREE
            .Properties(“Chase referrals“) = ADS_CHASE_REFERRALS_EXTERNAL
            Set oResult = .Execute
        End With
        If Not oResult Is Nothing Then
            Do Until oResult.EOF
                Debug.Print oResult(“name“), oResult(“description“)(0)
                oResult.MoveNext
            Loop
        End If
    End Function

 

第1章 活动目录库套书的使用 1.1 活动目录库套书的组成 1.2 活动目录库套书的编写思想 第2章 本书的内容 2.1 组策略编程 第3章 微软参考资源 3.1 微软开发者网络 3.1.1 MSDN和MSDN在线的比较 3.1.2 订阅MSDN 3.1.3 MSDN的使用 3.1.4 使用MSDN在线 3.2 Windows程序设计系列参考 第4章 寻找你需要的开发者资源 4.1 开发者支持 4.2 在线资源 4.3 关于学习的产品 4.4 会议 4.5 其他资源 第二部分 指南、例子和编程参考 第5章 需要首先知道的有关ADSI的知识 5.1 ADSI函数 5.1.1 ADsBuildEnumerator函数 5.1.2 ADsBuildVarArrayInt函数 5.1.3 ADsBuildArrayStr函数 5.1.4 ADsEncodebinaryData函数 5.1.5 ADsEnumertateNext函数 5.1.6 ADsFreeEnumertator函数 5.1.7 ADsGetLastError函数 5.1.8 ADsGetObject函数 5.1.9 ADsOpenObject函数 5.1.10 ADsSetLastError函数 5.1.11 AllocADsMem函数 5.1.12 AllocADsStr函数 5.1.13 FreeADsMem函数 5.1.14 FreeADsStr函数 5.1.15 ReallocADsMem函数 5.1.16 ReallocADsStr函数 5.1.17 舍弃的ADSI函数 5.2 ADSI结构 5.2.1 ADS_ATTR_DEF结构 5.2.2 ADS_ATTR_INFO结构 5.2.3 ADS_BACKLINK结构 5.2.4 ADS_CASEIGNORE_LIST结构 5.2.5 ADS_CLASS_DEF结构 5.2.6 ADS_DN_WITH_BINART结构 5.2.7 ADS_DN_WITH_STRING结构 5.2.8 ADS_EMAIL结构 5.2.9 ADS_FAXNUMBER结构 5.2.10 ADS_HOLD结构 5.2.11 ADS_NETADDRESS结构 5.2.12 ADS_NT_SECURITY_DESCRIPTOR 结构 5.2.13 ADS_OBJECT_INFO结构 5.2.14 ADS_OCTET_STRING结构 5.2.15 ADS_OCTET_STRING结构 5.2.16 ADS_PATH结构 5.2.17 ADS_POSTALADDRESS结构 5.2.18 ADS_PROV_SPECIFIC结构 5.2.19 ADS_REPLICAPOINTER结构 5.2.20 ADS_SEARCH_COLUMN结构 5.2.21 ADS_SEARCHPREF_INFO结构 5.2.22 ADS_SORTKEY结构 5.2.23 ADS_TIMESTAMP结构 5.2.24 ADS_TYPEDNAMP结构 5.2.25 ADSVALUE结构 第6章 使用ADSI 6.1 ADSI枚举 6.1.1 ADS_ACEFLAG_ENUM枚举 6.1.2 ADS_ACETYPE_ENUM枚举 6.1.3 ADS_AUTHENTICATION_ENUM枚举 6.1.4 ADS_cHASE_REFERRALS_ENUM 枚举 6.1.5 ADS_DEREFENUM枚举 6.1.6 ADS_DISPLAY_ENUM枚举 6.1.7 ADS_ESCAPE_MODE_ENUM枚举 6.1.8 ADS_FLAGTYPE_ENUM枚举 6.1.9 ADS_FORMAT_ENUM枚举 6.1.10 ADS_GROUP_TYPE_ENUM枚举 6.1.11 ADS_NAME_INITTYPE_ENUM枚举 6.1.12 ADS_NAME_TYPE_ENUM枚举 6.1.13 ADS_OPTION_ENUM枚举 6.1.14 ADS_PREFERENCES_ENUM枚举 6.1.15 ADS_PROPERTY_OPERATION_
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值