Index: docs/manual/mod/mod_auth_ldap.xml
===================================================================
--- docs/manual/mod/mod_auth_ldap.xml (revision 165060)
+++ docs/manual/mod/mod_auth_ldap.xml (working copy)
@@ -395,7 +395,7 @@
- The next example is similar to the previous one, but is
+ The next example is similar to the previous one, but it
uses the common name instead of the UID. Note that this
could be problematical if multiple people in the directory
share the same cn, because a search on cn
@@ -437,7 +437,7 @@
new LDAP group and ensure that the group's members remain
synchronized with the pager users. This becomes trivial
with filters. The goal is to grant access to anyone who has
- a filter, plus grant access to Joe Manager, who doesn't
+ a pager, plus grant access to Joe Manager, who doesn't
have a pager, but does need to access the same
resource:
@@ -783,9 +783,41 @@
the username that was passed by the client. It is turned off by
default.
+AuthLDAPAllowDNAuth
+AuthLDAPAllowDNAuth
+Allow the user to authenticate by passing a fully distinguished
+user name.
+AuthLDAPAllowDNAuth on|off
+AuthLDAPAllowDNAuth off
+directory.htaccess
+
+AuthConfig
+
+
+ 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.
+
+ Note
+ If a full user DN is allowed for authentication and the value of
+ AuthLDAPRemoteUserIsDN
+ 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
+ AuthLDAPUrl directive.
+
+
+
+
+
AuthLDAPUrl
URL specifying the LDAP search parameters
AuthLDAPUrl url
@@ -838,13 +870,16 @@
attribute
- The attribute to search for.
+ 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 uid. It's a good
- idea to choose an attribute that will be unique across all
- entries in the subtree you will be using.
+ 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 uid.
+ It's a good idea to choose an attribute that will be unique across
+ all entries in the subtree you will be searching.
scope
Index: modules/experimental/mod_auth_ldap.c
===================================================================
--- modules/experimental/mod_auth_ldap.c (revision 165194)
+++ modules/experimental/mod_auth_ldap.c (working copy)
@@ -81,6 +81,7 @@
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 */
} mod_auth_ldap_config_t;
typedef struct mod_auth_ldap_request_t {
@@ -160,7 +161,62 @@
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
* will fit in the buffer. We don't worry about the buffer not being able
@@ -178,18 +234,21 @@
*
* 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
void mod_auth_ldap_build_filter(char *filtbuf,
request_rec *r,
mod_auth_ldap_config_t *sec)
{
- char *p, *q, *filtbuf_end;
char *user;
apr_xlate_t *convset = NULL;
apr_size_t inbytes;
apr_size_t outbytes;
char *outbuf;
+ char **dnbuf = NULL;
if (r->user != NULL) {
user = apr_pstrdup (r->pool, r->user);
@@ -216,62 +275,50 @@
* Create the first part of the filter, which consists of the
* config-supplied portions.
*/
- apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(%s=", sec->filter, sec->attribute);
+ apr_snprintf(filtbuf, FILTER_LENGTH, "(&(%s)(&", sec->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=", sec->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 apr_status_t mod_auth_ldap_cleanup_connection_close(void *param)
@@ -732,6 +779,7 @@
sec->bindpw = NULL;
sec->deref = always;
sec->group_attrib_is_dn = 1;
+ sec->allow_fdn_auth = 0;
sec->frontpage_hack = 0;
sec->secure = 0;
@@ -986,6 +1034,11 @@
"Character set conversion configuration file. If omitted, character set"
"conversion is disabled."),
+ AP_INIT_FLAG("AuthLDAPAllowDNAuth", ap_set_flag_slot,
+ (void *)APR_OFFSETOF(mod_auth_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}
};