Skip to content

Commit ccc8666

Browse files
committed
Support caching of LDAP search attributes
1 parent 90708be commit ccc8666

File tree

1 file changed

+74
-19
lines changed

1 file changed

+74
-19
lines changed

ngx_http_auth_ldap_module.c

Lines changed: 74 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, LDAP **ld);
8484
#define ENCODING_B64 1
8585
#define ENCODING_HEX 2
8686

87-
#define MAX_ATTRS_COUNT 5 /* Maximum search attributes to display in log */
87+
#define DEFAULT_ATTRS_COUNT 3 /* The default number of search attributes */
88+
#define MAX_ATTRS_COUNT 5 /* Maximum search attributes to display in log */
89+
8890

8991

9092
typedef struct {
@@ -144,18 +146,26 @@ typedef struct {
144146
ngx_array_t *servers; /* array of ngx_http_auth_ldap_server_t* */
145147
} ngx_http_auth_ldap_loc_conf_t;
146148

149+
150+
typedef struct {
151+
ngx_str_t attr_name;
152+
ngx_str_t attr_value;
153+
} ldap_search_attribute_t;
154+
147155
typedef struct {
148156
uint32_t small_hash; /* murmur2 hash of username ^ &server */
149157
uint32_t outcome; /* OUTCOME_DENY or OUTCOME_ALLOW */
150158
ngx_msec_t time; /* ngx_current_msec when created */
151159
u_char big_hash[16]; /* md5 hash of (username, server, password) */
160+
ngx_array_t attributes; /* Attributes (ldap_search_attribute_t) retreived during the search */
152161
} ngx_http_auth_ldap_cache_elt_t;
153162

154163
typedef struct {
155164
ngx_http_auth_ldap_cache_elt_t *buckets;
156165
ngx_uint_t num_buckets;
157166
ngx_uint_t elts_per_bucket;
158167
ngx_msec_t expiration_time;
168+
ngx_pool_t *pool;
159169
} ngx_http_auth_ldap_cache_t;
160170

161171
typedef enum {
@@ -175,6 +185,7 @@ typedef struct {
175185
ngx_http_auth_ldap_request_phase_t phase;
176186
unsigned int iteration;
177187
int outcome;
188+
ngx_array_t attributes; /* Attributes (ldap_search_attribute_t) retreived during the search */
178189

179190
struct ngx_http_auth_ldap_connection *c;
180191
ngx_queue_t queue;
@@ -1117,6 +1128,9 @@ ngx_http_auth_ldap_init_cache(ngx_cycle_t *cycle)
11171128
577, 641, 701, 769, 839, 911, 983, 1049, 1109
11181129
};
11191130

1131+
cache = &ngx_http_auth_ldap_cache;
1132+
cache->pool = cycle->pool;
1133+
11201134
conf = (ngx_http_auth_ldap_main_conf_t *) ngx_http_cycle_get_module_main_conf(cycle, ngx_http_auth_ldap_module);
11211135
if (conf == NULL || !conf->cache_enabled) {
11221136
return NGX_OK;
@@ -1131,7 +1145,7 @@ ngx_http_auth_ldap_init_cache(ngx_cycle_t *cycle)
11311145
}
11321146
}
11331147

1134-
cache = &ngx_http_auth_ldap_cache;
1148+
11351149
cache->expiration_time = conf->cache_expiration_time;
11361150
cache->num_buckets = count;
11371151
cache->elts_per_bucket = 8;
@@ -1145,6 +1159,12 @@ ngx_http_auth_ldap_init_cache(ngx_cycle_t *cycle)
11451159
return NGX_ERROR;
11461160
}
11471161

1162+
/* Initialize the attributes array in each cache entry */
1163+
ngx_http_auth_ldap_cache_elt_t *cache_entry = cache->buckets;
1164+
for (i = 0; i < cache->num_buckets * cache->elts_per_bucket; i++, cache_entry++) {
1165+
ngx_array_init(&cache_entry->attributes, cache->pool, DEFAULT_ATTRS_COUNT, sizeof(ldap_search_attribute_t));
1166+
}
1167+
11481168
return NGX_OK;
11491169
}
11501170

@@ -1173,6 +1193,17 @@ ngx_http_auth_ldap_check_cache(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *
11731193
if (elt->small_hash == ctx->cache_small_hash &&
11741194
elt->time > time_limit &&
11751195
memcmp(elt->big_hash, ctx->cache_big_hash, 16) == 0) {
1196+
if (elt->outcome == OUTCOME_ALLOW || elt->outcome == OUTCOME_CACHED_ALLOW) {
1197+
/* Restore the cached attributes to the current context */
1198+
ctx->attributes.nelts = 0;
1199+
for (i = 0; i < elt->attributes.nelts; i++) {
1200+
ldap_search_attribute_t *ctx_attr = ngx_array_push(&ctx->attributes);
1201+
*ctx_attr = *((ldap_search_attribute_t *)elt->attributes.elts + i);
1202+
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1203+
"http_auth_ldap: ngx_http_auth_ldap_check_cache: restoring attribute '%V' = '%V' from cache",
1204+
&ctx_attr->attr_name, &ctx_attr->attr_value);
1205+
}
1206+
}
11761207
return elt->outcome;
11771208
}
11781209
}
@@ -1199,6 +1230,15 @@ ngx_http_auth_ldap_update_cache(ngx_http_auth_ldap_ctx_t *ctx,
11991230
oldest_elt->outcome = outcome;
12001231
oldest_elt->small_hash = ctx->cache_small_hash;
12011232
ngx_memcpy(oldest_elt->big_hash, ctx->cache_big_hash, 16);
1233+
/* save (copy) each attribute from the context to the cache */
1234+
oldest_elt->attributes.nelts = 0;
1235+
for (i = 0; i < ctx->attributes.nelts; i++) {
1236+
ldap_search_attribute_t *cache_attr = ngx_array_push(&oldest_elt->attributes);
1237+
*cache_attr = *((ldap_search_attribute_t *)ctx->attributes.elts + i);
1238+
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->r->connection->log, 0,
1239+
"http_auth_ldap: ngx_http_auth_ldap_update_cache: saving '%V' = '%V' to cache",
1240+
&cache_attr->attr_name, &cache_attr->attr_value);
1241+
}
12021242
}
12031243

12041244

@@ -1895,30 +1935,25 @@ ngx_http_auth_ldap_read_handler(ngx_event_t *rev)
18951935
BerElement *ber = NULL;
18961936
char *attr = NULL;
18971937
struct berval **vals = NULL;
1898-
ngx_table_elt_t *h;
18991938
for (attr = ldap_first_attribute(c->ld, result, &ber);
19001939
attr != NULL;
19011940
attr = ldap_next_attribute(c->ld, result, ber)) {
19021941
/* Get only first value for each attribute. */
19031942
if ((vals = ldap_get_values_len(c->ld, result, attr)) != NULL ) {
19041943
if(vals[0] != NULL) {
19051944
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Received attribute %s: %s", attr, vals[0]->bv_val);
1906-
h = ngx_list_push(&c->rctx->r->headers_out.headers);
1907-
if (h != NULL) {
1908-
santitize_str((u_char *)attr, SANITIZE_NO_CONV);
1909-
int attr_len = strlen(attr);
1910-
h->hash = 1;
1911-
#if (nginx_version >= 1023000)
1912-
h->next = NULL;
1913-
#endif
1914-
h->key.len = c->server->attribute_header_prefix.len + attr_len;
1915-
h->key.data = ngx_pnalloc(c->rctx->r->pool, h->key.len);
1916-
unsigned char *p = ngx_cpymem(h->key.data, c->server->attribute_header_prefix.data, c->server->attribute_header_prefix.len);
1917-
p = ngx_cpymem(p, attr, attr_len);
1918-
h->value.len = vals[0]->bv_len;
1919-
h->value.data = ngx_pnalloc(c->rctx->r->pool, h->value.len);
1920-
ngx_memcpy(h->value.data, vals[0]->bv_val, h->value.len);
1921-
}
1945+
/* Save attribute name and value in the context */
1946+
ldap_search_attribute_t * elt = ngx_array_push(&c->rctx->attributes);
1947+
santitize_str((u_char *)attr, SANITIZE_NO_CONV);
1948+
int attr_len = strlen(attr);
1949+
elt->attr_name.len = c->server->attribute_header_prefix.len + attr_len;
1950+
/* Use the pool of global cache to allocate strings, so that they can be used everywhere */
1951+
elt->attr_name.data = ngx_pnalloc(ngx_http_auth_ldap_cache.pool, elt->attr_name.len);
1952+
unsigned char *p = ngx_cpymem(elt->attr_name.data, c->server->attribute_header_prefix.data, c->server->attribute_header_prefix.len);
1953+
p = ngx_cpymem(p, attr, attr_len);
1954+
elt->attr_value.len = vals[0]->bv_len;
1955+
elt->attr_value.data = ngx_pnalloc(ngx_http_auth_ldap_cache.pool, elt->attr_value.len);
1956+
ngx_memcpy(elt->attr_value.data, vals[0]->bv_val, elt->attr_value.len);
19221957
}
19231958
ldap_value_free_len(vals);
19241959
}
@@ -2377,6 +2412,10 @@ ngx_http_auth_ldap_handler(ngx_http_request_t *r)
23772412
return NGX_HTTP_INTERNAL_SERVER_ERROR;
23782413
}
23792414
ctx->r = r;
2415+
2416+
/* Initialize the attributes array */
2417+
ngx_array_init(&ctx->attributes, r->pool, DEFAULT_ATTRS_COUNT, sizeof(ldap_search_attribute_t));
2418+
23802419
/* Other fields have been initialized to zero/NULL */
23812420
ngx_http_set_ctx(r, ctx, ngx_http_auth_ldap_module);
23822421
}
@@ -2587,6 +2626,22 @@ ngx_http_auth_ldap_authenticate(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t
25872626
}
25882627

25892628
if (ctx->outcome == OUTCOME_ALLOW || ctx->outcome == OUTCOME_CACHED_ALLOW) {
2629+
/* Create response headers for each search attributes found in context */
2630+
for (i = 0; i < ctx->attributes.nelts; i++) {
2631+
ldap_search_attribute_t *elt = (ldap_search_attribute_t *)ctx->attributes.elts + i;
2632+
ngx_table_elt_t *h = ngx_list_push(&r->headers_out.headers);
2633+
if (h != NULL) {
2634+
h->hash = 1;
2635+
#if (nginx_version >= 1023000)
2636+
h->next = NULL;
2637+
#endif
2638+
h->key = elt->attr_name;
2639+
h->value = elt->attr_value;
2640+
}
2641+
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2642+
"http_auth_ldap: ngx_http_auth_ldap_authenticate set response header %V : %V",
2643+
&elt->attr_name, &elt->attr_value);
2644+
}
25902645
return NGX_OK;
25912646
}
25922647

0 commit comments

Comments
 (0)