I'm not sure in modules/control and modules/watch/http-auth-ldap.
But it builds, installs and works for me on debian buster.

-- 
sergio.
diff -Naur debian/control debian+ldap/control
--- debian/control	2019-08-13 21:10:28.000000000 +0300
+++ debian+ldap/control	2019-11-08 04:49:04.948000000 +0300
@@ -13,6 +13,7 @@
                libluajit-5.1-dev [i386 amd64 kfreebsd-i386 armel armhf powerpc powerpcspe mips mipsel],
                libmhash-dev,
                libpam0g-dev,
+               libldap2-dev,
                libpcre3-dev,
                libperl-dev,
                libssl-dev,
@@ -66,6 +67,7 @@
 Package: nginx-full
 Architecture: any
 Depends: libnginx-mod-http-auth-pam (= ${binary:Version}),
+         libnginx-mod-http-auth-ldap (= ${binary:Version}),
          libnginx-mod-http-dav-ext (= ${binary:Version}),
          libnginx-mod-http-echo (= ${binary:Version}),
          libnginx-mod-http-geoip (= ${binary:Version}),
@@ -102,7 +104,7 @@
  .
  MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP.
  .
- THIRD PARTY MODULES: Auth PAM, DAV Ext, Echo, HTTP Substitutions, Upstream
+ THIRD PARTY MODULES: Auth PAM, LDAP, DAV Ext, Echo, HTTP Substitutions, Upstream
  Fair Queue.
 
 Package: nginx-light
@@ -135,6 +137,7 @@
 Package: nginx-extras
 Architecture: any
 Depends: libnginx-mod-http-auth-pam (= ${binary:Version}),
+         libnginx-mod-http-auth-ldap (= ${binary:Version}),
          libnginx-mod-http-cache-purge (= ${binary:Version}),
          libnginx-mod-http-dav-ext (= ${binary:Version}),
          libnginx-mod-http-echo (= ${binary:Version}),
@@ -179,7 +182,7 @@
  .
  MAIL MODULES: Mail Core, Auth HTTP, Proxy, SSL, IMAP, POP3, SMTP.
  .
- THIRD PARTY MODULES: Auth PAM, Cache Purge, DAV Ext, Echo, Fancy Index,
+ THIRD PARTY MODULES: Auth PAM, LDAP, Cache Purge, DAV Ext, Echo, Fancy Index,
  Headers More, Embedded Lua, HTTP Substitutions, Nchan, Upload Progress,
  Upstream Fair Queue.
 
@@ -253,6 +256,14 @@
  The module uses PAM as a backend for simple http authentication. It
  also allows setting the pam service name to allow more fine grained control.
 
+Package: libnginx-mod-http-auth-ldap
+Architecture: any
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Description: LDAP authentication module for Nginx
+ The nginx_http_auth_ldap module enables authentication using LDAP.
+ .
+ The module uses LDAP as a backend for simple http authentication.
+
 Package: libnginx-mod-http-lua
 Architecture: any
 Depends: libnginx-mod-http-ndk (= ${binary:Version}),
diff -Naur debian/copyright debian+ldap/copyright
--- debian/copyright	2019-08-13 21:10:28.000000000 +0300
+++ debian+ldap/copyright	2019-11-08 09:50:28.520000000 +0300
@@ -56,6 +56,10 @@
 Copyright: 2008-2013, Sergio Talens Oliag
 License: BSD-2-clause
 
+Files: debian/modules/http-auth-ldap/*
+Copyright: 2008-2013, Valery Komarov
+License: BSD-2-clause
+
 Files: debian/modules/http-echo/*
 Copyright: Copyright (c) 2009-2014, Yichun "agentzh" Zhang <agen...@gmail.com>
 License: BSD-2-clause
diff -Naur debian/libnginx-mod-http-auth-ldap.nginx debian+ldap/libnginx-mod-http-auth-ldap.nginx
--- debian/libnginx-mod-http-auth-ldap.nginx	1970-01-01 03:00:00.000000000 +0300
+++ debian+ldap/libnginx-mod-http-auth-ldap.nginx	2019-11-08 12:57:33.452000000 +0300
@@ -0,0 +1,13 @@
+#!/usr/bin/perl -w
+
+use File::Basename;
+
+# Guess module name
+$module = basename($0, '.nginx');
+$module =~ s/^libnginx-mod-//;
+
+$modulepath = $module;
+$modulepath =~ s/-/_/g;
+
+print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n";
+print "mod debian/libnginx-mod.conf/mod-${module}.conf\n";
diff -Naur debian/libnginx-mod.conf/mod-http-auth-ldap.conf debian+ldap/libnginx-mod.conf/mod-http-auth-ldap.conf
--- debian/libnginx-mod.conf/mod-http-auth-ldap.conf	1970-01-01 03:00:00.000000000 +0300
+++ debian+ldap/libnginx-mod.conf/mod-http-auth-ldap.conf	2019-11-08 04:49:04.952000000 +0300
@@ -0,0 +1 @@
+load_module modules/ngx_http_auth_ldap_module.so;
diff -Naur debian/modules/control debian+ldap/modules/control
--- debian/modules/control	2019-08-13 21:10:28.000000000 +0300
+++ debian+ldap/modules/control	2019-11-08 09:02:21.444000000 +0300
@@ -11,6 +11,10 @@
 Homepage: https://github.com/stogh/ngx_http_auth_pam_module
 Version: 1.5.1
 
+Module: http-auth-ldap
+Homepage: https://github.com/kvspb/nginx-auth-ldap
+Version: 0.1
+
 Module: http-echo
 Homepage: https://github.com/agentzh/echo-nginx-module
 Version: v0.61
diff -Naur debian/modules/http-auth-ldap/LICENSE debian+ldap/modules/http-auth-ldap/LICENSE
--- debian/modules/http-auth-ldap/LICENSE	1970-01-01 03:00:00.000000000 +0300
+++ debian+ldap/modules/http-auth-ldap/LICENSE	2019-11-08 04:49:04.980000000 +0300
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2011-2013 Valery Komarov <koma...@valerka.net>
+ * Copyright (C) 2013 Jiri Hruska <ji...@fud.cz>
+ * Copyright (C) 2015-2016 Victor Hahn Castell <victor.h...@flexoptix.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
diff -Naur debian/modules/http-auth-ldap/README.md debian+ldap/modules/http-auth-ldap/README.md
--- debian/modules/http-auth-ldap/README.md	1970-01-01 03:00:00.000000000 +0300
+++ debian+ldap/modules/http-auth-ldap/README.md	2019-11-08 04:49:04.980000000 +0300
@@ -0,0 +1,145 @@
+# LDAP Authentication module for nginx
+LDAP module for nginx which supports authentication against multiple LDAP servers.
+
+# How to install
+
+## FreeBSD
+
+```bash
+cd /usr/ports/www/nginx && make config install clean
+```
+
+Check HTTP_AUTH_LDAP options
+
+
+```
+[*] HTTP_AUTH_LDAP        3rd party http_auth_ldap module
+```
+
+## Linux
+
+```bash
+cd ~ && git clone https://github.com/kvspb/nginx-auth-ldap.git   
+```
+
+in nginx source folder
+
+```bash
+./configure --add-module=path_to_http_auth_ldap_module
+make install
+```
+
+# Example configuration
+Define list of your LDAP servers with required user/group requirements:
+
+```bash
+    http {
+      ldap_server test1 {
+        url ldap://192.168.0.1:3268/DC=test,DC=local?sAMAccountName?sub?(objectClass=person);
+        binddn "TEST\\LDAPUSER";
+        binddn_passwd LDAPPASSWORD;
+        group_attribute uniquemember;
+        group_attribute_is_dn on;
+        require valid_user;
+      }
+
+      ldap_server test2 {
+        url ldap://192.168.0.2:3268/DC=test,DC=local?sAMAccountName?sub?(objectClass=person);
+        binddn "TEST\\LDAPUSER";
+        binddn_passwd LDAPPASSWORD;
+        group_attribute uniquemember;
+        group_attribute_is_dn on;
+        require valid_user;
+      }
+    }
+```
+
+And add required servers in correct order into your location/server directive:
+```bash
+    server {
+        listen       8000;
+        server_name  localhost;
+
+        auth_ldap "Forbidden";
+        auth_ldap_servers test1;
+		auth_ldap_servers test2;
+
+        location / {
+            root   html;
+            index  index.html index.htm;
+        }
+
+    }
+```
+
+# Available config parameters
+
+## url
+expected value: string
+
+Available URL schemes: ldap://, ldaps://
+
+## binddn
+expected value: string
+
+## binddn_passwd
+expected value: string
+
+## group_attribute
+expected value: string
+
+## group_attribute_is_dn
+expected value: on or off, default off
+
+## require
+expected value: valid_user, user, group
+
+## satisfy
+expected value: all, any
+
+## max_down_retries
+expected value: a number, default 0
+
+Retry count for attempting to reconnect to an LDAP server if it is considered
+"DOWN".  This may happen if a KEEP-ALIVE connection to an LDAP server times 
+out or is terminated by the server end after some amount of time.  
+
+This can usually help with the following error:
+
+```
+http_auth_ldap: ldap_result() failed (-1: Can't contact LDAP server)
+```
+
+## connections
+expected value: a number greater than 0
+
+## ssl_check_cert
+expected value: on or off, default off
+
+Verify the remote certificate for LDAPs connections. If disabled, any remote certificate will be
+accepted which exposes you to possible man-in-the-middle attacks. Note that the server's
+certificate will need to be signed by a proper CA trusted by your system if this is enabled.
+See below how to trust CAs without installing them system-wide.
+
+This options needs OpenSSL >= 1.0.2; it is unavailable if compiled with older versions.
+
+## ssl_ca_file
+expected value: file path
+
+Trust the CA certificate in this file (see ssl_check_cert above).
+
+## ssl_ca_dir
+expected value: directory path
+
+Trust all CA certificates in this directory (see ssl_check_cert above).
+
+Note that you need to provide hash-based symlinks in the directory for this to work;
+you'll basically need to run OpenSSL's c_rehash command in this directory.
+
+## referral
+expected value: on, off
+
+LDAP library default is on. This option disables usage of referral messages from
+LDAP server. Usefull for authenticating against read only AD server without access
+to read write.
+
diff -Naur debian/modules/http-auth-ldap/config debian+ldap/modules/http-auth-ldap/config
--- debian/modules/http-auth-ldap/config	1970-01-01 03:00:00.000000000 +0300
+++ debian+ldap/modules/http-auth-ldap/config	2019-11-08 04:49:04.980000000 +0300
@@ -0,0 +1,23 @@
+ngx_addon_name=ngx_http_auth_ldap_module
+
+LDAP_REQUIRED_LIBS="-lldap"
+
+case "$NGX_PLATFORM" in
+    Darwin:*|FreeBSD:*|Linux:*|SunOS:*)
+        LDAP_REQUIRED_LIBS="$LDAP_REQUIRED_LIBS -llber"
+    ;;
+esac
+
+if test -n "$ngx_module_link"; then
+    ngx_module_type=HTTP
+    ngx_module_name=ngx_http_auth_ldap_module
+    ngx_module_incs=
+    ngx_module_deps=
+    ngx_module_srcs="$ngx_addon_dir/ngx_http_auth_ldap_module.c"
+    ngx_module_libs="$LDAP_REQUIRED_LIBS"
+    . auto/module
+else
+    HTTP_MODULES="$HTTP_MODULES ngx_http_auth_ldap_module"
+    NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_auth_ldap_module.c"
+    CORE_LIBS="$CORE_LIBS $LDAP_REQUIRED_LIBS"
+fi
diff -Naur debian/modules/http-auth-ldap/example.conf debian+ldap/modules/http-auth-ldap/example.conf
--- debian/modules/http-auth-ldap/example.conf	1970-01-01 03:00:00.000000000 +0300
+++ debian+ldap/modules/http-auth-ldap/example.conf	2019-11-08 04:49:04.980000000 +0300
@@ -0,0 +1,58 @@
+worker_processes  1;
+
+events {
+    worker_connections  1024;
+}
+
+http {
+    include       mime.types;
+    default_type  application/octet-stream;
+
+    sendfile        on;
+    keepalive_timeout  65;
+
+    # define ldap server
+    ldap_server ad_1 {
+      # user search base.
+      url "ldap://<YOUR LDAP SERVER>:3268/OU=Offices,DC=company,DC=com?sAMAccountName?sub?(objectClass=person)";
+      # bind as
+      binddn "CN=Operator,OU=Service Accounts,DC=company,DC=com";
+      # bind pw
+      binddn_passwd <PUT Operator's PASSWORD HERE>;
+      # group attribute name which contains member object
+      group_attribute member;
+      # search for full DN in member object
+      group_attribute_is_dn on;
+      # matching algorithm (any / all)
+      satisfy any;
+      # list of allowed groups
+      require group "CN=Admins,OU=My Security Groups,DC=company,DC=com";
+      require group "CN=New York Users,OU=My Security Groups,DC=company,DC=com";
+      # list of allowed users
+      # require 'valid_user' cannot be used together with 'user' as valid user is a superset
+      # require valid_user;
+      require user "CN=Batman,OU=Users,OU=New York Office,OU=Offices,DC=company,DC=com";
+      require user "CN=Robocop,OU=Users,OU=New York Office,OU=Offices,DC=company,DC=com";
+    }
+
+}
+
+server {
+  listen       8081;
+  server_name  localhost;
+
+  location / {
+    # adding ldap authentication
+    auth_ldap "Closed content";
+    auth_ldap_servers ad_1;
+
+    root html;
+    index index.html index.htm;
+  }
+
+  error_page   500 502 503 504  /50x.html;
+
+  location = /50x.html {
+    root html;
+  }
+}
diff -Naur debian/modules/http-auth-ldap/ngx_http_auth_ldap_module.c debian+ldap/modules/http-auth-ldap/ngx_http_auth_ldap_module.c
--- debian/modules/http-auth-ldap/ngx_http_auth_ldap_module.c	1970-01-01 03:00:00.000000000 +0300
+++ debian+ldap/modules/http-auth-ldap/ngx_http_auth_ldap_module.c	2019-11-08 04:49:04.980000000 +0300
@@ -0,0 +1,2355 @@
+/**
+ * Copyright (C) 2011-2013 Valery Komarov <koma...@valerka.net>
+ * Copyright (C) 2013 Jiri Hruska <ji...@fud.cz>
+ * Copyright (C) 2015-2016 Victor Hahn Castell <victor.h...@flexoptix.net>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+#include <ngx_md5.h>
+#include <ldap.h>
+#include <openssl/opensslv.h>
+
+// used for manual warnings
+#define XSTR(x) STR(x)
+#define STR(x) #x
+// make sure manual warnings don't get escalated to errors
+#ifdef __clang__
+#pragma clang diagnostic warning "-W#warnings"
+#else
+#ifdef __GNUC__
+#pragma GCC diagnostic warning "-Wcpp"
+#endif
+#endif
+// TODO: do the same stuff for MSVC and/or other compilers
+
+
+#ifndef LDAP_PROTO_EXT
+/* Some OpenLDAP headers are accidentally missing ldap_init_fd() etc. */
+
+#define LDAP_PROTO_TCP 1 /* ldap://  */
+#define LDAP_PROTO_UDP 2 /* reserved */
+#define LDAP_PROTO_IPC 3 /* ldapi:// */
+#define LDAP_PROTO_EXT 4 /* user-defined socket/sockbuf */
+
+extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, LDAP **ld);
+#endif
+
+#define OUTCOME_ERROR          -1 /* Some error occured in the process */
+#define OUTCOME_DENY            0
+#define OUTCOME_ALLOW           1
+#define OUTCOME_CACHED_DENY     2 /* Cached results */
+#define OUTCOME_CACHED_ALLOW    3
+#define OUTCOME_UNCERTAIN       4 /* Not yet decided */
+
+#define NGX_HTTP_AUTH_LDAP_MAX_SERVERS_SIZE 7
+
+
+typedef struct {
+    LDAPURLDesc *ludpp;
+    ngx_str_t url;
+    ngx_url_t parsed_url;
+    ngx_str_t alias;
+
+    ngx_str_t bind_dn;
+    ngx_str_t bind_dn_passwd;
+
+    ngx_str_t group_attribute;
+    ngx_flag_t group_attribute_dn;
+
+    ngx_flag_t ssl_check_cert;
+    ngx_str_t ssl_ca_dir;
+    ngx_str_t ssl_ca_file;
+
+    ngx_array_t *require_group;     /* array of ngx_http_complex_value_t */
+    ngx_array_t *require_user;      /* array of ngx_http_complex_value_t */
+    ngx_flag_t require_valid_user;
+    ngx_http_complex_value_t require_valid_user_dn;
+    ngx_flag_t satisfy_all;
+    ngx_flag_t referral;
+
+    ngx_uint_t connections;
+    ngx_uint_t max_down_retries;
+    ngx_uint_t max_down_retries_count;
+    ngx_msec_t connect_timeout;
+    ngx_msec_t reconnect_timeout;
+    ngx_msec_t bind_timeout;
+    ngx_msec_t request_timeout;
+    ngx_queue_t free_connections;
+    ngx_queue_t waiting_requests;
+} ngx_http_auth_ldap_server_t;
+
+typedef struct {
+    ngx_array_t *servers;        /* array of ngx_http_auth_ldap_server_t */
+    ngx_flag_t cache_enabled;
+    ngx_msec_t cache_expiration_time;
+    size_t cache_size;
+    ngx_int_t servers_size;
+#if (NGX_OPENSSL)
+    ngx_ssl_t ssl;
+#endif
+} ngx_http_auth_ldap_main_conf_t;
+
+typedef struct {
+    ngx_str_t realm;
+    ngx_array_t *servers;       /* array of ngx_http_auth_ldap_server_t* */
+} ngx_http_auth_ldap_loc_conf_t;
+
+typedef struct {
+    uint32_t small_hash;     /* murmur2 hash of username ^ &server       */
+    uint32_t outcome;        /* OUTCOME_DENY or OUTCOME_ALLOW            */
+    ngx_msec_t time;         /* ngx_current_msec when created            */
+    u_char big_hash[16];     /* md5 hash of (username, server, password) */
+} ngx_http_auth_ldap_cache_elt_t;
+
+typedef struct {
+    ngx_http_auth_ldap_cache_elt_t *buckets;
+    ngx_uint_t num_buckets;
+    ngx_uint_t elts_per_bucket;
+    ngx_msec_t expiration_time;
+} ngx_http_auth_ldap_cache_t;
+
+typedef enum {
+    PHASE_START,
+    PHASE_SEARCH,
+    PHASE_CHECK_USER,
+    PHASE_CHECK_GROUP,
+    PHASE_CHECK_BIND,
+    PHASE_REBIND,
+    PHASE_NEXT
+} ngx_http_auth_ldap_request_phase_t;
+
+typedef struct {
+    ngx_http_request_t *r;
+    ngx_uint_t server_index;
+    ngx_http_auth_ldap_server_t *server;
+    ngx_http_auth_ldap_request_phase_t phase;
+    unsigned int iteration;
+    int outcome;
+
+    struct ngx_http_auth_ldap_connection *c;
+    ngx_queue_t queue;
+    int replied;
+    int error_code;
+    ngx_str_t error_msg;
+    ngx_str_t dn;
+    ngx_str_t user_dn;
+    ngx_str_t group_dn;
+
+    ngx_http_auth_ldap_cache_elt_t *cache_bucket;
+    u_char cache_big_hash[16];
+    uint32_t cache_small_hash;
+} ngx_http_auth_ldap_ctx_t;
+
+typedef enum {
+    STATE_DISCONNECTED,
+    STATE_INITIAL_BINDING,
+    STATE_CONNECTING,
+    STATE_READY,
+    STATE_BINDING,
+    STATE_SEARCHING,
+    STATE_COMPARING
+} ngx_http_auth_ldap_connection_state_t;
+
+typedef struct ngx_http_auth_ldap_connection {
+    ngx_log_t *log;
+    ngx_http_auth_ldap_server_t *server;
+    ngx_peer_connection_t conn;
+    ngx_event_t reconnect_event;
+
+#if (NGX_OPENSSL)
+    ngx_pool_t *pool;
+    ngx_ssl_t *ssl;
+#endif
+
+    ngx_queue_t queue;
+    ngx_http_auth_ldap_ctx_t *rctx;
+
+    LDAP* ld;
+    ngx_http_auth_ldap_connection_state_t state;
+    int msgid;
+} ngx_http_auth_ldap_connection_t;
+
+static char * ngx_http_auth_ldap_ldap_server_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char * ngx_http_auth_ldap_ldap_server(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
+static char * ngx_http_auth_ldap(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char * ngx_http_auth_ldap_servers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char * ngx_http_auth_ldap_parse_url(ngx_conf_t *cf, ngx_http_auth_ldap_server_t *server);
+static char * ngx_http_auth_ldap_parse_require(ngx_conf_t *cf, ngx_http_auth_ldap_server_t *server);
+static char * ngx_http_auth_ldap_parse_satisfy(ngx_conf_t *cf, ngx_http_auth_ldap_server_t *server);
+static char * ngx_http_auth_ldap_parse_referral(ngx_conf_t *cf, ngx_http_auth_ldap_server_t *server);
+static void * ngx_http_auth_ldap_create_main_conf(ngx_conf_t *cf);
+static char * ngx_http_auth_ldap_init_main_conf(ngx_conf_t *cf, void *parent);
+static void * ngx_http_auth_ldap_create_loc_conf(ngx_conf_t *);
+static char * ngx_http_auth_ldap_merge_loc_conf(ngx_conf_t *, void *, void *);
+static ngx_int_t ngx_http_auth_ldap_init_worker(ngx_cycle_t *cycle);
+static ngx_int_t ngx_http_auth_ldap_init(ngx_conf_t *cf);
+static ngx_int_t ngx_http_auth_ldap_init_cache(ngx_cycle_t *cycle);
+static void ngx_http_auth_ldap_close_connection(ngx_http_auth_ldap_connection_t *c);
+static void ngx_http_auth_ldap_read_handler(ngx_event_t *rev);
+static void ngx_http_auth_ldap_reconnect_handler(ngx_event_t *);
+static ngx_int_t ngx_http_auth_ldap_init_connections(ngx_cycle_t *cycle);
+static ngx_int_t ngx_http_auth_ldap_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_auth_ldap_authenticate(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx,
+        ngx_http_auth_ldap_loc_conf_t *conf);
+static ngx_int_t ngx_http_auth_ldap_search(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx);
+static ngx_int_t ngx_http_auth_ldap_check_user(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx);
+static ngx_int_t ngx_http_auth_ldap_check_group(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx);
+static ngx_int_t ngx_http_auth_ldap_check_bind(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx);
+static ngx_int_t ngx_http_auth_ldap_recover_bind(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx);
+#if (NGX_OPENSSL)
+static ngx_int_t ngx_http_auth_ldap_restore_handlers(ngx_connection_t *conn);
+#endif
+
+ngx_http_auth_ldap_cache_t ngx_http_auth_ldap_cache;
+
+static ngx_command_t ngx_http_auth_ldap_commands[] = {
+    {
+        ngx_string("ldap_server"),
+        NGX_HTTP_MAIN_CONF | NGX_CONF_BLOCK | NGX_CONF_TAKE1,
+        ngx_http_auth_ldap_ldap_server_block,
+        NGX_HTTP_MAIN_CONF_OFFSET,
+        0,
+        NULL
+    },
+    {
+        ngx_string("auth_ldap_cache_enabled"),
+        NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
+        ngx_conf_set_flag_slot,
+        NGX_HTTP_MAIN_CONF_OFFSET,
+        offsetof(ngx_http_auth_ldap_main_conf_t, cache_enabled),
+        NULL
+    },
+    {
+        ngx_string("auth_ldap_cache_expiration_time"),
+        NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
+        ngx_conf_set_msec_slot,
+        NGX_HTTP_MAIN_CONF_OFFSET,
+        offsetof(ngx_http_auth_ldap_main_conf_t, cache_expiration_time),
+        NULL
+    },
+    {
+        ngx_string("auth_ldap_cache_size"),
+        NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
+        ngx_conf_set_size_slot,
+        NGX_HTTP_MAIN_CONF_OFFSET,
+        offsetof(ngx_http_auth_ldap_main_conf_t, cache_size),
+        NULL
+    },
+    {
+        ngx_string("auth_ldap_servers_size"),
+        NGX_HTTP_MAIN_CONF | NGX_CONF_TAKE1,
+        ngx_conf_set_num_slot,
+        NGX_HTTP_MAIN_CONF_OFFSET,
+        offsetof(ngx_http_auth_ldap_main_conf_t, servers_size),
+        NULL
+    },
+    {
+        ngx_string("auth_ldap"),
+        NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_TAKE1,
+        ngx_http_auth_ldap,
+        NGX_HTTP_LOC_CONF_OFFSET,
+        0,
+        NULL
+    },
+    {
+        ngx_string("auth_ldap_servers"),
+        NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_ANY,
+        ngx_http_auth_ldap_servers,
+        NGX_HTTP_LOC_CONF_OFFSET,
+        0,
+        NULL
+    },
+    ngx_null_command
+};
+
+static ngx_http_module_t ngx_http_auth_ldap_module_ctx = {
+    NULL,                                /* preconfiguration */
+    ngx_http_auth_ldap_init,             /* postconfiguration */
+    ngx_http_auth_ldap_create_main_conf, /* create main configuration */
+    ngx_http_auth_ldap_init_main_conf,   /* init main configuration */
+    NULL,                                /* create server configuration */
+    NULL,                                /* merge server configuration */
+    ngx_http_auth_ldap_create_loc_conf,  /* create location configuration */
+    ngx_http_auth_ldap_merge_loc_conf    /* merge location configuration */
+};
+
+ngx_module_t ngx_http_auth_ldap_module = {
+    NGX_MODULE_V1,
+    &ngx_http_auth_ldap_module_ctx,      /* module context */
+    ngx_http_auth_ldap_commands,         /* module directives */
+    NGX_HTTP_MODULE,                     /* module type */
+    NULL,                                /* init master */
+    NULL,                                /* init module */
+    ngx_http_auth_ldap_init_worker,      /* init process */
+    NULL,                                /* init thread */
+    NULL,                                /* exit thread */
+    NULL,                                /* exit process */
+    NULL,                                /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+/*** Configuration and initialization ***/
+
+/**
+ * Reads ldap_server block and sets ngx_http_auth_ldap_ldap_server as a handler of each conf value
+ */
+static char *
+ngx_http_auth_ldap_ldap_server_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char                           *rv;
+    ngx_str_t                      *value, name;
+    ngx_conf_t                     save;
+    ngx_http_auth_ldap_server_t    *server;
+    ngx_http_auth_ldap_main_conf_t *cnf = conf;
+
+    value = cf->args->elts;
+
+    name = value[1];
+
+    if (ngx_strlen(name.data) == 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Missing server name in ldap_server");
+        return NGX_CONF_ERROR;
+    }
+
+    if (cnf->servers == NULL) {
+        if (cnf->servers_size == NGX_CONF_UNSET) {
+            cnf->servers_size = NGX_HTTP_AUTH_LDAP_MAX_SERVERS_SIZE;
+        }
+        cnf->servers = ngx_array_create(cf->pool, cnf->servers_size, sizeof(ngx_http_auth_ldap_server_t));
+        if (cnf->servers == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    server = ngx_array_push(cnf->servers);
+    if (server == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    ngx_memzero(server, sizeof(*server));
+    server->connect_timeout = 10000;
+    server->reconnect_timeout = 10000;
+    server->bind_timeout = 5000;
+    server->request_timeout = 10000;
+    server->alias = name;
+    server->referral = 1;
+
+    save = *cf;
+    cf->handler = ngx_http_auth_ldap_ldap_server;
+    cf->handler_conf = conf;
+    rv = ngx_conf_parse(cf, NULL);
+    *cf = save;
+
+    if (rv != NGX_CONF_OK) {
+        return rv;
+    }
+
+    return NGX_CONF_OK;
+}
+
+#define CONF_MSEC_VALUE(cf,value,server,x) \
+if (ngx_strcmp(value[0].data, #x) == 0) { \
+        ngx_msec_t _i = ngx_parse_time(&value[1], 0); \
+        if (_i == (ngx_msec_t) NGX_ERROR || _i == 0) { \
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: '" #x "' value has to be a valid time unit greater than 0"); \
+            return NGX_CONF_ERROR; \
+        } \
+        server->x = _i; \
+    }
+/**
+ * Called for every variable inside ldap_server block
+ */
+static char *
+ngx_http_auth_ldap_ldap_server(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
+{
+    char                           *rv;
+    ngx_str_t                      *value;
+    ngx_http_auth_ldap_server_t    *server;
+    ngx_http_auth_ldap_main_conf_t *cnf = conf;
+    ngx_int_t                      i;
+
+    /* It should be safe to just use latest server from array */
+    server = ((ngx_http_auth_ldap_server_t *) cnf->servers->elts + (cnf->servers->nelts - 1));
+
+    value = cf->args->elts;
+
+    /* TODO: Add more validation */
+    if (ngx_strcmp(value[0].data, "url") == 0) {
+        return ngx_http_auth_ldap_parse_url(cf, server);
+    } else if (ngx_strcmp(value[0].data, "binddn") == 0) {
+        server->bind_dn = value[1];
+    } else if (ngx_strcmp(value[0].data, "binddn_passwd") == 0) {
+        server->bind_dn_passwd = value[1];
+    } else if (ngx_strcmp(value[0].data, "group_attribute") == 0) {
+        server->group_attribute = value[1];
+    } else if (ngx_strcmp(value[0].data, "group_attribute_is_dn") == 0 && ngx_strcmp(value[1].data, "on") == 0) {
+        server->group_attribute_dn = 1;
+    } else if (ngx_strcmp(value[0].data, "require") == 0) {
+        return ngx_http_auth_ldap_parse_require(cf, server);
+    } else if (ngx_strcmp(value[0].data, "satisfy") == 0) {
+        return ngx_http_auth_ldap_parse_satisfy(cf, server);
+    } else if (ngx_strcmp(value[0].data, "referral") == 0) {
+        return ngx_http_auth_ldap_parse_referral(cf, server);
+    } else if (ngx_strcmp(value[0].data, "max_down_retries") == 0) {
+        i = ngx_atoi(value[1].data, value[1].len);
+        if (i == NGX_ERROR) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: 'max_down_retries' value must be an integer: using default of 0");
+            i = 0;
+        }
+        server->max_down_retries = i;
+    } else if (ngx_strcmp(value[0].data, "connections") == 0) {
+        i = ngx_atoi(value[1].data, value[1].len);
+        if (i == NGX_ERROR || i == 0) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: 'connections' value has to be a number greater than 0");
+            return NGX_CONF_ERROR;
+        }
+        server->connections = i;
+    } else if (ngx_strcmp(value[0].data, "ssl_check_cert") == 0  && ngx_strcmp(value[1].data, "on") == 0) {
+      #if OPENSSL_VERSION_NUMBER >= 0x10002000
+      server->ssl_check_cert = 1;
+      #else
+      #warning "http_auth_ldap: Compiling with OpenSSL < 1.0.2, certificate verification will be unavailable. OPENSSL_VERSION_NUMBER == " XSTR(OPENSSL_VERSION_NUMBER)
+      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+        "http_auth_ldap: 'ssl_cert_check': cannot verify remote certificate's domain name because "
+        "your version of OpenSSL is too old. "
+        "Please install OpenSSL >= 1.02 and recompile nginx.");
+      #endif
+    } else if (ngx_strcmp(value[0].data, "ssl_ca_dir") == 0) {
+      server->ssl_ca_dir = value[1];
+    } else if (ngx_strcmp(value[0].data, "ssl_ca_file") == 0) {
+      server->ssl_ca_file = value[1];
+    }
+    else CONF_MSEC_VALUE(cf,value,server,connect_timeout)
+    else CONF_MSEC_VALUE(cf,value,server,reconnect_timeout)
+    else CONF_MSEC_VALUE(cf,value,server,bind_timeout)
+    else CONF_MSEC_VALUE(cf,value,server,request_timeout)
+    else if (ngx_strcmp(value[0].data, "include") == 0) {
+        return ngx_conf_include(cf, dummy, conf);
+    }
+
+    rv = NGX_CONF_OK;
+
+    return rv;
+}
+
+/**
+ * Parse auth_ldap directive
+ */
+static char *
+ngx_http_auth_ldap(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_str_t *value = cf->args->elts;
+    ngx_http_auth_ldap_loc_conf_t *cnf = conf;
+    u_char *p;
+
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        ngx_str_set(&cnf->realm, "");
+        return NGX_CONF_OK;
+    }
+
+    cnf->realm.len = sizeof("Basic realm=\"") - 1 + value[1].len + 1;
+    cnf->realm.data = ngx_pcalloc(cf->pool, cnf->realm.len);
+    if (cnf->realm.data == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    p = ngx_cpymem(cnf->realm.data, "Basic realm=\"", sizeof("Basic realm=\"") - 1);
+    p = ngx_cpymem(p, value[1].data, value[1].len);
+    *p = '"';
+
+    return NGX_CONF_OK;
+}
+
+/**
+ * Parse auth_ldap_servers directive
+ */
+static char *
+ngx_http_auth_ldap_servers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_auth_ldap_loc_conf_t *cnf;
+    ngx_http_auth_ldap_main_conf_t *mconf;
+    ngx_http_auth_ldap_server_t *server, *s, **target;
+    ngx_str_t *value;
+    ngx_uint_t i, j;
+
+    cnf = conf;
+    mconf = ngx_http_conf_get_module_main_conf(cf, ngx_http_auth_ldap_module);
+
+    for (i = 1; i < cf->args->nelts; i++) {
+        value = &((ngx_str_t *) cf->args->elts)[i];
+        server = NULL;
+
+	if (mconf->servers == NULL) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Using \"auth_ldap_servers\" when no \"ldap_server\" has been previously defined"
+	    					     " (make sure that \"auth_ldap_servers\" goes after \"ldap_server\"s in your configuration file)", value);
+            return NGX_CONF_ERROR;
+	}
+
+        for (j = 0; j < mconf->servers->nelts; j++) {
+            s = &((ngx_http_auth_ldap_server_t *) mconf->servers->elts)[j];
+            if (s->alias.len == value->len && ngx_memcmp(s->alias.data, value->data, s->alias.len) == 0) {
+                server = s;
+                break;
+            }
+        }
+
+        if (server == NULL) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Server \"%V\" has not been defined", value);
+            return NGX_CONF_ERROR;
+        }
+
+
+        if (cnf->servers == NGX_CONF_UNSET_PTR) {
+            cnf->servers = ngx_array_create(cf->pool, 4, sizeof(ngx_http_auth_ldap_server_t *));
+            if (cnf->servers == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+
+        target = (ngx_http_auth_ldap_server_t **) ngx_array_push(cnf->servers);
+        if (target == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        *target = server;
+    }
+
+    return NGX_CONF_OK;
+}
+
+/**
+ * Parse URL conf parameter
+ */
+static char *
+ngx_http_auth_ldap_parse_url(ngx_conf_t *cf, ngx_http_auth_ldap_server_t *server)
+{
+    ngx_str_t *value;
+    u_char *p;
+
+    value = cf->args->elts;
+
+    int rc = ldap_url_parse((const char *) value[1].data, &server->ludpp);
+    if (rc != LDAP_SUCCESS) {
+        switch (rc) {
+            case LDAP_URL_ERR_MEM:
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Cannot allocate memory space.");
+                break;
+
+            case LDAP_URL_ERR_PARAM:
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Invalid parameter.");
+                break;
+
+            case LDAP_URL_ERR_BADSCHEME:
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: URL doesnt begin with \"ldap[s]://\".");
+                break;
+
+            case LDAP_URL_ERR_BADENCLOSURE:
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: URL is missing trailing \">\".");
+                break;
+
+            case LDAP_URL_ERR_BADURL:
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Invalid URL.");
+                break;
+
+            case LDAP_URL_ERR_BADHOST:
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Host port is invalid.");
+                break;
+
+            case LDAP_URL_ERR_BADATTRS:
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Invalid or missing attributes.");
+                break;
+
+            case LDAP_URL_ERR_BADSCOPE:
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Invalid or missing scope string.");
+                break;
+
+            case LDAP_URL_ERR_BADFILTER:
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Invalid or missing filter.");
+                break;
+
+            case LDAP_URL_ERR_BADEXTS:
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Invalid or missing extensions.");
+                break;
+        }
+        return NGX_CONF_ERROR;
+    }
+
+    if (server->ludpp->lud_attrs == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: No user attribute specified in auth_ldap_url.");
+        return NGX_CONF_ERROR;
+    }
+
+    server->url.data = ngx_palloc(cf->pool, ngx_strlen(server->ludpp->lud_scheme) + sizeof("://") - 1 +
+        ngx_strlen(server->ludpp->lud_host) + sizeof(":65535"));
+    p = ngx_sprintf(server->url.data, "%s://%s:%d%Z", server->ludpp->lud_scheme, server->ludpp->lud_host,
+        server->ludpp->lud_port);
+    server->url.len = p - server->url.data - 1;
+
+    ngx_memzero(&server->parsed_url, sizeof(ngx_url_t));
+    server->parsed_url.url.data = (u_char *) server->ludpp->lud_host;
+    server->parsed_url.url.len = ngx_strlen(server->ludpp->lud_host);
+    server->parsed_url.default_port = server->ludpp->lud_port;
+    if (ngx_parse_url(cf->pool, &server->parsed_url) != NGX_OK) {
+        if (server->parsed_url.err) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: %s in LDAP hostname \"%V\"",
+                server->parsed_url.err, &server->parsed_url.url);
+        }
+        return NGX_CONF_ERROR;
+    }
+
+    if (ngx_strcmp(server->ludpp->lud_scheme, "ldap") == 0) {
+        return NGX_CONF_OK;
+#if (NGX_OPENSSL)
+    } else if (ngx_strcmp(server->ludpp->lud_scheme, "ldaps") == 0) {
+        ngx_http_auth_ldap_main_conf_t *halmcf =
+            ngx_http_conf_get_module_main_conf(cf, ngx_http_auth_ldap_module);
+        ngx_uint_t protos = NGX_SSL_SSLv2 | NGX_SSL_SSLv3 |
+            NGX_SSL_TLSv1 | NGX_SSL_TLSv1_1 | NGX_SSL_TLSv1_2;
+        if (halmcf->ssl.ctx == NULL && ngx_ssl_create(&halmcf->ssl, protos, halmcf) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
+        return NGX_CONF_OK;
+#endif
+    } else {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Protocol \"%s://\" is not supported.",
+            server->ludpp->lud_scheme);
+        return NGX_CONF_ERROR;
+    }
+}
+
+/**
+ * Parse "require" conf parameter
+ */
+static char *
+ngx_http_auth_ldap_parse_require(ngx_conf_t *cf, ngx_http_auth_ldap_server_t *server)
+{
+    ngx_str_t *value;
+    ngx_http_complex_value_t* target = NULL;
+    ngx_http_compile_complex_value_t ccv;
+
+    value = cf->args->elts;
+    ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "http_auth_ldap: parse_require");
+
+    if (ngx_strcmp(value[1].data, "valid_user") == 0) {
+        server->require_valid_user = 1;
+        if (cf->args->nelts < 3) {
+            return NGX_CONF_OK;
+        }
+        if (server->require_valid_user_dn.value.data != NULL) {
+            return "is duplicate";
+        }
+        target = &server->require_valid_user_dn;
+    } else if (ngx_strcmp(value[1].data, "user") == 0) {
+        if (server->require_user == NULL) {
+            server->require_user = ngx_array_create(cf->pool, 4, sizeof(ngx_http_complex_value_t));
+            if (server->require_user == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+        target = ngx_array_push(server->require_user);
+    } else if (ngx_strcmp(value[1].data, "group") == 0) {
+        ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "http_auth_ldap: Setting group");
+        if (server->require_group == NULL) {
+            server->require_group = ngx_array_create(cf->pool, 4, sizeof(ngx_http_complex_value_t));
+            if (server->require_group == NULL) {
+                return NGX_CONF_ERROR;
+            }
+        }
+        target = ngx_array_push(server->require_group);
+    }
+
+    if (target == NULL) {
+       return NGX_CONF_ERROR;
+    }
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+    ccv.cf = cf;
+    ccv.value = &value[2];
+    ccv.complex_value = target;
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+/**
+ * Parse "satisfy" conf parameter
+ */
+static char *
+ngx_http_auth_ldap_parse_satisfy(ngx_conf_t *cf, ngx_http_auth_ldap_server_t *server)
+{
+    ngx_str_t *value;
+    value = cf->args->elts;
+
+    if (ngx_strcmp(value[1].data, "all") == 0) {
+        ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "http_auth_ldap: Setting satisfy all");
+        server->satisfy_all = 1;
+        return NGX_CONF_OK;
+    }
+
+    if (ngx_strcmp(value[1].data, "any") == 0) {
+        server->satisfy_all = 0;
+        return NGX_CONF_OK;
+    }
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Incorrect value for auth_ldap_satisfy");
+    return NGX_CONF_ERROR;
+}
+
+/**
+ * Parse "referral" conf parameter
+ */
+static char *
+ngx_http_auth_ldap_parse_referral(ngx_conf_t *cf, ngx_http_auth_ldap_server_t *server)
+{
+    ngx_str_t *value;
+    value = cf->args->elts;
+
+    if (ngx_strcmp(value[1].data, "on") == 0) {
+        server->referral = 1;
+        return NGX_CONF_OK;
+    }
+
+    if (ngx_strcmp(value[1].data, "off") == 0) {
+        server->referral = 0;
+        return NGX_CONF_OK;
+    }
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "http_auth_ldap: Incorrect value for referral");
+    return NGX_CONF_ERROR;
+}
+
+/**
+ * Create main config which will store ldap_servers array
+ */
+static void *
+ngx_http_auth_ldap_create_main_conf(ngx_conf_t *cf)
+{
+    ngx_http_auth_ldap_main_conf_t *conf;
+
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_ldap_main_conf_t));
+    if (conf == NULL) {
+        return NULL;
+    }
+
+    conf->cache_enabled = NGX_CONF_UNSET;
+    conf->cache_expiration_time = NGX_CONF_UNSET_MSEC;
+    conf->cache_size = NGX_CONF_UNSET_SIZE;
+    conf->servers_size = NGX_CONF_UNSET;
+
+    return conf;
+}
+
+static char *
+ngx_http_auth_ldap_init_main_conf(ngx_conf_t *cf, void *parent)
+{
+    ngx_http_auth_ldap_main_conf_t *conf = parent;
+
+    if (conf->cache_enabled == NGX_CONF_UNSET) {
+        conf->cache_enabled = 0;
+    }
+    if (conf->cache_enabled == 0) {
+        return NGX_CONF_OK;
+    }
+
+    if (conf->cache_size == NGX_CONF_UNSET_SIZE) {
+        conf->cache_size = 100;
+    }
+    if (conf->cache_size < 100) {
+        ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "http_auth_ldap: auth_ldap_cache_size cannot be smaller than 100 entries.");
+        return NGX_CONF_ERROR;
+    }
+
+    if (conf->cache_expiration_time == NGX_CONF_UNSET_MSEC) {
+        conf->cache_expiration_time = 10000;
+    }
+    if (conf->cache_expiration_time < 1000) {
+        ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "http_auth_ldap: auth_ldap_cache_expiration_time cannot be smaller than 1000 ms.");
+        return NGX_CONF_ERROR;
+    }
+
+    return NGX_CONF_OK;
+}
+
+/**
+ * Create location conf
+ */
+static void *
+ngx_http_auth_ldap_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_auth_ldap_loc_conf_t *conf;
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_ldap_loc_conf_t));
+    if (conf == NULL) {
+        return NULL;
+    }
+    conf->servers = NGX_CONF_UNSET_PTR;
+
+    return conf;
+}
+
+/**
+ * Merge location conf
+ */
+static char *
+ngx_http_auth_ldap_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_auth_ldap_loc_conf_t *prev = parent;
+    ngx_http_auth_ldap_loc_conf_t *conf = child;
+
+    if (conf->realm.data == NULL) {
+        conf->realm = prev->realm;
+    }
+    ngx_conf_merge_ptr_value(conf->servers, prev->servers, NULL);
+
+    return NGX_CONF_OK;
+}
+
+static ngx_int_t
+ngx_http_auth_ldap_init_worker(ngx_cycle_t *cycle)
+{
+    ngx_int_t rc;
+
+    if (ngx_process != NGX_PROCESS_SINGLE && ngx_process != NGX_PROCESS_WORKER) {
+        return NGX_OK;
+    }
+
+    rc = ngx_http_auth_ldap_init_cache(cycle);
+    if (rc != NGX_OK) {
+        return rc;
+    }
+
+    rc = ngx_http_auth_ldap_init_connections(cycle);
+    if (rc != NGX_OK) {
+        return rc;
+    }
+
+    return NGX_OK;
+}
+
+/**
+ * Init module and add ldap auth handler to NGX_HTTP_ACCESS_PHASE
+ */
+static ngx_int_t
+ngx_http_auth_ldap_init(ngx_conf_t *cf)
+{
+    ngx_http_handler_pt *h;
+    ngx_http_core_main_conf_t *cmcf;
+
+    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+    h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = ngx_http_auth_ldap_handler;
+    return NGX_OK;
+}
+
+
+/*** Authentication cache ***/
+
+static ngx_int_t
+ngx_http_auth_ldap_init_cache(ngx_cycle_t *cycle)
+{
+    ngx_http_auth_ldap_main_conf_t *conf;
+    ngx_uint_t want, count, i;
+    ngx_http_auth_ldap_cache_t *cache;
+    static const uint16_t primes[] = {
+        13, 53, 101, 151, 199, 263, 317, 383, 443, 503,
+        577, 641, 701, 769, 839, 911, 983, 1049, 1109
+    };
+
+    conf = (ngx_http_auth_ldap_main_conf_t *) ngx_http_cycle_get_module_main_conf(cycle, ngx_http_auth_ldap_module);
+    if (conf == NULL || !conf->cache_enabled) {
+        return NGX_OK;
+    }
+
+    want = (conf->cache_size + 7) / 8;
+    count = 0;
+    for (i = 0; i < sizeof(primes)/sizeof(primes[0]); i++) {
+        count = primes[i];
+        if (count >= want) {
+            break;
+        }
+    }
+
+    cache = &ngx_http_auth_ldap_cache;
+    cache->expiration_time = conf->cache_expiration_time;
+    cache->num_buckets = count;
+    cache->elts_per_bucket = 8;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cycle->log, 0, "http_auth_ldap: Allocating %ud bytes of LDAP cache.",
+        cache->num_buckets * cache->elts_per_bucket * sizeof(ngx_http_auth_ldap_cache_elt_t));
+
+    cache->buckets = (ngx_http_auth_ldap_cache_elt_t *) ngx_calloc(count * 8 * sizeof(ngx_http_auth_ldap_cache_elt_t), cycle->log);
+    if (cache->buckets == NULL) {
+        ngx_log_error(NGX_LOG_ERR, cycle->log, 0, "http_auth_ldap: Unable to allocate memory for LDAP cache.");
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+static ngx_int_t
+ngx_http_auth_ldap_check_cache(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx,
+    ngx_http_auth_ldap_cache_t *cache, ngx_http_auth_ldap_server_t *server)
+{
+    ngx_http_auth_ldap_cache_elt_t *elt;
+    ngx_md5_t md5ctx;
+    ngx_msec_t time_limit;
+    ngx_uint_t i;
+
+    ctx->cache_small_hash = ngx_murmur_hash2(r->headers_in.user.data, r->headers_in.user.len) ^ (uint32_t) (ngx_uint_t) server;
+
+    ngx_md5_init(&md5ctx);
+    ngx_md5_update(&md5ctx, r->headers_in.user.data, r->headers_in.user.len);
+    ngx_md5_update(&md5ctx, server, offsetof(ngx_http_auth_ldap_server_t, free_connections));
+    ngx_md5_update(&md5ctx, r->headers_in.passwd.data, r->headers_in.passwd.len);
+    ngx_md5_final(ctx->cache_big_hash, &md5ctx);
+
+    ctx->cache_bucket = &cache->buckets[ctx->cache_small_hash % cache->num_buckets];
+
+    elt = ctx->cache_bucket;
+    time_limit = ngx_current_msec - cache->expiration_time;
+    for (i = 0; i < cache->elts_per_bucket; i++, elt++) {
+        if (elt->small_hash == ctx->cache_small_hash &&
+                elt->time > time_limit &&
+                memcmp(elt->big_hash, ctx->cache_big_hash, 16) == 0) {
+            return elt->outcome;
+        }
+    }
+
+    return -1;
+}
+
+static void
+ngx_http_auth_ldap_update_cache(ngx_http_auth_ldap_ctx_t *ctx,
+        ngx_http_auth_ldap_cache_t *cache, ngx_flag_t outcome)
+{
+    ngx_http_auth_ldap_cache_elt_t *elt, *oldest_elt;
+    ngx_uint_t i;
+
+    elt = ctx->cache_bucket;
+    oldest_elt = elt;
+    for (i = 1; i < cache->elts_per_bucket; i++, elt++) {
+        if (elt->time < oldest_elt->time) {
+            oldest_elt = elt;
+        }
+    }
+
+    oldest_elt->time = ngx_current_msec;
+    oldest_elt->outcome = outcome;
+    oldest_elt->small_hash = ctx->cache_small_hash;
+    ngx_memcpy(oldest_elt->big_hash, ctx->cache_big_hash, 16);
+}
+
+
+/*** OpenLDAP SockBuf implementation over nginx socket functions ***/
+
+static int
+ngx_http_auth_ldap_sb_setup(Sockbuf_IO_Desc *sbiod, void *arg)
+{
+    sbiod->sbiod_pvt = arg;
+    return 0;
+}
+
+static int
+ngx_http_auth_ldap_sb_remove(Sockbuf_IO_Desc *sbiod)
+{
+    ngx_http_auth_ldap_connection_t *c = (ngx_http_auth_ldap_connection_t *)sbiod->sbiod_pvt;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "ngx_http_auth_ldap_sb_remove()");
+    (void)c; /* 'c' would be left unused on debug builds */
+
+    sbiod->sbiod_pvt = NULL;
+    return 0;
+}
+
+static int
+ngx_http_auth_ldap_sb_close(Sockbuf_IO_Desc *sbiod)
+{
+    ngx_http_auth_ldap_connection_t *c = (ngx_http_auth_ldap_connection_t *)sbiod->sbiod_pvt;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "ngx_http_auth_ldap_sb_close()");
+
+    if (!c->conn.connection->read->error && !c->conn.connection->read->eof) {
+        if (ngx_shutdown_socket(c->conn.connection->fd, SHUT_RDWR) == -1) {
+            ngx_connection_error(c->conn.connection, ngx_socket_errno, ngx_shutdown_socket_n " failed");
+            ngx_http_auth_ldap_close_connection(c);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int
+ngx_http_auth_ldap_sb_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
+{
+    ngx_http_auth_ldap_connection_t *c = (ngx_http_auth_ldap_connection_t *)sbiod->sbiod_pvt;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "ngx_http_auth_ldap_sb_ctrl(opt=%d)", opt);
+
+    switch (opt) {
+        case LBER_SB_OPT_DATA_READY:
+            if (c->conn.connection->read->ready) {
+                return 1;
+            }
+            return 0;
+    }
+
+    return 0;
+}
+
+static ber_slen_t
+ngx_http_auth_ldap_sb_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+    ngx_http_auth_ldap_connection_t *c = (ngx_http_auth_ldap_connection_t *)sbiod->sbiod_pvt;
+    ber_slen_t ret;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "ngx_http_auth_ldap_sb_read(len=%d)", len);
+
+    ret = c->conn.connection->recv(c->conn.connection, buf, len);
+    if (ret < 0) {
+        errno = (ret == NGX_AGAIN) ? NGX_EAGAIN : NGX_ECONNRESET;
+        return -1;
+    }
+
+    return ret;
+}
+
+static ber_slen_t
+ngx_http_auth_ldap_sb_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+    ngx_http_auth_ldap_connection_t *c = (ngx_http_auth_ldap_connection_t *)sbiod->sbiod_pvt;
+    ber_slen_t ret;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "ngx_http_auth_ldap_sb_write(len=%d)", len);
+
+    ret = c->conn.connection->send(c->conn.connection, buf, len);
+    if (ret < 0) {
+        errno = (ret == NGX_AGAIN) ? NGX_EAGAIN : NGX_ECONNRESET;
+        return 0;
+    }
+
+    return ret;
+}
+
+static Sockbuf_IO ngx_http_auth_ldap_sbio =
+{
+    ngx_http_auth_ldap_sb_setup,
+    ngx_http_auth_ldap_sb_remove,
+    ngx_http_auth_ldap_sb_ctrl,
+    ngx_http_auth_ldap_sb_read,
+    ngx_http_auth_ldap_sb_write,
+    ngx_http_auth_ldap_sb_close
+};
+
+
+/*** Asynchronous LDAP connection handling ***/
+
+static void
+ngx_http_auth_ldap_close_connection(ngx_http_auth_ldap_connection_t *c)
+{
+    ngx_queue_t *q;
+
+    if (c->ld) {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Unbinding from the server \"%V\")",
+            &c->server->url);
+        ldap_unbind_ext(c->ld, NULL, NULL);
+        /* Unbind is always synchronous, even though the function name does not end with an '_s'. */
+        c->ld = NULL;
+    }
+
+    if (c->conn.connection) {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Closing connection (fd=%d)",
+            c->conn.connection->fd);
+
+#if (NGX_OPENSSL)
+        if (c->conn.connection->ssl) {
+            c->conn.connection->ssl->no_wait_shutdown = 1;
+            (void) ngx_ssl_shutdown(c->conn.connection);
+        }
+#endif
+
+        ngx_close_connection(c->conn.connection);
+        c->conn.connection = NULL;
+    }
+
+    q = ngx_queue_head(&c->server->free_connections);
+    while (q != ngx_queue_sentinel(&c->server->free_connections)) {
+        if (q == &c->queue) {
+            ngx_queue_remove(q);
+            break;
+        }
+        q = ngx_queue_next(q);
+    }
+
+    c->rctx = NULL;
+    if (c->state != STATE_DISCONNECTED) {
+        c->state = STATE_DISCONNECTED;
+        ngx_add_timer(&c->reconnect_event, c->server->reconnect_timeout);
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Connection scheduled for reconnection in %d ms", c->server->reconnect_timeout);
+    }
+}
+
+static void
+ngx_http_auth_ldap_wake_request(ngx_http_request_t *r)
+{
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Waking authentication request \"%V\"",
+        &r->request_line);
+    ngx_http_core_run_phases(r);
+}
+
+static int
+ngx_http_auth_ldap_get_connection(ngx_http_auth_ldap_ctx_t *ctx)
+{
+    ngx_http_auth_ldap_server_t *server;
+    ngx_queue_t *q;
+    ngx_http_auth_ldap_connection_t *c;
+
+    /*
+     * If we already have a connection, just say we got them one.
+     */
+    if (ctx->c != NULL)
+        return 1;
+
+    server = ctx->server;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->r->connection->log, 0, "http_auth_ldap: Wants a free connection to \"%V\"",
+        &server->alias);
+
+    if (!ngx_queue_empty(&server->free_connections)) {
+        q = ngx_queue_last(&server->free_connections);
+        ngx_queue_remove(q);
+        c = ngx_queue_data(q, ngx_http_auth_ldap_connection_t, queue);
+        c->rctx = ctx;
+        ctx->c = c;
+        ctx->replied = 0;
+        return 1;
+    }
+
+    q = ngx_queue_next(&server->waiting_requests);
+    while (q != ngx_queue_sentinel(&server->waiting_requests)) {
+        if (q == &ctx->queue) {
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->r->connection->log, 0, "http_auth_ldap: Tried to insert a same request");
+            return 0;
+        }
+        q = ngx_queue_next(q);
+    }
+    ngx_queue_insert_head(&server->waiting_requests, &ctx->queue);
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->r->connection->log, 0, "http_auth_ldap: No connection available at the moment, waiting...");
+    return 0;
+}
+
+static void
+ngx_http_auth_ldap_return_connection(ngx_http_auth_ldap_connection_t *c)
+{
+    ngx_queue_t *q;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Marking the connection to \"%V\" as free",
+        &c->server->alias);
+
+    if (c->rctx != NULL) {
+        c->rctx->c = NULL;
+        c->rctx = NULL;
+        c->msgid = -1;
+        c->state = STATE_READY;
+    }
+
+    ngx_queue_insert_head(&c->server->free_connections, &c->queue);
+    if (!ngx_queue_empty(&c->server->waiting_requests)) {
+        q = ngx_queue_last(&c->server->waiting_requests);
+        ngx_queue_remove(q);
+        ngx_http_auth_ldap_wake_request((ngx_queue_data(q, ngx_http_auth_ldap_ctx_t, queue))->r);
+    }
+}
+
+static void
+ngx_http_auth_ldap_reply_connection(ngx_http_auth_ldap_connection_t *c, int error_code, char* error_msg)
+{
+    ngx_http_auth_ldap_ctx_t *ctx = c->rctx;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: LDAP request to \"%V\" has finished",
+        &c->server->alias);
+
+    ctx->replied = 1;
+    ctx->error_code = error_code;
+    if (error_msg) {
+        ctx->error_msg.len = ngx_strlen(error_msg);
+        ctx->error_msg.data = ngx_palloc(ctx->r->pool, ctx->error_msg.len);
+        ngx_memcpy(ctx->error_msg.data, error_msg, ctx->error_msg.len);
+    } else {
+        ctx->error_msg.len = 0;
+        ctx->error_msg.data = NULL;
+    }
+
+    ngx_http_auth_ldap_wake_request(ctx->r);
+}
+
+static void
+ngx_http_auth_ldap_dummy_write_handler(ngx_event_t *wev)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http_auth_ldap: Dummy write handler");
+
+    if (ngx_handle_write_event(wev, 0) != NGX_OK) {
+        ngx_http_auth_ldap_close_connection(((ngx_connection_t *) wev->data)->data);
+    }
+}
+
+
+#if (NGX_OPENSSL)
+/* Make sure the event handlers are activated. */
+static ngx_int_t
+ngx_http_auth_ldap_restore_handlers(ngx_connection_t *conn)
+{
+    ngx_int_t rc;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, conn->log, 0, "http_auth_ldap: Restoring event handlers. read=%d write=%d", conn->read->active, conn->write->active);
+
+    if (!conn->read->active) {
+        rc = ngx_add_event(conn->read, NGX_READ_EVENT, 0);
+        if (rc != NGX_OK) {
+            return rc;
+        }
+    }
+
+    if (!conn->write->active &&
+        (conn->write->handler != ngx_http_auth_ldap_dummy_write_handler)) {
+        rc = ngx_add_event(conn->write, NGX_WRITE_EVENT, 0);
+        if (rc != NGX_OK) {
+            return rc;
+        }
+    }
+
+    return NGX_OK;
+}
+#endif
+
+static void
+ngx_http_auth_ldap_connection_established(ngx_http_auth_ldap_connection_t *c)
+{
+    ngx_connection_t *conn;
+    Sockbuf *sb;
+    ngx_int_t rc;
+    struct berval cred;
+
+    conn = c->conn.connection;
+    ngx_del_timer(conn->read);
+    conn->write->handler = ngx_http_auth_ldap_dummy_write_handler;
+
+
+    /* Initialize OpenLDAP on the connection */
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Initializing connection using URL \"%V\"", &c->server->url);
+
+    rc = ldap_init_fd(c->conn.connection->fd, LDAP_PROTO_EXT, (const char *) c->server->url.data, &c->ld);
+    if (rc != LDAP_SUCCESS) {
+        ngx_log_error(NGX_LOG_ERR, c->log, errno, "http_auth_ldap: ldap_init_fd() failed (%d: %s)", rc, ldap_err2string(rc));
+        ngx_http_auth_ldap_close_connection(c);
+        return;
+    }
+
+    if (c->server->referral == 0) {
+        rc = ldap_set_option(c->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+        if (rc != LDAP_OPT_SUCCESS) {
+            ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: ldap_set_option() failed (%d: %s)", rc, ldap_err2string(rc));
+            ngx_http_auth_ldap_close_connection(c);
+            return;
+        }
+    }
+
+    rc = ldap_get_option(c->ld, LDAP_OPT_SOCKBUF, (void *) &sb);
+    if (rc != LDAP_OPT_SUCCESS) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: ldap_get_option() failed (%d: %s)", rc, ldap_err2string(rc));
+        ngx_http_auth_ldap_close_connection(c);
+        return;
+    }
+
+    ber_sockbuf_add_io(sb, &ngx_http_auth_ldap_sbio, LBER_SBIOD_LEVEL_PROVIDER, (void *) c);
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Connection initialized");
+
+
+    /* Perform initial bind to the server */
+
+    cred.bv_val = (char *) c->server->bind_dn_passwd.data;
+    cred.bv_len = c->server->bind_dn_passwd.len;
+    rc = ldap_sasl_bind(c->ld, (const char *) c->server->bind_dn.data, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &c->msgid);
+    if (rc != LDAP_SUCCESS) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: ldap_sasl_bind() failed (%d: %s)",
+            rc, ldap_err2string(rc));
+        ngx_http_auth_ldap_close_connection(c);
+        return;
+    }
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: ldap_sasl_bind() -> msgid=%d", c->msgid);
+
+    c->state = STATE_INITIAL_BINDING;
+    ngx_add_timer(c->conn.connection->read, c->server->bind_timeout);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: bind_timeout=%d", c->server->bind_timeout);
+}
+
+#if (NGX_OPENSSL)
+static void
+ngx_http_auth_ldap_ssl_handshake_handler(ngx_connection_t *conn, ngx_flag_t validate)
+{
+    ngx_http_auth_ldap_connection_t *c;
+    c = conn->data;
+
+    if (conn->ssl->handshaked) {
+        #if OPENSSL_VERSION_NUMBER >= 0x10002000
+        if (validate) { // verify remote certificate if requested
+          X509 *cert = SSL_get_peer_certificate(conn->ssl->connection);
+          long chain_verified = SSL_get_verify_result(conn->ssl->connection);
+
+          int addr_verified;
+          char *hostname = c->server->ludpp->lud_host;
+          addr_verified = X509_check_host(cert, hostname, 0, 0, 0);
+
+          if (!addr_verified) { // domain not in cert? try IP
+            size_t len; // get IP length
+            if (conn->sockaddr->sa_family == 4) len = 4;
+            else if (conn->sockaddr->sa_family == 6) len = 16;
+            else { // very unlikely indeed
+              ngx_http_auth_ldap_close_connection(c);
+              return;
+            }
+            addr_verified = X509_check_ip(cert, (const unsigned char*)conn->sockaddr->sa_data, len, 0);
+          }
+
+          // Find anything fishy?
+          if ( !(cert && addr_verified && chain_verified == X509_V_OK) ) {
+            if (!addr_verified) {
+              ngx_log_error(NGX_LOG_ERR, c->log, 0,
+                "http_auth_ldap: Remote side presented invalid SSL certificate: "
+                "does not match address (neither server's domain nor IP in certificate's CN or SAN)");
+                fprintf(stderr, "DEBUG: SSL cert domain mismatch\n"); fflush(stderr);
+            } else {
+              ngx_log_error(NGX_LOG_ERR, c->log, 0,
+                "http_auth_ldap: Remote side presented invalid SSL certificate: error %l, %s",
+                chain_verified, X509_verify_cert_error_string(chain_verified));
+            }
+            ngx_http_auth_ldap_close_connection(c);
+            return;
+          }
+        }
+        #endif
+
+        // handshaked validation successful -- or not required in the first place
+        conn->read->handler = &ngx_http_auth_ldap_read_handler;
+        ngx_http_auth_ldap_restore_handlers(conn);
+        ngx_http_auth_ldap_connection_established(c);
+        return;
+    }
+    else { // handshake failed
+      ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: SSL handshake failed");
+      ngx_http_auth_ldap_close_connection(c);
+    }
+}
+
+static void
+ngx_http_auth_ldap_ssl_handshake_validating_handler(ngx_connection_t *conn)
+{ ngx_http_auth_ldap_ssl_handshake_handler(conn, 1); }
+
+static void
+ngx_http_auth_ldap_ssl_handshake_non_validating_handler(ngx_connection_t *conn)
+{ ngx_http_auth_ldap_ssl_handshake_handler(conn, 0); }
+
+typedef void (*ngx_http_auth_ldap_ssl_callback)(ngx_connection_t *conn);
+
+static void
+ngx_http_auth_ldap_ssl_handshake(ngx_http_auth_ldap_connection_t *c)
+{
+    ngx_int_t rc;
+
+    c->conn.connection->pool = c->pool;
+    rc = ngx_ssl_create_connection(c->ssl, c->conn.connection, NGX_SSL_BUFFER | NGX_SSL_CLIENT);
+    if (rc != NGX_OK) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: SSL initialization failed");
+        ngx_http_auth_ldap_close_connection(c);
+        return;
+    }
+
+    c->log->action = "SSL handshaking to LDAP server";
+    ngx_connection_t *transport = c->conn.connection;
+
+    ngx_http_auth_ldap_ssl_callback callback;
+    if (c->server->ssl_check_cert) {
+      // load CA certificates: custom ones if specified, default ones instead
+      if (c->server->ssl_ca_file.data || c->server->ssl_ca_dir.data) {
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+        int setcode = SSL_CTX_load_verify_locations(transport->ssl->session_ctx,
+          (char*)(c->server->ssl_ca_file.data), (char*)(c->server->ssl_ca_dir.data));
+#else
+        int setcode = SSL_CTX_load_verify_locations(transport->ssl->connection->ctx,
+          (char*)(c->server->ssl_ca_file.data), (char*)(c->server->ssl_ca_dir.data));
+#endif
+        if (setcode != 1) {
+          unsigned long error_code = ERR_get_error();
+          char *error_msg = ERR_error_string(error_code, NULL);
+          ngx_log_error(NGX_LOG_ERR, c->log, 0,
+            "http_auth_ldap: SSL initialization failed. Could not set custom CA certificate location. "
+            "Error: %lu, %s", error_code, error_msg);
+        }
+      }
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+      int setcode = SSL_CTX_set_default_verify_paths(transport->ssl->session_ctx);
+#else
+      int setcode = SSL_CTX_set_default_verify_paths(transport->ssl->connection->ctx);
+#endif
+      if (setcode != 1) {
+        unsigned long error_code = ERR_get_error();
+        char *error_msg = ERR_error_string(error_code, NULL);
+        ngx_log_error(NGX_LOG_ERR, c->log, 0,
+          "http_auth_ldap: SSL initialization failed. Could not use default CA certificate location. "
+          "Error: %lu, %s", error_code, error_msg);
+      }
+
+      // use validating version of next function
+      callback = &ngx_http_auth_ldap_ssl_handshake_validating_handler;
+    } else {
+      // use non-validating version of next function
+      callback = &ngx_http_auth_ldap_ssl_handshake_non_validating_handler;
+    }
+
+    rc = ngx_ssl_handshake(transport);
+    if (rc == NGX_AGAIN) {
+        transport->ssl->handler = callback;
+        return;
+    }
+
+    (*callback)(transport);
+    return;
+}
+#endif
+
+static void
+ngx_http_auth_ldap_connect_handler(ngx_event_t *wev)
+{
+    ngx_connection_t *conn;
+    ngx_http_auth_ldap_connection_t *c;
+    int keepalive;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http_auth_ldap: Connect handler");
+
+    conn = wev->data;
+    c = conn->data;
+
+    if (ngx_handle_write_event(wev, 0) != NGX_OK) {
+        ngx_http_auth_ldap_close_connection(c);
+        return;
+    }
+
+    keepalive = 1;
+    if (setsockopt(conn->fd, SOL_SOCKET, SO_KEEPALIVE, (const void *) &keepalive, sizeof(int)) == -1)
+    {
+        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, "http_auth_ldap: setsockopt(SO_KEEPALIVE) failed");
+    }
+
+#if (NGX_OPENSSL)
+    if (ngx_strcmp(c->server->ludpp->lud_scheme, "ldaps") == 0) {
+        ngx_http_auth_ldap_ssl_handshake(c);
+        return;
+    }
+#endif
+
+    ngx_http_auth_ldap_connection_established(c);
+}
+
+static void
+ngx_http_auth_ldap_read_handler(ngx_event_t *rev)
+{
+    ngx_connection_t *conn;
+    ngx_http_auth_ldap_connection_t *c;
+    ngx_int_t rc;
+    struct timeval timeout = {0, 0};
+    LDAPMessage *result;
+    int error_code;
+    char *error_msg;
+    char *dn;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http_auth_ldap: Read handler");
+
+    conn = rev->data;
+    c = conn->data;
+
+    if (c->ld == NULL) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: Could not connect");
+        ngx_http_auth_ldap_close_connection(c);
+        return;
+    }
+
+    if (rev->timedout) {
+        ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, "http_auth_ldap: Request timed out (state=%d)", c->state);
+        conn->timedout = 1;
+        ngx_http_auth_ldap_close_connection(c);
+        return;
+    }
+
+    c->log->action = "reading response from LDAP";
+
+    for (;;) {
+        rc = ldap_result(c->ld, LDAP_RES_ANY, 0, &timeout, &result);
+        if (rc < 0) {
+            ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: ldap_result() failed (%d: %s)",
+                rc, ldap_err2string(rc));
+            ngx_http_auth_ldap_close_connection(c);
+
+            // if LDAP_SERVER_DOWN (usually timeouts or server disconnects)
+            if (rc == LDAP_SERVER_DOWN && \
+                c->server->max_down_retries_count < c->server->max_down_retries) { 
+                /** 
+                    update counter (this is always reset in 
+                    ngx_http_auth_ldap_connect() for a successful ldap 
+                    connection  
+                **/
+                c->server->max_down_retries_count++;
+                ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: LDAP_SERVER_DOWN: retry count: %d",
+                    c->server->max_down_retries_count);
+                c->state = STATE_DISCONNECTED;
+                // immediate reconnect synchronously, this schedules another
+                // timer call to this read handler again
+                ngx_http_auth_ldap_reconnect_handler(rev);
+                return;
+            } 
+
+            return;
+        }
+        if (rc == 0) {
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: ldap_result() -> rc=0");
+            break;
+        }
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: ldap_result() -> rc=%d, msgid=%d, msgtype=%d",
+            rc, ldap_msgid(result), ldap_msgtype(result));
+
+        if (ldap_msgid(result) != c->msgid) {
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Message with unknown ID received, ignoring.");
+            ldap_msgfree(result);
+            continue;
+        }
+
+        rc = ldap_parse_result(c->ld, result, &error_code, NULL, &error_msg, NULL, NULL, 0);
+        if (rc == LDAP_NO_RESULTS_RETURNED) {
+            error_code = LDAP_NO_RESULTS_RETURNED;
+            error_msg = NULL;
+        } else if (rc != LDAP_SUCCESS) {
+            ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: ldap_parse_result() failed (%d: %s)",
+                rc, ldap_err2string(rc));
+            ldap_msgfree(result);
+            ngx_http_auth_ldap_close_connection(c);
+            return;
+        }
+
+        switch (c->state) {
+            case STATE_INITIAL_BINDING:
+                if (ldap_msgtype(result) != LDAP_RES_BIND) {
+                    break;
+                }
+                ngx_del_timer(conn->read);
+                if (error_code == LDAP_SUCCESS) {
+                    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Initial bind successful");
+                    c->state = STATE_READY;
+                    ngx_http_auth_ldap_return_connection(c);
+                } else {
+                    ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: Initial bind failed (%d: %s [%s])",
+                        error_code, ldap_err2string(error_code), error_msg ? error_msg : "-");
+                    ldap_memfree(error_msg);
+                    ldap_msgfree(result);
+                    ngx_http_auth_ldap_close_connection(c);
+                    return;
+                }
+                break;
+
+            case STATE_BINDING:
+                if (ldap_msgtype(result) != LDAP_RES_BIND) {
+                    break;
+                }
+                ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Received bind response (%d: %s [%s])",
+                    error_code, ldap_err2string(error_code), error_msg ? error_msg : "-");
+                ngx_http_auth_ldap_reply_connection(c, error_code, error_msg);
+                break;
+
+            case STATE_SEARCHING:
+                if (ldap_msgtype(result) == LDAP_RES_SEARCH_ENTRY) {
+                    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Received a search entry");
+                    if (c->rctx->dn.data == NULL) {
+                        dn = ldap_get_dn(c->ld, result);
+                        if (dn != NULL) {
+                            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Found entry with DN \"%s\"", dn);
+                            c->rctx->dn.len = ngx_strlen(dn);
+                            c->rctx->dn.data = (u_char *) ngx_palloc(c->rctx->r->pool, c->rctx->dn.len + 1);
+                            ngx_memcpy(c->rctx->dn.data, dn, c->rctx->dn.len + 1);
+                            ldap_memfree(dn);
+                        }
+                    }
+                } else if (ldap_msgtype(result) == LDAP_RES_SEARCH_RESULT) {
+                    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Received search result (%d: %s [%s])",
+                        error_code, ldap_err2string(error_code), error_msg ? error_msg : "-");
+                    ngx_http_auth_ldap_reply_connection(c, error_code, error_msg);
+                }
+                break;
+
+            case STATE_COMPARING:
+                if (ldap_msgtype(result) != LDAP_RES_COMPARE) {
+                    break;
+                }
+                ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Received comparison result (%d: %s [%s])",
+                    error_code, ldap_err2string(error_code), error_msg ? error_msg : "-");
+                ngx_http_auth_ldap_reply_connection(c, error_code, error_msg);
+                break;
+
+            default:
+                break;
+        }
+
+        ldap_memfree(error_msg);
+        ldap_msgfree(result);
+    }
+
+    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+        ngx_http_auth_ldap_close_connection(c);
+        return;
+    }
+}
+
+static void
+ngx_http_auth_ldap_connect(ngx_http_auth_ldap_connection_t *c)
+{
+    ngx_peer_connection_t *pconn;
+    ngx_connection_t *conn;
+    ngx_addr_t *addr;
+    ngx_int_t rc;
+
+    addr = &c->server->parsed_url.addrs[ngx_random() % c->server->parsed_url.naddrs];
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: Connecting to LDAP server \"%V\".",
+        &addr->name);
+
+    pconn = &c->conn;
+    pconn->sockaddr = addr->sockaddr;
+    pconn->socklen = addr->socklen;
+    pconn->name = &addr->name;
+    pconn->get = ngx_event_get_peer;
+    pconn->log = c->log;
+    pconn->log_error = NGX_ERROR_ERR;
+
+    rc = ngx_event_connect_peer(pconn);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: ngx_event_connect_peer() -> %d.", rc);
+    if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
+        ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: Unable to connect to LDAP server \"%V\".",
+            &addr->name);
+        ngx_add_timer(&c->reconnect_event, c->server->reconnect_timeout);
+        return;
+    }
+
+    conn = pconn->connection;
+    conn->data = c;
+#if (NGX_OPENSSL)
+    conn->pool = c->pool;
+#endif
+    conn->write->handler = ngx_http_auth_ldap_connect_handler;
+    conn->read->handler = ngx_http_auth_ldap_read_handler;
+    ngx_add_timer(conn->read, c->server->connect_timeout);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http_auth_ldap: connect_timeout=%d.", c->server->connect_timeout);
+
+    c->server->max_down_retries_count = 0;   /* reset retries count */
+    c->state = STATE_CONNECTING;
+}
+
+static void
+ngx_http_auth_ldap_connection_cleanup(void *data)
+{
+    ngx_http_auth_ldap_close_connection((ngx_http_auth_ldap_connection_t *) data);
+}
+
+static void
+ngx_http_auth_ldap_reconnect_handler(ngx_event_t *ev)
+{
+    ngx_connection_t *conn = ev->data;
+    ngx_http_auth_ldap_connection_t *c = conn->data;
+    ngx_http_auth_ldap_connect(c);
+}
+
+static ngx_int_t
+ngx_http_auth_ldap_init_connections(ngx_cycle_t *cycle)
+{
+    ngx_http_auth_ldap_connection_t *c;
+    ngx_http_auth_ldap_main_conf_t *halmcf;
+    ngx_http_auth_ldap_server_t *server;
+    ngx_pool_cleanup_t *cleanup;
+    ngx_connection_t *dummy_conn;
+    ngx_uint_t i, j;
+    int option;
+
+    halmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_auth_ldap_module);
+    if (halmcf == NULL || halmcf->servers == NULL) {
+	return NGX_OK;
+    }
+
+    option = LDAP_VERSION3;
+    ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &option);
+
+    for (i = 0; i < halmcf->servers->nelts; i++) {
+        server = &((ngx_http_auth_ldap_server_t *) halmcf->servers->elts)[i];
+        ngx_queue_init(&server->free_connections);
+        ngx_queue_init(&server->waiting_requests);
+        if (server->connections <= 1) {
+            server->connections = 1;
+        }
+
+        for (j = 0; j < server->connections; j++) {
+            c = ngx_pcalloc(cycle->pool, sizeof(ngx_http_auth_ldap_connection_t));
+            cleanup = ngx_pool_cleanup_add(cycle->pool, 0);
+            dummy_conn = ngx_pcalloc(cycle->pool, sizeof(ngx_connection_t));
+            if (c == NULL || cleanup == NULL || dummy_conn == NULL) {
+                return NGX_ERROR;
+            }
+
+            cleanup->handler = &ngx_http_auth_ldap_connection_cleanup;
+            cleanup->data = c;
+
+            c->log = cycle->log;
+            c->server = server;
+            c->state = STATE_DISCONNECTED;
+
+            /* Various debug logging around timer management assume that the field
+               'data' in ngx_event_t is a pointer to ngx_connection_t, therefore we
+               have a dummy such structure around so that it does not crash etc. */
+            dummy_conn->data = c;
+            c->reconnect_event.log = c->log;
+            c->reconnect_event.data = dummy_conn;
+            c->reconnect_event.handler = ngx_http_auth_ldap_reconnect_handler;
+
+#if (NGX_OPENSSL)
+            c->pool = cycle->pool;
+            c->ssl = &halmcf->ssl;
+#endif
+
+            ngx_http_auth_ldap_connect(c);
+        }
+    }
+
+    return NGX_OK;
+}
+
+
+
+/*** Per-request authentication processing ***/
+
+/**
+ * Respond with "403 Forbidden" and add correct headers
+ */
+static ngx_int_t
+ngx_http_auth_ldap_set_realm(ngx_http_request_t *r, ngx_str_t *realm)
+{
+    r->headers_out.www_authenticate = ngx_list_push(&r->headers_out.headers);
+    if (r->headers_out.www_authenticate == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    r->headers_out.www_authenticate->hash = 1;
+    r->headers_out.www_authenticate->key.len = sizeof("WWW-Authenticate") - 1;
+    r->headers_out.www_authenticate->key.data = (u_char *) "WWW-Authenticate";
+    r->headers_out.www_authenticate->value = *realm;
+
+    return NGX_HTTP_UNAUTHORIZED;
+}
+
+/**
+ * LDAP Authentication handler
+ */
+static ngx_int_t
+ngx_http_auth_ldap_handler(ngx_http_request_t *r)
+{
+    ngx_http_auth_ldap_loc_conf_t *alcf;
+    ngx_http_auth_ldap_ctx_t *ctx;
+    int rc;
+
+    alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_ldap_module);
+    if (alcf->realm.len == 0) {
+        return NGX_DECLINED;
+    }
+
+    if (alcf->servers == NULL || alcf->servers->nelts == 0) {
+        /* No LDAP servers for the location. */
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: \"auth_ldap\" requires "
+                      "one or more \"auth_ldap_servers\" in the same location");
+        return ngx_http_auth_ldap_set_realm(r, &alcf->realm);
+    }
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_auth_ldap_module);
+    if (ctx == NULL) {
+        rc = ngx_http_auth_basic_user(r);
+        if (rc == NGX_DECLINED) {
+            return ngx_http_auth_ldap_set_realm(r, &alcf->realm);
+        }
+        if (rc == NGX_ERROR) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Username is \"%V\"",
+            &r->headers_in.user);
+        if (r->headers_in.passwd.len == 0)
+        {
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Password is empty");
+            return ngx_http_auth_ldap_set_realm(r, &alcf->realm);
+        }
+
+        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_ldap_ctx_t));
+        if (ctx == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+        ctx->r = r;
+        /* Other fields have been initialized to zero/NULL */
+        ngx_http_set_ctx(r, ctx, ngx_http_auth_ldap_module);
+    }
+
+    return ngx_http_auth_ldap_authenticate(r, ctx, alcf);
+}
+
+/**
+ * Iteratively handle all phases of the authentication process, might be called many times
+ */
+static ngx_int_t
+ngx_http_auth_ldap_authenticate(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx,
+        ngx_http_auth_ldap_loc_conf_t *conf)
+{
+    ngx_int_t rc;
+    ngx_uint_t i;
+    ngx_http_auth_ldap_server_t *s;
+
+    if (r->connection->write->timedout) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: Authentication timed out");
+        if (ctx->c != NULL) {
+            ngx_http_auth_ldap_return_connection(ctx->c);
+        }
+
+        // Remove ctx from waiting_requests queue if it was added.
+        if (ngx_queue_next(&ctx->queue)) {
+            ngx_queue_remove(&ctx->queue);
+        }
+
+        return NGX_ERROR;
+    }
+
+    /*
+     * If we are not starting up a request (ctx->phase != PHASE_START) and we actually already
+     * sent a request (ctx->iteration > 0) and didn't receive a reply yet (!ctx->replied) we
+     * ask to be called again at a later time when we hopefully have received a reply.
+     *
+     * It is quite possible that we reach this if while not having sent a request yet (ctx->iteration == 0) -
+     * this happens when we are trying to get an LDAP connection but all of them are busy right now.
+     */
+    if (ctx->iteration > 0 && !ctx->replied && ctx->phase != PHASE_START) {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: The LDAP operation did not finish yet");
+        return NGX_AGAIN;
+    }
+
+    for (;;) {
+        loop:
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Authentication loop (phase=%d, iteration=%d)",
+            ctx->phase, ctx->iteration);
+
+        switch (ctx->phase) {
+            case PHASE_START:
+                ctx->server = ((ngx_http_auth_ldap_server_t **) conf->servers->elts)[ctx->server_index];
+                ctx->outcome = OUTCOME_UNCERTAIN;
+
+                ngx_add_timer(r->connection->write, ctx->server->request_timeout);
+                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: request_timeout=%d",ctx->server->request_timeout);
+
+
+                /* Check cache if enabled */
+                if (ngx_http_auth_ldap_cache.buckets != NULL) {
+                    for (i = 0; i < conf->servers->nelts; i++) {
+                        s = &((ngx_http_auth_ldap_server_t *) conf->servers->elts)[i];
+                        rc = ngx_http_auth_ldap_check_cache(r, ctx, &ngx_http_auth_ldap_cache, s);
+                        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Using cached outcome %d from server %d", rc, i);
+                        if (rc == OUTCOME_DENY || rc == OUTCOME_ALLOW) {
+                            ctx->outcome = (rc == OUTCOME_DENY ? OUTCOME_CACHED_DENY : OUTCOME_CACHED_ALLOW);
+                            ctx->phase = PHASE_NEXT;
+                            goto loop;
+                        }
+                    }
+                }
+
+                if (ctx->server->require_valid_user_dn.value.data != NULL) {
+                    /* Construct user DN */
+                    if (ngx_http_complex_value(r, &ctx->server->require_valid_user_dn, &ctx->user_dn) != NGX_OK) {
+                        ngx_del_timer(r->connection->write);
+                        return NGX_ERROR;
+                    }
+                    ctx->phase = PHASE_CHECK_USER;
+                    break;
+                }
+
+                ctx->phase = PHASE_SEARCH;
+                ctx->iteration = 0;
+                break;
+
+            case PHASE_SEARCH:
+                /* Search the directory to retrieve full user DN */
+                rc = ngx_http_auth_ldap_search(r, ctx);
+                if (rc == NGX_AGAIN) {
+                    /* LDAP operation in progress, wait for the results */
+                    return NGX_AGAIN;
+                }
+                if (rc != NGX_OK) {
+                    /* Search failed, try next server */
+                    ctx->phase = PHASE_NEXT;
+                    break;
+                }
+
+                /* User DN has been found, check user next */
+                ctx->phase = PHASE_CHECK_USER;
+                break;
+
+            case PHASE_CHECK_USER:
+                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: User DN is \"%V\"",
+                    &ctx->user_dn);
+
+                if (ctx->server->require_user != NULL) {
+                    rc = ngx_http_auth_ldap_check_user(r, ctx);
+                    if (rc != NGX_OK) {
+                        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Not ok", &ctx->user_dn);
+                        /* User check failed, try next server */
+                        ctx->phase = PHASE_NEXT;
+                        break;
+                    }
+                }
+
+                /* User not yet fully authenticated, check group next */
+                if ((ctx->outcome == OUTCOME_UNCERTAIN) &&
+                    (ctx->server->require_group != NULL)) {
+                        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Moving to group check", &ctx->user_dn);
+                        ctx->phase = PHASE_CHECK_GROUP;
+                        ctx->iteration = 0;
+                        break;
+                }
+
+                /* No groups to validate, try binding next */
+                ctx->phase = PHASE_CHECK_BIND;
+                ctx->iteration = 0;
+                break;
+
+            case PHASE_CHECK_GROUP:
+                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Checking group", &ctx->user_dn);
+                rc = ngx_http_auth_ldap_check_group(r, ctx);
+                if (rc == NGX_AGAIN) {
+                    /* LDAP operation in progress, wait for the results */
+                    return NGX_AGAIN;
+                }
+                if (rc != NGX_OK) {
+                    /* Group check failed, try next server */
+                    ctx->phase = PHASE_NEXT;
+                    break;
+                }
+
+                /* Groups validated, try binding next */
+                ctx->phase = PHASE_CHECK_BIND;
+                ctx->iteration = 0;
+                break;
+
+            case PHASE_CHECK_BIND:
+                if (ctx->outcome == OUTCOME_UNCERTAIN) {
+                    /* If we're still uncertain when satisfy is 'any' and there
+                     * is at least one require user/group rule, it means no
+                     * rule has matched.
+                     */
+                    if ((ctx->server->satisfy_all == 0) && (
+                            (ctx->server->require_user != NULL) ||
+                            (ctx->server->require_group != NULL))){
+                        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: no requirement satisfied");
+                        ctx->outcome = OUTCOME_DENY;
+                        ctx->phase = PHASE_NEXT;
+                        /*rc = NGX_DECLINED;*/
+                        break;
+                    } else {
+                        /* So far so good */
+                        ctx->outcome = OUTCOME_ALLOW;
+                    }
+                }
+
+                /* Initiate bind using the found DN and request password */
+                rc = ngx_http_auth_ldap_check_bind(r, ctx);
+                if (rc == NGX_AGAIN) {
+                    /* LDAP operation in progress, wait for the result */
+                    return NGX_AGAIN;
+                }
+
+                /* All steps done, finish the processing */
+                ctx->phase = PHASE_REBIND;
+                ctx->iteration = 0;
+                break;
+
+            case PHASE_REBIND:
+                /* Initiate bind using the found DN and request password */
+                rc = ngx_http_auth_ldap_recover_bind(r, ctx);
+                if (rc == NGX_AGAIN) {
+                    /* LDAP operation in progress, wait for the result */
+                    return NGX_AGAIN;
+                }
+
+                /* All steps done, finish the processing */
+                ctx->phase = PHASE_NEXT;
+                break;
+
+            case PHASE_NEXT:
+                if (r->connection->write->timer_set) {
+                    ngx_del_timer(r->connection->write);
+                }
+
+                if (ctx->c != NULL) {
+                    ngx_http_auth_ldap_return_connection(ctx->c);
+                }
+
+                if (ngx_http_auth_ldap_cache.buckets != NULL &&
+                    (ctx->outcome == OUTCOME_DENY || ctx->outcome == OUTCOME_ALLOW)) {
+                    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Caching outcome %d", ctx->outcome);
+                    ngx_http_auth_ldap_update_cache(ctx, &ngx_http_auth_ldap_cache, ctx->outcome);
+                }
+
+                if (ctx->outcome == OUTCOME_ALLOW || ctx->outcome == OUTCOME_CACHED_ALLOW) {
+                    return NGX_OK;
+                }
+
+                ctx->server_index++;
+                if (ctx->server_index >= conf->servers->nelts) {
+                    return ngx_http_auth_ldap_set_realm(r, &conf->realm);
+                }
+
+                ctx->phase = PHASE_START;
+                break;
+        }
+    }
+}
+
+static ngx_int_t
+ngx_http_auth_ldap_search(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx)
+{
+    LDAPURLDesc *ludpp;
+    u_char *filter;
+    char *attrs[2];
+    ngx_int_t rc;
+
+    /* On the first call, initiate the LDAP search operation */
+    if (ctx->iteration == 0) {
+        if (!ngx_http_auth_ldap_get_connection(ctx)) {
+            return NGX_AGAIN;
+        }
+
+        ludpp = ctx->server->ludpp;
+        filter = ngx_pcalloc(
+            r->pool,
+            (ludpp->lud_filter != NULL ? ngx_strlen(ludpp->lud_filter) : ngx_strlen("(objectClass=*)")) +
+            ngx_strlen("(&(=))") + ngx_strlen(ludpp->lud_attrs[0]) + r->headers_in.user.len + 1);
+        ngx_sprintf(filter, "(&%s(%s=%V))%Z",
+                ludpp->lud_filter != NULL ? ludpp->lud_filter : "(objectClass=*)",
+                ludpp->lud_attrs[0], &r->headers_in.user);
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Search filter is \"%s\"",
+            (const char *) filter);
+
+        attrs[0] = LDAP_NO_ATTRS;
+        attrs[1] = NULL;
+
+        rc = ldap_search_ext(ctx->c->ld, ludpp->lud_dn, ludpp->lud_scope, (const char *) filter, attrs, 0, NULL, NULL, NULL, 0, &ctx->c->msgid);
+        if (rc != LDAP_SUCCESS) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: ldap_search_ext() failed (%d, %s)",
+                rc, ldap_err2string(rc));
+            ngx_http_auth_ldap_return_connection(ctx->c);
+            return NGX_ERROR;
+        }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: ldap_search_ext() -> msgid=%d",
+            ctx->c->msgid);
+        ctx->c->state = STATE_SEARCHING;
+        ctx->iteration++;
+        return NGX_AGAIN;
+    }
+
+    /* On the second call, handle the search results */
+    if (ctx->error_code != LDAP_SUCCESS) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: ldap_search_ext() request failed (%d: %s)",
+            ctx->error_code, ldap_err2string(ctx->error_code));
+        return NGX_ERROR;
+    }
+
+    if (ctx->dn.data == NULL) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: Could not find user DN");
+        return NGX_ERROR;
+    } else {
+        ctx->user_dn.len = ngx_strlen(ctx->dn.data);
+        ctx->user_dn.data = (u_char *) ngx_palloc(ctx->r->pool, ctx->user_dn.len + 1);
+        ngx_memcpy(ctx->user_dn.data, ctx->dn.data, ctx->user_dn.len + 1);
+        ctx->dn.data = NULL;
+        ctx->dn.len = 0;
+    }
+
+    return NGX_OK;
+}
+
+static ngx_int_t
+ngx_http_auth_ldap_check_user(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx)
+{
+    ngx_http_complex_value_t *values;
+    ngx_uint_t i;
+
+    values = ctx->server->require_user->elts;
+    for (i = 0; i < ctx->server->require_user->nelts; i++) {
+        ngx_str_t val;
+        if (ngx_http_complex_value(r, &values[i], &val) != NGX_OK) {
+            ctx->outcome = OUTCOME_ERROR;
+            return NGX_ERROR;
+        }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Comparing user DN with \"%V\"", &val);
+        if (val.len == ctx->user_dn.len && ngx_memcmp(val.data, ctx->user_dn.data, val.len) == 0) {
+            if (ctx->server->satisfy_all == 0) {
+                ctx->outcome = OUTCOME_ALLOW;
+                return NGX_OK;
+            }
+        } else {
+            if (ctx->server->satisfy_all == 1) {
+                ctx->outcome = OUTCOME_DENY;
+                return NGX_DECLINED;
+            }
+        }
+    }
+
+    return NGX_OK;
+}
+
+static ngx_int_t
+ngx_http_auth_ldap_check_group(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx)
+{
+    ngx_http_complex_value_t *values;
+    ngx_int_t rc;
+    u_char *filter;
+    char *user_val;
+    char *attrs[2];
+    size_t for_filter;
+
+    /* Handle result of the search started during previous call */
+    if (ctx->iteration > 0) {
+        ctx->group_dn.data = ctx->dn.data;
+        if (ctx->group_dn.data == NULL) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: ldap_search_ext() returned NULL result");
+            if (ctx->server->satisfy_all == 1) {
+                ctx->outcome = OUTCOME_DENY;
+                return NGX_DECLINED;
+            }
+        } else {
+            if (ctx->error_code == LDAP_SUCCESS) {
+                if (ctx->server->satisfy_all == 0) {
+                    ctx->outcome = OUTCOME_ALLOW;
+                    return NGX_OK;
+                }
+            } else if (ctx->error_code == LDAP_NO_RESULTS_RETURNED) {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: ldap_search_ext() request failed (%d: %s)",
+                              ctx->error_code, ldap_err2string(ctx->error_code));
+                if (ctx->server->satisfy_all == 1) {
+                    ctx->outcome = OUTCOME_DENY;
+                    return NGX_DECLINED;
+                }
+            } else {
+                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: ldap_search_ext() request failed (%d: %s)",
+                    ctx->error_code, ldap_err2string(ctx->error_code));
+                return NGX_ERROR;
+            }
+        }
+    }
+
+    /* Check next group */
+    if (ctx->iteration >= ctx->server->require_group->nelts) {
+        /* No more groups */
+        return NGX_OK;
+    }
+
+    if (!ngx_http_auth_ldap_get_connection(ctx)) {
+        return NGX_AGAIN;
+    }
+
+    ctx->replied = 0;
+    ngx_str_t val;
+    values = ctx->server->require_group->elts;
+    if (ngx_http_complex_value(r, &values[ctx->iteration], &val) != NGX_OK) {
+        ctx->outcome = OUTCOME_ERROR;
+        ngx_http_auth_ldap_return_connection(ctx->c);
+        return NGX_ERROR;
+    }
+
+    char *gr;
+    char *cn_gr;
+    char *tail_gr;
+    gr = ngx_pcalloc(r->pool,val.len+1);
+    ngx_memcpy(gr, val.data, val.len);
+    gr[val.len] = '\0';
+    tail_gr = ngx_strchr(gr, ',');
+    if (tail_gr == NULL) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: Incorrect group DN: \"%s\"", gr);
+        ctx->outcome = OUTCOME_ERROR;
+        ngx_http_auth_ldap_return_connection(ctx->c);
+        return NGX_ERROR;
+    }
+    *tail_gr = '\0';
+    tail_gr++;
+    cn_gr = gr;
+
+    if (ctx->server->group_attribute_dn == 1) {
+        user_val = ngx_pcalloc(
+            r->pool,
+            ctx->user_dn.len + 1);
+        ngx_memcpy(user_val, ctx->user_dn.data, ctx->user_dn.len);
+        user_val[ctx->user_dn.len] = '\0';
+    } else {
+        user_val = ngx_pcalloc(
+            r->pool,
+            r->headers_in.user.len + 1);
+        ngx_memcpy(user_val, r->headers_in.user.data, r->headers_in.user.len);
+        user_val[r->headers_in.user.len] = '\0';
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Search user in group \"%V\"", &val);
+
+    if (ctx->server->group_attribute.data == NULL) {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: group_attribute.data is \"%V\" so calling a failure here", ctx->server->group_attribute.data);
+        rc = !LDAP_SUCCESS;
+    } else {
+        for_filter = ngx_strlen(cn_gr) + ctx->server->group_attribute.len + ngx_strlen((const char *) user_val) + ngx_strlen("(&()(=))") + 1;
+        filter = ngx_pcalloc(
+            r->pool,
+            for_filter);
+        ngx_sprintf(filter, "(&(%s)(%s=%s))", cn_gr, ctx->server->group_attribute.data, user_val);
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Search group filter is \"%s\"", (const char *) filter);
+        attrs[0] = LDAP_NO_ATTRS;
+        attrs[1] = NULL;
+        rc = ldap_search_ext(ctx->c->ld, tail_gr, LDAP_SCOPE_ONELEVEL, (const char *) filter, attrs, 0, NULL, NULL, NULL, 0, &ctx->c->msgid);
+    }
+    if (rc != LDAP_SUCCESS) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: ldap_search_ext() failed (%d: %s)",
+            rc, ldap_err2string(rc));
+        ctx->outcome = OUTCOME_ERROR;
+        ngx_http_auth_ldap_return_connection(ctx->c);
+        return NGX_ERROR;
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: ldap_search_ext() -> msgid=%d",
+        ctx->c->msgid);
+    ctx->c->state = STATE_SEARCHING;
+    ctx->iteration++;
+    return NGX_AGAIN;
+}
+
+/**
+ * Initiate and handle a bind operation using the authentication parameters
+ */
+static ngx_int_t
+ngx_http_auth_ldap_check_bind(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx)
+{
+    struct berval cred;
+    ngx_int_t rc;
+
+    /* On the first call, initiate the bind LDAP operation */
+    if (ctx->iteration == 0) {
+        if (!ngx_http_auth_ldap_get_connection(ctx)) {
+            return NGX_AGAIN;
+        }
+
+        cred.bv_val = (char *) r->headers_in.passwd.data;
+        cred.bv_len = r->headers_in.passwd.len;
+        rc = ldap_sasl_bind(ctx->c->ld, (const char *) ctx->user_dn.data, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &ctx->c->msgid);
+        if (rc != LDAP_SUCCESS) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: ldap_sasl_bind() failed (%d: %s)",
+                rc, ldap_err2string(rc));
+            ctx->outcome = OUTCOME_ERROR;
+            ngx_http_auth_ldap_return_connection(ctx->c);
+            return NGX_ERROR;
+        }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: ldap_sasl_bind() -> msgid=%d",
+            ctx->c->msgid);
+        ctx->c->state = STATE_BINDING;
+        ctx->iteration++;
+
+        return NGX_AGAIN;
+    }
+
+    /* On the second call, process the operation result */
+    if (ctx->error_code != LDAP_SUCCESS) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: User bind failed (%d: %s)",
+            ctx->error_code, ldap_err2string(ctx->error_code));
+        ctx->outcome = OUTCOME_DENY;
+    } else {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: User bind successful");
+        ctx->outcome = OUTCOME_ALLOW;
+    }
+    return NGX_OK;
+}
+
+static ngx_int_t
+ngx_http_auth_ldap_recover_bind(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx)
+{
+    struct berval cred;
+    ngx_int_t rc;
+
+    /* On the first call, initiate the bind LDAP operation */
+    if (ctx->iteration == 0) {
+        if (!ngx_http_auth_ldap_get_connection(ctx)) {
+            return NGX_AGAIN;
+        }
+
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Rebinding to binddn");
+        cred.bv_val = (char *) ctx->server->bind_dn_passwd.data;
+        cred.bv_len = ctx->server->bind_dn_passwd.len;
+        rc = ldap_sasl_bind(ctx->c->ld, (const char *) ctx->server->bind_dn.data, LDAP_SASL_SIMPLE, &cred, NULL, NULL, &ctx->c->msgid);
+        if (rc != LDAP_SUCCESS) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: ldap_sasl_bind() failed (%d: %s)",
+                rc, ldap_err2string(rc));
+            ctx->outcome = OUTCOME_ERROR;
+            ngx_http_auth_ldap_return_connection(ctx->c);
+            return NGX_ERROR;
+        }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: ldap_sasl_bind() -> msgid=%d",
+            ctx->c->msgid);
+        ctx->c->state = STATE_BINDING;
+        ctx->iteration++;
+        return NGX_AGAIN;
+    }
+
+    /* On the second call, process the operation result */
+    if (ctx->error_code != LDAP_SUCCESS) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: binddn bind failed (%d: %s)",
+            ctx->error_code, ldap_err2string(ctx->error_code));
+    } else {
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: binddn bind successful");
+    }
+    return NGX_OK;
+}
diff -Naur debian/modules/watch/http-auth-ldap debian+ldap/modules/watch/http-auth-ldap
--- debian/modules/watch/http-auth-ldap	1970-01-01 03:00:00.000000000 +0300
+++ debian+ldap/modules/watch/http-auth-ldap	2019-11-08 09:07:27.328000000 +0300
@@ -0,0 +1,4 @@
+version=4
+opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-auth-ldap-$1.tar.gz%" \
+    https://github.com/kvspb/nginx-auth-ldap/tags \
+    (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-auth-ldap
diff -Naur debian/rules debian+ldap/rules
--- debian/rules	2019-08-13 21:10:28.000000000 +0300
+++ debian+ldap/rules	2019-11-08 04:49:04.980000000 +0300
@@ -8,6 +8,7 @@
 FLAVOURS := full light extras
 DYN_MODS := \
 	http-auth-pam \
+	http-auth-ldap \
 	http-cache-purge \
 	http-dav-ext \
 	http-echo \
@@ -99,6 +100,7 @@
 			--with-mail=dynamic \
 			--with-mail_ssl_module \
 			--add-dynamic-module=$(MODULESDIR)/http-auth-pam \
+			--add-dynamic-module=$(MODULESDIR)/http-auth-ldap \
 			--add-dynamic-module=$(MODULESDIR)/http-dav-ext \
 			--add-dynamic-module=$(MODULESDIR)/http-echo \
 			--add-dynamic-module=$(MODULESDIR)/http-upstream-fair \
@@ -125,6 +127,7 @@
 			--with-stream_ssl_preread_module \
 			--add-dynamic-module=$(MODULESDIR)/http-headers-more-filter \
 			--add-dynamic-module=$(MODULESDIR)/http-auth-pam \
+			--add-dynamic-module=$(MODULESDIR)/http-auth-ldap \
 			--add-dynamic-module=$(MODULESDIR)/http-cache-purge \
 			--add-dynamic-module=$(MODULESDIR)/http-dav-ext \
 			--add-dynamic-module=$(MODULESDIR)/http-ndk \
diff -Naur debian/tests/control debian+ldap/tests/control
--- debian/tests/control	2019-08-13 21:10:28.000000000 +0300
+++ debian+ldap/tests/control	2019-11-08 05:08:51.348000000 +0300
@@ -23,6 +23,7 @@
 Depends: nginx-full,
          curl,
          libnginx-mod-http-auth-pam,
+         libnginx-mod-http-auth-ldap,
          libnginx-mod-http-cache-purge,
          libnginx-mod-http-dav-ext,
          libnginx-mod-http-echo,
@@ -46,6 +47,7 @@
 Depends: nginx-light,
          curl,
          libnginx-mod-http-auth-pam,
+         libnginx-mod-http-auth-ldap,
          libnginx-mod-http-cache-purge,
          libnginx-mod-http-dav-ext,
          libnginx-mod-http-echo,
@@ -69,6 +71,7 @@
 Depends: nginx-extras,
          curl,
          libnginx-mod-http-auth-pam,
+         libnginx-mod-http-auth-ldap,
          libnginx-mod-http-cache-purge,
          libnginx-mod-http-dav-ext,
          libnginx-mod-http-echo,

Reply via email to