You are not logged in Log in Join
You are here: Home » Members » Søren Roug » Certificate Mapping in Apache

Log in
Name

Password

 

Certificate Mapping in Apache

Beware that this how-to is work in progress!

Since I have some Zope webservices to support that use BasicAuth and I wanted to move towards certificates I was faced with the problem of having to convert the subject name of the client certificate to REMOTE_USER. The FakeBasicAuth of mod_ssl is unusable in this context as it produces a username that is different than the usernames already used in Zope.

So I managed to use mod_rewrite in Apache to create a mapping facility.

In the current installation I only want to require client authentication for the /admin subdirectory.

First the httpd.conf configuration:

(Server context - nothing unusual) 
SSLPassPhraseDialog  builtin 
SSLSessionCache         dbm:logs/ssl_scache 
SSLSessionCacheTimeout  300 
SSLMutex  file:logs/ssl_mutex 
SSLRandomSeed startup builtin 
SSLRandomSeed connect builtin 

(Virtual host context for SSL port) 
<VirtualHost _default_:443> 
SSLEngine on 
SSLCertificateFile    conf/butterfly.crt 
SSLCertificateKeyFile conf/butterfly.key 
SSLCACertificateFile  conf/ssl.crt/eionet-ca.crt
SSLVerifyClient       none 
SSLVerifyDepth        10 

RewriteMap dnmap txt:/etc/httpd/conf/certmap 
RewriteMap escape int:escape 
RewriteEngine on 

RewriteCond %{LA-U:SSL_CLIENT_S_DN} (..*) 
RewriteRule (.*) ${escape:%1} [C] 
RewriteRule (.*) - [e=REMOTE_USER:${dnmap:$1},C] 
RewriteRule .* %{REQUEST_URI} [L] 

<Location /admin> 
SSLVerifyClient require 
SSLVerifyDepth  1 
SSLOptions -StdEnvVars -FakeBasicAuth 
</Location> 
</VirtualHost> 

What happens here is that if there is an SSL_CLIENT_S_DN server variable, then the url gets rewritten with the SSL_CLIENT_S_DN for further processing. I escape the spaces in the DN and then I apply a rewritemap called dnmap, that contains the DN and the userid.

The content of the certmap file looks like this:
/L=Europe/O=EIONET/OU=Users/CN=Soren0Roug/Email=soren.roug@eea.eu.int mrroug

I have a small problem here; There is a space between Soren and Roug in the DN. I use the escape internal map to convert space into %20, but since the rewrite module takes the %2 and translates it into the empty string, what has to go into the mapping file is a 0 everywhere there was a space. I have been unable to get around this problem. Maybe if I used a dbm-file, and used a loading program that used tabs instead of space as a delimiter.

The next step is to configure Zope to use authentication through Apache. This is not covered here yet, but take a look on this:

Zope and IIS together in remote user mode
Primarily for Internet Information Server, but you can get some pointers from here
M2Crypto and ZServerSSL
An alternative that uses Python

Caveats

While the above looks like a simple way to provide single-signon, in practice it could reduce the security. Rather than entering a password from memory, the user presents a certificate stored on the computer's harddisk. You as a server administrator don't know if the user has a password on the certificate or not. Therefore if the user is careless with his certificate it could end up in the wrong hands. Even if it is protected with a password. If it gets stolen, the thief can leisurely apply many computers to run a dictionary attack on the password. Nobody would notice. If a password-guessing attack was perpetrated against a regular webserver with Basic-Auth, you would notice in the server log-files after a few hours (or weeks) and could terminate that account.

Nowadays we use certificates more as a two-factor login approach. You must present a valid certificate, but also login the normal way with Basic-Auth. We simply let Apache check the cert and Zope the login/password. Therefore the mapping business shown above is not used by us at the moment.

If you plan to do the same, here is what you put into Apache's configuration file:

#SSLCACertificatePath /etc/httpd/conf/ssl.crt
SSLCACertificateFile /etc/httpd/conf/ssl.crt/orgcacert.crt
orgcacert.crt is the CA certificate that you created with openssl. This ensures that only certificates generated/signed by your organization can be verified.
 SSLOptions +OptRenegotiate
 SSLVerifyClient require
 SSLVerifyDepth  1
<Location />
 SSLRequire %{SSL_CLIENT_S_DN_O} eq "Widget Company, Inc."
</Location>
This specifies that only user certificates whose O in the DN is Widget Company, Inc. can gain entry. That makes it possible for you to create certificates with other O content that can't be used for entry. Feel free to use any other field such as OU.