|  | -*- text -*- | 
|  |  | 
|  | This file documents what users should expect from path-based authz, | 
|  | and the responsibilities of the implementor of said feature. | 
|  |  | 
|  |  | 
|  | ============================================================================ | 
|  | WHAT USERS SHOULD EXPECT FROM PATH-BASED AUTHZ | 
|  | ============================================================================ | 
|  |  | 
|  | 1. CHECKOUTS | 
|  |  | 
|  | Unreadable paths will not be downloaded into a working copy. | 
|  | However, 'svn update' may cause working paths to disappear or | 
|  | re-appear based on changing server authorization policies. | 
|  |  | 
|  | (Note: the .svn/entries file may still leak the name of the | 
|  | unreadable path; see the 'Known Leakage' section below.) | 
|  |  | 
|  |  | 
|  | 2. LOG MESSAGES | 
|  |  | 
|  | Log information may be restricted, based on readability of | 
|  | changed-paths. | 
|  |  | 
|  | * If the target of 'svn log' wanders into unreadable territory, | 
|  | then log output will simply stop at the last readable revision. | 
|  | If the log is tracing backwards through time, as the plain | 
|  | "svn log" command does, the target will appear to be added | 
|  | (without history) in that revision. | 
|  |  | 
|  | * If a revision returned by 'svn log' contains a mixture of | 
|  | readable/unreadable changed-paths, then the log message is | 
|  | suppressed, along with the unreadable changed-paths.  Only the | 
|  | revision number, author, date, and readable paths are | 
|  | displayed. | 
|  |  | 
|  | * If a revision returned by 'svn log' contains only unreadable | 
|  | changed-paths, then only the revision number is displayed. | 
|  |  | 
|  | It's an official recommendation ("best practice") to avoid the | 
|  | "mixed" changed-path situation; users should avoid making a single | 
|  | commit that includes changes to files in both readable and | 
|  | unreadable areas.  This scenario is quite annoying for people who | 
|  | can't read all the changed-paths. | 
|  |  | 
|  |  | 
|  | 3. COPIES (BRANCHING AND TAGGING) | 
|  |  | 
|  | Subversion does O(1) copies of entire trees, but unfortunately, | 
|  | this isn't completely compatible with path-based access control. | 
|  | In order to copy an entire tree, every path in the tree must be | 
|  | checked for readability: this is an O(N) operation. | 
|  |  | 
|  | Depending on the specific path-based authz module being used, | 
|  | however, there are sometimes solutions that aren't quite so | 
|  | expensive as O(N). | 
|  |  | 
|  |  | 
|  | 4. TRACING PATH CHANGES | 
|  |  | 
|  | If a Subversion 1.1 client attempts to fetch an older version of a | 
|  | file or directory, e.g.: | 
|  |  | 
|  | svn cat -r5 foo.c | 
|  | svn diff -r10:28 bar.c | 
|  |  | 
|  | ...then there is a potential for failure, should older versions of | 
|  | the file exist at unreadable paths.  In other words, the tracing of | 
|  | copies/renames is subject to readability checks. | 
|  |  | 
|  | If history-tracing wanders into unreadable territory, the process | 
|  | halts; no further information is retrieved. | 
|  |  | 
|  | Example 1: while 'bar.c' might be perfectly readable in both | 
|  | revisions 10 and 28, the 'svn diff' command (above) will return | 
|  | error if the file has an unreadable ancestor somewhere between | 
|  | those two revisions. | 
|  |  | 
|  | Example 2: 'svn blame bar.c' will not be able to retrieve | 
|  | unauthorized versions of a file, or any ancestors that precede | 
|  | it.  So it will appear that 'bar.c' was wholly added -- without | 
|  | history -- in the first public version *after* the unreadable | 
|  | version. | 
|  |  | 
|  | So again, an official recommendation ("best practice") is to avoid | 
|  | renaming or copying files between public and private areas.  For | 
|  | users without omnipotent read permissions, this will make renames | 
|  | difficult to follow, and client commands which attempt to trace | 
|  | history are likely to fail. | 
|  |  | 
|  |  | 
|  | 5. REVISION PROPERTIES | 
|  |  | 
|  | Users are allowed to attach arbitrary, unversioned properties to | 
|  | revisions.  Additionally, most revisions also have "standard" | 
|  | revision props (revprops), such as svn:author, svn:date, and | 
|  | svn:log.  Access to revprops may be restricted, based on | 
|  | readability of changed-paths. | 
|  |  | 
|  | * If a revision contains nothing but unreadable changed-paths, | 
|  | then all revprops are unreadable and unwritable. | 
|  |  | 
|  | * If a revision has a mixture of readable/unreadable | 
|  | changed-paths, then all revprops are unreadable, except for | 
|  | svn:author and svn:date.  All revprops are unwritable. | 
|  |  | 
|  | It's an official recommendation ("best practice") to avoid the | 
|  | latter situation; users should avoid making a single commit that | 
|  | includes changes to files in both readable and unreadable areas. | 
|  | This situation is quite annoying for people who can't read all the | 
|  | changed-paths. | 
|  |  | 
|  |  | 
|  | 6. KNOWN LEAKAGE OF UNREADABLE PATHS | 
|  |  | 
|  | Subversion may (occasionally) leak knowledge of the existence of an | 
|  | unreadable path.  However, the *contents* of an unreadable file or | 
|  | directory will never be leaked. | 
|  |  | 
|  | Here are the known times when this happens: | 
|  |  | 
|  | * 'svn ls directory-URL': an unreadable directory entry is still | 
|  | listed along with other entries. | 
|  |  | 
|  | * 'svn checkout/update': an unreadable child doesn't appear in | 
|  | the working copy, but the .svn/entries file still contains an | 
|  | entry for it (marked 'absent'). | 
|  |  | 
|  | 7. LOCKING | 
|  |  | 
|  | If a client attempts to lock or unlock an unreadable path, the | 
|  | command will fail.  If a client attempts to retrieve a lock on one | 
|  | path, or a list of all locks "below" a directory, only readable | 
|  | paths will ever be returned; unreadable locked paths remain | 
|  | unknown. | 
|  |  | 
|  |  | 
|  | ============================================================================ | 
|  | HOW TO IMPLEMENT PATH-BASED AUTHZ | 
|  | ============================================================================ | 
|  |  | 
|  | If an RA server implementation wants to implement path-based authz, | 
|  | here are its responsibilities: | 
|  |  | 
|  | 1. Implement a read-authz callback (see svn_repos_authz_read_func_t), | 
|  | and pass it to the following svn_repos.h functions: | 
|  |  | 
|  | svn_repos_begin_report() | 
|  | svn_repos_dir_delta() | 
|  | svn_repos_history2() | 
|  | svn_repos_get_logs3() | 
|  | svn_repos_trace_node_locations() | 
|  | svn_repos_get_file_revs() | 
|  | svn_repos_fs_get_locks() | 
|  | svn_repos_fs_change_rev_prop2() | 
|  | svn_repos_fs_revision_prop() | 
|  | svn_repos_fs_revision_proplist() | 
|  | svn_repos_get_commit_editor3() | 
|  | svn_repos_replay2() | 
|  |  | 
|  | 2. Manually implement authz for incoming network requests that | 
|  | represent calls to: | 
|  |  | 
|  | RA->get_file() | 
|  | RA->get_dir() | 
|  | RA->check_path() | 
|  | RA->stat() | 
|  | RA->lock() | 
|  | RA->lock_many() | 
|  | RA->unlock() | 
|  | RA->unlock_many() | 
|  | RA->get_lock() | 
|  |  | 
|  | (These concepts aren't wrapped by libsvn_repos because it's just | 
|  | as easy to call an authz func directly on a single path, rather | 
|  | than pass it to a repos wrapper.) | 
|  |  | 
|  | 3. Manually implement authz when receiving network requests that | 
|  | represent calls to a commit editor: | 
|  |  | 
|  | - do write checks for most editor operations | 
|  | - do read *and* write checks for copy operations. | 
|  |  | 
|  | (Note that doing full-out authz on whole trees fundamentally | 
|  | contradicts Subversion's O(1) copy philosophy; in practice, | 
|  | however, specific authz implementations are able to get the same | 
|  | effect while being less expensive than O(N).) |