svnserve程序是一个轻量级的服务器,使用基于TCP/IP上的一个自定义的、有状态的协议来与客户端通信。
客户端用以svn:// 或 svn+ssh://开头的URL模式来连接svnserve服务。
本节将解释运行svnserve的不同方式,客户端如何在服务器上认证他们,以及如何为你的资料库配置合适的访问控制。
调用svnserve程序有几种不同的方式。如果不带参数调用,那么你将只看到帮助信息。但是,如果你计划
让inetd运行这个进程,那么你可以转递-i(--inetd)参数:
$ svnserve -i ( success ( 1 2 ( ANONYMOUS ) ( edit-pipeline ) ) )
当用 --inetd 参数调用时,svnserve尝试通过stdin 和
stdout用一种自定的协议于Subversion客户端通信。这是通过inetd来运行的程序的
标准行为。IANA为Subversion协议保留了3690端口,因此,在Unix类系统上你可以在/etc/services中添加如下几行(
如果它们不存在的话):
svn 3690/tcp # Subversion svn 3690/udp # Subversion
并且如果你的系统使用经典的Unix类的inetd守护程序,你可以在/etc/inetd.conf添加这样一行:
svn stream tcp nowait svnowner /usr/local/bin/svnserve svnserve -i
确认“svnowner”是一个有适当的访问你资料库的权限。现在,当一个客户连接连接到你的服务器的3690端口时, inetd将生成一个svnserve来为它服务。
在Windows系统上,有些第三方工具可以使svnserve作为服务运行。查看Subversion的网站可以找到工具列表。
另一种选择是让svnserve作为一个独立的“守护daemon”进程运行。这要使用-d参数:
$ svnserve -d $ # svnserve is now running, listening on port 3690
当在守护模式运行svnserve时,你可以使用--listen-port=和--listen-host=
选项来定制要“绑定”的主机名和实际的端口号。
还有第三种调用svnserve的方法,这是一种“隧道模式”,要用-t选项。
这种模式假设一个远程服务程序比如RSH 或 SSH已经成功地认证了一个用户并且现在是
以这个用户来调用svnserve进程。svnserve程序正常运转(通过
stdin和stdout来通信),并假定通信流被自动重定向到客户端背后的某种隧道。
当 svnserve 是通过被像这样的隧道代理程序调用时,要确认认证的用户有对资料库数据库文件的完全的读写权限
(参见服务器和权限:一点警告)。这本质上和本地用户通过file:///这样的URL访问资料库是一样的。
一旦svnserve开始运行,它将使你的系统上的所有资料库上网。客户端需要在资料库URL中
指定绝对路径。例如,如果一个资料库位于/usr/local/repositories/project1,那么客户端
要通过svn://host.example.com/usr/local/repositories/project1
来访问它。为了增强完全性,你可以传递-r选项给svnserve,它限定了
只公开在指定路径下的资料库
$ svnserve -d -r /usr/local/repositories …
使用-r选项有效的修改了服务程序作为远程文件系统空间的根目录的位置。从而客户端可以使用不包含这部分路径的URL,
使得URL短很多(并更少暴露内情):
$ svn checkout svn://host.example.com/project1 …
当一个客户端连接一个svnserve进程时,发生了下列的事情:
客户端选择一个指定的资料库。
服务器处理资料库的conf/svnserve.conf文件,并开始执行所有在那儿定义的认证和授权政策。
根据情况和授权政策,
允许客户端匿名发出请求,而不会受到任何认证要求,或
在任何时候客户端都可能被要求认证,或
如果在“隧道模式”下操作,客户端会宣布它自己已经被外部认证了。
在写的时候,服务器只知道如何发送一个CRAM-MD5[20]认证要求。本质上,服务器 发送了一点数据给数据库。数据库使用MD5散列算法来创建数据和密码结合后的指纹,然后把指纹作为一个响应发送。服务器用保存的 密码执行相同的计算来验证结果是否相同。真实的密码永远不会通过网络来传输。
当然,对客户端来说也可能通过通道代理程序外部认证,比如 SSH。在这种情况下,服务器只检查运行它的用户,并 把这作为认证后的用户名。
你应该已经猜到,资料库的svnserve.conf是控制认证和授权的中心机制。这个文件和其他的配置文件
(参见???)有相同的格式:段名用方括号标记([ 和 ]),
注释以井号(#)开头,每段包含可以设置(variable =
value)的特定变量。让我们浏览一下这个文件并学习如何使用它。
现在,svnserve.conf文件的[general]段有你需要的所有变量。开始于定义一个包含
用户名和密码的文件,以及一个认证范围。
[general] password-db = userfile realm = example realm
realm是一个你定义的名字。它告诉客户端它们连接到哪种“认证名字空间”;Subversion客户端在
认证提示的时候显示它,并用它作为一个键(连同服务器的主机名和端口)来在磁盘上缓存凭证(参见“客户凭证缓存”一节)。password-db变量指向一个不同的文件,它包含用户名和密码的
列表,并使用同样的我们已经熟悉的格式。例如
[users] harry = foopassword sally = barpassword
password-db的值可以是用户文件的绝对或相对路径。对很多管理员来说,就在资料库的conf/
区域,svnserve.conf旁边保存这个文件会很方便。另一方面,可能你想让两个或更多的资料库共享同样的用户文件;
在这种情况下,这个文件应该位于更公共的地方。共享这个用户文件的资料库应该也被配置为有相同的认证范围,因为用户列表本质上定义
了认证范围。不管这个文件在哪儿,一定要正确地设置文件的读写权限。如果你知道哪个(些)用户会被用来运行svnserve,必须限制它们对用户文件只有读权限。
svnserve.conf文件中设置了另外两个变量:它们决定未认证的(匿名的)用户和认证的用户分别被允许作什么。
anon-access和 auth-access这两个变量可以被赋值为 none,read或者write。赋值为none限制了任何种类的访问;read允许对资料库的只读访问,write允许对资料的完全的读/写访问。例如:
[general] password-db = userfile realm = example realm # anonymous users can only read the repository anon-access = read # authenticated users can both read and write auth-access = write
事实上这个例子设置是变量的缺省值,以免你忘了定义它们。如果你想更保守点,你可以完全阻止匿名访问。
[general] password-db = userfile realm = example realm # anonymous users aren't allowed anon-access = none # authenticated users can both read and write auth-access = write
注意svnserve只理解“一揽子的”访问控制。一个用户或者有全局的读写访问权,全局的读访问权, 或没有访问权。没有对资料库中特定路径的细节的控制。对很多项目和场所,这种水平的访问控制足够了。但是,如果你需要对每个目录 的访问控制,那么你需要使用Apache而不是svnserve来做你的服务器进程。
虽然svnserve本身没有提供任何对单个路径授权的方法,但是可以用pre-commit钩子来执行对单个路径的访问控制。 Subversion分发版包含commit-access-control.pl 和更复杂的svnperms.py脚本以便在 pre-commit脚本中使用。
svnserve内建的认证非常便利,因为它避免了创建真正的系统帐号的需要。另一方面,一些管理员已经建立了一个 很好的SSH认证框架。在这种情况下,所有的项目用户已经有了系统帐号和通过“SSH进入”系统机器的能力。
联合使用SSH和svnserve是很容易的。客户端只要用svn+ssh:// URL模式来连接:
$ whoami harry $ svn list svn+ssh://host.example.com/repos/project harry@host.example.com's password: ***** foo bar baz …
这里发生的过程是:Subversion客户端调用一个本地的ssh进程,连接到host.example.com,以用户
harry来认证,然后在远程机器上生成一个私有的svnserve进程。svnserve
命令以隧道模式(-t)来调用,它的网络协议从隧道代理ssh建立的加密连接中“穿过”。
svnserve知道它以用户harry在运行,如果客户端执行一个提交,这个认证的用户名将被作为
新修订版的作者存到修订版属性。
当在隧道上运行时,授权主要通过操作系统对资料库数据库文件的权限来来控制;这和Harry通过一个file:/// URL
直接访问资料库时完全相同。如果多个系统用户要直接访问资料库,你应该把它们放到一个共同的用户组中,并且你需要注意他们的umask。
(一定要读“支持多种资料库访问方式”一节)但是即使在隧道情况下,svnserve.conf文件仍然可以被用来阻止访问,
只要设置auth-access = read 或 auth-access
= none。
也许你认为SSH隧道到这就说完了,但是还没有。Subversion允许你在你的运行时config文件
(参见???)里创建自定义的隧道行为。例如,假设你想使用RSH而不是SSH。只要在你的config文件的[tunnels]段像下面这样定义:
[tunnels] rsh = rsh
现在,你可以通过和你的新变量名匹配的URL模式来使用这个新的隧道定义:svn+rsh://host/path。当使用新URL模式
时,Subversion 客户端实际上将在后台运行命令rsh host svnserve -t。如果你在URL中包含了用户名(例如,
svn+rsh://username@host/path),客户端也将在它的命令(rsh
username@host svnserve -t)里包含它。但是你可以定义比这更智能的新隧道模式:
[tunnels] joessh = $JOESSH /opt/alternate/ssh -p 29934
这个例子显示了几件事情。首先,它显示如何用Subversion客户端来运行一个非常特殊的带特定选项的隧道(位于/opt/alternate/ssh)命令。在这种情况下,访问svn+joessh:// URL将调用
这个特定的SSH命令并带着-p 29934作为参数——如果你想要隧道程序连接一个非标准的端口时会用得着。
第二,它演示了如何定义自定义的环境变量来代替隧道程序的名字。设置SVN_SSH环境变量是一个替换缺省SSH
隧道代理程序的简便方法。但是,如果你需要有几种不同的替换,分别用于不同的服务器,可能连接不同的端口或传递不同的参数组,那么
你可以使用在这个例子里演示的机制。现在如果我们要设置JOESSH环境变量,那么它的值将完全覆盖隧道变量的值
——会执行$JOESSH而不是/opt/alternate/ssh -p 29934。
最后说明:在使用svn+ssh:// URL访问资料库时,记住是ssh程序在提示你认证,而不是
svn程序。这意味着没有自动密码缓存过程(参见“客户凭证缓存”一节)。如果你想阻止ssh重复的问你密码,你可以使用其它的内存缓存工具,
比如在Unix系统上的ssh-agent,或Windows上的pageant。