We wish to restrict access on our development server to those users who have a valid SSL Client certificate. We are running Apache 2.2.16 on Debian 6.
However, for some sections (mainly git-http, setup with gitolite on https://my.server/git/) we need an exception since many git clients don't support SSL client certificates.
I have succeeded in requiring client cert authentication for the server, and in adding exceptions for some locations. However, it seems this does not work for git.
The current setup is as follows:
SSLCACertificateFile ssl-certs/client-ca-certs.crt
<Location />
SSLVerifyClient require
SSLVerifyDepth 2
</Location>
# this works
<Location /foo>
SSLVerifyClient none
</Location>
# this does not
<Location /git>
SSLVerifyClient none
</Location>
I have also tried an alternative solution, with the same results:
# require authentication everywhere except /git and /foo
<LocationMatch "^/(?!git|foo)">
SSLVerifyClient require
SSLVerifyDepth 2
</LocationMatch>
In both these cases, a user without client certificate can perfectly access my.server/foo/, but not my.server/git/ (access is refused because no valid client certificate is given). If I disable SSL client certificate authentication completely, my.server/git/ works ok.
The ScriptAlias problem
Gitolite is setup using the ScriptAlias directive. I have found that the problem occurs with any similar ScriptAlias:
# Gitolite
ScriptAlias /git/ /path/to/gitolite-shell/
ScriptAlias /gitmob/ /path/to/gitolite-shell/
# My test
ScriptAlias /test/ /path/to/test/script/
Note that /path/to/test/script is a file, not a directory, the same goes for /path/to/gitolite-shell/
My test script simply prints out the environment, super simple:
#!/usr/bin/perl
print "Content-type:text/plain\n\n";
print "TEST\n";
@keys = sort(keys %ENV);
foreach (@keys) {
print "$_ => $ENV{$_}\n";
}
It seems that if I go to https://my.server/test/someLocation, that any SSLVerifyClient directives are being applied which are in Location blocks that match /test/someLocation or just /someLocation.
If I have the following config:
<LocationMatch "^/f">
SSLVerifyClient require
SSLVerifyDepth 2
</LocationMatch>
Then, the following URL requires a client certificate: https://my.server/test/foo. However, the following URL does not: https://my.server/test/somethingElse/foo
Note that this only seems to apply for SSL configuration. The following has no effect whatsoever on https://my.server/test/foo:
<LocationMatch "^/f">
Order allow,deny
Deny from all
</LocationMatch>
However, it does block access to https://my.server/foo.
This presents a major problem for cases where I have some project running at https://my.server/project (which has to require SSL client certificate authorization), and there is a git repository for that project at https://my.server/git/project which cannot require a SSL client certificate. Since the /git/project URL also gets matched agains /project Location blocks, such a configuration seems impossible given my current findings.
Question: Why is this happening, and how do I solve my problem?
In the end, I want to require SSL Client certificate authorization for the whole server except for /git and /someLocation, with as minimal configuration as possible (so I don't have to modify the configuration each time something new is deployed or a new git repository is added).
Note: I rewrote my question (instead of just adding more updates at the bottom) to take into account my new findings and hopefully make this more clear.