Authz and Anon Authn Agony
A recent first-time attempt at using Subversion’s path-based authorization module turned out to be less trivial than I’d planned because I was trying to use it with a repository that allowed anonymous read access. Things went well at first — I did some copying and pasting of sample httpd.conf directives and authz file contents from Version Control with Subversion, tweaking as necessary to suit my needs. In a short time, I had what I thought was the perfect setup. I was wrong.
Say, like me, you wish to configure a repository such that it permits anonymous reads to most of it, authenticated reads to the rest of it, and authenticated writes to the whole thing. You already have an Apache htpasswd file with your writers’ usernames and password hashes, and you’ve configured Apache to use that htpasswd file for authentication, and an authz file for authorization. You then make the obvious additions to your authz file:
[groups] writers = someuser1, someuser2, … [repository:/] * = r @writers = rw [repository:/trunk/private-area] * = @writers = rw
There’s a group with your writers’ usernames. There’s a rule which grants anonymous read to the world, and write access to just the writers. And there’s an override rule which removes read access from unauthenticated users in the repository’s private area. Looks great.
Then you start testing.
Upon checking out your repository’s /trunk directory, anonymous users get what you’d expect — the tree, minus the /trunk/private-area directory.
But what about your authenticated would-be writers? Ah, therein lies the rub! There are no authenticated users. Since anonymous users can checkout the tree, Apache never bothers to query you for authentication credentials. And you can’t force Subversion to transmit authentication credentials when Apache hasn’t asked for them.
So what’s the workaround?
First, you could disable anonymous access altogether, and force non-writers to share a username like “anonymous” and a publicized password. In your authz rules, the user “anonymous” would have only read permission, and only on the public portion of the repository. This works fine, but at some discomfort to non-writers. They now have to supply a password which, though not secret, might still be non-obvious and/or unknown to them.
Secondly, you could just leave things the way they are, and force writers to checkout just the private area of the repository separately. They won’t have the luxury of both the public and private areas being connected inside a single working copy, but that might be okay.
Thirdly, you could keep the private stuff in its own repository. For writers, this is very similar to the second workaround. But your writers won’t be able to make a private thing public without breaking the history across repositories.
Finally, you could setup a second <Location> block in your httpd.conf file which points to the same repository but with a slightly different URL (for example, with “-no-anon” appended to it). In this block, disallow anonymous access. Then add a matching redundant entry in your authz file, too:
[repository-no-anon:/] * = @writers = rw
Now, anonymous non-writers can checkout from the original repository URL without prompting, and won’t see the private area. Non-anonymous writers can checkout from the alternate repository URL with prompting, and will see the private area. (Thanks to Max Bowsher for this great hybrid workaround idea.)