How do I configure apache to accept a client ssl certificate (if present) or authenticate using ldap (if the cert is absent)?
Solution 1:
This is somewhat of a guess (I don't have any easy way to try this) but perhaps some combination of SSLOptions +FakeBasicAuth
and Satisfy Any
will see you through?
Solution 2:
I've figured out a way of doing this for both Apache 2.2 and 2.4, will need some final cleanup for whatever your needs are though, but the tricky bit should be done (or at least done enough for anyone else to figure out where to go from here).
Both configurations result in the same end goal: a client/user may supply a certificate, if none is provided they'll be prompted for LDAP credentials.
You'll need to enable mod_ssl and mod_authnz_ldap. For Apache 2.2 you'll also need to enable mod_rewrite and mod_alias.
Apache 2.4 introduces a general purpose If/ElseIf/Else directive which simplifies this task greatly: http://httpd.apache.org/docs/current/mod/core.html#if
I'm not an Apache guru, so there may be something horribly wrong with what I've done, but it does seem to achieve the state purpose.
Apache 2.2:
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerName Dummy-testing-kbd
ServerAdmin webmaster@localhost
# Normal HTTPS Server Certificate Config
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/server.crt
SSLCertificateKeyFile /etc/apache2/ssl/server.key
# End HTTPS Config
DocumentRoot /var/www
Alias /ldap /
<Location /ldap/>
# LDAP Authentication Config
AuthType Basic
AuthBasicProvider ldap
AuthzLDAPAuthoritative on
AuthName "Password Protected. Enter your AD Username and Password"
AuthLDAPURL "ldaps://ldaps-auth.mydomain.com/OU=People,DC=mydomain"
Require valid-user
# End LDAP
</Location>
<Location />
# Client Cert Config
SSLRequireSSL
SSLCACertificateFile /etc/ssl/ca/private/ca.crt
SSLVerifyClient optional
SSLVerifyDepth 2
# Populate REMOTE_USER with the value from the client certificate
SSLUserName SSL_CLIENT_S_DN_CN
# End Client Cert Config
# Hacky way to use an internal redirect to force LDAP authentication if the certificate didn't populate the REMOTE_USER variable
RewriteEngine on
RewriteCond %{REMOTE_USER} ^$
RewriteRule (.*) /ldap/$1 [L]
</Location>
ErrorLog ${APACHE_LOG_DIR}/cert_or_ldap_error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel debug
CustomLog ${APACHE_LOG_DIR}/cert_or_ldap_access.log combined
</VirtualHost>
</IfModule>
Apache 2.4:
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerName Dummy-testing-kbd2
ServerAdmin webmaster@localhost
# Normal HTTPS Server Certificate Config
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/server.crt
SSLCertificateKeyFile /etc/apache2/ssl/server.key
# End HTTPS Config
# Client Cert Config - setup Certificate Authority
SSLCACertificateFile /etc/ssl/ca/private/ca.crt
# End Client Cert Config
DocumentRoot /var/www
<Location />
# Client Cert Config
SSLRequireSSL
SSLVerifyClient optional
SSLVerifyDepth 2
# Populate REMOTE_USER with the value from the client certificate
SSLUserName SSL_CLIENT_S_DN_CN
# End Client Cert Config
# Configuring LDAP:
# If no REMOTE_USER is defined (by the certificate) then do LDAP authentication
<If "-z %{REMOTE_USER}">
AuthType Basic
AuthBasicProvider ldap
AuthName "Password Protected. Enter your AD Username and Password"
AuthLDAPURL "ldaps://ldaps-auth.mydomain.com/OU=People,DC=mydomain"
Require valid-user
</If>
# End LDAP
</Location>
ErrorLog ${APACHE_LOG_DIR}/cert_or_ldap_error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel debug
CustomLog ${APACHE_LOG_DIR}/cert_or_ldap_access.log combined
</VirtualHost>
</IfModule>