At this point, if you configured httpd.conf to contain something such as the following:
<Location /svn> DAV svn SVNParentPath /var/svn </Location>
your repository is “anonymously” accessible to the
world. Until you configure some authentication and authorization
policies, the Subversion repositories that you make available via the
Location
directive will be generally
accessible to everyone. In other words:
Anyone can use a Subversion client to check out a working copy of a repository URL (or any of its subdirectories).
Anyone can interactively browse the repository’s latest revision simply by pointing a web browser to the repository URL.
Anyone can commit to the repository.
Of course, you might have already set up a pre-commit
hook script to prevent
commits (see Implementing Repository Hooks). But as you
read on, you’ll see that it’s also possible to use Apache’s built-in
methods to restrict access in specific ways.
The easiest way to authenticate a client is via the HTTP Basic authentication mechanism, which simply uses a username and password to verify that a user is who she says she is. Apache provides an htpasswd utility for managing the list of acceptable usernames and passwords. Let’s grant commit access to Sally and Harry. First, we need to add them to the password file:
$ ### First time: use -c to create the file $ ### Use -m to use MD5 encryption of the password, which is more secure $ htpasswd -cm /etc/svn-auth-file harry New password: ***** Re-type new password: ***** Adding password for user harry $ htpasswd -m /etc/svn-auth-file sally New password: ******* Re-type new password: ******* Adding password for user sally
Next, you need to add some more httpd.conf directives inside your <Location>
block to tell Apache what
to do with your new password file. The AuthType
directive specifies the type of authentication system to use. In
this case, we want to specify the Basic
authentication system. AuthName
is an arbitrary name that you give
for the authentication domain. Most browsers will display this name in
the pop-up dialog box when the browser queries the user for her name
and password. Finally, use the AuthUserFile
directive to specify the
location of the password file you created using htpasswd.
After adding these three directives, your <Location>
block should look like
this:
<Location /svn> DAV svn SVNParentPath /var/svn AuthType Basic AuthName "Subversion repository" AuthUserFile /etc/svn-auth-file </Location>
This <Location>
block
is not yet complete, and it will not do anything useful. It’s merely
telling Apache that whenever authorization is required, Apache should
harvest a username and password from the Subversion client. What’s
missing here, however, are directives that tell Apache
which sorts of client requests require
authorization. Wherever authorization is required, Apache will demand
authentication as well. The simplest thing to do is protect all
requests. Adding Require valid-user
tells Apache that all requests require an authenticated user:
<Location /svn> DAV svn SVNParentPath /var/svn AuthType Basic AuthName "Subversion repository" AuthUserFile /etc/svn-auth-file Require valid-user </Location>
Be sure to read the next section (Authorization Options) for more details on the
Require
directive and other ways to
set authorization policies.
One word of warning: HTTP Basic Auth passwords pass in very nearly plain text over the network, and thus are extremely insecure.
Another option is to use Digest authentication instead of Basic. Digest authentication allows the server to verify the client’s identity without passing the plain-text password over the network. Assuming that the client and server both know the user’s password, they can verify that the password is the same by using it to apply a hashing function to a one-time bit of information. The server sends a small random-ish string to the client; the client uses the user’s password to hash the string; the server then looks to see whether the hashed value is what it expected.
Configuring Apache for Digest authentication is also fairly easy and only a small variation on our prior example. Be sure to consult Apache’s documentation for full details:
<Location /svn> DAV svn SVNParentPath /var/svn AuthType Digest AuthName "Subversion repository" AuthDigestDomain /svn/ AuthUserFile /etc/svn-auth-file Require valid-user </Location>
If you’re looking for maximum security, public key cryptography
is the best solution. It may be best to use some sort of SSL
encryption, so that clients authenticate via https://
instead of http://
. At a bare minimum, you can
configure Apache to use a self-signed server certificate.[45] Consult Apache’s documentation (and OpenSSL
documentation) about how to do that.
Businesses that need to expose their repositories for access outside the company firewall should be conscious of the possibility that unauthorized parties could be “sniffing” their network traffic. SSL makes that kind of unwanted attention less likely to result in sensitive data leaks.
If a Subversion client is compiled to use OpenSSL, it gains the
ability to speak to an Apache server via https://
URLs. The Neon library used by the Subversion client is not
only able to verify server certificates, but it can also supply client
certificates when challenged. When the client and server have
exchanged SSL certificates and successfully authenticated one another,
all further communication is encrypted via a session key.
It’s beyond the scope of this book to describe how to generate client and server certificates and how to configure Apache to use them. Many other books, including Apache’s own documentation, describe this task. But what we can cover here is how to manage server and client certificates from an ordinary Subversion client.
When speaking to Apache via https://
, a Subversion client can receive
two different types of information:
A server certificate
A demand for a client certificate
If the client receives a server certificate, it needs to verify that it trusts the certificate: is the server really who it claims to be? The OpenSSL library does this by examining the signer of the server certificate, or certificate authority (CA). If OpenSSL is unable to automatically trust the CA, or if some other problem occurs (such as an expired certificate or hostname mismatch), the Subversion command-line client will ask you whether you want to trust the server certificate anyway:
$ svn list https://host.example.com/repos/project Error validating server certificate for 'https://host.example.com:443': - The certificate is not issued by a trusted authority. Use the fingerprint to validate the certificate manually! Certificate information: - Hostname: host.example.com - Valid: from Jan 30 19:23:56 2004 GMT until Jan 30 19:23:56 2006 GMT - Issuer: CA, example.com, Sometown, California, US - Fingerprint: 7d:e1:a9:34:33:39:ba:6a:e9:a5:c4:22:98:7b:76:5c:92:a0:9c:7b (R)eject, accept (t)emporarily or accept (p)ermanently?
This dialogue should look familiar; it’s essentially the same
question you’ve probably seen coming from your web browser (which is
just another HTTP client like Subversion). If you choose the (p)
ermanent option, the server certificate
will be cached in your private runtime auth/ area in just the same way your
username and password are cached (see Client Credentials Caching). If cached,
Subversion will automatically trust this certificate in future
negotiations.
Your runtime servers file
also gives you the ability to make your Subversion client
automatically trust specific CAs, either globally or on a per-host
basis. Simply set the ssl-authority-files
variable to a semicolon-separated list of PEM-encoded CA
certificates:
[global] ssl-authority-files = /path/to/CAcert1.pem;/path/to/CAcert2.pem
Many OpenSSL installations also have a predefined set of “default”
CAs that are nearly universally trusted. To make the Subversion client
automatically trust these standard authorities, set the ssl-trust-default-ca
variable to true
.
When talking to Apache, a Subversion client might also receive a challenge for a client certificate. Apache is asking the client to identify itself: is the client really who it says it is? If all goes correctly, the Subversion client sends back a private certificate signed by a CA that Apache trusts. A client certificate is usually stored on disk in encrypted format, protected by a local password. When Subversion receives this challenge, it will ask you for a path to the certificate and the password that protects it:
$ svn list https://host.example.com/repos/project Authentication realm: https://host.example.com:443 Client certificate filename: /path/to/my/cert.p12 Passphrase for '/path/to/my/cert.p12': ******** ...
Notice that the client certificate is a “p12” file. To use a client certificate with Subversion, it must be in PKCS#12 format, which is a portable standard. Most web browsers are already able to import and export certificates in that format. Another option is to use the OpenSSL command-line tools to convert existing certificates into PKCS#12.
Again, the runtime servers file allows you to automate this challenge on a per-host basis. Either or both pieces of information can be described in runtime variables:
[groups] examplehost = host.example.com [examplehost] ssl-client-cert-file = /path/to/my/cert.p12 ssl-client-cert-password = somepassword
Once you’ve set the ssl-client-cert-file
and ssl-client-cert-password
variables, the Subversion client can automatically respond to a
client certificate challenge without prompting you.[46]
[45] Although self-signed server certificates are still vulnerable to a “man-in-the-middle” attack, such an attack is much more difficult for a casual observer to pull off, compared to sniffing unprotected passwords.
[46] More security-conscious folk might not want to store the client certificate password in the runtime servers file.