### httpd,Apache的HTTP服务器 Apache的HTTP服务器是一个Subversion可以利用的“重型”网络服务器,通过一个自定义模块,**httpd**可以让Subversion版本库通过WebDAV/DeltaV协议在客户端前可见,WebDAV/DeltaV协议是HTTP 1.1的扩展(见`http://www.webdav.org/`来查看详细信息)。这个协议利用了无处不在的HTTP协议是广域网的核心这一点,添加了写能力―更明确一点,版本化的写―能力。结果就是这样一个标准化的健壮的系统,作为Apache 2.0软件的一部分打包,被许多操作系统和第三方产品支持,网络管理员也不需要打开另一个自定义端口。 这样一个Apache-Subversion服务器具备了许多**svnserve**没有的特性,但是也有一点难于配置,灵活通常会带来复杂性。 下面的讨论包括了对Apache配置指示的引用,给了一些使用这些指示的例子,详细地描述不在本章的范围之内,Apache小组维护了完美的文档,公开存放在他们的站点`http://httpd.apache.org`。例如,一个一般的配置参考位于`http://httpd.apache.org/docs-2.0/mod/directives.html`。 同样,当你修改你的Apache设置,很有可能会出现一些错误,如果你还不熟悉Apache的日志子系统,你一定需要认识到这一点。在你的文件`httpd.conf`里会指定Apache生成的访问和错误日志(`CustomLog`和`ErrorLog`指示)的磁盘位置。Subversion的mod_dav_svn使用Apache的错误日志接口,你可以浏览这个文件的内容查看信息来查找难于发现的问题根源。 **为什么是Apache 2?** 如果你系统管理员,很有可能是你已经运行了Apache服务器,并且有一些高级经验。写本文的时候,Apache 1.3是Apache最流行的版本,这个世界因为许多原因而放缓升级到2.X系列:如人们害怕改变,特别是像web服务器这种重要的变化,有些人需要一些在Apache 1.3 API下工作的插件模块,在等待2.X的版本。无论什么原因,许多人会在首次发现Subversion的Apache模块只是为Apache 2 API写的后开始担心。 对此问题的适当反应是:不需要担心,同时运行Apache 1.3和Apache 2非常简单,只需要安装到不同的位置,用Apache 2作为Subversion的专用服务器,并且不使用80端口,客户端可以访问版本库时在URL里指定端口: ~~~ $ svn checkout http://host.example.com:7382/repos/project … ~~~ ### 必备条件 为了让你的版本库使用HTTP网络,你基本上需要两个包里的四个部分。你需要Apache **httpd** 2.0和包括的**mod_dav** DAV模块,Subversion和与之一同分发的**mod_dav_svn**文件系统提供者模块,如果你有了这些组件,网络化你的版本库将非常简单,如: - 配置好httpd 2.0,并且使用mod_dav启动, - 为mod_dav安装mod_dav_svn插件,它会使用Subversion的库访问版本库,并且 - 配置你的`httpd.conf`来输出(或者说暴露)版本库。 你可以通过从源代码编译**httpd**和Subversion来完成前两个项目,也可以通过你的系统上的已经编译好的二进制包来安装。最新的使用Apache HTTP的Subversion的编译方法和Apache的配置方式可以看Subversion源代码树根目录的`INSTALL`文件。 ### 基本的Apache配置 一旦你安装了必须的组件,剩下的工作就是在`httpd.conf`里配置Apache,使用`LoadModule`来加载mod_dav_svn模块,这个指示必须先与其它Subversion相关的其它配置出现,如果你的Apache使用缺省布局安装,你的**mod_dav_svn**模块一定在Apache安装目录(通常是在`/usr/local/apache2`)的`modules`子目录,`LoadModule`指示的语法很简单,影射一个名字到它的共享库的物理位置: ~~~ LoadModule dav_svn_module modules/mod_dav_svn.so ~~~ 注意,如果**mod_dav**是作为共享对象编译(而不是静态链接到**httpd**程序),你需要为它使用使用`LoadModule`语句,一定确定它在**mod_dav_svn**之前: ~~~ LoadModule dav_module modules/mod_dav.so LoadModule dav_svn_module modules/mod_dav_svn.so ~~~ 在你的配置文件后面的位置,你需要告诉Apache你在什么地方保存Subversion版本库(也许是多个),`位置`指示有一个很像XML的符号,开始于一个开始标签,以一个结束标签结束,配合中间许多的其它配置。`Location`指示的目的是告诉Apache在特定的URL以及子URL下需要特殊的处理,如果是为Subversion准备的,你希望可以通过告诉Apache特定URL是指向版本化的资源,从而把支持转交给DAV层,你可以告诉Apache将所有路径部分(URL中服务器名称和端口之后的部分)以`/repos/`开头的URL交由DAV服务提供者处理。一个DAV服务提供者的版本库位于`/absolute/path/to/repository`,可以使用如下的`httpd.conf`语法: ~~~ <Location /repos> DAV svn SVNPath /absolute/path/to/repository </Location> ~~~ 如果你计划支持多个具备相同父目录的Subversion版本库,你有另外的选择,`SVNParentPath`指示,来表示共同的父目录。举个例子,如果你知道你会在`/usr/local/svn`下创建多个Subversion版本库,并且通过类似`http://my.server.com/svn/repos1`,`http://my.server.com/svn/repos2`的URL访问,你可以用后面例子中的`httpd.conf`配置语法: ~~~ <Location /svn> DAV svn # any "/svn/foo" URL will map to a repository /usr/local/svn/foo SVNParentPath /usr/local/svn </Location> ~~~ 使用上面的语法,Apache会代理所有URL路径部分为`/svn/`的请求到Subversion的DAV提供者,Subversion会认为`SVNParentPath`指定的目录下的所有项目是真实的Subversion版本库,这通常是一个便利的语法,不像是用`SVNPath`指示,我们在此不必为创建新的版本库而重启Apache。 请确定当你定义新的`位置`,不会与其它输出的位置重叠,例如你的主要`DocumentRoot`是`/www`,不要把Subversion版本库输出到`<Location /www/repos>`,如果一个请求的URI是`/www/repos/foo.c`,Apache不知道是直接到`repos/foo.c`访问这个文件还是让**mod_dav_svn**代理从Subversion版本库返回`foo.c`。 **服务器名称和拷贝请求** Subversion利用`COPY`请求类型来执行服务器端的文件和目录拷贝,作为一个健全的Apache模块的一部分,拷贝源和拷贝的目标通常坐落在同一个机器上,为了满足这个需求,你或许需要告诉mod_dav服务器主机的名称,通常你可以使用`httpd.conf`的`ServerName`指示来完成此目的。 ~~~ ServerName svn.example.com ~~~ 如果你通过`NameVirtualHost`指示使用Apache的虚拟主机,你或许需要`ServerAlias`指示来指定额外的名称,再说一次,可以查看Apache文档的来得到更多细节。 在本阶段,你一定要考虑访问权限问题,如果你已经作为普通的web服务器运行过Apache,你一定有了一些内容―网页、脚本和其他。这些项目已经配置了许多在Apache下可以工作的访问许可,或者更准确一点,允许Apache与这些文件一起工作。Apache当作为Subversion服务器运行时,同样需要正确的访问许可来读写你的Subversion版本库。(见[服务器和访问许可:一个警告]( "服务器和访问许可:一个警告")。) 你会需要检验权限系统的设置满足Subversion的需求,同时不会把以前的页面和脚本搞乱。这或许意味着修改Subversion的访问许可来配合Apache服务器已经使用的工具,或者可能意味着需要使用`httpd.conf`的`User`和`Group`指示来指定Apache作为运行的用户和Subversion版本库的组。并不是只有一条正确的方式来设置许可,每个管理员都有不同的原因来以特定的方式操作,只需要意识到许可关联的问题经常在为Apache配置Subversion版本库的过程中被疏忽。 ### 认证选项 此时,如果你配置的`httpd.conf`保存如下的内容 ~~~ <Location /svn> DAV svn SVNParentPath /usr/local/svn </Location> ~~~ 这样你的版本库对全世界是可以“匿名”访问的,直到你配置了一些认证授权政策,你通过`Location`指示来使Subversion版本库可以被任何人访问,换句话说, - 任何人可以使用Subversion客户端来从版本库URL取出一个工作拷贝(或者是它的子目录), - 任何人可以在浏览器输入版本库URL交互浏览的方式来查看版本库的最新修订版本,并且 - 任何人可以提交到版本库。 #### 基本HTTP认证 最简单的客户端认证方式是通过HTTP基本认证机制,简单的使用用户名和密码来验证一个用户所自称的身份,Apache提供了一个**htpasswd**工具来管理可接受的用户名和密码,这些就是你希望赋予Subversion特别权限的用户,让我们给Sally和Harry赋予提交权限,首先,我们需要添加他们到密码文件。 ~~~ $ ### First time: use -c to create the file $ ### Use -m to use MD5 encryption of the password, which is more secure $ htpasswd -cm /etc/svn-auth-file harry New password: ***** Re-type new password: ***** Adding password for user harry $ htpasswd -m /etc/svn-auth-file sally New password: ******* Re-type new password: ******* Adding password for user sally $ ~~~ 下一步,你需要在`httpd.conf`的`Location`区里添加一些指示来告诉Apache如何来使用这些密码文件,`AuthType`指示指定系统使用的认证类型,这种情况下,我们需要指定`Basic`认证系统,`AuthName`是你提供给认证域一个任意名称,大多数浏览器会在向用户询问名称和密码的弹出窗口里显示这个名称,最终,使用`AuthUserFile`指示来指定使用**htpasswd**创建的密码文件的位置。 添加完这三个指示,你的`<Location>`区块一定像这个样子: ~~~ <Location /svn> DAV svn SVNParentPath /usr/local/svn AuthType Basic AuthName "Subversion repository" AuthUserFile /etc/svn-auth-file </Location> ~~~ 这个`<Location>`区块还没有结束,还不能做任何有用的事情,它只是告诉Apache当需要授权时,要去向Subversion客户端索要用户名和密码。我们这里遗漏的,是一些告诉Apache*什么样*客户端需要授权的指示。哪里需要授权,Apache就会在哪里要求认证,最简单的方式是保护所有的请求,添加`Require valid-user`来告诉Apache任何请求需要认证的用户: ~~~ <Location /svn> DAV svn SVNParentPath /usr/local/svn AuthType Basic AuthName "Subversion repository" AuthUserFile /etc/svn-auth-file Require valid-user </Location> ~~~ 一定要阅读后面的部分([“授权选项”一节]( "授权选项"))来得到`Require`的细节,和授权政策的其他设置方法。 需要警惕:HTTP基本认证的密码是用明文传输,因此非常不可靠的,如果你担心密码偷窥,最好是使用某种SSL加密,所以客户端认证使用`https://`而不是`http://`,为了方便,你可以配置Apache为自签名认证。 [[23](#)] 参考Apache的文档(和OpenSSL文档)来查看怎样做。 #### SSL证书管理 商业应用需要越过公司防火墙的版本库访问,防火墙需要小心的考虑非认证用户“吸取”他们的网络流量的情况,SSL让那种形式的关注更不容易导致敏感数据泄露。 如果Subversion使用OpenSSL编译,它就会具备与Subversion服务器使用`https://`的URL通讯的能力,Subversion客户端使用的Neon库不仅仅可以用来验证服务器证书,也可以必要时提供客户端证书,如果客户端和服务器交换了SSL证书并且成功地互相认证,所有剩下的交流都会通过一个会话关键字加密。 怎样产生客户端和服务器端证书以及怎样使用它们已经超出了本书的范围,许多书籍,包括Apache自己的文档,描述这个任务,现在我们*可以*覆盖的是普通的客户端怎样来管理服务器与客户端证书。 当通过`https://`与Apache通讯时,一个Subversion客户端可以接收两种类型的信息: - 一个服务器证书 - 一个客户端证书的要求 如果客户端接收了一个服务器证书,它需要去验证它是可以相信的:这个服务器是它自称的那一个吗?OpenSSL库会去检验服务器证书的签名人或者是*核证机构*(CA)。如果OpenSSL不可以自动信任这个CA,或者是一些其他的问题(如证书过期或者是主机名不匹配),Subversion命令行客户端会询问你是否愿意仍然信任这个证书: ~~~ $ svn list https://host.example.com/repos/project Error validating server certificate for 'https://host.example.com:443': - The certificate is not issued by a trusted authority. Use the fingerprint to validate the certificate manually! Certificate information: - Hostname: host.example.com - Valid: from Jan 30 19:23:56 2004 GMT until Jan 30 19:23:56 2006 GMT - Issuer: CA, example.com, Sometown, California, US - Fingerprint: 7d:e1:a9:34:33:39:ba:6a:e9:a5:c4:22:98:7b:76:5c:92:a0:9c:7b (R)eject, accept (t)emporarily or accept (p)ermanently ~~~ 这个对话看起来很熟悉,这是你会在web浏览器(另一种HTTP客户端,就像Subversion)经常看到的问题,如果你选择(p)ermanent选项,服务器证书会存放在你存放那个用户名和密码缓存(见[“客户端凭证缓存”一节]("客户端凭证缓存")。)的私有运行区`auth/`中,缓存后,Subversion会自动记住在以后的交流中信任这个证书。 你的运行中`servers`文件也会给你能力可以让Subversion客户端自动信任特定的CA,包括全局的或是每主机为基础的,只需要设置`ssl-authority-files`为一组逗号隔开的PEM加密的CA证书列表: ~~~ [global] ssl-authority-files = /path/to/CAcert1.pem;/path/to/CAcert2.pem ~~~ 许多OpenSSL安装包括一些预先定义好的可以普遍信任的“缺省的”CA,为了让Subversion客户端自动信任这些标准权威,设置`ssl-trust-default-ca`为`true`。 当与Apache通话时,Subversion客户端也会收到一个证书的要求,Apache是询问客户端来证明自己的身份:这个客户端是否是他所说的那一个?如果一切正常,Subversion客户端会发送回一个通过Apache信任的CA签名的私有证书,一个客户端证书通常会以加密方式存放在磁盘,使用本地密码保护,当Subversion收到这个要求,它会询问你证书的路径和保护用的密码: ~~~ $ svn list https://host.example.com/repos/project Authentication realm: https://host.example.com:443 Client certificate filename: /path/to/my/cert.p12 Passphrase for '/path/to/my/cert.p12': ******** … ~~~ 注意这个客户端证书是一个“p12”文件,为了让Subversion使用客户端证书,它必须是运输标准的PKCS#12格式,大多数浏览器可以导入和导出这种格式的证书,另一个选择是用OpenSSL命令行工具来转化存在的证书为PKCS#12格式。 再次,运行中`servers`文件允许你为每个主机自动响应这种要求,单个或两条信息可以用运行参数来描述: ~~~ [groups] examplehost = host.example.com [examplehost] ssl-client-cert-file = /path/to/my/cert.p12 ssl-client-cert-password = somepassword ~~~ 一旦你设置了`ssl-client-cert-file`和 `ssl-client-cert-password`参数,Subversion客户端可以自动响应客户端证书请求而不会打扰你。 ### 授权选项 此刻,你已经配置了认证,但是没有配置授权,Apache可以要求用户认证并且确定身份,但是并没有说明这个身份的怎样允许和限制,这个部分描述了两种控制访问版本库的策略。 #### 整体访问控制 最简单的访问控制形式是授权特定用户为只读版本库访问或者是读/写访问版本库。 你可以通过在`<Location>`区块添加`Require valid-user`指示来限制所有的版本库操作,使用我们前面的例子,这意味着只有客户端只可以是`harry`或者`sally`,而且他们必须提供正确的用户名及对应密码,这样允许对Subversion版本库做任何事: ~~~ <Location /svn> DAV svn SVNParentPath /usr/local/svn # how to authenticate a user AuthType Basic AuthName "Subversion repository" AuthUserFile /path/to/users/file # only authenticated users may access the repository Require valid-user </Location> ~~~ 有时候,你不需要这样严密,举个例子,Subversion自己在`http://svn.collab.net/repos/svn`的源代码允许全世界的人执行版本库的只读操作(例如检出我们的工作拷贝和使用浏览器浏览版本库),但是限定只有认证用户可以执行写操作。为了执行特定的限制,你可以使用`Limit`和`LimitExcept`配置指示,就像`Location`指示,这个区块有开始和结束标签,你需要在`<Location>`中添加这个指示。 在`Limit`和`LimitExcept`中使用的参数是可以被这个区块影响的HTTP请求类型,举个例子,如果你希望禁止所有的版本库访问,只是保留当前支持的只读操作,你可以使用`LimitExcept`指示,并且使用`GET`,`PROPFIND`,`OPTIONS`和`REPORT`请求类型参数,然后前面提到过的`Require valid-user`指示将会在`<LimitExcept>`区块中而不是在`<Location>`区块。 ~~~ <Location /svn> DAV svn SVNParentPath /usr/local/svn # how to authenticate a user AuthType Basic AuthName "Subversion repository" AuthUserFile /path/to/users/file # For any operations other than these, require an authenticated user. <LimitExcept GET PROPFIND OPTIONS REPORT> Require valid-user </LimitExcept> </Location> ~~~ 这里只是一些简单的例子,想看关于Apache访问控制`Require`指示的更深入信息,可以查看Apache文档中的教程集`http://httpd.apache.org/docs-2.0/misc/tutorials.html`中的`Security`部分。 #### 每目录访问控制 也可以使用Apache的httpd模块**mod_authz_svn**更加细致的设置访问权限,这个模块收集客户端传递过来的不同的晦涩的URL信息,询问**mod_dav_svn**来解码,然后根据在配置文件定义的访问政策来裁决请求。 如果你从源代码创建Subversion,**mod_authz_svn**会自动附加到**mod_dav_svn**,许多二进制分发版本也会自动安装,为了验证它是安装正确,确定它是在`httpd.conf`的`LoadModule`指示中的**mod_dav_svn**后面: ~~~ LoadModule dav_module modules/mod_dav.so LoadModule dav_svn_module modules/mod_dav_svn.so LoadModule authz_svn_module modules/mod_authz_svn.so ~~~ 为了激活这个模块,你需要配置你的`Location`区块的`AuthzSVNAccessFile`指示,指定保存路径中的版本库访问政策的文件。(一会儿我们将会讨论这个文件的格式。) Apache非常的灵活,你可以从三种模式里选择一种来配置你的区块,作为开始,你选择一种基本的配置模式。(下面的例子非常简单;见Apache自己的文档中的认证和授权选项来查看更多的细节。) 最简单的区块是允许任何人可以访问,在这个场景里,Apache决不会发送认证请求,所有的用户作为“匿名”对待。 **例6.1.匿名访问的配置实例。** ~~~ <Location /repos> DAV svn SVNParentPath /usr/local/svn # our access control policy AuthzSVNAccessFile /path/to/access/file </Location> ~~~ 在另一个极端,你可以配置为拒绝所有人的认证,所有客户端必须提供证明自己身份的证书,你通过`Require valid-user`指示来阻止无条件的认证,并且定义一种认证的手段。 **例6.2.一个认证访问的配置实例。** ~~~ <Location /repos> DAV svn SVNParentPath /usr/local/svn # our access control policy AuthzSVNAccessFile /path/to/access/file # only authenticated users may access the repository Require valid-user # how to authenticate a user AuthType Basic AuthName "Subversion repository" AuthUserFile /path/to/users/file </Location> ~~~ 第三种流行的模式是允许认证和匿名用户的组合,举个例子,许多管理员希望允许匿名用户读取特定的版本库路径,但希望只有认证用户可以读(或者写)更多敏感的区域,在这个设置里,所有的用户开始时用匿名用户访问版本库,如果你的访问控制策略在任何时候要求一个真实的用户名,Apache将会要求认证客户端,为此,你可以同时使用`Satisfy Any`和`Require valid-user`指示。 **例6.3.一个混合认证/匿名访问的配置实例。** ~~~ <Location /repos> DAV svn SVNParentPath /usr/local/svn # our access control policy AuthzSVNAccessFile /path/to/access/file # try anonymous access first, resort to real # authentication if necessary. Satisfy Any Require valid-user # how to authenticate a user AuthType Basic AuthName "Subversion repository" AuthUserFile /path/to/users/file </Location> ~~~ 一旦你的基本`Location`区块已经配置了,你可以创建一个定义一些授权规则的访问文件。 访问文件的语法与**svnserve.conf**和运行中配置文件非常相似,以(`#`)开头的行会被忽略,在它的简单形式里,每一小节命名一个版本库和一个里面的路径,认证用户名是在每个小节中的选项名,每个选项的值描述了用户访问版本库的级别:`r`(只读)或者`rw`(读写),如果用户没有提到,访问是不允许的。 具体一点:这个小节的名称是`[repos-name:path]`或者`[path]`的形式,如果你使用`SVNParentPath`指示,指定版本库的名字是很重要的,如果你漏掉了他们,`[/some/dir]`部分就会与`/some/dir`的所有版本库匹配,如果你使用`SVNPath`指示,因此在你的小节中只是定义路径也很好―毕竟只有一个版本库。 ~~~ [calc:/branches/calc/bug-142] harry = rw sally = r ~~~ 在第一个例子里,用户`harry`对`calc`版本库中`/branches/calc/bug-142`具备完全的读写权利,但是用户`sally`只有读权利,任何其他用户禁止访问这个目录。 当然,访问控制是父目录传递给子目录的,这意味着我们可以为Sally指定一个子目录的不同访问策略: ~~~ [calc:/branches/calc/bug-142] harry = rw sally = r # give sally write access only to the 'testing' subdir [calc:/branches/calc/bug-142/testing] sally = rw ~~~ 现在Sally可以读取分支的`testing`子目录,但对其他部分还是只可以读,同时,Harry对整个分支还继续有完全的读写权限。 也可以通过继承规则明确的的拒绝某人的访问,只需要设置用户名参数为空: ~~~ [calc:/branches/calc/bug-142] harry = rw sally = r [calc:/branches/calc/bug-142/secret] harry = ~~~ 在这个例子里,Harry对`bug-142`目录树有完全的读写权限,但是对`secret`子目录没有任何访问权利。 有一件事需要记住的是需要找到最匹配的目录,**mod_authz_svn**模块首先找到匹配自己的目录,然后父目录,然后父目录的父目录,就这样继续下去,更具体的路径控制会覆盖所有继承下来的访问控制。 缺省情况下,没有人对版本库有任何访问,这意味着如果你已经从一个空文件开始,你会希望给所有用户对版本库根目录具备读权限,你可以使用`*`实现,用来代表“所有用户”: ~~~ [/] * = r ~~~ 这是一个普通的设置;注意在小节名中没有提到版本库名称,这让所有版本库对所有的用户可读,不管你是使用`SVNPath`或是`SVNParentPath`。当所有用户对版本库有了读权利,你可以赋予特定用户对特定子目录的`rw`权限。 星号(`*`)参数需要在这里详细强调:这是匹配匿名用户的*唯一*模式,如果你已经配置了你的`Location`区块允许匿名和认证用户的混合访问,所有用户作为Apache匿名用户开始访问,**mod_authz_svn**会在要访问路径的定义中查找`*`值;如果找不到,Apache就会要求真实的客户端认证。 访问文件也允许你定义一组的用户,很像Unix的`/etc/group`文件: ~~~ [groups] calc-developers = harry, sally, joe paint-developers = frank, sally, jane everyone = harry, sally, joe, frank, sally, jane ~~~ 组可以被赋予通用户一样的访问权限,使用“at”(`@`)前缀来加以区别: ~~~ [calc:/projects/calc] @calc-developers = rw [paint:/projects/paint] @paint-developers = rw jane = r ~~~ ...并且非常接近。 #### 关闭路径为基础的检查 **mod_dav_svn**模块做了许多工作来确定你标记为“不可读”的数据不会因意外而泄露,这意味着需要紧密监控通过**svn checkout**或是**svn update**返回的路径和文件内容,如果这些命令遇到一些根据认证策略不是可读的路径,这个路径通常会被一起忽略,在历史或者重命名操作时―例如运行一个类似**svn cat -r OLD foo.c**的命令来操作一个很久以前改过名字的文件 ― 如果一个对象的以前的名字检测到是只读的,重命令追踪就会终止。 所有的路径检查在有时会非常昂贵,特别是**svn log**的情况。当检索一列修订版本时,服务器会查看所有修订版本修改的路径,并且检查可读性,如果发现了一个不可读路径,它会从修订版本的修改路径中忽略(可以查看`--verbose`选项),并且整个的日志信息会被禁止,不必多说,这种影响大量文件修订版本的操作会非常耗时。这是安全的代价:即使你并没有配置**mod_authz_svn**模块,**mod_dav_svn**还是会询问**httpd**来对所有路径运行认证检查,**mod_dav_svn**模块没有办法知道那个认证模块被安装,所以只有询问Apache来调用所提供的模块。 在另一方面,也有一个安全舱门允许你用安全特性来交换速度,如果你不是坚持要求有每目录授权(如不使用 **mod_authz_svn**和类似的模块),你就可以关闭所有的路径检查,在你的`httpd.conf`文件,使用`SVNPathAuthz`指示: **例6.4.关闭所有的路经检查** ~~~ <Location /repos> DAV svn SVNParentPath /usr/local/svn SVNPathAuthz off </Location> ~~~ `SVNPathAuthz`指示缺省是打开的,当设置为“off”时,所有的路径为基础的授权都会关闭;**mod_dav_svn**停止对每个目录调用授权检查。 ### 额外的糖果 我们已经覆盖了关于认证和授权的Apache和mod_dav_svn的大多数选项,但是Apache还提供了许多很好的特性。 #### 版本库浏览 一个非常有用的好处是使用Apache/WebDAV配置Subversion版本库时可以用普通的浏览器察看最新的版本库文件,因为Subversion使用URL来鉴别版本库版本化的资源,版本库使用的HTTP为基础的URL也可以直接输入到Web浏览器中,你的浏览器会发送一个`GET`请求到URL,根据访问的URL是指向一个版本化的目录还是文件,mod_dav_svn会负责列出目录列表或者是文件内容。 因为URL不能确定你所希望看到的资源的版本,mod_dav_svn会一直返回最新的版本,这样会有一些美妙的副作用,你可以直接把Subversion的URL传递给文档作为引用,这些URL会一直指向文档最新的材料,当然,你也可以在别的网站作为超链使用这些URL。 你通常会在版本化的文件的URL之外得到更多地用处―毕竟那里是有趣的内容存在的地方,但是你会偶尔浏览一个Subversion的目录列表,你会很快发现展示列表生成的HTML非常基本,并且一定没有在外观上(或者是有趣上)下功夫,为了自定义这些目录显示,Subversion提供了一个XML目录特性,一个单独的`SVNIndexXSLT`指示在你的`httpd.conf`文件版本库的`Location`块里,它将会指导mod_dav_svn在显示目录列表的时候生成XML输出,并且引用你选择的XSLT样式表文件: ~~~ <Location /svn> DAV svn SVNParentPath /usr/local/svn SVNIndexXSLT "/svnindex.xsl" … </Location> ~~~ 使用`SVNIndexXSLT`指示和创建一个XSLT样式表,你可以让你的目录列表的颜色模式与你的网站的其它部分匹配,否则,如果你愿意,你可以使用Subversion源分发版本中的`tools/xslt/`目录下的样例样式表。记住提供给`SVNIndexXSLT` 指示的路径是一个URL路径―浏览器需要阅读你的样式表来利用它们! **我可以看到老的修订版本吗?** 通过一个普通的浏览器?一句话:不可以,至少是当你只使用**mod_dav_svn**作为唯一的工具时。 你的Web浏览器只会说普通的HTTP,也就是说它只会GET公共的URL,这个URL代表了最新版本的文件和目录,根据WebDAV/DeltaV规范,每种服务器定义了一种私有的URL语法来代表老的资源的版本,这个语法对客户端是不透明的,为了得到老的版本,一个客户端必须通过一种规范过程来“发现”正确的URL;这个过程包括执行一系列WebDAV PROPFIND请求和理解DeltaV概念,这些事情一般是你的web浏览器做不了的。 为了回答这些问题,一个明显的看老版本文件和目录的方式是带`--revision`参数的**svn list**和**svn cat**命令,为了在浏览器里察看老版本,你可以使用第三方的软件,一个好的例子是ViewCVS(`http://viewcvs.sourceforge.net/`),ViewCVS最初写出来是为了在web显示CVS版本库,最新的带血的(此时正在编写)版本也已经可以理解Subversion版本库了。 #### 其它特性 Apache作为一个健壮的Web服务器的许多特性也可以用来增加Subversion的功能性和安全性,Subversion使用Neon与Apache通讯,这是一种一般的HTTP/WebDAV库,可以支持SSL和Deflate压缩(是**gzip**和**PKZIP**程序用来“压缩”文件为数据块的一样的算法)之类的机制。你只需要编译你希望Subversion和Apache需要的特性,并且正确的配置程序来使用这些特性。 Deflate压缩给服务器和客户端带来了更多地负担,压缩和解压缩减少了网络传输的实际文件的大小,如果网络带宽比较紧缺,这种方法会大大提高服务器和客户端之间发送数据的速度,在极端情况下,这种最小化的传输会造成超时和成功的区别。 不怎么有趣,但同样重要,是Apache和Subversion关系的一些特性,像可以指定自定义的端口(而不是缺省的HTTP的80)或者是一个Subversion可以被访问的虚拟主机名,或者是通过代理服务器访问的能力,这些特性都是Neon所支持的,所以Subversion轻易得到这些支持。 最后,因为**mod_dav_svn**是使用一个半完成的WebDAV/DeltaV方言,所以通过第三方的DAV客户端访问也是可能的,几乎所有的现代操作系统(Win32、OS X和Linux)都有把DAV服务器影射为普通的网络“共享”的内置能力,这是一个复杂的主题;察看[附录C, *WebDAV和自动版本化*]( "附录C.WebDAV和自动版本化")来得到更多细节。 他们讨厌这样做。 当使用自签名的服务器时仍会遭受“中间人”攻击,但是与偷取未保护的密码相比,这样的攻击比一个偶然的获取要艰难许多。 更多有安全意识的人不会希望在运行中`servers`文件保存客户端证书密码。