<?xml version="1.0" encoding="utf-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Path-Based Authorization</title> <link rel="stylesheet" type="text/css" href="styles.css" /> <meta name="generator" content="DocBook XSL Stylesheets V1.79.1" /> <style type="text/css"> body { background-image: url('images/draft.png'); background-repeat: no-repeat; background-position: top left; /* The following properties make the watermark "fixed" on the page. */ /* I think that's just a bit too distracting for the reader... */ /* background-attachment: fixed; */ /* background-position: center center; */ }</style> <link rel="home" href="index.html" title="Version Control with Subversion [DRAFT]" /> <link rel="up" href="svn.serverconfig.html" title="Chapter 6. Server Configuration" /> <link rel="prev" href="svn.serverconfig.httpd.html" title="httpd, the Apache HTTP Server" /> <link rel="next" href="svn.serverconfig.operational-logging.html" title="High-level Logging" /> </head> <body> <div xmlns="" id="vcws-version-notice"> <p>This text is a work in progress—highly subject to change—and may not accurately describe any released version of the Apache™ Subversion® software. Bookmarking or otherwise referring others to this page is probably not such a smart idea. Please visit <a href="http://www.svnbook.com/">http://www.svnbook.com/</a> for stable versions of this book.</p> </div> <div class="navheader"> <table width="100%" summary="Navigation header"> <tr> <th colspan="3" align="center">Path-Based Authorization</th> </tr> <tr> <td width="20%" align="left"><a accesskey="p" href="svn.serverconfig.httpd.html">Prev</a> </td> <th width="60%" align="center">Chapter 6. Server Configuration</th> <td width="20%" align="right"> <a accesskey="n" href="svn.serverconfig.operational-logging.html">Next</a></td> </tr> </table> <hr /> </div> <div class="sect1"> <div class="titlepage"> <div> <div> <h2 class="title" style="clear: both"><a id="svn.serverconfig.pathbasedauthz"></a>Path-Based Authorization</h2> </div> </div> </div> <p>Both Apache and <span class="command"><strong>svnserve</strong></span> 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).</p> <p>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. It's even possible to restrict access on a per file basis.</p> <p>Both Subversion servers use a common file format to describe these path-based access rules. In this section, we will explain that file format, as well how to configure your Subversion server to use it for managing path-based authorization.</p> <div class="sidebar"> <div class="titlepage"> <div> <div> <p class="title"> <strong>Do You Really Need Path-Based Access Control?</strong> </p> </div> </div> </div> <p>A lot of administrators setting up Subversion for the first time tend to jump into path-based access control without giving it a lot of thought. The administrator usually knows which teams of people are working on which projects, so it's easy to jump in and grant certain teams access to certain directories and not others. It seems like a natural thing, and it appeases the administrator's desire to maintain tight control of the repository.</p> <p>Note, though, that there are often invisible (and visible!) costs associated with this feature. In the visible category, the server needs to do a lot more work to ensure that the user has the right to read or write each specific path; in certain situations, there's very noticeable performance loss. In the invisible category, consider the culture you're creating. Most of the time, while certain users <span class="emphasis"><em>shouldn't</em></span> be committing changes to certain parts of the repository, that social contract doesn't need to be technologically enforced. Teams can sometimes spontaneously collaborate with each other; someone may want to help someone else out by committing to an area she doesn't normally work on. By preventing this sort of thing at the server level, you're setting up barriers to unexpected collaboration. You're also creating a bunch of rules that need to be maintained as projects develop, new users are added, and so on. It's a bunch of extra work to maintain.</p> <p>Remember that this is a version control system! Even if somebody accidentally commits a change to something she shouldn't, it's easy to undo the change. And if a user commits to the wrong place with deliberate malice, it's a social problem anyway, and that the problem needs to be dealt with outside Subversion.</p> <p>So, before you begin restricting users' access rights, ask yourself whether there's a real, honest need for this, or whether it's just something that <span class="quote">“<span class="quote">sounds good</span>”</span> to an administrator. Decide whether it's worth sacrificing some server speed, and remember that there's very little risk involved; it's bad to become dependent on technology as a crutch for social problems.<a href="#ftn.idm8880" class="footnote" id="idm8880"><sup class="footnote">[70]</sup></a></p> <p>As an example to ponder, consider that the Subversion project itself has always had a notion of who is allowed to commit where, but it's always been enforced socially. This is a good model of community trust, especially for open source projects. Of course, sometimes there <span class="emphasis"><em>are</em></span> truly legitimate needs for path-based access control; within corporations, for example, certain types of data really can be sensitive, and access needs to be genuinely restricted to small groups of people.</p> </div> <div class="sect2"> <div class="titlepage"> <div> <div> <h3 class="title"><a id="svn.serverconfig.pathbasedauthz.getting-started"></a>Getting Started with Path-Based Access Control</h3> </div> </div> </div> <p>Subversion offers path-based access control in Apache via the <span class="command"><strong>mod_authz_svn</strong></span> module, which must be loaded using the <code class="literal">LoadModule</code> directive in <code class="filename">httpd.conf</code> in the same fashion that <span class="command"><strong>mod_dav_svn</strong></span> itself is loaded. To enable the use of this module for your repositories, you'll add the <code class="literal">AuthzSVNAccessFile</code> or <code class="literal">AuthzSVNReposRelativeAccessFile</code> directives (again within the <code class="filename">httpd.conf</code> file) pointing to your own access rules file. (For a full explanation, see <a class="xref" href="svn.serverconfig.httpd.html#svn.serverconfig.httpd.authz.perdir" title="Per-directory access control">the section called “Per-directory access control”</a>.)</p> <p>To configure path-based authorization in <span class="command"><strong>svnserve</strong></span>, simply point the <code class="literal">authz-db</code> configuration variable (within your <code class="filename">svnserve.conf</code> file) to your access rules file.</p> <p>Once your server knows where to look for your access rules, it's time to define those rules.</p> <p>The syntax of the Subversion access file is the same familiar one used by <code class="filename">svnserve.conf</code> and the runtime configuration files. Lines that start with a hash (<code class="literal">#</code>) are ignored. In its simplest form, each section names a versioned path and, optionally, the repository in which that path is found. In other words, except for a few reserved sections, section names are of one of two forms: either <code class="literal">[repos-name:path]</code> or <code class="literal">[path]</code> when <code class="literal">AuthzSVNAccessFile</code> is used. If you configured per repository access files via <code class="literal">AuthzSVNReposRelativeAccessFile</code> directive, you should always use <code class="literal">[path]</code> form only. Authenticated usernames are the option names within each section, and an option's value describes that user's level of access to the repository path: either <code class="literal">r</code> (read-only) or <code class="literal">rw</code> (read/write). If the user is not mentioned at all, no access is allowed.</p> <div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"> <table border="0" summary="Note"> <tr> <td rowspan="2" align="center" valign="top" width="25"> <img alt="[Note]" src="images/note.png" /> </td> <th align="left">Note</th> </tr> <tr> <td align="left" valign="top"> <p>Paths used in access file sections must be specified using Subversion's <span class="quote">“<span class="quote">internal style</span>”</span>, which mostly just means that they are encoded in UTF-8 and use forward slash (<code class="literal">/</code>) characters as directory separators (even on Windows systems). Note also that these paths do not employ any character escaping mechanism (such as URI-encoding)—spaces in path names should be represented exactly as such in access file section names (<code class="literal">[repos-name:path with spaces]</code>, e.g.)</p> </td> </tr> </table> </div> <p>Here's a simple example demonstrating a piece of the access configuration which grants read access Sally, and read/write access to Harry, for the path <code class="filename">/branches/calc/bug-142</code> (and all its children) in the repository <code class="literal">calc</code>:</p> <div class="informalexample"> <pre class="programlisting"> [calc:/branches/calc/bug-142] harry = rw sally = r </pre> </div> <div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"> <table border="0" summary="Warning"> <tr> <td rowspan="2" align="center" valign="top" width="25"> <img alt="[Warning]" src="images/warning.png" /> </td> <th align="left">Warning</th> </tr> <tr> <td align="left" valign="top"> <p>Prior to version 1.7, Subversion treated repository names and paths in a case-insensitive fashion for the purposes of access control, converting them to lower case internally before comparing them against the contents of your access file. It now does these comparisons case-sensitively. If you upgraded to Subversion 1.7 from an older version, you should review your access files for case correctness.</p> </td> </tr> </table> </div> <p>The name of a repository as evaluated by the authorization subsystem is derived directly from the repository's path. Exactly how this happens differs between to two server options. <span class="command"><strong>mod_dav_svn</strong></span> uses only the basename of the repository's root URL<a href="#ftn.idm8924" class="footnote" id="idm8924"><sup class="footnote">[71]</sup></a>, while <span class="command"><strong>svnserve</strong></span> uses the entire relative path from the serving root (as determined by its <code class="option">--root</code> (<code class="option">-r</code>) command-line option) to the repository.</p> <div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"> <table border="0" summary="Warning"> <tr> <td rowspan="2" align="center" valign="top" width="25"> <img alt="[Warning]" src="images/warning.png" /> </td> <th align="left">Warning</th> </tr> <tr> <td align="left" valign="top"> <p>The differences in the ways that a repository's name is determined by each of <span class="command"><strong>mod_dav_svn</strong></span> and <span class="command"><strong>svnserve</strong></span> can cause problems when trying to serve a repository via both servers simultaneously. Naturally, an administrator would prefer to point both servers' configurations toward a common access file. However, for this to work, you must ensure that the repository name portion of the file's section names are compatible with each server's idea of what the repository name should be—for example, by configuring <span class="command"><strong>svnserve</strong></span>'s root to be the same as <span class="command"><strong>mod_dav_svn</strong></span>'s configured <code class="literal">SVNParentPath</code>, or by using a different access file per repository so that section names needn't reference the repository at all.</p> </td> </tr> </table> </div> <p>If you're using the <code class="literal">SVNParentPath</code> directive, it's important to specify the repository names in your sections. If you omit them, a section such as <code class="literal">[/some/dir]</code> will match the path <code class="filename">/some/dir</code> in <span class="emphasis"><em>every</em></span> repository. If you're using the <code class="literal">SVNPath</code> directive, however, it's fine to provide only paths in your sections—after all, there's only one repository.</p> <p>Permissions are inherited from a path's parent directory. That means we can specify a subdirectory with a different access policy for Sally. Let's continue our previous example, and grant Sally write access to a child of the branch that she's otherwise permitted only to read:</p> <div class="informalexample"> <pre class="programlisting"> [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 </pre> </div> <p>Now Sally can write to the <code class="filename">testing</code> subdirectory of the branch, but can still only read other parts. Harry, meanwhile, continues to have complete read/write access to the whole branch.</p> <p>It's also possible to explicitly deny permission to someone via inheritance rules, by setting the username variable to nothing:</p> <div class="informalexample"> <pre class="programlisting"> [calc:/branches/calc/bug-142] harry = rw sally = r [calc:/branches/calc/bug-142/secret] harry = </pre> </div> <p>In this example, Harry has read/write access to the entire <code class="filename">bug-142</code> tree, but has absolutely no access at all to the <code class="filename">secret</code> subdirectory within it.</p> <div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"> <table border="0" summary="Tip"> <tr> <td rowspan="2" align="center" valign="top" width="25"> <img alt="[Tip]" src="images/tip.png" /> </td> <th align="left">Tip</th> </tr> <tr> <td align="left" valign="top"> <p>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 access file will always override any permissions inherited from parent directories.</p> <p>Similarly, sections that specify a repository name have precedence over those that don't: if both <code class="literal">[calc:/some/path]</code> and <code class="literal">[/some/path]</code> are present, the former will be used and the latter ignored for <code class="literal">calc</code>.</p> </td> </tr> </table> </div> <p>By default, nobody has any access to any 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 roots of the repositories. You can do this by using the asterisk variable (<code class="literal">*</code>), which means <span class="quote">“<span class="quote">all users</span>”</span>:</p> <div class="informalexample"> <pre class="programlisting"> [/] * = r </pre> </div> <p>This is a common setup; notice that no repository name is 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 <code class="literal">rw</code> permission to certain users on specific subdirectories within specific repositories.</p> <p>Note that while all of the previous examples use directories, that's only because defining access rules on directories is the most common case. You may similarly restrict access on file paths, too.</p> <div class="informalexample"> <pre class="programlisting"> [calendar:/projects/calendar/manager.ics] harry = rw sally = r </pre> </div> </div> <div class="sect2"> <div class="titlepage"> <div> <div> <h3 class="title"><a id="svn.serverconfig.pathbasedauthz.groups"></a>Access Control Groups</h3> </div> </div> </div> <p>The access file also allows you to define whole groups of users, much like the Unix <code class="filename">/etc/group</code> file. To do this, create a <code class="literal">groups</code> section in your access file, and then describe your groups within that section: each variable's name defines the name of the group, and its value is a comma-delimited list of usernames which are part of that group.</p> <div class="informalexample"> <pre class="programlisting"> [groups] calc-developers = harry, sally, joe paint-developers = frank, sally, jane everyone = harry, sally, joe, frank, jane </pre> </div> <p>Groups can be granted access control just like users. Distinguish them with an <span class="quote">“<span class="quote">at sign</span>”</span> (<code class="literal">@</code>) prefix:</p> <div class="informalexample"> <pre class="programlisting"> [calc:/projects/calc] @calc-developers = rw [paint:/projects/paint] jane = r @paint-developers = rw </pre> </div> <p>Another important fact is that group permissions are not overridden by individual user permissions. Rather, the <span class="emphasis"><em>combination</em></span> of all matching permissions is granted. In the prior example, Jane is a member of the <code class="literal">paint-developers</code> group, which has read/write access. Combined with the <code class="literal">jane = r</code> rule, this still gives Jane read/write access. Permissions for group members can only be extended beyond the permissions the group already has. Restricting users who are part of a group to less than their group's permissions is impossible.</p> <p>Groups can also be defined to contain other groups:</p> <div class="informalexample"> <pre class="programlisting"> [groups] calc-developers = harry, sally, joe paint-developers = frank, sally, jane everyone = @calc-developers, @paint-developers </pre> </div> </div> <div class="sect2"> <div class="titlepage"> <div> <div> <h3 class="title"><a id="svn.serverconfig.pathbasedauthz.aliases"></a>Username Aliases</h3> </div> </div> </div> <p>Some authentication systems expect and carry relatively short usernames of the sorts we've been describing here—<code class="literal">harry</code>, <code class="literal">sally</code>, <code class="literal">joe</code>, and so on. But other authentication systems—such as those which use LDAP stores or SSL client certificates—may carry much more complex usernames. For example, Harry's username in an LDAP-protected system might be <code class="literal">CN=Harold Hacker,OU=Engineers,DC=red-bean,DC=com</code>. With usernames like that, the access file can become quite bloated with long or obscure usernames that are easy to mistype.</p> <p>Fortunately, Subversion 1.5 introduced username aliases to the access file syntax. Username aliases allow you to have to type the correct complex username only once, in a statement which assigns to it a more easily digestable alias.</p> <p>Username aliases are defined in the special <code class="literal">aliases</code> section of the access file, with each variable name in that section defining an alias, and the value of those variables carrying the real Subversion username which is being aliased.</p> <div class="informalexample"> <pre class="programlisting"> [aliases] harry = CN=Harold Hacker,OU=Engineers,DC=red-bean,DC=com sally = CN=Sally Swatterbug,OU=Engineers,DC=red-bean,DC=com joe = CN=Gerald I. Joseph,OU=Engineers,DC=red-bean,DC=com … </pre> </div> <p>Once you've defined a set of aliases, you can refer to the users elsewhere in the access file via their aliases in all the same places you could have instead used their actual usernames. Simply prepend an ampersand to the alias to distinguish it from a regular username:</p> <div class="informalexample"> <pre class="programlisting"> [groups] calc-developers = &harry, &sally, &joe paint-developers = &frank, &sally, &jane everyone = @calc-developers, @paint-developers </pre> </div> <p>You might also choose to use aliases if your users' usernames change frequently. Doing so allows you to need to update only the aliases table when these username changes occur, instead of doing global search-and-replace operations on the whole access file.</p> </div> <div class="sect2"> <div class="titlepage"> <div> <div> <h3 class="title"><a id="svn.serverconfig.pathbasedauthz.authclass-tokens"></a>Advanced Access Control Features</h3> </div> </div> </div> <p>Beginning with Subversion 1.5, the access file syntax also supports some <span class="quote">“<span class="quote">magic</span>”</span> tokens for helping you to make rule assignments based on the user's authentication class. One such token is the <code class="literal">$authenticated</code> token. Use this token where you would otherwise specify a username, alias, or group name in your authorization rules to declare the permissions granted to any user who has authenticated with any username at all. Similarly employed is the <code class="literal">$anonymous</code> token, except that it matches everyone who has <span class="emphasis"><em>not</em></span> authenticated with a username.</p> <div class="informalexample"> <pre class="programlisting"> [calendar:/projects/calendar] $anonymous = r $authenticated = rw </pre> </div> <p>Another handy bit of access file syntax magic is the use of the tilde (<code class="literal">~</code>) character as an exclusion marker. In your authorization rules, prefixing a username, alias, group name, or authentication class token with a tilde character will cause Subversion to apply the rule to users who do <span class="emphasis"><em>not</em></span> match the rule. Though somewhat unnecessarily obfuscated, the following block is equivalent to the one in the previous example:</p> <div class="informalexample"> <pre class="programlisting"> [calendar:/projects/calendar] ~$authenticated = r ~$anonymous = rw </pre> </div> <p>A less obvious example might be as follows:</p> <div class="informalexample"> <pre class="programlisting"> [groups] calc-developers = &harry, &sally, &joe calc-owners = &hewlett, &packard calc = @calc-developers, @calc-owners # Any calc participant has read-write access... [calc:/projects/calc] @calc = rw # ...but only allow the owners to make and modify release tags. [calc:/projects/calc/tags] ~@calc-owners = r </pre> </div> </div> <div class="sect2"> <div class="titlepage"> <div> <div> <h3 class="title"><a id="svn.serverconfig.pathbasedauthz.gotchas"></a>Some Gotchas with Access Control</h3> </div> </div> </div> <p>If you're using Apache as your Subversion server and have made certain subdirectories of your repository unreadable to certain users, you need to be aware of a possible nonoptimal behavior with <span class="command"><strong>svn checkout</strong></span>.</p> <p>Depending on which HTTP communication library the Subversion client is using, it may request that the entire payload of a checkout or update be delivered in a single (often large) response to the primary checkout/update request. When this happens, this single request is the <span class="emphasis"><em>only</em></span> opportunity Apache has to demand user authentication. This has some odd side effects. For example, if a certain subdirectory of the repository is readable only by user Sally, and user Harry checks out a parent directory, his client will respond to the initial authentication challenge as Harry. As the server generates the large response, there's no way it can resend an authentication challenge when it reaches the special subdirectory; thus the subdirectory is skipped altogether, rather than asking the user to reauthenticate as Sally at the right moment.</p> <p>In a similar way, if the root of the repository is anonymously world-readable, the entire checkout will be done without authentication—again, skipping the unreadable directory, rather than asking for authentication partway through.<a href="#ftn.idm9030" class="footnote" id="idm9030"><sup class="footnote">[72]</sup></a></p> </div> <div class="footnotes"> <br /> <hr style="width:100; text-align:left;margin-left: 0" /> <div id="ftn.idm8880" class="footnote"> <p><a href="#idm8880" class="para"><sup class="para">[70] </sup></a>A common theme in this book!</p> </div> <div id="ftn.idm8924" class="footnote"> <p><a href="#idm8924" class="para"><sup class="para">[71] </sup></a>Any human-readable name for a repository configured via the <code class="literal">SVNReposName</code> <code class="filename">httpd.conf</code> directive will be ignored by the authorization subsystem. Your access control file sections must refer to repositories by their server-sensitive paths as previously described.</p> </div> <div id="ftn.idm9030" class="footnote"> <p><a href="#idm9030" class="para"><sup class="para">[72] </sup></a>For more on this, see the blog post <span class="emphasis"><em>Authz and Anon Authn Agony</em></span> at <a class="ulink" href="http://blogs.collab.net/subversion/2007/03/authz_and_anon_/" target="_top">http://blogs.collab.net/subversion/2007/03/authz_and_anon_/</a>.</p> </div> </div> </div> <div class="navfooter"> <hr /> <table width="100%" summary="Navigation footer"> <tr> <td width="40%" align="left"><a accesskey="p" href="svn.serverconfig.httpd.html">Prev</a> </td> <td width="20%" align="center"> <a accesskey="u" href="svn.serverconfig.html">Up</a> </td> <td width="40%" align="right"> <a accesskey="n" href="svn.serverconfig.operational-logging.html">Next</a></td> </tr> <tr> <td width="40%" align="left" valign="top">httpd, the Apache HTTP Server </td> <td width="20%" align="center"> <a accesskey="h" href="index.html">Home</a> </td> <td width="40%" align="right" valign="top"> High-level Logging</td> </tr> </table> </div> <div xmlns="" id="vcws-footer"> <hr /> <img src="images/cc-by.png" style="float: right;" /> <p>You are reading <em>Version Control with Subversion</em> (for Subversion 1.8), by Ben Collins-Sussman, Brian W. Fitzpatrick, and C. Michael Pilato.</p> <p>This work is licensed under the <a href="http://creativecommons.org/licenses/by/2.0/">Creative Commons Attribution License v2.0</a>.</p> <p>To submit comments, corrections, or other contributions to the text, please visit <a href="http://www.svnbook.com/">http://www.svnbook.com/</a>.</p> </div> </body> </html>