Showing posts with label subversion. Show all posts
Showing posts with label subversion. Show all posts

Thursday, 22 March 2007

apache settings for svnparentpath

Subversion http://subversion.tigris.org/ is a wonderful open-sourced version control system. With the mighty apache http://www.apache.org/, you can do very fine access control.

Here I record a small trick to deal with a problem when I set up apache+subversion.

For apache to view a subversion repository, you can either use SVNPath or SVNParentPath directive (you have to make sure the WedDAV is enabled). The former explicitly specify the location of a repository; the latter, as the name hints, specify the parent path of several repositories. This is quite handy when you want to host multiple repsitories. You just put all of them in the same directory and apache will pick them up automatically. So you don’t need to change the apache configuration everytime you add/delete a repository, if you use SVNParentPath over SVNPath.

But there will be a minor problem here. For example you decide to put repositories repo1, repo2, repo3, ... under /var/svn/ directory, and you set apache to browse them as http://www.mysite.org/svn/repo1/, ..., which is all fine, until you type http://www.mysite.org/svn/ in your browser address bar. Err, what have you got? An ulgy svndav error message. The reason is because /var/svn itself is not a repository, all its subdirectories are.

So what you can do to get rid of the scaring error message?

The apache mod_rewrite comes to rescue!

At least you have two choices here. Both use mod-rewrite to make apache serve the browser with a different url: (1) you rewrite the request with another page where all available repositories are listed (you’ll update that simple page whenever you add/remove a repository of course); (2) you redirect the request to a default repository you chosen (this works only when the default repository is not removed/renamed of course). You can choose whichever you like. But I found the second choice is suitable for apache virtual hosts where you don’t want a request escaping the virtual host scope.

Here is the sample part of /etc/httpd/conf/httpd.conf for the first option: (you browse http://www.mysite.org/svn/ and get a proxy page, http://www.mysite.org/svnrepo.html, where you can list all available repositories)

# subversion settings

DAV svn
# Set the parent path for all repositories.
SVNParentPath /var/svn
# Turn off all path-based authorization thus increase speed (default is on).
SVNPathAuthz Off
# For per-directory access control policy
#AuthzSVNAccessFile /var/svn/httpaccess
# Limit write permission to list of valid users.

AuthType Basic
AuthName "My Subversion Repository"
AuthUserFile /var/svn/httpauth
Require valid-user

# Use mod_rewrite to serve a proxy page if unspecified.
# Otherwise requests on /svn/ receive a DAV-SVN error as the directory
# itself is not a repository - its subdirectories are.
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/svn/$
# can rewrite to a full url or better only rewrite to the requested uri
# Also note the P or proxy flag here for proxy.
#RewriteRule /svn/ http://svn.mysite.org/svnrepo.html [proxy]
RewriteRule /svn/ /svnrepo.html [proxy]

and here is sample for the second option: (you browse http://svn.mysite.org/ and get redirected to the default repository, http://svn.mysite.org/software/)

# subversion settings

# DocumentRoot has actually no effect here.
# In fact it should be omitted to avoid confusion.
#DocumentRoot /var/svn
ServerName svn.mysite.org

DAV svn
# Set the parent path for all repositories.
SVNParentPath /var/svn
# Turn off all path-based authorization thus increase speed (default is on).
SVNPathAuthz Off
# For per-directory access control policy
#AuthzSVNAccessFile /var/svn/httpaccess
# Limit write permission to list of valid users.

AuthType Basic
AuthName "My Subversion Repository"
AuthUserFile /var/svn/httpauth
Require valid-user

# Use mod_rewrite to set default repository if unspecified.
# Otherwise requests on / receive a DAV-SVN error as the directory
# itself is not a repository - its subdirectories are.
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/$
# can rewrite to a full url or better only rewrite to the requested uri
#RewriteRule / http://svn.mysite.org/software/ [redirect=permanent]
RewriteRule / /software/ [redirect=permanent]

Note:

  1. In above samples, the basic apache authentication is used. Anonymous users can read the repositories but only authenticated users have write accresses. The authentication info is stored in /var/svn/httpauth which is managed by the htpasswd utility.
  2. The above two samples assume you have webdav and svndav modules loaded appropriately. In most case the modules are enabled with a seperate apache configuration file, say, /etc/httpd/conf.d/subversion.conf, whilst I recommend to put the above configurations in the apache master confoguration file, /etc/httpd/conf/httpd.conf.

Update:

  1. Since v1.3 and later versions of subversion (specifically, mod_dav_svn), the Apache httpd-based server can now display (in a web browser) the collection of repositories exported by the SVNParentPath directive: simply set ‘SVNListParentPath on’ in the apache configuration file. Therefore, the hack described in this page is now largely irrelevant. ;)

re-root subversion with svn+ssh schema

It is simple to re-root a subversion repository with svn+ssh accessing schema.

The easiest one to re-define the svn command as an alias. For example, if you have repo1, repo2, ... in /var/svn directory. Usually you access them with svn+ssh://myserver/var/svn/repo1/, svn+ssh://myserver/var/svn/repo2/, ...

Now if you want to access them with shortened URLs, like svn+ssh://myserver/repo1/, svn+ssh://myserver/repo2/, ... What can you do?

You can compose a simple script like this:

#!/bin/sh
# /usr/local/bin/svnserve
# This script redefines the svn command so that svn repositories are re-rooted.
# Please make sure this script is before the system command, /usr/bin/svn, in
# the search path. Also please note the proper quotation for commandline options.
#alias svnserve='/usr/bin/svnserve -r /var/svn "$@"'
/usr/bin/svnserve -r /var/svn "$@"

and put it in /usr/local/bin/ and name it as svnserve as well. This is because the OpenSSH server built with default compilation options will put /usr/local/bin before /usr/bin in the searching path for executables.

The above method works when you have a system account on the server.

With new version of OpenSSH, a nice feature called proxy command is added. So you can let multiple users access a subversion repository, using the same system account but with different identities! Say, you decide to use a system account, svn, for this. Then you need to hack ~svn/.ssh/config and ~svn/.ssh/authorised_keys, where ~svn refers to the home directory of the svn account as usual, and in our case, it would be /var/svn.

I’ve got the second method worked but it is slightly complicated. It involves defining proxy commands for different public keys. Check ssh_config and sshd_config manpages for the syntax of ~/.ssh/authorised_keys file.

Oh, did I mention that for this to work you have to use key-based authentication for ssh? You better use key-based authentication for svn+ssh accesses anyway. Otherwise you’ll get bored to type in your password again and again as subversion doesn’t accept pushed client authentication. According to the subversion design document, this is on purpose. It pulls authentication info from a client whenever needed, for a better security.


Additioanlly, on the client side you can define your own schema with this svn+ approach. The following example defines an essh command which is actually a wrapper to the ssh command:

#!/bin/sh
# ~/bin/essh
# a wrap script for svn+ssh scheme to define the svnserve root directory
# the evniroment variable SVN_SSH should be set to this script
/usr/bin/ssh $1 /usr/bin/svnserve -r /var/svn/ -t

With this command defined, you can now access the respository sitting at /var/svn/software/ with the URL below

svn+essh://myserver/software/

Apparently you can insert in more options into the wrapper script. For example, you change the last line to:

/usr/bin/ssh -l svn $1 /usr/bin/svnserve -r /var/svn/software/ -t

or

/usr/bin/ssh $1 /usr/bin/svnserve -r /var/svn/software/ -t --tunnel-user svn

then you access the same repository with svn+essh://myserver/ URL and you always login as user svn.