Gmane
Gravatar
From: Dick Davies <rasputnik <at> hellooperator.net>
Subject: chase up - Re: couple of questions on ldap auth
Newsgroups: gmane.comp.web.lighttpd
Date: 2005-03-18 15:30:06 GMT (4 years, 15 weeks, 2 days, 18 hours and 44 minutes ago)
No ones' sent me hate mail regarding this yet - is it ok,                                                                                                                
or do I need to start over?
* Dick Davies <rasputnik <at> hellooperator.net> [0332 00:32]:
> * Jan Kneschke <jan <at> kneschke.de> [0353 14:53]:
> > On Wed, Mar 09, 2005 at 02:47:05PM +0000, Dick Davies wrote:
> > >
> > > Hi there, loving lighttpd, just wanted a sanity check.
> > >
> > > 1. does lighttpd support secure connections to an LDAP server (startTLS or SSL)?
> >
> > It does nothing explicit. I have to look into the ldap/ssl part to give
> > you an answer.
> 
> Here's a patch (against trunk) to enable startTLS - I haven't done SSL because
> 
> a) it's deprecated
> b) it requires more changes to the source, different ports, etc.
> b) I'm trying to migrate away from it :)
> 
> Let me know if it sucks, because I'd like to add some more features:
> 
>  * decent debugging  - in particular, ldap_set_option() doesn't fail
>    if the ca certificate isn't there or is a jpeg of your dog -
>    you just get a 'Connect failed' from the bind.
> 
>  * LDAP URI support and multiple servers (one thing apaches mod_auth_ldap
>    does well)
> 
>  * reuse of connections - an ldap auth cache is pretty complicated, but
>    just rebinding on an existing connection with each pair of credentials
>    would probably help almost as much (I'd have to benchmark to see if
>    that's worth the hassle, and understand the code a little better to keep
>    it secure first).
> 
> > > 2. how do I say 'require valid-user'?
> >
> > This is a todo.
> 
> Been thinking about this one too - would it make sense to default to 'any
> user in the backend' if require is unset?
> (That's the simplest way I can think of and would work for me, with LDAP
> the search filter is ludicrously flexible anyway)
> 
> --
> 'common sense is what tells you that the world is flat.'
> 		-- Principia Discordia
> Rasputin :: Jack of All Trades - Master of Nuns

> Index: src/http_auth.c
> ===================================================================
> --- src/http_auth.c	(revision 109)
> +++ src/http_auth.c	(working copy)
> @@ -568,7 +568,17 @@
>  			return -1;
>  		}
>  		
> +		if (p->conf.auth_ldap_starttls == 1) {
> +	 		if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL,  NULL))) {
> +	 			log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
>  		
> +				ldap_unbind_s(ldap);
> +				
> +				return -1;
> +	 		}
> + 		}
> +
> +		
>  		if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
>  			log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
>  			
> Index: src/http_auth.h
> ===================================================================
> --- src/http_auth.h	(revision 109)
> +++ src/http_auth.h	(working copy)
> @@ -28,6 +28,8 @@
>  	buffer *auth_ldap_hostname;
>  	buffer *auth_ldap_basedn;
>  	buffer *auth_ldap_filter;
> +	buffer *auth_ldap_cafile;
> +	unsigned short auth_ldap_starttls;
>  	
>  	unsigned short auth_debug;
>  	
> Index: src/mod_auth.c
> ===================================================================
> --- src/mod_auth.c	(revision 109)
> +++ src/mod_auth.c	(working copy)
> @@ -68,6 +68,7 @@
>  			buffer_free(s->auth_ldap_hostname);
>  			buffer_free(s->auth_ldap_basedn);
>  			buffer_free(s->auth_ldap_filter);
> +			buffer_free(s->auth_ldap_cafile);
>  			
>  #ifdef USE_LDAP
>  			buffer_free(s->ldap_filter_pre);
> @@ -131,6 +132,10 @@
>  				PATCH(auth_ldap_basedn);
>  			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
>  				PATCH(auth_ldap_filter);
> +			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.cafile"))) {
> +				PATCH(auth_ldap_cafile);
> +			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
> +				PATCH(auth_ldap_starttls);
>  			}
>  		}
>  	}
> @@ -153,6 +158,8 @@
>  	PATCH(auth_ldap_hostname);
>  	PATCH(auth_ldap_basedn);
>  	PATCH(auth_ldap_filter);
> +	PATCH(auth_ldap_cafile);
> +	PATCH(auth_ldap_starttls);
>  #ifdef USE_LDAP
>  	PATCH(ldap);
>  	PATCH(ldap_filter_pre);
> @@ -297,9 +304,11 @@
>  		{ "auth.backend.ldap.hostname",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
>  		{ "auth.backend.ldap.base-dn",      NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
>  		{ "auth.backend.ldap.filter",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
> +		{ "auth.backend.ldap.cafile",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
> +		{ "auth.backend.ldap.starttls",     NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
>  		{ "auth.backend.htdigest.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
>  		{ "auth.backend.htpasswd.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
> -		{ "auth.debug",                     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
> +		{ "auth.debug",                     NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
>  		{ NULL,                             NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
>  	};
>  	
> @@ -321,6 +330,8 @@
>  		s->auth_ldap_hostname = buffer_init();
>  		s->auth_ldap_basedn = buffer_init();
>  		s->auth_ldap_filter = buffer_init();
> +		s->auth_ldap_cafile = buffer_init();
> +		s->auth_ldap_starttls = 0;
>  		s->auth_debug = 0;
>  		
>  		s->auth_require = array_init();
> @@ -338,9 +349,11 @@
>  		cv[4].destination = s->auth_ldap_hostname;
>  		cv[5].destination = s->auth_ldap_basedn;
>  		cv[6].destination = s->auth_ldap_filter;
> -		cv[7].destination = s->auth_htdigest_userfile;
> -		cv[8].destination = s->auth_htpasswd_userfile;
> -		cv[9].destination = &(s->auth_debug);
> +		cv[7].destination = s->auth_ldap_cafile;
> +		cv[8].destination = &(s->auth_ldap_starttls);
> +		cv[9].destination = s->auth_htdigest_userfile;
> +		cv[10].destination = s->auth_htpasswd_userfile;
> +		cv[11].destination = &(s->auth_debug);
>  		
>  		p->config_storage[i] = s;
>  		ca = ((data_config *)srv->config_context->data[i])->value;
> @@ -526,9 +539,23 @@
>  				ret = LDAP_VERSION3;
>  				if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
>  					log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
> -					
> +				
>  					return HANDLER_ERROR;
>  				}
> +			
> +				if (s->auth_ldap_starttls == 1 ) {
> +					if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
s->auth_ldap_cafile->ptr))) {
> +						log_error_write(srv, __FILE__, __LINE__, "ss", "Loading CA certificate failed:", ldap_err2string(ret));
> +						
> +						return HANDLER_ERROR;
> +					}
> +	
> +					if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL,  NULL))) {
> +						log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
> +						
> +						return HANDLER_ERROR;
> +					}
> +				}
>  				
>  				
>  				/* 1. */
> Index: doc/authentification.txt
> ===================================================================
> --- doc/authentification.txt	(revision 109)
> +++ doc/authentification.txt	(working copy)
> @@ -39,7 +39,7 @@
>  ``````
>  
>  The Digest method only transfers a hashed value over the 
> -network which is performes a lot of work to harden the 
> +network which performs a lot of work to harden the 
>  authentification process in insecure networks.
>  
>  Backends
> @@ -112,7 +112,7 @@
>  ldap
>  ````
>  
> -the ldap backend is basicly performing the following steps 
> +the ldap backend is basically performing the following steps 
>  to authenticate a user
>    
>  1. connect anonymously  (at plugin init)
> @@ -120,7 +120,7 @@
>  3. auth against ldap server
>  4. disconnect
>     
> -if step 4 is performs without any error the user is 
> +if all 4 steps are performed without any error the user is 
>  authenticated
>  
>  Configuration
> @@ -152,6 +152,10 @@
>    auth.backend.ldap.hostname = "localhost"
>    auth.backend.ldap.base-dn  = "dc=my-domain,dc=com"
>    auth.backend.ldap.filter   = "(uid=$)"
> +  # if enabled, startTLS needs a valid (base64-encoded) CA 
> +  # certificate
> +  auth.backend.ldap.starttls   = "enable"
> +  auth.backend.ldap.cafile   = "/etc/CAcertificate.pem"
>  
>    ## restrictions
>    # set restrictions:
> @@ -162,7 +166,7 @@
>    #     "require" => "user=<username>" )
>    # )
>    #
> -  # <realm> is a string that is should be display in the dialog 
> +  # <realm> is a string to display in the dialog 
>    #         presented to the user and is also used for the 
>    #         digest-algorithm and has to match the realm in the 
>    #         htdigest file (if used)
> @@ -182,10 +186,10 @@
>  		   )
>                   )
>  
> -Limitiations
> +Limitations
>  ============
>  
>  - The implementation of digest method is currently not 
> -  completely conforming to the standard as it is still allowing 
> +  completely compliant with the standard as it still allows
>    a replay attack.
>  

-- 
'Yeah, well I'm gonna build my own themepark! With blackjack aaand Hookers!
Actually, forget the park. And the blackjack.'
		-- Bender
Rasputin :: Jack of All Trades - Master of Nuns