From: Eric Covener
Date: Tue, 1 Jun 2010 21:19:06 +0000 (+0000)
Subject: mod_authnz_ldap: Search or Comparison during authorization phase
X-Git-Tag: 2.3.6~79
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a8720fa901ad02235780ef0830d9e5bc4aea1223;p=apache
mod_authnz_ldap: Search or Comparison during authorization phase
can use the credentials from the authentication phase
(AuthLDAPSearchAsUSer,AuthLDAPCompareAsUser).
PR 48340
Submitted by: Domenico Rotiroti, Eric Covener
Reviewed by: Eric Covener
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@950248 13f79535-47bb-0310-9956-ffa450edef68
---
diff --git a/CHANGES b/CHANGES
index a468fa732e..7e565b985d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -28,6 +28,11 @@ Changes with Apache 2.3.7
processing is completed, avoiding orphaned callback pointers.
[Brett Gervasoni , Jeff Trawick]
+ *) mod_authnz_ldap: Search or Comparison during authorization phase
+ can use the credentials from the authentication phase
+ (AuthLDAPSearchAsUSer,AuthLDAPCompareAsUser).
+ PR 48340 [Domenico Rotiroti, Eric Covener]
+
*) mod_authnz_ldap: Allow the initial DN search during authentication
to use the HTTP username/pass instead of an anonymous or hard-coded
LDAP id (AuthLDAPInitialBindAsUser, AuthLDAPInitialBindPattern).
diff --git a/docs/manual/mod/mod_authnz_ldap.html.en b/docs/manual/mod/mod_authnz_ldap.html.en
index 831f8536ab..f1f53dd1ac 100644
--- a/docs/manual/mod/mod_authnz_ldap.html.en
+++ b/docs/manual/mod/mod_authnz_ldap.html.en
@@ -64,6 +64,7 @@ for HTTP Basic authentication.
AuthLDAPBindDN
AuthLDAPBindPassword
AuthLDAPCharsetConfig
+
AuthLDAPCompareAsUser
AuthLDAPCompareDNOnServer
AuthLDAPDereferenceAliases
AuthLDAPGroupAttribute
@@ -73,6 +74,7 @@ for HTTP Basic authentication.
AuthLDAPMaxSubGroupDepth
AuthLDAPRemoteUserAttribute
AuthLDAPRemoteUserIsDN
+
AuthLDAPSearchAsUser
AuthLDAPSubGroupAttribute
AuthLDAPSubGroupClass
AuthLDAPUrl
@@ -870,6 +872,40 @@ authorization
The case of the extension does not matter. Blank lines, and lines
beginning with a hash character (#
) are ignored.
+
+
+
+
+
When set, and mod_authnz_ldap
has authenticated the
+ user, comparisons for authorization use the credentials provided via
+ HTTP basic authentication instead of the servers own credentials.
+
+
The ldap-attribute, ldap-user, and ldap-group (single-level only)
+ authorization checks use comparisons.
+
+
This directive only has effect on the comparisons performed during
+ nested group processing when
+ AuthLDAPSearchAsUser
is also enabled.
+
+
This directive should only be used when your LDAP server doesn't
+ accept anonymous comparisons and you cannot use a dedicated
+ AuthLDAPBindDN
.
+
+
+
See also
+

@@ -990,6 +1026,8 @@ own username, instead of anonymously or with hard-coded credentials for the serv
@@ -1099,6 +1137,40 @@ environment variable
the username that was passed by the client. It is turned off by
default.
+
+
+
+
+
When set, and mod_authnz_ldap
has authenticated the
+ user, searches for authorization use the credentials provided via
+ HTTP basic authentication instead of the servers own credentials.
+
+
The ldap-filter and ldap-dn authorization
+ checks use searches.
+
+
This directive only has effect on the comparisons performed during
+ nested group processing when
+ AuthLDAPCompareAsUser
is also enabled.
+
+
This directive should only be used when your LDAP server doesn't
+ accept anonymous searches and you cannot use a dedicated
+ AuthLDAPBindDN
.
+
+
+
See also
+

diff --git a/docs/manual/mod/mod_authnz_ldap.xml b/docs/manual/mod/mod_authnz_ldap.xml
index 281c0f41f0..6aa45eb7c5 100644
--- a/docs/manual/mod/mod_authnz_ldap.xml
+++ b/docs/manual/mod/mod_authnz_ldap.xml
@@ -837,6 +837,8 @@ own username, instead of anonymously or with hard-coded credentials for the serv
AuthLDAPInitialBindPattern
AuthLDAPBindDN
+
AuthLDAPCompareAsUser
+
AuthLDAPSearchAsUser
@@ -938,6 +940,38 @@ to perform a DN lookup
+
+AuthLDAPCompareAsUser
+Use the authenticated users credentials to perform authorization comparisons
+AuthLDAPCompareAsUser on|off
+AuthLDAPCompareAsUser off
+directory.htaccess
+
+Available in version 2.3.7 and later
+AuthConfig
+
+
+ When set, and mod_authnz_ldap has authenticated the
+ user, LDAP comparisons for authorization use the queried distinguished name (DN)
+ and HTTP basic authentication password of the authenticated user instead of
+ the servers configured credentials.
+
+ The ldap-attribute, ldap-user, and ldap-group (single-level only)
+ authorization checks use comparisons.
+
+ This directive only has effect on the comparisons performed during
+ nested group processing when
+ AuthLDAPSearchAsUser is also enabled.
+
+ This directive should only be used when your LDAP server doesn't
+ accept anonymous comparisons and you cannot use a dedicated
+ AuthLDAPBindDN.
+
+
+AuthLDAPInitialBindAsUser
+AuthLDAPSearchAsUser
+
+
AuthLDAPCompareDNOnServer
Use the LDAP server to compare the DNs
@@ -1085,6 +1119,38 @@ environment variable
+
+AuthLDAPSearchAsUser
+Use the authenticated users credentials to perform authorization searches
+AuthLDAPSearchAsUser on|off
+AuthLDAPSearchAsUser off
+directory.htaccess
+
+Available in version 2.3.7 and later
+AuthConfig
+
+
+ When set, and mod_authnz_ldap has authenticated the
+ user, LDAP searches for authorization use the queried distinguished name (DN)
+ and HTTP basic authentication password of the authenticated user instead of
+ the servers configured credentials.
+
+ The ldap-filter and ldap-dn authorization
+ checks use searches.
+
+ This directive only has effect on the comparisons performed during
+ nested group processing when
+ AuthLDAPCompareAsUser is also enabled.
+
+ This directive should only be used when your LDAP server doesn't
+ accept anonymous searches and you cannot use a dedicated
+ AuthLDAPBindDN.
+
+
+AuthLDAPInitialBindAsUser
+AuthLDAPCompareAsUser
+
+
AuthLDAPSubGroupAttribute
Specifies the attribute labels, one value per
diff --git a/modules/aaa/mod_authnz_ldap.c b/modules/aaa/mod_authnz_ldap.c
index 0ec97ae674..2a6826f10d 100644
--- a/modules/aaa/mod_authnz_ldap.c
+++ b/modules/aaa/mod_authnz_ldap.c
@@ -83,18 +83,25 @@ typedef struct {
int initial_bind_as_user; /* true if we should try to bind (to lookup DN) directly with the basic auth username */
ap_regex_t *bind_regex; /* basic auth -> bind'able username regex */
const char *bind_subst; /* basic auth -> bind'able username substitution */
+ int search_as_user; /* true if authz searches should be done with the users credentials (when we did authn) */
+ int compare_as_user; /* true if authz compares should be done with the users credentials (when we did authn) */
} authn_ldap_config_t;
typedef struct {
char *dn; /* The saved dn from a successful search */
char *user; /* The username provided by the client */
const char **vals; /* The additional values pulled during the DN search*/
+ char *password; /* if this module successfully authenticates, the basic auth password, else null */
} authn_ldap_request_t;
-enum auth_ldap_phase{
+enum auth_ldap_phase {
LDAP_AUTHN, LDAP_AUTHZ
};
-
+
+enum auth_ldap_optype {
+ LDAP_SEARCH, LDAP_COMPARE, LDAP_COMPARE_AND_SEARCH /* nested groups */
+};
+
/* maximum group elements supported */
#define GROUPATTR_MAX_ELTS 10
@@ -412,6 +419,32 @@ static const char *ldap_determine_binddn(request_rec *r, const char *user) {
return result;
}
+
+/* Some LDAP servers restrict who can search or compare, and the hard-coded ID
+ * might be good for the DN lookup but not for later operations.
+ */
+static util_ldap_connection_t *get_connection_for_authz(request_rec *r, enum auth_ldap_optype type) {
+ authn_ldap_request_t *req =
+ (authn_ldap_request_t *)ap_get_module_config(r->request_config, &authnz_ldap_module);
+ authn_ldap_config_t *sec =
+ (authn_ldap_config_t *)ap_get_module_config(r->per_dir_config, &authnz_ldap_module);
+
+ char *binddn = sec->binddn;
+ char *bindpw = sec->bindpw;
+
+ /* If the per-request config isn't set, we didn't authenticate this user, and leave the default credentials */
+ if (req && req->password &&
+ ((type == LDAP_SEARCH && sec->search_as_user) ||
+ (type == LDAP_COMPARE && sec->compare_as_user) ||
+ (type == LDAP_COMPARE_AND_SEARCH && sec->compare_as_user && sec->search_as_user))){
+ binddn = req->dn;
+ bindpw = req->password;
+ }
+
+ return util_ldap_connection_find(r, sec->host, sec->port,
+ binddn, bindpw,
+ sec->deref, sec->secure);
+}
/*
* Authentication Phase
* --------------------
@@ -545,6 +578,7 @@ start_over:
/* mark the user and DN */
req->dn = apr_pstrdup(r->pool, dn);
req->user = apr_pstrdup(r->pool, user);
+ req->password = apr_pstrdup(r->pool, password);
if (sec->user_is_dn) {
r->user = req->dn;
}
@@ -591,9 +625,7 @@ static authz_status ldapuser_check_authorization(request_rec *r,
}
if (sec->host) {
- ldc = util_ldap_connection_find(r, sec->host, sec->port,
- sec->binddn, sec->bindpw, sec->deref,
- sec->secure);
+ ldc = get_connection_for_authz(r, LDAP_COMPARE);
apr_pool_cleanup_register(r->pool, ldc,
authnz_ldap_cleanup_connection_close,
apr_pool_cleanup_null);
@@ -732,9 +764,7 @@ static authz_status ldapgroup_check_authorization(request_rec *r,
}
if (sec->host) {
- ldc = util_ldap_connection_find(r, sec->host, sec->port,
- sec->binddn, sec->bindpw, sec->deref,
- sec->secure);
+ ldc = get_connection_for_authz(r, LDAP_COMPARE); /* for the top-level group only */
apr_pool_cleanup_register(r->pool, ldc,
authnz_ldap_cleanup_connection_close,
apr_pool_cleanup_null);
@@ -869,6 +899,15 @@ static authz_status ldapgroup_check_authorization(request_rec *r,
return AUTHZ_GRANTED;
}
case LDAP_COMPARE_FALSE: {
+ /* nested groups need searches and compares, so grab a new handle */
+ authnz_ldap_cleanup_connection_close(ldc);
+ apr_pool_cleanup_kill(r->pool, ldc,authnz_ldap_cleanup_connection_close);
+
+ ldc = get_connection_for_authz(r, LDAP_COMPARE_AND_SEARCH);
+ apr_pool_cleanup_register(r->pool, ldc,
+ authnz_ldap_cleanup_connection_close,
+ apr_pool_cleanup_null);
+
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"[%" APR_PID_T_FMT "] auth_ldap authorise: require group \"%s\": "
"failed [%s][%d - %s], checking sub-groups",
@@ -932,9 +971,7 @@ static authz_status ldapdn_check_authorization(request_rec *r,
}
if (sec->host) {
- ldc = util_ldap_connection_find(r, sec->host, sec->port,
- sec->binddn, sec->bindpw, sec->deref,
- sec->secure);
+ ldc = get_connection_for_authz(r, LDAP_SEARCH); /* _comparedn is a searche */
apr_pool_cleanup_register(r->pool, ldc,
authnz_ldap_cleanup_connection_close,
apr_pool_cleanup_null);
@@ -1046,9 +1083,7 @@ static authz_status ldapattribute_check_authorization(request_rec *r,
}
if (sec->host) {
- ldc = util_ldap_connection_find(r, sec->host, sec->port,
- sec->binddn, sec->bindpw, sec->deref,
- sec->secure);
+ ldc = get_connection_for_authz(r, LDAP_COMPARE);
apr_pool_cleanup_register(r->pool, ldc,
authnz_ldap_cleanup_connection_close,
apr_pool_cleanup_null);
@@ -1165,9 +1200,7 @@ static authz_status ldapfilter_check_authorization(request_rec *r,
}
if (sec->host) {
- ldc = util_ldap_connection_find(r, sec->host, sec->port,
- sec->binddn, sec->bindpw, sec->deref,
- sec->secure);
+ ldc = get_connection_for_authz(r, LDAP_SEARCH);
apr_pool_cleanup_register(r->pool, ldc,
authnz_ldap_cleanup_connection_close,
apr_pool_cleanup_null);
@@ -1249,8 +1282,14 @@ static authz_status ldapfilter_check_authorization(request_rec *r,
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"[%" APR_PID_T_FMT "] auth_ldap authorize: checking dn match %s",
getpid(), dn);
+ if (sec->compare_as_user) {
+ /* ldap-filter is the only authz that requires a search and a compare */
+ apr_pool_cleanup_kill(r->pool, ldc, authnz_ldap_cleanup_connection_close);
+ authnz_ldap_cleanup_connection_close(ldc);
+ ldc = get_connection_for_authz(r, LDAP_COMPARE);
+ }
result = util_ldap_cache_comparedn(r, ldc, sec->url, req->dn, dn,
- sec->compare_dn_on_server);
+ sec->compare_dn_on_server);
}
switch(result) {
@@ -1607,6 +1646,14 @@ static const command_rec authnz_ldap_cmds[] =
AP_INIT_TAKE2("AuthLDAPInitialBindPattern", set_bind_pattern, NULL, OR_AUTHCFG,
"The regex and substitution to determine a username that can bind based on an HTTP basic auth username"),
+ AP_INIT_FLAG("AuthLDAPSearchAsUser", ap_set_flag_slot,
+ (void *)APR_OFFSETOF(authn_ldap_config_t, search_as_user), OR_AUTHCFG,
+ "Set to 'on' to perform authorization-based searches with the users credentials, when this module"
+ " has also performed authentication. Does not affect nested groups lookup."),
+ AP_INIT_FLAG("AuthLDAPCompareAsUser", ap_set_flag_slot,
+ (void *)APR_OFFSETOF(authn_ldap_config_t, compare_as_user), OR_AUTHCFG,
+ "Set to 'on' to perform authorization-based compares with the users credentials, when this module"
+ " has also performed authentication. Does not affect nested groups lookups."),
{NULL}
};