这份文档是用来描述 Subversion 1.2 的。如果你运行的是更新版本的 Subversion,我们强烈建议你访问 https://svnbook.subversion.org.cn/ 并查阅适合你 Subversion 版本的文档。

httpd,Apache HTTP 服务器

Apache HTTP Server 是一款“重型”网络服务器,Subversion 可以利用它。通过自定义模块,httpd 使 Subversion 仓库可以通过 WebDAV/DeltaV 协议被客户端访问,该协议是 HTTP 1.1 的扩展(有关详细信息,请参阅 http://www.webdav.org/)。该协议使用万维网的核心协议 HTTP 协议,并添加了写入功能,特别是版本化的写入功能。其结果是一个标准化、健壮的系统,它作为 Apache 2.0 软件的一部分便捷地打包,得到众多操作系统和第三方产品的支持,并且不需要网络管理员打开另一个自定义端口。[25]虽然 Apache-Subversion 服务器比 svnserve 具有更多功能,但设置起来也更难。灵活性通常意味着更高的复杂性。

以下讨论的很多内容都包括对 Apache 配置指令的引用。虽然这里给出了一些这些指令用法的示例,但对其进行完整描述超出了本章的范围。Apache 团队在其网站上维护着优秀的文档,并公开发布在 https://httpd.apache.ac.cn 上。例如,可以在 https://httpd.apache.ac.cn/docs-2.0/mod/directives.html 中找到配置指令的通用参考。

此外,当你对 Apache 设置进行更改时,很可能在某个地方会犯错误。如果你还不熟悉 Apache 的日志记录子系统,你应该了解它。在你的 httpd.conf 文件中,有一些指令指定了 Apache 生成的访问日志和错误日志的磁盘位置(分别是 CustomLogErrorLog 指令)。Subversion 的 mod_dav_svn 也使用 Apache 的错误日志记录接口。你始终可以浏览这些文件的内容,以查找可能揭示问题来源的信息,这些信息在其他情况下并不明显。

先决条件

要通过 HTTP 连接你的仓库,你需要四个组件,它们包含在两个包中。你需要 Apache httpd 2.0,它附带的 mod_dav DAV 模块,Subversion 以及随 Subversion 一起分发的 mod_dav_svn 文件系统提供者模块。一旦你拥有了所有这些组件,连接你的仓库的过程就和下面一样简单

  • 让 httpd 2.0 以及 mod_dav 模块运行起来,

  • 将 mod_dav_svn 插件安装到 mod_dav 中,它使用 Subversion 的库来访问仓库,以及

  • 配置你的 httpd.conf 文件来导出(或公开)仓库。

你可以通过编译 httpd 和 Subversion 源代码来完成前两个项目,或者在你的系统上安装它们的预构建二进制包。有关如何编译 Subversion 以与 Apache HTTP Server 一起使用,以及如何为此目的编译和配置 Apache 本身的最新信息,请参阅 Subversion 源代码树顶层的 INSTALL 文件。

基本的 Apache 配置

一旦你在系统上安装了所有必需的组件,剩下的就是通过它的 httpd.conf 文件配置 Apache。使用 LoadModule 指令来指示 Apache 加载 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 仓库(或仓库)在哪里。Location 指令使用 XML 类似的符号,以一个开始标签开头,并以一个结束标签结尾,中间包含各种其他配置指令。Location 指令的目的是指示 Apache 在处理指向特定 URL 或其子 URL 的请求时执行一些特殊操作。在 Subversion 的情况下,你希望 Apache 只将对指向版本化资源的 URL 的支持传递给 DAV 层。你可以指示 Apache 将所有路径部分(URL 中跟随服务器名称和可选端口号的部分)以 /repos/ 开头的 URL 的处理委托给 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/repos1http://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 将把所有路径部分以 /svn/ 开头的 URL 的处理委托给 Subversion DAV 提供者,然后它将假定 SVNParentPath 指令指定的目录中的任何项目都是 Subversion 仓库。这种语法非常方便,因为与使用 SVNPath 指令不同,你不需要重启 Apache 就可以创建和连接新的仓库。

请确保在定义新的 Location 时,它不会与其他已导出的 Location 重叠。例如,如果你的主 DocumentRoot/www,不要在 <Location /www/repos> 中导出 Subversion 仓库。如果收到一个针对 URI /www/repos/foo.c 的请求,Apache 将无法知道是在 DocumentRoot 中查找一个名为 repos/foo.c 的文件,还是委托 mod_dav_svn 从 Subversion 仓库中返回 foo.c

在这个阶段,你应该认真考虑权限问题。如果你已经运行了 Apache 一段时间作为你的常规 Web 服务器,你可能已经拥有了一组内容,例如网页、脚本等。这些项目已经配置了一组权限,允许它们与 Apache 协同工作,或者更确切地说,允许 Apache 与这些文件协同工作。Apache 在用作 Subversion 服务器时,也需要正确的权限才能读取和写入你的 Subversion 仓库。(请参阅 服务器和权限:一个警告。)

你需要确定一个权限系统设置,它既满足 Subversion 的要求,又不会弄乱以前存在的任何网页或脚本安装。这可能意味着更改 Subversion 仓库上的权限以匹配 Apache 为你服务的其他内容所使用的权限,或者它可能意味着在 httpd.conf 中使用 UserGroup 指令来指定 Apache 应该以拥有 Subversion 仓库的用户和组的身份运行。没有一种单一正确的设置权限的方式,每个管理员都会有不同的原因以特定方式执行操作。只需要意识到,权限相关问题可能是配置 Subversion 仓库以与 Apache 一起使用时最常见的疏忽。

身份验证选项

到目前为止,如果你配置 httpd.conf 包含类似以下内容

<Location /svn>
  DAV svn
  SVNParentPath /usr/local/svn
</Location>

...那么你的仓库就是“匿名”地向全世界开放。在你配置一些身份验证和授权策略之前,你通过 Location 指令提供的 Subversion 仓库将对所有人开放。换句话说,

  • 任何人都可以使用他们的 Subversion 客户端签出仓库 URL(或其任何子目录)的工作副本,

  • 任何人都可以通过将他们的 Web 浏览器指向仓库 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
$

接下来,您需要在 Location 块中添加一些额外的 httpd.conf 指令,告诉 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,每当需要授权时,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 Basic Auth 密码在网络上传输时几乎是明文的,因此非常不安全。如果您担心密码被窃取,最好使用某种 SSL 加密,这样客户端可以通过 https:// 而不是 http:// 进行身份验证;至少,您可以配置 Apache 使用自签名服务器证书。 [26] 请查阅 Apache 文档(以及 OpenSSL 文档)了解如何执行此操作。

SSL 证书管理

需要将存储库暴露给公司防火墙之外的访问权限的企业,应该意识到未经授权的方可能会“嗅探”他们的网络流量。SSL 使这种不受欢迎的关注不太可能导致敏感数据泄露。

如果 Subversion 客户端被编译为使用 OpenSSL,那么它将获得通过 https:// URL 与 Apache 服务器进行通信的能力。Subversion 客户端使用的 Neon 库不仅能够验证服务器证书,还可以在受到挑战时提供客户端证书。当客户端和服务器交换了 SSL 证书并成功相互认证后,所有后续通信都将通过会话密钥进行加密。

本书无法详细介绍如何生成客户端和服务器证书,以及如何配置 Apache 使用它们。许多其他书籍,包括 Apache 自身的文档,都描述了此任务。但是,本书可以介绍如何从普通的 Subversion 客户端管理服务器和客户端证书。

通过 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?

此对话应该看起来很熟悉;这本质上与您可能从网络浏览器(它只是像 Subversion 一样的另一个 HTTP 客户端!)中看到的相同问题!如果您选择(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,这些 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-filessl-client-cert-password 变量后,Subversion 客户端可以自动响应客户端证书挑战,而无需提示您。 [27]

授权选项

此时,您已经配置了身份验证,但还没有配置授权。Apache 能够挑战客户端并确认身份,但它没有被告知如何允许或限制对持有这些身份的客户端的访问权限。本节介绍两种控制对存储库访问权限的策略。

整体访问控制

最简单的访问控制形式是授权某些用户对存储库进行只读访问,或对存储库进行读写访问。

您可以通过将 Require valid-user 指令添加到您的 <Location> 块中来限制对所有存储库操作的访问权限。使用我们之前的示例,这意味着只有声称自己是 harrysally 并且提供了其相应用户名正确密码的客户端,才被允许对 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 允许世界上任何人都执行只读存储库任务(例如检出工作副本和使用网络浏览器浏览存储库),但将所有写操作限制为经过身份验证的用户。要进行这种选择性限制,您可以使用 LimitLimitExcept 配置指令。与 Location 指令一样,这些块也有开始和结束标签,您需要将它们嵌套在您的 <Location> 块中。

LimitLimitExcept 指令上存在的参数是受该块影响的 HTTP 请求类型。例如,如果您想禁止对存储库的所有访问,除了当前支持的只读操作外,您将使用 LimitExcept 指令,并传递 GETPROPFINDOPTIONSREPORT 请求类型参数。然后,前面提到的 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 文档教程集合的 Security 部分,网址为 https://httpd.apache.ac.cn/docs-2.0/misc/tutorials.html.

每个目录访问控制

可以使用第二个 Apache httpd 模块 mod_authz_svn 设置更细粒度的权限。此模块获取从客户端传递到服务器的各种不透明 URL,要求 mod_dav_svn 对它们进行解码,然后可能根据配置文件中定义的访问策略拒绝请求。

如果您从源代码构建了 Subversion,mod_authz_svn 会自动与 mod_dav_svn 一起构建和安装。许多二进制发行版也会自动安装它。要验证它是否已正确安装,请确保它紧随 mod_dav_svnLoadModule 指令出现在 httpd.conf

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 身份验证和授权选项的更多详细信息。)

最简单的块是允许所有人开放访问。在这种情况下,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 AnyRequire 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

在这个第一个示例中,用户 harrycalc 存储库中的 /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 模块尝试匹配路径本身,然后匹配路径的父级,再匹配其父级,依此类推。最终效果是,在 accessfile 中提及特定路径将始终覆盖从父目录继承的任何权限。

默认情况下,任何人都无法访问存储库。这意味着如果您从一个空文件开始,您可能需要至少为存储库根目录中的所有用户授予读取权限。您可以使用星号变量 (*) 来做到这一点,它的含义是“所有用户

[/]
* = 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 

还可以定义包含其他组的组

[groups]
calc-developers = harry, sally, joe
paint-developers = frank, sally, jane
everyone = @calc-developers, @paint-developers

…就是这样了。

禁用基于路径的检查

mod_dav_svn 模块会付出很多努力来确保您标记为“不可读”的数据不会意外泄露。这意味着它需要密切监控 svn checkoutsvn update 命令等命令返回的所有路径和文件内容。如果这些命令遇到根据某些授权策略不可读的路径,则通常会完全省略该路径。在历史或重命名跟踪的情况下,例如,对一个很久以前重命名的文件运行 svn cat -r OLD foo.c 这样的命令,如果确定该对象的某个旧名称受到读限制,则重命名跟踪将简单地停止。

所有这些路径检查有时会非常昂贵,尤其是在 svn log 的情况下。在检索修订版本列表时,服务器会查看每个修订版本中的每个更改路径,并检查其可读性。如果发现不可读的路径,则会将其从修订版本更改路径列表中省略(通常使用 --verbose 选项查看),并且会抑制整个日志消息。不用说,这在影响大量文件的修订版本上可能非常耗时。这是安全性的代价:即使您根本没有配置 mod_authz_svn 之类的模块,mod_dav_svn 模块仍然要求 Apache 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 指令默认情况下为“on”。当设置为“off”时,所有基于路径的授权检查都被禁用;mod_dav_svn 停止对它发现的每个路径调用授权检查。

额外的好东西

我们已经介绍了 Apache 和 mod_dav_svn 的大多数身份验证和授权选项。但 Apache 还提供了一些其他不错的功能。

存储库浏览

Apache/WebDAV 为您的 Subversion 存储库配置带来的最有用好处之一是,您可以通过普通 Web 浏览器立即查看版本控制文件的最新修订版本。由于 Subversion 使用 URL 来标识版本控制的资源,因此用于基于 HTTP 的存储库访问的那些 URL 可以直接键入 Web 浏览器。您的浏览器将针对该 URL 发出 GET 请求,并且根据该 URL 是否表示版本控制的目录或文件,mod_dav_svn 将使用目录列表或文件内容进行响应。

由于 URL 不包含有关您要查看的资源的哪个版本的任何信息,因此 mod_dav_svn 将始终使用最新版本进行回复。此功能具有奇妙的副作用,您可以将 Subversion URL 传递给您的同行作为对文档的引用,而这些 URL 将始终指向该文档的最新版本。当然,您甚至可以将这些 URL 用作来自其他网站的超链接。

您通常会更多地使用指向版本控制文件的 URL——毕竟,有趣的内容往往在那里。但是,您可能需要浏览 Subversion 目录列表,您会很快注意到用于显示该列表的生成的 HTML 非常基础,当然不打算美观(甚至有趣)。为了启用这些目录显示的自定义,Subversion 提供了 XML 索引功能。在您的存储库的 httpd.conf 文件的 Location 块中,单个 SVNIndexXSLT 指令将指示 mod_dav_svn 在显示目录列表时生成 XML 输出,并引用您选择的 XSLT 样式表

<Location /svn>
  DAV svn
  SVNParentPath /usr/local/svn
  SVNIndexXSLT "/svnindex.xsl"
  …
</Location>

使用 SVNIndexXSLT 指令和一个创意 XSLT 样式表,您可以使您的目录列表与您网站其他部分使用的颜色方案和图像匹配。或者,如果您愿意,您可以使用 Subversion 源代码分发中的 tools/xslt/ 目录中提供的示例样式表。请记住,提供给 SVNIndexXSLT 目录的路径实际上是一个 URL 路径——浏览器需要能够读取您的样式表才能使用它们!

其他功能

Apache 作为强大的 Web 服务器在自身提供的功能中,有许多功能也可以用于提高 Subversion 的功能或安全性。Subversion 使用 Neon 与 Apache 通信,Neon 是一个通用的 HTTP/WebDAV 库,支持 SSL(安全套接字层,如前所述)和 Deflate 压缩(与 gzipPKZIP 程序用于将文件“缩小”为较小数据块的算法相同)等机制。您只需要将您想要的特性支持编译到 Subversion 和 Apache 中,并正确配置这些程序以使用这些特性。

Deflate 压缩会给客户端和服务器带来一些负担,以压缩和解压缩网络传输,以最大限度地减少实际传输的大小。在网络带宽不足的情况下,这种类型的压缩可以大大提高服务器和客户端之间通信的速度。在极端情况下,这种最小化的网络传输可能是操作超时或成功完成之间的区别。

Apache 和 Subversion 关系的其他功能不太令人感兴趣,但同样有用,例如,指定自定义端口(而不是默认的 HTTP 端口 80)或 Subversion 存储库应该通过其访问的虚拟域名,或者通过代理访问存储库。这些功能都由 Neon 支持,因此 Subversion 免费获得了这些支持。

最后,由于 mod_dav_svn 正在使用 WebDAV/DeltaV 的半完整方言,因此可以通过第三方 DAV 客户端访问存储库。大多数现代操作系统(Win32、OS X 和 Linux)都具有将 DAV 服务器作为标准网络“共享”挂载的内置功能。这是一个复杂的话题;有关详细信息,请阅读 附录 B,WebDAV 和自动版本控制



[25] 他们真的不喜欢这样做。

[26] 虽然自签名服务器证书仍然容易受到“中间人”攻击,但与嗅探未受保护的密码相比,这种攻击对于偶然观察者来说要困难得多。

[27] 更注重安全的人可能不想将客户端证书密码存储在运行时 servers 文件中。

[28] 当时,它被称为“ViewCVS”。

TortoiseSVN 官方中文版 1.14.7 发布