内容


Python 和 LDAP

用 Python-LDAP 执行 LDAP 的 CRUD(创建、读取、更新和删除)操作:

Comments

简介

在本文中,作者将讲解如何在 Amazon EC2 虚拟机上安装 OpenLDAP 的实例,设置 Apache/LDAP 身份验证,然后使用 Python 执行 CRUD(即创建、读取、更新和删除)操作。一定要注意,可以在 Fedora、Ubuntu、Red Hat、AIX® 等操作系统上安装 LDAP。但是在本文中,我们决定采用 Amazon EC2 虚拟机。您可以在任何 Linux® 发行版或手边的任何环境中进行实践。最后,我们将在本文中讨论许多代码和复杂的技术。您应该首先下载 示例代码,供阅读本文时参考。

通过程序控制 LDAP 常常是系统管理员的工作,所以 Python 中存在一个用来操作 LDAP 的库就不奇怪了。python-ldap 模块已经存在了一段时间了,在 参考资料 一节中可以找到官方文档的链接。

我们假设您熟悉一般的 LDAP 概念,比如目录模式、Distinguished Names (DN)、Common Names (CN)、过滤器和属性。本文不是 LDAP 教程;我们不喜欢大谈理论,而是主要关注使用和管理 LDAP 数据库的实际示例。

LDAP 的初始设置和填充

如果希望按照本文的说明设置 LDAP,那么需要一个 Fedora Core 8 实例。我们使用一个运行 Fedora Core 8 32-bit 的 Amazon EC2 虚拟机实例。可以在物理服务器上安装 LDAP,也可以使用您选择的技术在虚拟机上安装。注意,对于所有示例,我们使用一个称为 unisonis.com 的域,但是有一份 RFC 建议使用 example.com。

步骤 1:使用 yum 安装 openldap 包:

        [root@domU ]# yum install openldap  openldap-devel 
         openldap-servers openldap-clients 
        
        [root@domU ]# yum list installed | grep openldap 
        openldap.i386           2.3.39-4.fc8   installed        
        openldap-clients.i386   2.3.39-4.fc8   installed        
        openldap-devel.i386     2.3.39-4.fc8   installed        
        openldap-servers.i386   2.3.39-4.fc8   installed

步骤 2:设置管理员密码(我们将把 SSHA 散列值粘贴在 slapd.conf 中)。注意,slapd 代表 Standalone LDAP 服务,所以此服务控制 LDAP 本身:

       [root@domU ]# slappasswd 
        New password:  
        Re-enter new password:

步骤 3:编辑 slapd.conf 配置文件并添加一般 LDAP 安装所需的条目,比如根 DN 和根/管理员密码:

      [root@domU ]# vi /etc/openldap/slapd.conf 

      #Add entries:

      database bdb 
      suffix "dc=unisonis,dc=com" 
      rootdn "cn=Manager,dc=unisonis,dc=com" 
      rootpw {SSHA}pasted_from_slappasswd_output
      directory /var/lib/ldap

步骤 4:启动 LDAP 服务:

        [root@domU ]# service ldap start 
        Starting slapd:                                            [  OK  ]

步骤 5:运行 LDAP 并搜索 'namingContexts' 属性,从而测试 LDAP:

        [root@domU ]# ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts 
        # extended LDIF 
        # 
        # LDAPv3 
        # base <> with scope baseObject 
        # filter: (objectclass=*) 
        # requesting: namingContexts  
        # 
 
        # 
        dn: 
        namingContexts: dc=unisonis,dc=com 
 
        # search result 
        search: 2 
        result: 0 Success 
 
        # numResponses: 2 
        # numEntries: 1

步骤 6:使用 ldapadd 和 LDIF 文件在 LDAP 数据库中添加更多条目。注意,LDIF 代表 LDAP Data Interchange Format,这是用于对 LDAP 数据库进行大量更新的数据格式:

          [root@domU ]# cat unisonis.ldif  
          dn: dc=unisonis,dc=com 
          objectclass: dcObject 
          objectclass: organization 
          o: Example Company 
          dc: unisonis 
          
          dn: cn=Manager,dc=unisonis,dc=com 
          objectclass: organizationalRole 
          cn: Manager 
           
          [root@domU ]# ldapadd -x -D "cn=Manager,dc=unisonis,dc=com" -W -f
 unisonis.ldif  
          Enter LDAP Password:  
          adding new entry "dc=unisonis,dc=com" 
 
          adding new entry "cn=Manager,dc=unisonis,dc=com"

步骤 7:下一步是用示例条目填充 LDAP 目录。我们使用三个小丑的信息(灵感来源于 LDAP 文章 http://www.yolinux.com/TUTORIALS/LinuxTutorialLDAP.html):

        [root@domU ]# cat stooges.ldif; # to conserve space, we show the LDAP data for
 only one of the three stooges
        dn: ou=MemberGroupA,dc=unisonis,dc=com 
        ou: MemberGroupA 
        objectClass: top 
        objectClass: organizationalUnit 
        description: Members of MemberGroupA 
         
        dn: ou=MemberGroupB,dc=unisonis,dc=com 
        ou: MemberGroupB 
        objectClass: top 
        objectClass: organizationalUnit 
        description: Members of MemberGroupB 
         
        dn: cn=Larry Fine,ou=MemberGroupA,dc=unisonis,dc=com 
        ou: MemberGroupA 
        o: stooges 
        cn: Larry Fine 
        objectClass: top 
        objectClass: person 
        objectClass: organizationalPerson 
        objectClass: inetOrgPerson 
        mail: LFine@unisonis.com 
        givenname: Larry 
        sn: Fine 
        uid: larry 
        homePostalAddress: 15 Cherry Ln. Plano TX 78888 
        postalAddress: 215 Fitzhugh Ave. 
        l: Dallas 
        st: TX 
        postalcode: 75226 
        telephoneNumber: (800)555-1212 
        homePhone: 800-555-1313 
        facsimileTelephoneNumber: 800-555-1414 
        userPassword: larrysecret 
        title: Account Executive 
        destinationindicator: /bios/images/lfine.jpg 
        
        [root@domU ]# ldapadd -x -D "cn=Manager,dc=unisonis,dc=com" -W -f stooges.ldif

如果愿意,现在就可以对刚才创建的 LDAP 数据库做各种搜索。下面的示例搜索与 'stooges' 组织相关的所有 LDAP 条目:

      [root@domU conf.d]# ldapsearch -x -b 'dc=unisonis,dc=com' '(o=stooges)'

在下一节中,我们讨论如何通过配置 Apache 实现 LDAP 身份验证,然后讨论 Python 和 LDAP。

设置 Apache LDAP 身份验证

LDAP 最常见的用途之一是为 Web 服务等提供身份验证数据。在本节中,我们使用前面预先填充的 LDAP 数据库控制对一个 Apache 虚拟主机的访问。

首先,需要为使用 LDAP 身份验证的虚拟主机创建一个 Apache 配置文件。对于试图登录的用户,要求提供有效的电子邮件地址和密码。配置文件如下所示:

          [root@domU ]# cat /etc/httpd/conf.d/unisonis.conf  
          <VirtualHost *:80> 
          ServerName www.unisonis.com 
          DocumentRoot "/ebs1/www/unisonis" 
          <Directory "/ebs1/www/unisonis"> 
              AuthType Basic 
              AuthName "unisonis.com: please login with email address" 
              AuthBasicProvider ldap 
              AuthLDAPURL ldap://localhost:389/dc=unisonis,dc=com?mail?sub?(o=stooges) 
              require valid-user 
              Order Allow,Deny 
              Allow from all 
              Options Indexes FollowSymLinks 
              AllowOverride None 
          </Directory> 
         </VirtualHost>

通过 mod_auth_ldap 模块向 Apache 提供 LDAP 身份验证,此模块是在 Fedora Core 8 httpd 包中默认安装的。对于试图登录的用户,要求在 'stooges' 组织中包含有效的电子邮件地址和密码,这样才能访问上面定义的 Apache 虚拟主机。请注意 AuthLDAPURL 指令,它指定通过 LDAP 服务器实现用户身份验证所用的查询。我们搜索 'mail' 属性并应用过滤器 (o=stooges)。AuthLDAPURL 指令的完整语法请参见 http://httpd.apache.org/docs/2.0/mod/mod_auth_ldap.html#authldapurl

关于在 Apache 上配置 LDAP 的更多信息请参见 参考资料

用 Python-LDAP 执行 CRUD 操作

现在,准备使用 Python 与 LDAP 交互。为此,必须安装 python-ldap 模块。在 参考资料 中,可以找到关于安装此模块的详细信息的链接。实际上,只需要执行 “easy install”。首先下载 easy_install 脚本:

       http://peak.telecommunity.com/dist/ez_setup.py

然后输入:

          sudo easy_install python-ldap

注意,根据操作系统的不同,此包依赖的一些软件略有差异。如果在安装此包时遇到问题,请仔细阅读安装说明。

安装 python-ldap 之后,就可以执行 CRUD 操作了。下面编写一个执行这些操作的类。

Python LDAP CRUD 类
       #!/bin/env python
      
      import sys, ldap
      
      LDAP_HOST = 'localhost'
      LDAP_BASE_DN = 'dc=unisonis,dc=com'
      MGR_CRED = 'cn=Manager,dc=unisonis,dc=com'
      MGR_PASSWD = 'mypasswd'
      STOOGE_FILTER = 'o=stooges'
      
      class StoogeLDAPMgmt:
      
          def __init__(self, ldap_host=None, ldap_base_dn=None, mgr_cred=None,
 mgr_passwd=None):
              if not ldap_host:
                  ldap_host = LDAP_HOST
              if not ldap_base_dn:
                  ldap_base_dn = LDAP_BASE_DN
              if not mgr_cred:
                  mgr_cred = MGR_CRED
              if not mgr_passwd:
                  mgr_passwd = MGR_PASSWD
              self.ldapconn = ldap.open(ldap_host)
              self.ldapconn.simple_bind(mgr_cred, mgr_passwd)
              self.ldap_base_dn = ldap_base_dn
      
          def list_stooges(self, stooge_filter=None, attrib=None):
              if not stooge_filter:
                  stooge_filter = STOOGE_FILTER
              s = self.ldapconn.search_s(self.ldap_base_dn, ldap.SCOPE_SUBTREE,
 stooge_filter, attrib)
              print "Here is the complete list of stooges:"
              stooge_list = []
              for stooge in s:
                  attrib_dict = stooge[1]
                  for a in attrib:
                      out = "%s: %s" % (a, attrib_dict[a])
                      print out
                      stooge_list.append(out)
              return stooge_list
      
          def add_stooge(self, stooge_name, stooge_ou, stooge_info):
              stooge_dn = 'cn=%s,ou=%s,%s' % (stooge_name, stooge_ou, self.ldap_base_dn)
              stooge_attrib = [(k, v) for (k, v) in stooge_info.items()]
              print "Adding stooge %s with ou=%s" % (stooge_name, stooge_ou)
              self.ldapconn.add_s(stooge_dn, stooge_attrib)    
      
          def modify_stooge(self, stooge_name, stooge_ou, stooge_attrib):
              stooge_dn = 'cn=%s,ou=%s,%s' % (stooge_name, stooge_ou, self.ldap_base_dn)
              print "Modifying stooge %s with ou=%s" % (stooge_name, stooge_ou)
              self.ldapconn.modify_s(stooge_dn, stooge_attrib)    
      
          def delete_stooge(self, stooge_name, stooge_ou):
              stooge_dn = 'cn=%s,ou=%s,%s' % (stooge_name, stooge_ou, self.ldap_base_dn)
              print "Deleting stooge %s with ou=%s" % (stooge_name, stooge_ou)
              self.ldapconn.delete_s(stooge_dn)

此类中的方法名就能够说明方法的作用,所以我们只讨论在实现这个类时的一些步骤。如果您已经按照前面的步骤填充了 LDAP 数据库,现在还应该下载代码示例。

首先,创建此类的实例:

      l = StoogeLDAPMgmt()

然后就可以执行 CRUD 了。

接下来,用 Python 代码添加一些功能。应该复制并粘贴下载的源代码,因为手工输入容易出错。下面是 CRUD 中的 “C”(创建):

LDAP 创建
          # add new stooge: Harry Potter
          stooge_name = 'Harry Potter'
          stooge_ou = 'MemberGroupB'
          stooge_info = {'cn': ['Harry Potter'], 'objectClass': ['top', 'person',
 'organizationalPerson', 'inetOrgPerson'],
                'uid': ['harry'], 'title': ['QA Engineer'], 'facsimileTelephoneNumber':
 ['800-555-3318'], 'userPassword': ['harrysecret'],
                'postalCode': ['75206'], 'mail': ['HPotter@unisonis.com'],
 'postalAddress':  ['2908 Greenville Ave.'],
                'homePostalAddress': ['14 Cherry Ln. Plano TX 78888'], 'pager':
 ['800-555-1319'], 'homePhone': ['800-555-7777'],
                'telephoneNumber': ['(800)555-1214'], 'givenName': ['Harry'], 'mobile':
 ['800-555-1318'], 'l': ['Dallas'],
                'o': ['stooges'], 'st': ['TX'], 'sn': ['Potter'], 'ou': ['MemberGroupB'],
 'destinationIndicator': ['/bios/images/hpotter.jpg'], }
          try:
              l.add_stooge(stooge_name, stooge_ou, stooge_info)       
          except ldap.LDAPError, error:
              print 'problem with ldap',error

现在对此条目执行 “R”(读取):

LDAP 读取
       # see if it was added
       l.list_stooges(attrib=['cn', 'mail', 'homePhone'])

现在更新此条目,即执行 “U”:

LDAP 更新
        # now modify home phone
        stooge_modified_attrib = [(ldap.MOD_REPLACE, 'homePhone', '800-555-8888')]
        try:
            l.modify_stooge(stooge_name, stooge_ou, stooge_modified_attrib)
        except ldap.LDAPError, error:
            print 'problem with ldap',error

最后,执行 “D”(删除):

LDAP 删除
       # now delete Harry Potter
       try:
           l.delete_stooge(stooge_name, stooge_ou)
       except ldap.LDAPError, error:
           print 'problem with ldap',error

结束语

本文简要介绍了在 Amazon EC2 Fedora 实例上安装 OpenLDAP 的过程,我们用测试数据填充了 LDAP 数据库,简要讨论了从命令行与 LDAP 数据库交互,演示了如何通过配置 Apache 实现 LDAP 身份验证。最后,通过 Python 代码控制 LDAP。Python 示例最出色的优点之一是,与脚本(比如 bash 脚本)代码相比,Python 代码看起来舒服得多。Python 代码因其简洁和可读性强而闻名,这在处理 LDAP 编程等复杂操作时表现尤为突出。

我们实际上没有研究 LDAP 和 Python 的实际示例,但是介绍了如何使用 API 执行 CRUD 操作。使用 python-ldap 库是一种很实用的想法。在每次创建 TRAC 新实例时,您可能希望用 LDAP 组中的所有用户填充不同的 TRAC 项目管理网站。这很容易用我们讨论的技术实现:查询 LDAP 组,在 TRAC 中为每个组成员插入许可。还有许多其他操作 LDAP 的实用方法,希望本文能帮助您如何在自己的项目中进一步利用 LDAP。

我衷心感谢 David Goodger 帮助审阅了本文!


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=AIX and UNIX, Open source
ArticleID=362073
ArticleTitle=Python 和 LDAP
publish-date=01052009