众所周知,SVN的repository可以使用自带的 svnserve或者apache httpd两种途径来访问。使用apache httpd管理对SVN的访问的好处是:可以利用httpd已有的模块控制对SVN的认证(authentication)和授权(authorization),其中就包括了本人梦寐以求的用LDAP目录服务的帐户来登录SVN。如此一来,所有和用户帐户和组相关的信息都可以集中保存在LDAP中啦!和管理到处存在的类似passwd和groups的文件相比,这样做岂不是激动人心?
如何配置和往LDAP里添加用户帐户以及安装SVN这些内容考拉就不包括在这篇文章里了。考拉一直使用的是CentOS系统,这点一方面是因为它和RHEL的极高兼容性,另外也是受了鸟哥的影响拉:P
在LDAP配置完成并正常运行之后,我们就要编辑httpd的配置文件了/etc/httpd/conf/httpd.conf。首先我们要保证需要的module在httpd启动的时候都能够成功加载,找到文件里LoadModule集中的那些行,然后确保mod_ldap, mod_authnz_ldap和mod_dav_svn都存在:
LoadModule ldap_module modules/mod_ldap.so
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
LoadModule dav_svn_module modules/mod_dav_svn.so
我们可以认为:
- mod_ldap是httpd和LDAP进行交互所以需要的库。
- mod_authnz_ldap是控制LDAP认证和授权的模块,它依赖mod_ldap。它之所以叫authnz是因为这个模块同时实现了authentication和authorization。
- mod_dav_svn则是httpd用来操作svn repository的模块。
然后我们在httpd.conf中添加如下内容,以实现对svn访问的认证和授权:
<Location /repos>
DAV svn
SVNParentPath /var/svn
SVNListParentPath on
SVNReposName "Xin Liu's Home SVN"
# authentication
AuthType Basic
AuthName "xliu.home.svn"
AuthBasicProvider ldap
#AuthLDAPBindDN "CN=root,DC=xliu-home,DC=org"
#AuthLDAPBindPassword MyLdapPasswdInPlainText
AuthLDAPURL http://www.cnblogs.com/livepencil/admin/ldap://localhost:389/DC=xliu-home,DC=org?uid?sub?(objectClass=*)"
# authorization
AuthLDAPGroupAttributeIsDN on
Require ldap-group cn=SVNUsers,ou=Group,dc=xliu-home,dc=org
AuthLDAPGroupAttribute memberUid
</Location>
让考拉先从authentication(认证)来说起。
在认证的过程中,httpd首先在LDAP目录中搜索客户端提供的用户名(通过AuthLDAPURL配置如何搜索),假如未找到,则认证失败;如果搜索到,则尝试使用客户端提供的用户名和密码来bind LDAP,如果bind成功则认证通过。
在我们的httpd.conf文件中,AuthLDAPBindDN和AuthLDAPBindPassword也是用来bind到LDAP服务的。考拉一开始对此迷惑了好久,不是说用httpd客户端提供的用户名和密码来bind LDAP的么,怎么这里又有个bind?httpd的官方文档对AuthLDAPBindDN是如此描述的:
An optional DN used to bind to the server when searching for entries. If not provided, mod_authnz_ldap
will use an anonymous bind.
原来,刚才说到认证的第一步是对LDAP目录进行搜索。其实AuthLDAPBindDN和AuthLDAPBindPassword所对应的就是搜索这个操作的bind。如果没有配置这两兄弟的话,httpd会使用匿名bind来搜索目录。为了不让LDAP的密码以明文的形式出现在配置文件中,考拉强烈建议在httpd.conf中不要使用这两个配置项。考拉的LDAP服务可是允许匿名绑定的哦~(当然匿名bind只有读取的权限,不过对于search操作而言,足够了呀)。
在authentication中获取了用户的DN之后,接下来httpd要做的就是authorization(授权)的步骤了。
在这里不得不先点一下LDAP目录中的一个细节。在posixAccount中,每个用户帐户有一个gidNumber的属性,它表明了该用户的primary group ID number。所以每个用户只能有一个gidNumber:
# yyd, People, xliu-home.org
dn: uid=yyd,ou=People,dc=xliu-home,dc=org
uid: yyd
cn: YeYouDan
objectClass: account
objectClass: posixAccount
objectClass: top
loginShell: /bin/bash
homeDirectory: /home/yyd
gidNumber: 901
uidNumber: 902
在这里901的gid对应了PowerUsers组:
# PowerUsers, Group, xliu-home.org
dn: cn=PowerUsers,ou=Group,dc=xliu-home,dc=org
objectClass: posixGroup
objectClass: top
cn: PowerUsers
gidNumber: 901
memberUid: 900
这样看起来很直观,但是等等,如果yyd这个用户不仅仅隶属于PowerUsers组,考拉还想让她属于SVNUsers组,那该怎么办?办法照样很简单很直观,在SVNUsers这个组上,添加一个memberUid属性就可以了,注意这个属性可以有多个值哦:
# SVNUsers, Group, xliu-home.org
dn: cn=SVNUsers,ou=Group,dc=xliu-home,dc=org
cn: SVNUsers
gidNumber: 903
objectClass: posixGroup
objectClass: top
memberUid: uid=xliu,ou=People,dc=xliu-home,dc=org
memberUid: uid=yyd,ou=People,dc=xliu-home,dc=org
通常memberUid中保存的都是用户的DN,httpd默认也是这么设置的。当然你也可以把它设置为uid的值。这样一来,SVNUsers就成为了yyd用户的secondary group。
好了,讲了这么多LDAP的内容,让我们再回过头来看看httpd.conf:
- Require ldap-group cn=SVNUsers,ou=Group,dc=xliu-home,dc=org:这条配置告诉httpd,客户端提供的用户,必须隶属于SVNUsers这个组,注意这里一定要使用DN。
- AuthLDAPGroupAttribute memberUid:它告诉httpd去读取LDAP中SVNUsers这个组记录的memberUid属性来和客户端提供的用户DN来比较。
- AuthLDAPGroupAttributeIsDN on:它告诉httpd,memberUid这个属性里保存的是隶属于该组的用户的DN,httpd就会根据客户端提供的用户名和密码来寻找匹配的用户记录DN,再用这条DN来匹配SVNUsers组的memberUid属性的值。考拉在这个配置项上吃了点苦头,因为它默认值是on,所以简单注解掉该条配置项是没有用的,必须显式地把它设置为off。如果我们设置成off,那么就可以将LDAP中SVNUsers的memberUid设置成yyd了,不过考拉认为还是用memberUid来存储DN比较和谐。
好了,现在保存httpd.conf并且启动apache服务器,在浏览器里输入网址http://%3cmyserver%3e/repos,看看svn是不是能像你希望的那样来访问了?