基于路径的授权
基于路径的授权
Apache和svnserve都可以给用户赋予(或拒绝)访问许可,通常是对整个版本库:一个用户可以读版本库(或不),而且他可以写版本库(或不)。如果可能,也可以定义细粒度的访问规则。一组用户可以有版本库的一个目录的读写权限,但是没有其它的;另一个目录可以是只对一少部分用户可读。
两种服务器都使用同样的文件格式描述路径为基础的规则,如果是Apache,需要加载mod_authz_svn模块,然后添加AuthzSVNAccessFile
指示(在文件httpd.conf
中)指明你的规则文件。(完全解释可以看“每目录访问控制”一节。)如果你在使用svnserve,你需要让你的authz-db
变量(在svnserve.conf
中)指向规则文件。
你真的需要基于路径的访问控制吗?
许多第一次设置Subversion的管理员会在未经太多的思考的情况下轻易选择使用路径为基础的访问控制,管理员通常知道团队的成员工作在哪个项目,所以很容易确定赋予哪些团队访问哪些目录,不能访问哪些目录。这看起来是很自然的事情,它满足了管理员紧密控制版本库访问的愿望。
注意,这个特性通常有一些看不见(和可见的)代价。可见的,需要更多的工作来确信用户对某个路径有读写权限;在一些情况下,会是非常大的性能损失。不可见的,考虑你创建的文化,大多数情况下,因为特定用户不能够在特定目录提交修改,所以社会契约不必通过技术来加强。团队有时候可以自然的互相协作;一些人会通过为他人提交不能正常工作目录的内容的方法帮助别人,你设置了一种不期望交流的障碍。你也要建立一套项目开发、新人加入等活动的规则,还有很多额外的工作。
记住这是一个版本控制系统,即使一些人不小心提交了一些不该提交的东西,很容易回退修改。如果一个用户故意提交到了错误的位置,这是一个社会问题,需要在Subversion之外解决。
所以在开始限制用户的访问权限之前,你要问你自己是否有一个真正的、正直的需要,或仅仅是为了对一个管理员来说这样“听起来不错”。决定是否值得影响服务器的速度,必须记住只有很小的风险;依靠技术手段解决社会问题并不好。[44]。
作为一个思考的例子,考虑Subversion项目本身有允许某个用户可以在那个目录提交的设置,而只是通过社交方式规定。这是一个社区信任的好模型,特别是对开源项目。当然,有时候需要正统的路径为基础的访问控制;在公司中,例如,只有部分数据是敏感的,只允许以小组人可以访问。
当你的服务器知道去查找规则文件时,就是需要定义规则的时候了。
访问文件的语法与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
子目录没有任何访问权利。
需要记住的是最详细的的路径会被匹配,服务器首先找到匹配自己的目录,然后父目录,然后父目录的父目录,就这样继续下去,更具体的路径控制会覆盖所有继承下来的访问控制。
缺省情况下,没有人对版本库有任何访问,这意味着如果你已经从一个空文件开始,你会希望给所有用户对版本库根目录具备读权限,你可以使用星号(*
)实现,用来代表“所有用户”:
[/] * = r
这是一个普通的设置;注意在小节名中没有提到版本库名称,这让所有版本库对所有的用户可读。当所有用户对版本库有了读权利,你可以赋予特定用户对特定子目录的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
部分可读性和检出
如果你使用Apache作为Subversion服务器,并让版本库的某些子目录对特定用户不可读,然后你需要知道svn checkout会有一个不理想的执行方式。
当客户端通过HTTP请求检出或更新时,它会做出一个单独的服务器请求,并接收一个单独的(通常很大)服务器响应,当服务器接收到请求,这是Apache服务器要求用户认证的唯一机会,这有一些副作用。例如,如果版本库的一个特定子目录只对用户Sally可读,用户Harry检出父目录,他的客户端会在收到认证要求时返回用户名Harry,因为服务器生成的响应很大,无法在达到特别子目录时重新发送认证请求;因此子目录会被一起略过,而不会询问用户是否使用Sally重新认证。如果版本库是匿名可访问的,则整个检出将不需要认证—再一次,略过不可读的目录,而不会中途要求认证。
[44] 本书的共同主题!