[PATCH] mod_auth_ntlm_winbind - support for REMOTE_USER lookahead when reverse proxy

Michael Baltaks mbaltaks at gmail.com
Tue Sep 23 23:39:54 GMT 2008


Hi,

Here is a patch that adds two things to mod_auth_ntlm_winbind, and has 
been in production use on my server for over a year.

1) Allows using %{LA-U:REMOTE_USER} in rewrite rules when in reverse 
proxy mode and authenticating with mod_auth_ntlm_winbind, useful for 
letting httpd handle Active Directory authentication, and then pass the 
user name to a backend server like zope/plone.

2) Adds two extra options to the config, [NTLMOmitDomain] allowing the 
omission of the domain part of the username, and [NTLMDomainSeparator] 
setting a separator for domain and username (so you can match the 
winbind separator setting).

-Michael.
-------------- next part --------------
--- /Users/mick/Desktop/mod_auth_ntlm_winbind.c	2008-09-24 09:23:39.000000000 +1000
+++ ./mod_auth_ntlm_winbind.c	2008-08-27 11:25:48.000000000 +1000
@@ -97,6 +97,8 @@
     char *ntlm_auth_helper;
     char *negotiate_ntlm_auth_helper;
     char *ntlm_plaintext_helper;
+    unsigned int omit_domain;
+    char * domain_separator;
 } ntlm_config_rec;
 
 /* A structure to hold per-connection information about authentications
@@ -118,6 +120,7 @@
     char *auth_type;
     apr_pool_t *pool;
     int keepalives; /* used to detect redirected auths */
+    request_rec * r_main; /* track the main request if this is a subreq */
 };
 
 struct _ntlm_child_stuff {
@@ -194,6 +197,15 @@
                    (void *) APR_OFFSETOF(ntlm_config_rec, ntlm_basic_realm),
                    OR_AUTHCFG, "realm to use for Basic authentication" ),
 
+    AP_INIT_FLAG( "NTLMOmitDomain", ap_set_flag_slot,
+                  (void *) APR_OFFSETOF(ntlm_config_rec, omit_domain),
+                  OR_AUTHCFG,
+                  "set to 'on' to strip the domain name from the user name" ),
+
+    AP_INIT_TAKE1( "NTLMDomainSeparator", ap_set_string_slot,
+                   (void *) APR_OFFSETOF(ntlm_config_rec, domain_separator),
+                   OR_AUTHCFG, "the separator between domain and user name" ),
+
 #else
     /* NTLM authentication commands */
 
@@ -234,11 +246,20 @@
     { "NTLMBasicRealm", ap_set_string_slot,
       (void *) XtOffsetOf(ntlm_config_rec, ntlm_basic_realm),
       OR_AUTHCFG, TAKE1, "realm to use for Basic authentication" },
+
+    { "NTLMOmitDomain", ap_set_flag_slot,
+      (void *) XtOffsetOf(ntlm_config_rec, omit_domain),
+      OR_AUTHCFG, FLAG, "set to 'on' to strip the domain name from the user name" },
+
+    { "NTLMDomainSeparator", ap_set_string_slot,
+      (void *) XtOffsetOf(ntlm_config_rec, domain_separator),
+      OR_AUTHCFG, TAKE1, "the separator between domain and user name" },
 #endif
 
     { NULL }
 };
 
+
 /* both apache1 and apache2 use this to maintain per-child context */
 static ntlm_context_t global_ntlm_context;
 
@@ -290,6 +311,30 @@
 }
 #endif
 
+
+/* strip domain name from user name */
+char *
+strip_domain_name(request_rec * r, char * username)
+{
+    char * new_username = username;
+    ntlm_config_rec *crec = (ntlm_config_rec *)
+        ap_get_module_config(   r->per_dir_config,
+                                &auth_ntlm_winbind_module );
+    if (crec->omit_domain)
+    {
+        RDEBUG( "removing domain name from %s", username);
+        char *s = strstr(username, crec->domain_separator);
+        if (s)
+        {
+            RDEBUG( "user name without domain is %s", s + 1);
+            s++;
+            new_username = s;
+        }
+    }
+    return new_username;
+}
+
+
 /* helper function to pull out the context data */
 static ntlm_connection_context_t *get_connection_context( struct conn_rec *connection ) {
     ntlm_connection_context_t *retval = NULL;
@@ -347,7 +392,7 @@
     if ( ctxt->connected_user_authenticated &&
          ctxt->connected_user_authenticated->pool ) {
         apr_pool_destroy( ctxt->connected_user_authenticated->pool );
-	ctxt->connected_user_authenticated = NULL;
+        ctxt->connected_user_authenticated = NULL;
     }
 
     return HTTP_UNAUTHORIZED;
@@ -409,7 +454,7 @@
 static int
 send_auth_reply(request_rec * r, const char *auth_scheme, const char *reply)
 {
-    RDEBUG( "sending back %s", reply );
+    RDEBUG( "sending to http client: %s", reply );
     /* Read negotiate from ntlm_auth */
 
     apr_table_setn(r->err_headers_out,
@@ -496,7 +541,7 @@
     char *newline;
     char args_to_helper[HUGE_STRING_LEN];
     char args_from_helper[HUGE_STRING_LEN];
-    size_t bytes_written;
+    apr_size_t bytes_written;
     int bytes_read;
 
     if (( global_ntlm_context.ntlm_plaintext_helper = get_auth_helper( r, global_ntlm_context.ntlm_plaintext_helper, crec->ntlm_plaintext_helper, CLEANUP(cleanup_ntlm_plaintext_helper))) == NULL ) {
@@ -506,7 +551,7 @@
     if ( ctxt->connected_user_authenticated == NULL ) {
         apr_pool_t *pool;
 
-        RDEBUG( "creating auth user" );
+        RDEBUG( "creating auth user for plaintext" );
 
 #ifdef APACHE2
         apr_pool_create_ex( &pool, r->connection->pool, NULL, NULL );
@@ -586,7 +631,7 @@
 
     if ( strncmp( args_from_helper, "OK", 2 ) == 0 ) {
         RDEBUG( "authentication succeeded!" );
-        ctxt->connected_user_authenticated->user = apr_pstrdup(ctxt->connected_user_authenticated->pool, user);
+        ctxt->connected_user_authenticated->user = apr_pstrdup(ctxt->connected_user_authenticated->pool, strip_domain_name(r, user) );
         ctxt->connected_user_authenticated->keepalives = r->connection->keepalives;
 #ifdef APACHE2
         r->user = ctxt->connected_user_authenticated->user;
@@ -625,7 +670,7 @@
     char args_to_helper[HUGE_STRING_LEN];
     char args_from_helper[HUGE_STRING_LEN];
     ntlm_connection_context_t *ctxt = get_connection_context( r->connection );
-    size_t bytes_written;
+    apr_size_t bytes_written;
     int bytes_read;
     struct _ntlm_auth_helper *auth_helper;
 
@@ -675,6 +720,14 @@
         message_type = "KK";
     }
 
+    /* if last time was a subreq, and this isn't, start over */
+    if ( ctxt->connected_user_authenticated->r_main && !r->main )
+    {
+        message_type = "YR";
+        RDEBUG( "resetting NTLM dance" );
+    }
+    ctxt->connected_user_authenticated->r_main = r->main;
+
     /* Decode the information the WWW-Authenticate header */
     if ((client_msg = get_auth_header(r, crec, auth_type)) == NULL) {
         RDEBUG( "client did not return NTLM authentication header");
@@ -701,7 +754,7 @@
 #ifdef APACHE2
     apr_file_flush( auth_helper->proc->in );
 
-    RDEBUG( "parsing reply from helper to %s", args_to_helper );
+    RDEBUG( "sending to winbind via auth helper: %s", args_to_helper );
 
     if ( apr_file_gets(args_from_helper, HUGE_STRING_LEN, auth_helper->proc->out ) == APR_SUCCESS ) {
         bytes_read = strlen( args_from_helper );
@@ -739,7 +792,7 @@
         *newline = '\0';
     }
 
-    RDEBUG( "got response: %s", args_from_helper );
+    RDEBUG( "read from winbind via auth helper: %s", args_from_helper );
 
     /* inspect message type */
 
@@ -771,7 +824,7 @@
         if (strncmp(args_from_helper, "AF ", 3) == 0) {
             ctxt->connected_user_authenticated->user =
                 apr_pstrdup(ctxt->connected_user_authenticated->pool,
-                            childarg);
+                            strip_domain_name(r, childarg) );
             ctxt->connected_user_authenticated->keepalives =
                 r->connection->keepalives;
 #ifdef APACHE2
@@ -887,6 +940,8 @@
     crec->ntlm_auth_helper = "ntlm_auth --helper-protocol=squid-2.5-ntlmssp";
     crec->negotiate_ntlm_auth_helper = "ntlm_auth --helper-protocol=gss-spnego";
     crec->ntlm_plaintext_helper = "ntlm_auth --helper-protocol=squid-2.5-basic";
+    crec->omit_domain = 0;
+    crec->domain_separator = "\\";
 
     return crec;
 }
@@ -970,7 +1025,7 @@
 #endif
             return OK;
         } else {
-            RDEBUG( "reauth" );
+            RDEBUG( "client wishes to re-authenticate this TCP socket" );
             /* client wishes to re-authenticate this TCP socket */
             if ( ctxt->connected_user_authenticated->pool ) {
                 apr_pool_destroy(ctxt->connected_user_authenticated->pool);
@@ -1023,7 +1078,7 @@
 
     if (ctxt->connected_user_authenticated && ctxt->connected_user_authenticated->pool ) {
         apr_pool_destroy(ctxt->connected_user_authenticated->pool);
-	ctxt->connected_user_authenticated = NULL;
+        ctxt->connected_user_authenticated = NULL;
     }
 
     RDEBUG( "declined" );


More information about the samba-technical mailing list