ASF Bugzilla – Attachment 19734 Details for
Bug 38515
Dynamic LDAP Group Support
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Continuation of previous patch
ldap.patch.new (text/plain), 20.04 KB, created by
Gregory Szorc
on 2007-03-18 19:54:25 UTC
(
hide
)
Description:
Continuation of previous patch
Filename:
MIME Type:
Creator:
Gregory Szorc
Created:
2007-03-18 19:54:25 UTC
Size:
20.04 KB
patch
obsolete
>Index: modules/ldap/util_ldap.c >=================================================================== >--- modules/ldap/util_ldap.c (revision 489745) >+++ modules/ldap/util_ldap.c (working copy) >@@ -703,6 +703,264 @@ > > } > >+static int uldap_cache_comparedynamicgroup(request_rec *r, >+ util_ldap_connection_t *ldc, >+ const char *url, const char *dn, >+ const char *base, int scope, >+ const char *user, const char *userdn) >+{ >+ >+ int result = 0; >+ int failures = 0; >+ int i; >+ LDAPMessage *groupResult; >+ char *groupAttr[] = { "objectClass", "memberURL", NULL}; >+ char *uidAttr[] = { "uid", NULL}; >+ char **attr, **tmpAttr; >+ char memberURL[255]; >+ apr_ldap_url_desc_t *groupUrl, *origUrl; >+ apr_ldap_err_t *lgroupResult; >+ >+ >+start_over: >+ if (failures++ > 10) { >+ return result; >+ } >+ >+ if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) { >+ return result; >+ } >+ >+ /* first thing we do is find if the specified group has any memberURL entries */ >+ if ((result = ldap_search_s(ldc->ldap, base, scope, dn, >+ groupAttr, 0, &groupResult)) >+ == LDAP_SERVER_DOWN) { >+ >+ ldc->reason = "ldap_search_s() failed with server down"; >+ uldap_connection_unbind(ldc); >+ goto start_over; >+ } >+ >+ ldc->reason = "LDAP search for dynamic group members complete"; >+ >+ if ((result = ldap_count_entries(ldc->ldap, groupResult)) != 1) { >+ ldc->reason = "LDAP search for dynamic group didn't have 1 result"; >+ ldap_msgfree(groupResult); >+ return LDAP_COMPARE_FALSE; >+ } >+ >+ if ((groupResult = ldap_first_entry(ldc->ldap, groupResult)) == NULL) { >+ ldc->reason = "ldap_first_entry return NULL"; >+ return LDAP_COMPARE_FALSE; >+ } >+ >+ attr = ldap_get_values(ldc->ldap, groupResult, "objectClass"); >+ >+ if (attr = NULL) { >+ ldc->reason = "ldap_get_values() for objectClass returned NULL"; >+ return LDAP_COMPARE_FALSE; >+ } >+ >+ if ((attr = ldap_get_values(ldc->ldap, groupResult, "memberURL")) == NULL) { >+ ldc->reason = "ldap_get_values() for \"memberURL\" return NULL"; >+ return LDAP_COMPARE_FALSE; >+ } >+ >+ tmpAttr = attr; >+ i = 0; >+ >+ while (*tmpAttr != NULL) { >+ bzero(memberURL, sizeof(memberURL)); >+ strcpy(memberURL, *tmpAttr++); >+ >+ /* now, memberURL should be an LDAP URL pointing to a group */ >+ if ((result = apr_ldap_url_parse(r->pool, >+ (char *)memberURL, >+ &groupUrl, >+ &lgroupResult)) >+ != APR_SUCCESS) >+ { >+ ldc->reason = "could not parse returned URL"; >+ continue; >+ } >+ else { >+ /* we have a good LDAP url, now search to see if the user is there */ >+ >+ if ((result = ldap_search_s(ldc->ldap, userdn, LDAP_SCOPE_SUBTREE, >+ groupUrl->lud_filter, uidAttr, >+ 0, &groupResult)) >+ != LDAP_SUCCESS) >+ { >+ continue; >+ } >+ else { >+ if (ldap_count_entries(ldc->ldap, groupResult) >= 1) { >+ return LDAP_COMPARE_TRUE; >+ } >+ } >+ >+ } >+ >+ >+ >+ >+ } >+ >+ return LDAP_COMPARE_FALSE; >+} >+ >+char ** uldap_cache_getattributevalues(request_rec *r, util_ldap_connection_t *ldc, >+ const char *url, const char *dn, >+ const char *attrib) >+{ >+ char **arr = NULL; >+ char **attr; >+ >+ int failures = 0; >+ int result = 0; >+ int count; >+ char *filter = NULL; >+ int numvals = 0; >+ >+ LDAPMessage *res, *entry; >+ >+ util_url_node_t *curl; >+ util_url_node_t curnode; >+ util_search_node_t *search_nodep; >+ util_search_node_t the_search_node; >+ apr_time_t curtime; >+ >+ util_ldap_state_t *st = >+ (util_ldap_state_t *)ap_get_module_config(r->server->module_config, >+ &ldap_module); >+ >+ LDAP_CACHE_LOCK(); >+ curnode.url = url; >+ curl = (util_url_node_t *)util_ald_cache_fetch(st->util_ldap_cache, >+ &curnode); >+ >+ char * key = apr_pstrcat(r->pool, dn, "::", attrib, NULL); >+ >+ if (curl == NULL) { >+ curl = util_ald_create_caches(st, url); >+ } >+ LDAP_CACHE_UNLOCK(); >+ >+ if (curl) { >+ LDAP_CACHE_LOCK(); >+ the_search_node.username = key; >+ search_nodep = util_ald_cache_fetch(curl->search_cache, >+ &the_search_node); >+ >+ if (search_nodep != NULL) { >+ /* found attributes in search cache */ >+ >+ curtime = apr_time_now(); >+ >+ if ((curtime - search_nodep->lastbind) > st->search_cache_ttl) { >+ /* ...but entry is too old */ >+ util_ald_cache_remove(curl->search_cache, search_nodep); >+ } >+ else { >+ /* entry isn't too old, so return the results */ >+ arr = (char **)(search_nodep->vals); >+ LDAP_CACHE_UNLOCK(); >+ return arr; >+ } >+ } >+ >+ LDAP_CACHE_UNLOCK(); >+ >+ } >+ >+ /* didn't get hit from cache */ >+start_over: >+ if (failures++ > 10) { >+ return arr; >+ } >+ if (LDAP_SUCCESS != (result = uldap_connection_open(r, ldc))) { >+ return arr; >+ } >+ >+ /* try do the search */ >+ filter = apr_pstrcat(st->pool, "objectClass", attrib, NULL); >+ if ((result = ldap_search_ext_s(ldc->ldap, >+ (char *)dn, LDAP_SCOPE_SUBTREE, >+ filter, (char *)(attrib), 0, >+ NULL, NULL, NULL, -1, &res)) >+ == LDAP_SERVER_DOWN) >+ { >+ ldc->reason = "ldap_search_ext_s() for attribute failed with server down"; >+ uldap_connection_unbind(ldc); >+ goto start_over; >+ } >+ >+ /* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */ >+ if (result != LDAP_SUCCESS) { >+ ldc->reason = "ldap_search_ext_s() for attribute failed"; >+ return arr; >+ } >+ >+ /* >+ * We should have found exactly one entry; to find a different >+ * number is an error. >+ */ >+ count = ldap_count_entries(ldc->ldap, res); >+ if (count != 1) >+ { >+ if (count == 0 ) >+ ldc->reason = "Attribute not found"; >+ else >+ ldc->reason = "Attribute search found multiple records. This shouldn't happen"; >+ ldap_msgfree(res); >+ return arr; >+ } >+ else { >+ entry = ldap_first_entry(ldc->ldap, res); >+ >+ attr = ldap_get_values(ldc->ldap, entry, "objectClass"); >+ >+ if (attr == NULL) { >+ ldc->reason = "ldap_get_values() for objectClass returned NULL"; >+ return arr; >+ } >+ >+ if ((attr = ldap_get_values(ldc->ldap, entry, attrib)) == NULL) { >+ ldc->reason = "ldap_get_values() for attribute return NULL"; >+ return arr; >+ } >+ >+ /* attr has the values */ >+ if (attr) { >+ int k = 0; >+ int i = 0; >+ >+ while (attr[k++]); >+ arr = apr_pcalloc(r->pool, sizeof(char *) * (k+1)); >+ numvals = k; >+ >+ while (attr[i]) { >+ char **values; >+ int j = 0; >+ char *str = NULL; >+ >+ values = ldap_get_values(ldc->ldap, entry, attr[i]); >+ while (values && values[j]) { >+ str = str ? apr_pstrcat(r->pool, str, "; ", values[j], NULL) >+ : apr_pstrdup(r->pool, values[j]); >+ j++; >+ } >+ ldap_value_free(values); >+ arr[i] = str; >+ i++; >+ } >+ } >+ >+ } >+ >+ return arr; >+} >+ > /* > * Does an generic ldap_compare operation. It accepts a cache that it will use > * to lookup the compare in the cache. We cache two kinds of compares >@@ -2099,6 +2357,8 @@ > APR_REGISTER_OPTIONAL_FN(uldap_connection_find); > APR_REGISTER_OPTIONAL_FN(uldap_cache_comparedn); > APR_REGISTER_OPTIONAL_FN(uldap_cache_compare); >+ APR_REGISTER_OPTIONAL_FN(uldap_cache_comparedynamicgroup); >+ APR_REGISTER_OPTIONAL_FN(uldap_cache_getattributevalues); > APR_REGISTER_OPTIONAL_FN(uldap_cache_checkuserid); > APR_REGISTER_OPTIONAL_FN(uldap_cache_getuserdn); > APR_REGISTER_OPTIONAL_FN(uldap_ssl_supported); >Index: modules/aaa/mod_authnz_ldap.c >=================================================================== >--- modules/aaa/mod_authnz_ldap.c (revision 489745) >+++ modules/aaa/mod_authnz_ldap.c (working copy) >@@ -74,6 +74,9 @@ > it's the exact string passed by the HTTP client */ > > int secure; /* True if SSL connections are requested */ >+ >+ int dynamic_group_lookup; /* True if dynamic group lookups desired */ >+ apr_array_header_t *dynamicgroupattr; /* List of dynamic group attributes */ > } authn_ldap_config_t; > > typedef struct { >@@ -94,6 +97,8 @@ > static APR_OPTIONAL_FN_TYPE(uldap_connection_find) *util_ldap_connection_find; > static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedn) *util_ldap_cache_comparedn; > static APR_OPTIONAL_FN_TYPE(uldap_cache_compare) *util_ldap_cache_compare; >+static APR_OPTIONAL_FN_TYPE(uldap_cache_comparedynamicgroup) *util_ldap_cache_comparedynamicgroup; >+static APR_OPTIONAL_FN_TYPE(uldap_cache_getattributevalues) *util_ldap_cache_getattributevalues; > static APR_OPTIONAL_FN_TYPE(uldap_cache_checkuserid) *util_ldap_cache_checkuserid; > static APR_OPTIONAL_FN_TYPE(uldap_cache_getuserdn) *util_ldap_cache_getuserdn; > static APR_OPTIONAL_FN_TYPE(uldap_ssl_supported) *util_ldap_ssl_supported; >@@ -287,6 +292,8 @@ > */ > sec->groupattr = apr_array_make(p, GROUPATTR_MAX_ELTS, > sizeof(struct mod_auth_ldap_groupattr_entry_t)); >+ sec->dynamicgroupattr = apr_array_make(p, GROUPATTR_MAX_ELTS, >+ sizeof(struct mod_auth_ldap_groupattr_entry_t)); > > sec->have_ldap_url = 0; > sec->url = ""; >@@ -306,6 +313,9 @@ > sec->user_is_dn = 0; > sec->remote_user_attribute = NULL; > sec->compare_dn_on_server = 0; >+ >+ sec->dynamic_group_lookup = 0; /* dynamic group lookup disabled by default */ >+ > > return sec; > } >@@ -514,8 +524,8 @@ > int method_restricted = 0; > > char filtbuf[FILTER_LENGTH]; >- const char *dn = NULL; >- const char **vals = NULL; >+ char *dn = NULL; >+ char **vals = NULL; > > /* > if (!sec->enabled) { >@@ -558,6 +568,22 @@ > apr_thread_mutex_unlock(sec->lock); > #endif > } >+ >+ /* >+ * If there are no elements in the dynamic group attribute array, populate default >+ * of "memberURL". This is the same code as above block but for dynamicgroupattr array >+ */ >+ if (sec->dynamicgroupattr->nelts == 0) { >+ struct mod_auth_ldap_groupattr_entry_t *dyngrp; >+#if APR_HAS_THREADS >+ apr_thread_mutex_lock(sec->lock); >+#endif >+ dyngrp = apr_array_push(sec->dynamicgroupattr); >+ dyngrp->name = "memberURL"; >+#if APR_HAS_THREADS >+ apr_thread_mutex_unlock(sec->lock); >+#endif >+ } > > if (!reqs_arr) { > ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, >@@ -738,6 +764,78 @@ > } > } > } >+ >+ /* Regular group membership has failed at this point. Do dynamic group checking if it is enabled */ >+ if (sec->dynamic_group_lookup) { >+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, >+ "[%" APR_PID_T_FMT "] auth_ldap_authorise: require group: " >+ "testing for dynamic group: %s (%s)", getpid(), >+ sec->group_attrib_is_dn ? req->dn : req->user, t); >+ >+ for (i = 0; i < sec->dynamicgroupattr->nelts; i++) { >+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, >+ "[%" APR_PID_T_FMT "] auth_ldap_authorise: require group: " >+ "dynamic group attribute %s: %s (%s)", getpid(), >+ ent[i].name, sec->group_attrib_is_dn ? req->dn : req->user, t); >+ >+ /* first we get all the attribute values for the current dynamic group attribute */ >+ vals = util_ldap_cache_getattributevalues(r, ldc, sec->url, req->dn, ent[i].name); >+ >+ int key = 0; >+ >+ /* loop through all found attribute values and do a search */ >+ while (vals[key]) { >+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, >+ "[%" APR_PID_T_FMT "] auth_ldap_authorise: require group: " >+ , getpid()); >+ >+ /* build search filter */ >+ authn_ldap_build_filter(filtbuf, r, req->user, vals[key], sec); >+ result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, >+ sec->scope, sec->attributes, filtbuf, &dn, &vals); >+ >+ if (result == LDAP_SUCCESS) { >+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, >+ "[%" APR_PID_T_FMT "] auth_ldap_authorise: checking dn match %s", >+ getpid(), dn); >+ result = util_ldap_cache_comparedn(r, ldc, sec->url, req->dn, dn, >+ sec->compare_dn_on_server); >+ >+ } >+ >+ switch (result) { >+ case LDAP_COMPARE_TRUE: { >+ >+ } >+ case LDAP_FILTER_ERROR: { >+ >+ } >+ default: { >+ >+ } >+ } >+ >+ key++; >+ } >+ >+ switch (result) { >+ case LDAP_COMPARE_TRUE: { >+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, >+ "[%" APR_PID_T_FMT "] auth_ldap_authorise: require dynamic group: " >+ "authorisation successful [%s][%s]", >+ getpid(), ldc->reason, ldap_err2string(result)); >+ return OK; >+ } >+ default : { >+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, >+ "[%" APR_PID_T_FMT "] auth_ldap authorise: require dynamic group: " >+ "authorisation failed [%s][%s]", >+ getpid(), ldc->reason, ldap_err2string(result)); >+ >+ } >+ } >+ } >+ } > } > else if (strcmp(w, "ldap-attribute") == 0) { > if (req->dn == NULL || strlen(req->dn) == 0) { >@@ -1015,6 +1113,21 @@ > return NULL; > } > >+static const char *mod_auth_ldap_add_dynamic_group_attribute(cmd_parms *cmd, void *config, const char *arg) >+{ >+ struct mod_auth_ldap_groupattr_entry_t *new; >+ >+ authn_ldap_config_t *sec = config; >+ >+ if (sec->dynamicgroupattr->nelts > GROUPATTR_MAX_ELTS) >+ return "Too many AuthLDAPDynamicGroupAttribute directives"; >+ >+ new = apr_array_push(sec->dynamicgroupattr); >+ new->name = apr_pstrdup(cmd->pool, arg); >+ >+ return NULL; >+} >+ > static const char *set_charset_config(cmd_parms *cmd, void *config, const char *arg) > { > ap_set_module_config(cmd->server->module_config, &authnz_ldap_module, >@@ -1106,6 +1219,15 @@ > "Character set conversion configuration file. If omitted, character set" > "conversion is disabled."), > >+ AP_INIT_FLAG("AuthLDAPDynamicGroupLookup", ap_set_flag_slot, >+ (void *)APR_OFFSETOF(authn_ldap_config_t, dynamic_group_lookup), OR_AUTHCFG, >+ "If set to 'on', auth_ldap will look for dynamic group URI in a group DN " >+ "and attempt to see if a user is part of a group defined by that URI " >+ "Defaults to 'off'."), >+ >+ AP_INIT_TAKE1("AuthLDAPDynamicGroupAttribute", mod_auth_ldap_add_dynamic_group_attribute, NULL, OR_AUTHCFG, >+ "A list of attributes containing dynamic group URIs. Defaults to \"memberURL\"."), >+ > {NULL} > }; > >@@ -1203,6 +1325,8 @@ > util_ldap_connection_find = APR_RETRIEVE_OPTIONAL_FN(uldap_connection_find); > util_ldap_cache_comparedn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedn); > util_ldap_cache_compare = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_compare); >+ util_ldap_cache_comparedynamicgroup = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_comparedynamicgroup); >+ util_ldap_cache_getattributevalues = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getattributevalues); > util_ldap_cache_checkuserid = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_checkuserid); > util_ldap_cache_getuserdn = APR_RETRIEVE_OPTIONAL_FN(uldap_cache_getuserdn); > util_ldap_ssl_supported = APR_RETRIEVE_OPTIONAL_FN(uldap_ssl_supported); >Index: modules/aaa/NWGNUauthnzldap >=================================================================== >--- modules/aaa/NWGNUauthnzldap (revision 489745) >+++ modules/aaa/NWGNUauthnzldap (working copy) >@@ -217,6 +217,8 @@ > util_ldap_cache_getuserdn \ > util_ldap_cache_compare \ > util_ldap_cache_comparedn \ >+ util_ldap_cache_comparedynamicgroup \ >+ util_ldap_cache_getattributevalues \ > @$(APR)/aprlib.imp \ > @$(NWOS)/httpd.imp \ > @libc.imp \ >Index: include/util_ldap.h >=================================================================== >--- include/util_ldap.h (revision 489745) >+++ include/util_ldap.h (working copy) >@@ -140,6 +140,9 @@ > > } util_ldap_state_t; > >+typedef struct util_ldap_attrvalue_entry_t { >+ char *value; >+} util_ldap_attrvalue_entry_t; > > /** > * Open a connection to an LDAP server >@@ -248,6 +251,34 @@ > const char *url, const char *dn, const char *attrib, const char *value)); > > /** >+ * Checks to see if a DN is part of a dynamic group >+ * @param r The request record >+ * @param ldc The LDAP connection being used >+ * @param url The URL of the LDAP connection - used for deciding which cache to use >+ * @param dn The DN of the object containing the dynamic group attributes >+ * @param groupattrib The attribute containing the dynamic group URI's >+ * @param userattrib The user attribute >+ * @param base The search base of the connection >+ * @param scope The search scope of the connection >+ * @param user The user we are comparing >+ */ >+APR_DECLARE_OPTIONAL_FN(int,uldap_cache_comparedynamicgroup,(request_rec *r, util_ldap_connection_t *ldc, >+ const char *url, const char *dn, >+ const char *base, int scope, >+ const char *user, const char *userdn)); >+ >+/** >+ * Returns an array of values for an attribute in a DN >+ * @param r The request record >+ * @param ldc The LDAP connection being used >+ * @param url The URL of the LDAP connection - used for deciding which cache to use >+ * @param dn The DN of the object containing the attribute >+ * @param attrib The attrib for which to return values >+ */ >+APR_DECLARE_OPTIONAL_FN(char **, uldap_cache_getattributevalues,(request_rec *r, util_ldap_connection_t *ldc, >+ const char *url, const char *dn, const char *attrib)); >+ >+/** > * Checks a username/password combination by binding to the LDAP server > * @param r The request record > * @param ldc The LDAP connection being used.
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 38515
:
17599
| 19734 |
24730