@@ -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
9092typedef 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+
147155typedef 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
154163typedef 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
161171typedef 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