Setting up a Build Environment under Windows, using Subversion (Part 2)

This is part 2 in a multi-part series about setting up a build environment under Windows, featuring Subversion. In Part 1, we've set up an Apache Web Server and made it happily live next to an IIS Web Server. In part 2, we will now answer the question "Where's the beef?", or more precisely, we'll set up Subversion.

Part 2: Installing Subversion with Apache integration and user authentication

Ok, Apache is up and running, now let's set up Subversion. Head over to the Subversion Download site, and download Subversion. Important: Make sure to get a Version that is compatible with your Apache version. I assume you use Apache 2.2, and the link in this article leads to a Apache 2.2 compatible Version. At the time of writing, svn-1.4.6-setup.exe was the most recent file to download.

Installation is straight-forward: Download and execute the file and click "Next" until it's finished – no rocket science involved here.

Integrating Subversion with Apache

You might now ask: Why integrate Subversion with Apache? After all, you could just put your repository on a File Share and have your users use file:// URLs to access the repository. Let me quote the Subversion book here:

  • Allows Subversion to use any of the numerous authentication systems already integrated with Apache.
  • No need to create system accounts on server.
  • Full Apache logging.
  • Network traffic can be encrypted via SSL.
  • HTTP(S) can usually go through corporate firewalls.
  • Built-in repository browsing via web browser.
  • Repository can be mounted as a network drive for transparent version control.

While there are a few drawbacks (It's a bit slower than file:// or the Subversion-svnserve, and it's a bit more complicated to set up), the main advantages are SSL support, Repository Browsing (while this is rather simple, I found it a very useful feature quite often) and User Authentication that works with any of the eleventy billion ways Apache can do user authentication.

Ok, so let's create a folder for our Subversion repositories. You can setup different authentication for each repository, which is needed when you want to give some people access to only some repositories or when you want people to be able to read but not commit to some repositories while they can commit to others. You can also use different authentication methods, i.e. have the user credentials for some repositories stored in a MySQL database while other repositories use a password file.

To keep the example simple, I use 1 password file that applies to the whole repository tree. I've created a new folder c:\repos and inside that folder, I've created 2 Repositories, repo1 and repo2.

Now, we need to install one module into Apache that comes with Subversion. Open your Subversion\bin folder and copy mod_dav_svn.so to your Apache\modules folder.

Now, open your conf\httpd.conf and look for this line:
#LoadModule dav_module modules/mod_dav.so

Uncomment this line, and add a new line for the Subversion Module:
LoadModule dav_module modules/mod_dav.so
LoadModule dav_svn_module modules/mod_dav_svn.so

That will load the Modules when Apache restarts. But we're not done yet. We now need to tell Apache about our Repository.

Telling Apache about our repository

Scroll to the very bottom of the file and add this block (I'll tell you about what each of these settings mean in a Minute, don't worry):
<Location /svn>
DAV svn
SVNParentPath c:\repos
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile c:\svn-user-file
Require valid-user
</Location>

Ok, the first Setting is the <Location> Tag. This is the virtual Path on your Website to which this section applies.
In other words: We have just created http://blogtest/svn and these settings will apply to it.
DAV svn tells Apache to use the mod_dav Module, and it tells the mod_dav module to use SVN here. Essentially, this like makes sure that the Subversion Apache Module is used here.

The next Setting is SVNParentPath. This setting points to the folder which we created earlier to hold our repositories. Now, there is one important thing to know about this setting: This is only to be used if you have multiple repositories under one common parent directory! In our case, we got repo1 and repo2 under c:\repos, and we want both to be accessible with the same settings. If you do not want to use multiple repositories or if you want to have specific settings for one repository, create a <Location> and use SVNPath instead. I will make an example for this later in this article, so if you are confused right now, just keep in mind: SVNParentPath = Multiple Repositories, SVNPath = Single Repository.

The next four lines are our settings for Authentication.
AuthType is the type of authentication used, and commonly, there are two options: "Basic" and "Digest". Basic authentication sends your password in cleartext over the line, whereas Digest encrypts it. Unfortunately, Digest is not very well supported by the SVN Client, which leaves us with Basic. If you are worried that your password may be sniffed or if you are accessing your SVN Server through the internet, make sure to use HTTPS instead of HTTP in your Apache!

AuthName is just a name that will be displayed to your user.

AuthUserFile is the file where we will store our usernames and passwords. We will create this file in a minute; let's just say for now that you should put this in a secure location.

Require will tell Apache which users can authenticate. Valid-user is any user in our password file.

Save this, restart Apache and try to access http://blogtest/svn/repo1 - you should get a Password prompt. Cancel for now, as you can't authenticate anyway yet.

Creating the User file

Ok, Apache is all set, we want to create a user file now. We will use the Apache htpasswd tool, which you find in the Apache\bin directory.
htpasswd -cm c:\svn-user-file pgibbons

This will create the user file (-c) and add our first user, pgibbons. It will also ask us for a password.

Adding a second user is done without the –c switch, only –m is used:
htpassmd -m c:\svn-user-file snagheenanajar

Make sure to read the section about security concern at the bottom of this article! We now have 2 users in our user file. Try accessing the site now and log in as pgibbons – if all went good, you should see your repository now.

Please be aware that you have to give the full link to the repository. For example: http://blogtest/svn/repo1/ and http://blogtest/svn/repo2/ work, but http://blogtest/svn/ will not work and give a 403 forbidden error instead.

Your repository can also be accessed through any Subversion client, be it the command line svn.exe or for example TortoiseSVN:

 

Congratulations! You have just set up a Subversion Repository that is accessed through Apache Web Server and uses user authentication.

Bonus: Different Permissions for one repository

Ok, let's say we have a third repository, where everyone (including anonymous users) can read, but only 1 developer can commit. In our example, the repository is c:\repos\repo3 and only snagheenanajar should be able to commit to this. In your Apache httpd.conf, under your existing </Location> tag, add this:

<Location /svn/repo3>
DAV svn
SVNPath c:\repos\repo3
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile c:\svn-user-file
<LimitExcept GET PROPFIND OPTIONS REPORT>
Require snagheenanajar
</LimitExcept>
</Location>

First off, the <Location> needs to be the name of your Repository, so that it overrides the previous setting that applied to the whole /svn virtual directory.

Then, notice that we use SVNPath instead of SVNParentPath. Remember: Multiple Repositories = SVNParentPath, Single Repository = SVNPath. As this section applies explicitely to repo3, we use SVNPath. The next 3 lines are our standard Auth Settings, but then it gets interesting. Essentially, we are telling the module to only Require user authentication if the commands are not one of the listed ones.

That means: Everyone is able to GET, PROPFIND, OPTIONS or REPORT, i.e. everyone can browse and check-out the repository. Try it: While http://blogtest/svn/repo1/ asks you for a user login, http://blogtest/svn/repo3/ does not. Now, if you want to commit, you will be asked as commit is not listed in the <LimitExcept>-clause. Here, instead of "Require valid-user", we explicitely require snagheenanajar as our user, which means that only he can commit to this repository.

Security Concern: Adding new users

When we add new users, we execute htpasswd and type in the credentials – but wait, we need to type in the password, which means that the Admin needs to know the user password. That is bad practice and should not be done. Instead, ask your users to generate their password hashes and only send you the hash. To do that, copy htpasswd.exe from your Apache\bin directory somewhere where it is accessible and have your users create their passwords using the -n switch:
htpasswd -m -n mbolton

Ask them to send you the line that they receive, and add it to the bottom of your userfile. You do not need to restart Apache when you change the user file by the way.

There are various other options available instead of using htpasswd. For example, have a web application where the user just types in username and password, and the result is automatically mailed to the admin or automatically added to the file – be creative, but always keep in mind that telling the Admin the password in cleartext is a big No-No.

 

That concludes Part 2 of this series. You now have a working Subversion Environment that supports User Authentication and runs on a Windows Server. In the next Article of this series, we look at automated backups, because Source Control is worthless without backups.

Comments (3)

[...] a specific version, it is really only if you want to use Subversion with Apache, as outlined in an older article by me). If you ARE using Apache, I don’t really know how you could resolve it. One guess is to [...]

RaviAugust 11th, 2009 at 11:41

I learnt a lot from these articles on Subversion for Windows. Any plans on writing part 3 & 4.

sandrarSeptember 10th, 2009 at 22:38

Hi! I was surfing and found your blog post... nice! I love your blog. 🙂 Cheers! Sandra. R.