summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBradley Nicholes <bnicholes@apache.org>2005-05-03 23:07:43 +0000
committerBradley Nicholes <bnicholes@apache.org>2005-05-03 23:07:43 +0000
commit3a3447622ca1e8cfb49b2fe7110d276ae3bb8c9f (patch)
tree10cda5dfc4cea0f99a12dac8065ef29c79b1206f
parent2a84c5acdf0e679fab3573958bf272c3dd524bae (diff)
downloadhttpd-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.xml45
-rw-r--r--modules/aaa/mod_authnz_ldap.c155
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_&lt;Attribute&gt;=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}
};