Both Apache and svnserve are capable of granting (or denying) permissions to users. Typically this is done over the entire repository: a user can read the repository (or not), and she can write to the repository (or not). It's also possible, however, to define finer-grained access rules. One set of users may have permission to write to a certain directory in the repository, but not others; another directory might not even be readable by all but a few special people.
Both servers use a common file format to describe these
path-based access rules. In the case of Apache, one needs to
load the mod_authz_svn module and then add
the AuthzSVNAccessFile
directive (within
the httpd.conf
file) pointing to your own
rules-file. (For a full explanation, see
the section called “Per-Directory Access Control”.) If
you're using svnserve, then you need to make
the authz-db
variable
(within svnserve.conf
) point to your
rules-file.
Once your server knows where to find your rules-file, it's time to define the rules.
The syntax of the file is the same familiar one used
by svnserve.conf and the runtime
configuration files. Lines that start with a hash
(#
) are ignored. In its simplest form, each
section names a repository and path within it, and the
authenticated usernames are the option names within each
section. The value of each option describes the user's level of
access to the repository path: either
r
(read-only) or rw
(read-write). If the user is not mentioned at all, no access is
allowed.
To be more specific: the value of the section-names are
either of the form [repos-name:path]
or the
form [path]
. If you're using the
SVNParentPath
directive, then it's important
to specify the repository names in your sections. If you omit
them, then a section like
[/some/dir]
will match the path
/some/dir
in every
repository. If you're using the SVNPath
directive, however, then it's fine to only define paths in your
sections—after all, there's only one repository.
[calc:/branches/calc/bug-142] harry = rw sally = r
In this first example, the user harry
has
full read and write access on the
/branches/calc/bug-142
directory in the
calc
repository, but the user
sally
has read-only access. Any other users
are blocked from accessing this directory.
Of course, permissions are inherited from parent to child directory. That means that we can specify a subdirectory with a different access policy for 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
Now Sally can write to the testing
subdirectory of the branch, but can still only read other parts.
Harry, meanwhile, continues to have complete read-write access
to the whole branch.
It's also possible to explicitly deny permission to someone via inheritance rules, by setting the username variable to nothing:
[calc:/branches/calc/bug-142] harry = rw sally = r [calc:/branches/calc/bug-142/secret] harry =
In this example, Harry has read-write access to the
entire bug-142
tree, but has absolutely no
access at all to the secret
subdirectory
within it.
The thing to remember is that the most specific path always matches first. The server tries to match the path itself, and then the parent of the path, then the parent of that, and so on. The net effect is that mentioning a specific path in the accessfile will always override any permissions inherited from parent directories.
By default, nobody has any access to the repository at all.
That means that if you're starting with an empty file, you'll
probably want to give at least read permission to all users at
the root of the repository. You can do this by using the
asterisk variable (*
), which means “all
users”:
[/] * = r
This is a common setup; notice that there's no repository
name mentioned in the section name. This makes all repositories
world readable to all users. Once all users have read-access to
the repositories, you can give explicit
rw
permission to certain users on specific
subdirectories within specific repositories.
The asterisk variable (*
) is also worth
special mention here: it's the
only pattern which matches an anonymous
user. If you've configured your server block to allow a mixture
of anonymous and authenticated access, all users start out
accessing anonymously. The server looks for a
*
value defined for the path being accessed;
if it can't find one, then it demands real authentication from
the client.
The access file also allows you to define whole groups of
users, much like the Unix /etc/group
file:
[groups] calc-developers = harry, sally, joe paint-developers = frank, sally, jane everyone = harry, sally, joe, frank, sally, jane
Groups can be granted access control just like users.
Distinguish them with an “at”
(@
) prefix:
[calc:/projects/calc] @calc-developers = rw [paint:/projects/paint] @paint-developers = rw jane = r
Groups can also be defined to contain other groups:
[groups] calc-developers = harry, sally, joe paint-developers = frank, sally, jane everyone = @calc-developers, @paint-developers