AD & ADSI入门 (转)

AD & ADSI入门 (转)[@more@]
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、IAd SCOntainer、IAdsDirectorySearch等以外,Windows默认提供了一些接口类如IAdsUser、IAdsGroup,当安装了一些基于AD的服务之后,又会增加一些专有接口,如安装 Exchange 2000之后,会出现Person,同时扩展了User。
  在使用AD的过程中比较重要的一个问题是访问者的权限,如果使用Get object的方式操作,那么应用 程序是以当前登录用户的权限访问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_MACHINESOFTWARE microsoftADsProvidersLDAPExtensionsUser]
[HKEY_LOCAL_MACHINESOFTWAREMicrosoftADsProvidersLDAPExtensionsUser{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,root>),所以在这个Container下我们可以枚举到整个AD中所有的attributeSchema和classSchema。但是我发觉有一个有趣的现象,如果不是以域用户的身份去访问,那么不能得到全集,获得的是Abstract Class和相关的属性,无法得到Structure Class,例如:User。
  其次,针对attributeSchema和classSchema都有一些特性:
  OID(governsID),LDAP所需要的对象的唯一表示符,这是一个字符串,但是不同于GUID根据本机信息生成,而是逐级分配的属性结构,最上层由ISO分配,逐级授权,所以很麻烦。MS提供了一个工具OIDGEN.exe,随 Windows 2000的Re source 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="
  De bug.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 sPass word 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.Creat emailbox("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 ADO db.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
  L oop
  End If
End Function
 
 
PS:很久以前写的东西,望指正。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752019/viewspace-962353/,如需转载,请注明出处,否则将追究法律责任。

user_pic_default.png
请登录后发表评论 登录
全部评论
<%=items[i].createtime%>

<%=items[i].content%>

<%if(items[i].items.items.length) { %>
<%for(var j=0;j
<%=items[i].items.items[j].createtime%> 回复

<%=items[i].items.items[j].username%>   回复   <%=items[i].items.items[j].tousername%><%=items[i].items.items[j].content%>

<%}%> <%if(items[i].items.total > 5) { %>
还有<%=items[i].items.total-5%>条评论 ) data-count=1 data-flag=true>点击查看
<%}%>
<%}%>
<%}%>

转载于:http://blog.itpub.net/10752019/viewspace-962353/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值