diff options
author | Bradley Nicholes <bnicholes@apache.org> | 2005-05-03 23:07:43 +0000 |
---|---|---|
committer | Bradley Nicholes <bnicholes@apache.org> | 2005-05-03 23:07:43 +0000 |
commit | 3a3447622ca1e8cfb49b2fe7110d276ae3bb8c9f (patch) | |
tree | 10cda5dfc4cea0f99a12dac8065ef29c79b1206f | |
parent | 2a84c5acdf0e679fab3573958bf272c3dd524bae (diff) | |
download | httpd-3a3447622ca1e8cfb49b2fe7110d276ae3bb8c9f.tar.gz |
Add the directive AuthLDAPAllowDNAuth to allow a user to authenticate against an LDAP directory using a full user DN. This directive allows a user to authenticate against a subcontext that may contain non-unique user IDs.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@168016 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | docs/manual/mod/mod_authnz_ldap.xml | 45 | ||||
-rw-r--r-- | modules/aaa/mod_authnz_ldap.c | 155 |
2 files changed, 142 insertions, 58 deletions
diff --git a/docs/manual/mod/mod_authnz_ldap.xml b/docs/manual/mod/mod_authnz_ldap.xml index 526de29f98..9b46e639b9 100644 --- a/docs/manual/mod/mod_authnz_ldap.xml +++ b/docs/manual/mod/mod_authnz_ldap.xml @@ -819,6 +819,38 @@ environment variable</description> the username that was passed by the client. It is turned off by default.</p> </usage> +<seealso><directive module="mod_authnz_ldap">AuthLDAPAllowDNAuth</directive></seealso> +</directivesynopsis> + +<directivesynopsis> +<name>AuthLDAPAllowDNAuth</name> +<description>Allow the user to authenticate by passing a fully distinguished +user name.</description> +<syntax>AuthLDAPAllowDNAuth on|off</syntax> +<default>AuthLDAPAllowDNAuth off</default> +<contextlist><context>directory</context><context>.htaccess</context> +</contextlist> +<override>AuthConfig</override> + +<usage> + <p>If this directive is set to ON, users are allowed to pass a fully + distinguished user name as the user ID. Regardless of this setting, + Auth_LDAP will still allow a contextless login. This directive is + turned off by default.</p> + + <note><title>Note</title> + <p>If a full user DN is allowed for authentication and the value of + <directive module="mod_authnz_ldap">AuthLDAPRemoteUserIsDN</directive> + is set to OFF, the value of the REMOTE_USER environment variable + will contain the actual user name value passed in the request. If + this directive is set to ON, the REMOTE_USER environment variable + will always be set to the user DN retrieved from the LDAP directory. + If a contextless user ID is required in all cases instead of a + full DN, it is possible to retrieve the desired attribute value + from the user object by specifying an attribute list in the + <directive module="mod_authnz_ldap">AuthLDAPUrl</directive> directive.</p> + </note> +</usage> </directivesynopsis> <directivesynopsis> @@ -874,13 +906,16 @@ environment variable</description> <dt>attribute</dt> - <dd>The attribute to search for. + <dd>The attribute to search for as well as additional attribute + values to extract from the authenticated user object. Although RFC 2255 allows a comma-separated list of attributes, only the first attribute will be used, no - matter how many are provided. If no attributes are - provided, the default is to use <code>uid</code>. It's a good - idea to choose an attribute that will be unique across all - entries in the subtree you will be using.</dd> + matter how many are provided. The values of all other listed + attributes will be extracted from the user object and assigned + to environment variables (AUTHENTICATE_<Attribute>=value). + If no attributes are provided, the default is to use <code>uid</code>. + It's a good idea to choose an attribute that will be unique across + all entries in the subtree you will be searching.</dd> <dt>scope</dt> diff --git a/modules/aaa/mod_authnz_ldap.c b/modules/aaa/mod_authnz_ldap.c index a26e33712c..d38e6a9441 100644 --- a/modules/aaa/mod_authnz_ldap.c +++ b/modules/aaa/mod_authnz_ldap.c @@ -73,6 +73,7 @@ typedef struct { it's the exact string passed by the HTTP client */ int secure; /* True if SSL connections are requested */ + int allow_fdn_auth; /* Set to True if user is allowed to authenticate using an FDN */ } authn_ldap_config_t; typedef struct { @@ -150,6 +151,61 @@ static apr_xlate_t* get_conv_set (request_rec *r) return NULL; } +#define FILTER_LENGTH MAX_STRING_LEN +static char* cat_escape_dn_element(char *filtbuf, char *user) +{ + char *p, *q, *filtbuf_end; + + /* + * Now add the client-supplied username to the filter, ensuring that any + * LDAP filter metachars are escaped. + */ + filtbuf_end = filtbuf + FILTER_LENGTH - 1; +#if APR_HAS_MICROSOFT_LDAPSDK + for (p = user, q=filtbuf + strlen(filtbuf); + *p && q < filtbuf_end; ) { + if (strchr("*()\\", *p) != NULL) { + if ( q + 3 >= filtbuf_end) + break; /* Don't write part of escape sequence if we can't write all of it */ + *q++ = '\\'; + switch ( *p++ ) + { + case '*': + *q++ = '2'; + *q++ = 'a'; + break; + case '(': + *q++ = '2'; + *q++ = '8'; + break; + case ')': + *q++ = '2'; + *q++ = '9'; + break; + case '\\': + *q++ = '5'; + *q++ = 'c'; + break; + } + } + else + *q++ = *p++; + } +#else + for (p = user, q=filtbuf + strlen(filtbuf); + *p && q < filtbuf_end; *q++ = *p++) { + if (strchr("*()\\", *p) != NULL) { + *q++ = '\\'; + if (q >= filtbuf_end) { + break; + } + } + } +#endif + *q = '\0'; + + return filtbuf; +} /* * Build the search filter, or at least as much of the search filter that @@ -168,20 +224,23 @@ static apr_xlate_t* get_conv_set (request_rec *r) * * Further, assume that the userid passed by the client was `userj'. The * search filter will be (&(posixid=*)(uid=userj)). + * + * If a full DN is allowed for authentication, the a userid of + * cn=userj,o=dev will result in the following search filter: + * (&(objectclass=*)(&(cn:dn:=userj)(o:dn:=dev))) */ -#define FILTER_LENGTH MAX_STRING_LEN static void authn_ldap_build_filter(char *filtbuf, request_rec *r, const char* sent_user, const char* sent_filter, authn_ldap_config_t *sec) { - char *p, *q, *filtbuf_end; char *user, *filter; apr_xlate_t *convset = NULL; apr_size_t inbytes; apr_size_t outbytes; char *outbuf; + char **dnbuf = NULL; if (sent_user != NULL) { user = apr_pstrdup (r->pool, sent_user); @@ -210,66 +269,50 @@ static void authn_ldap_build_filter(char *filtbuf, } } - /* - * Create the first part of the filter, which consists of the - * config-supplied portions. - */ - apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(%s=", filter, sec->attribute); + apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(&", filter); - /* - * Now add the client-supplied username to the filter, ensuring that any - * LDAP filter metachars are escaped. - */ - filtbuf_end = filtbuf + FILTER_LENGTH - 1; -#if APR_HAS_MICROSOFT_LDAPSDK - for (p = user, q=filtbuf + strlen(filtbuf); - *p && q < filtbuf_end; ) { - if (strchr("*()\\", *p) != NULL) { - if ( q + 3 >= filtbuf_end) - break; /* Don't write part of escape sequence if we can't write all of it */ - *q++ = '\\'; - switch ( *p++ ) - { - case '*': - *q++ = '2'; - *q++ = 'a'; - break; - case '(': - *q++ = '2'; - *q++ = '8'; - break; - case ')': - *q++ = '2'; - *q++ = '9'; - break; - case '\\': - *q++ = '5'; - *q++ = 'c'; - break; - } - } - else - *q++ = *p++; + /* If FDN authentication is not allowed then don't attempt to explode + the user ID. The result is that dnbuf well be NULL which will + bypass building a FDN unique filter. */ + if (sec->allow_fdn_auth) { + dnbuf = ldap_explode_dn (user, 0); } -#else - for (p = user, q=filtbuf + strlen(filtbuf); - *p && q < filtbuf_end; *q++ = *p++) { - if (strchr("*()\\", *p) != NULL) { - *q++ = '\\'; - if (q >= filtbuf_end) { - break; + + if (dnbuf && (strchr(*dnbuf, '='))) { + char **buf; + char *dnfilter = "&"; + for (buf = dnbuf; *buf; buf++) { + char *eq = strchr (*buf, '='); + char *newdn = *buf; + + if (eq) { + newdn = apr_pstrcat (r->pool, apr_pstrndup (r->pool, *buf, eq-(*buf)), + ":dn:", eq, NULL); } - } + + apr_snprintf(filtbuf, FILTER_LENGTH, "%s(", filtbuf); + cat_escape_dn_element(filtbuf, newdn); + apr_snprintf(filtbuf, FILTER_LENGTH, "%s)", filtbuf); + } + } + else { + /* + * Create the first part of the filter, which consists of the + * config-supplied portions. + */ + apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(%s=", filter, sec->attribute); + cat_escape_dn_element(filtbuf, user); } -#endif - *q = '\0'; + ldap_value_free (dnbuf); /* * Append the closing parens of the filter, unless doing so would * overrun the buffer. */ - if (q + 2 <= filtbuf_end) - strcat(filtbuf, "))"); + apr_snprintf(filtbuf, FILTER_LENGTH, "%s))", filtbuf); + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, + "[%d] auth_ldap authenticate: using filter %s", getpid(), filtbuf); } static void *create_authnz_ldap_dir_config(apr_pool_t *p, char *d) @@ -295,6 +338,7 @@ static void *create_authnz_ldap_dir_config(apr_pool_t *p, char *d) sec->deref = always; sec->group_attrib_is_dn = 1; sec->auth_authoritative = 1; + sec->allow_fdn_auth = 0; /* sec->frontpage_hack = 0; @@ -1053,6 +1097,11 @@ static const command_rec authnz_ldap_cmds[] = "Character set conversion configuration file. If omitted, character set" "conversion is disabled."), + AP_INIT_FLAG("AuthLDAPAllowDNAuth", ap_set_flag_slot, + (void *)APR_OFFSETOF(authn_ldap_config_t, allow_fdn_auth), OR_AUTHCFG, + "If set to 'on', auth_ldap allows the user to authenicate using a fully" + "distinguished user name. Defaults to 'off'."), + {NULL} }; |