You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modules-dev@httpd.apache.org by "Thomas, Peter" <pt...@HPTI.com> on 2010/03/24 21:54:16 UTC

In-progress review: adding "AuthType Certificate" to integrate Apache web server's mod_ssl & mod_authnz_ldap modules

All:

I've been working on integrating mod_ssl and mod_authnz_ldap for
non-password-based environments.  I contemplate "AuthType Certificate"
in https://issues.apache.org/bugzilla/show_bug.cgi?id=48780 .  This
enhancement is targeted for environments where the user is authenticated
if they:

1) present a valid SSL client certificate, and
2) a single object corresponding[*1] to that user's certificate exists
at the targeted LDAP server.

To take advantage of the flexibility and utility of the existing module,
I'm extending mod_authnz_ldap instead of writing a separate handler. For
example, once authenticated one can then leverage the "Require ldap-*"
directives in mod_authnz_ldap.  mod_authnz_ldap also populates the
environment with all requested LDAP attributes in AUTHENTICATE_*
environment variables. These can be used in subsequent request
processing [such as fine-grained access control or other logic within
request handlers].

To implement the initial "DN matching" approach, I had to make a change
to mod_ssl.c to pull out an RFC2253 compliant representation of the
subject DN.  My debugging so far suggests this may be causing me
problems--I've included the patch diff at the end of this e-mail for
review and suggestions.

I hope to have a comprehensive prototype patch available shortly for
others that want to test this out.  A summary of the changes made to
date follows:

-----
Added:

modules/aaa/mod_auth_cert.c
* provider module defining AuthType Certificate based
* registers check user hook "authenticate_certificate_user"
* TODO:  (from [*1], above) matching certificate subject DN to LDAP
object DN is overly restrictive; someday implement a more general
approach which might be based on creating a filter expression to match
DN components, certificate attributes, &c.
-----
Modified:

Modouls/aaa/mod_auth.h:
* appended check_certificate member to authn_provider struct

modules/aaa/config.m4:
* add "APACHE_MODULE(auth_cert, X.509 certificate authentication, , ,
most)"

modules/aaa/mod_authnz_ldap.c:
* added authn_ldap_check_certificate, a wrapper for
authn_ldap_check_password after testing for certificate auth
pre-conditions
* changed authn_ldap_check_password to use util_ldap_cache_getuserdn
instead of ..._checkuserid if AuthType is Certificate
* registered authn_ldap_check_certificate as the check_certificate
function for 

Modules/ssl/mod_ssl.h:
* TODO:  Make the following item configurable, defaulting to original
behavior [ I need RFC2253 format because that is how DNs are stored in
our LDAP server ]
* changed ssl_var_lookup(..., "SSL_CLIENT_S_DN") to return
RFC2253-compliant DN instead of using deprecated X509_NAME_oneline 

Issues/other TODO items:

* TODO: enhance APR-Util & mod_ldap to support two-way SSL and
ldap_sasl_bind_s for environments that support SASL EXTERNAL
authentication based on the LDAP client's certificate; right now
mod_ldap only supports simple binding--anonymous, or with a binddn and
password.
* ssl_var_lookup(..., "SSL_CLIENT_S_DN") bails out unexpectedly when
called from mod_auth_cert.c:authenticate_certificate_user
  [I know it works elsewhere, because I can get the user name logged in
access_log by using SSLUserName SSL_CLIENT_S_DN]

Here's the diff fragment if anyone wants to take a stab puzzling out
anything I've done wrong:

--- http-2.2.15-baseline/modules/ssl//ssl_engine_vars.c Sat Feb 27
16:00:58 2010
--- http-2.2.15/modules/ssl//ssl_engine_vars.c  Tue Mar 23 14:22:53 2010
@@ -367,10 +367,20 @@
     }
     else if (strcEQ(var, "S_DN")) {
         xsname = X509_get_subject_name(xs);
-        cp = X509_NAME_oneline(xsname, NULL, 0);
-        result = apr_pstrdup(p, cp);
-        modssl_free(cp);
-        resdup = FALSO;
+        BIO *bio;
+        int n;
+        
+        if ((bio = BIO_new(BIO_s_mem())) == NULL) {
+            result = NULL;
+        } else {
+            X509_NAME_print_ex(bio, xsname, 0, XN_FLAG_RFC2253);
+            n = BIO_pending(bio);
+            result = apr_pcalloc(p, n+1);
+            n = BIO_read(bio, result, n);
+            result[n] = NUL;
+            BIO_free(bio);
+            resdup = FALSE;
+        }
     }
     else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) {
         xsname = X509_get_subject_name(xs)