ScriptAlias makes requests match too many Location blocks. What is going on?

Posted by brain99 on Server Fault See other posts from Server Fault or by brain99
Published on 2012-08-24T08:29:18Z Indexed on 2012/08/28 9:40 UTC
Read the original article Hit count: 303

Filed under:
|
|
|

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.

© Server Fault or respective owner

Related posts about apache2

Related posts about ssl