mirror of
https://github.com/mainnika/nginx-auth-ldap.git
synced 2026-07-03 20:22:33 +00:00
@@ -1,5 +1,14 @@
|
|||||||
ngx_addon_name=ngx_http_auth_ldap_module
|
ngx_addon_name=ngx_http_auth_ldap_module
|
||||||
HTTP_MODULES="$HTTP_MODULES ngx_http_auth_ldap_module"
|
HTTP_MODULES="$HTTP_MODULES ngx_http_auth_ldap_module"
|
||||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_auth_ldap_module.c"
|
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_auth_ldap_module.c"
|
||||||
|
|
||||||
CORE_LIBS="$CORE_LIBS -lldap"
|
CORE_LIBS="$CORE_LIBS -lldap"
|
||||||
|
|
||||||
|
case "$NGX_PLATFORM" in
|
||||||
|
SunOS:*)
|
||||||
|
CORE_LIBS="$CORE_LIBS -llber"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CFLAGS="$CFLAGS"
|
||||||
CFLAGS="$CFLAGS"
|
CFLAGS="$CFLAGS"
|
||||||
|
|||||||
+82
-24
@@ -42,6 +42,14 @@
|
|||||||
extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, LDAP **ld);
|
extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, LDAP **ld);
|
||||||
#endif
|
#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 */
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
LDAPURLDesc *ludpp;
|
LDAPURLDesc *ludpp;
|
||||||
ngx_str_t url;
|
ngx_str_t url;
|
||||||
@@ -82,7 +90,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t small_hash; /* murmur2 hash of username ^ &server */
|
uint32_t small_hash; /* murmur2 hash of username ^ &server */
|
||||||
uint32_t outcome; /* 0 = authentication failed, 1 = succeeded */
|
uint32_t outcome; /* OUTCOME_DENY or OUTCOME_ALLOW */
|
||||||
ngx_msec_t time; /* ngx_current_msec when created */
|
ngx_msec_t time; /* ngx_current_msec when created */
|
||||||
u_char big_hash[16]; /* md5 hash of (username, server, password) */
|
u_char big_hash[16]; /* md5 hash of (username, server, password) */
|
||||||
} ngx_http_auth_ldap_cache_elt_t;
|
} ngx_http_auth_ldap_cache_elt_t;
|
||||||
@@ -178,6 +186,7 @@ static ngx_int_t ngx_http_auth_ldap_check_user(ngx_http_request_t *r, ngx_http_a
|
|||||||
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_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_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);
|
static ngx_int_t ngx_http_auth_ldap_recover_bind(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *ctx);
|
||||||
|
static ngx_int_t ngx_http_auth_ldap_restore_handlers(ngx_connection_t *conn);
|
||||||
|
|
||||||
ngx_http_auth_ldap_cache_t ngx_http_auth_ldap_cache;
|
ngx_http_auth_ldap_cache_t ngx_http_auth_ldap_cache;
|
||||||
|
|
||||||
@@ -350,6 +359,8 @@ ngx_http_auth_ldap_ldap_server(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
|
|||||||
return NGX_CONF_ERROR;
|
return NGX_CONF_ERROR;
|
||||||
}
|
}
|
||||||
server->connections = i;
|
server->connections = i;
|
||||||
|
} else if (ngx_strcmp(value[0].data, "include") == 0) {
|
||||||
|
return ngx_conf_include(cf, dummy, conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = NGX_CONF_OK;
|
rv = NGX_CONF_OK;
|
||||||
@@ -1078,6 +1089,33 @@ ngx_http_auth_ldap_dummy_write_handler(ngx_event_t *wev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Make sure the event hendlers 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;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ngx_http_auth_ldap_connection_established(ngx_http_auth_ldap_connection_t *c)
|
ngx_http_auth_ldap_connection_established(ngx_http_auth_ldap_connection_t *c)
|
||||||
{
|
{
|
||||||
@@ -1141,6 +1179,7 @@ ngx_http_auth_ldap_ssl_handshake_handler(ngx_connection_t *conn)
|
|||||||
|
|
||||||
if (conn->ssl->handshaked) {
|
if (conn->ssl->handshaked) {
|
||||||
conn->read->handler = &ngx_http_auth_ldap_read_handler;
|
conn->read->handler = &ngx_http_auth_ldap_read_handler;
|
||||||
|
ngx_http_auth_ldap_restore_handlers(conn);
|
||||||
ngx_http_auth_ldap_connection_established(c);
|
ngx_http_auth_ldap_connection_established(c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1558,7 +1597,7 @@ ngx_http_auth_ldap_authenticate(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t
|
|||||||
switch (ctx->phase) {
|
switch (ctx->phase) {
|
||||||
case PHASE_START:
|
case PHASE_START:
|
||||||
ctx->server = ((ngx_http_auth_ldap_server_t **) conf->servers->elts)[ctx->server_index];
|
ctx->server = ((ngx_http_auth_ldap_server_t **) conf->servers->elts)[ctx->server_index];
|
||||||
ctx->outcome = -1;
|
ctx->outcome = OUTCOME_UNCERTAIN;
|
||||||
|
|
||||||
ngx_add_timer(r->connection->write, 10000); /* TODO: Per-server request timeout */
|
ngx_add_timer(r->connection->write, 10000); /* TODO: Per-server request timeout */
|
||||||
|
|
||||||
@@ -1566,8 +1605,8 @@ ngx_http_auth_ldap_authenticate(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t
|
|||||||
if (ngx_http_auth_ldap_cache.buckets != NULL) {
|
if (ngx_http_auth_ldap_cache.buckets != NULL) {
|
||||||
rc = ngx_http_auth_ldap_check_cache(r, ctx, &ngx_http_auth_ldap_cache, ctx->server);
|
rc = ngx_http_auth_ldap_check_cache(r, ctx, &ngx_http_auth_ldap_cache, ctx->server);
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Using cached outcome %d", rc);
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Using cached outcome %d", rc);
|
||||||
if (rc == 0 || rc == 1) {
|
if (rc == OUTCOME_DENY || rc == OUTCOME_ALLOW) {
|
||||||
ctx->outcome = 2 + rc;
|
ctx->outcome = (rc == OUTCOME_DENY ? OUTCOME_CACHED_DENY : OUTCOME_CACHED_ALLOW);
|
||||||
ctx->phase = PHASE_NEXT;
|
ctx->phase = PHASE_NEXT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1617,8 +1656,10 @@ ngx_http_auth_ldap_authenticate(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* User validated, check group next */
|
/* User not yet fully authenticated, check group next */
|
||||||
if (ctx->server->require_group != NULL) {
|
if ((ctx->outcome == OUTCOME_UNCERTAIN) &&
|
||||||
|
(ctx->server->require_group != NULL)) {
|
||||||
|
|
||||||
ctx->phase = PHASE_CHECK_GROUP;
|
ctx->phase = PHASE_CHECK_GROUP;
|
||||||
ctx->iteration = 0;
|
ctx->iteration = 0;
|
||||||
break;
|
break;
|
||||||
@@ -1647,6 +1688,26 @@ ngx_http_auth_ldap_authenticate(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PHASE_CHECK_BIND:
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->server->require_valid_user == 0) {
|
if (ctx->server->require_valid_user == 0) {
|
||||||
ctx->phase = PHASE_NEXT;
|
ctx->phase = PHASE_NEXT;
|
||||||
break;
|
break;
|
||||||
@@ -1685,12 +1746,13 @@ ngx_http_auth_ldap_authenticate(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t
|
|||||||
ngx_http_auth_ldap_return_connection(ctx->c);
|
ngx_http_auth_ldap_return_connection(ctx->c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ngx_http_auth_ldap_cache.buckets != NULL && (ctx->outcome == 0 || ctx->outcome == 1)) {
|
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_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);
|
ngx_http_auth_ldap_update_cache(ctx, &ngx_http_auth_ldap_cache, ctx->outcome);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->outcome == 1 || ctx->outcome == 2 + 1) {
|
if (ctx->outcome == OUTCOME_ALLOW || ctx->outcome == OUTCOME_CACHED_ALLOW) {
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1773,19 +1835,19 @@ ngx_http_auth_ldap_check_user(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *c
|
|||||||
for (i = 0; i < ctx->server->require_user->nelts; i++) {
|
for (i = 0; i < ctx->server->require_user->nelts; i++) {
|
||||||
ngx_str_t val;
|
ngx_str_t val;
|
||||||
if (ngx_http_complex_value(r, &values[i], &val) != NGX_OK) {
|
if (ngx_http_complex_value(r, &values[i], &val) != NGX_OK) {
|
||||||
ctx->outcome = -1;
|
ctx->outcome = OUTCOME_ERROR;
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Comparing user DN with \"%V\"", &val);
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: Comparing user DN with \"%V\"", &val);
|
||||||
if (val.len == ctx->dn.len && ngx_memcmp(val.data, ctx->dn.data, val.len) == 0) {
|
if (val.len == ctx->dn.len && ngx_memcmp(val.data, ctx->dn.data, val.len) == 0) {
|
||||||
if (ctx->server->satisfy_all == 0) {
|
if (ctx->server->satisfy_all == 0) {
|
||||||
ctx->outcome = 1;
|
ctx->outcome = OUTCOME_ALLOW;
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ctx->server->satisfy_all == 1) {
|
if (ctx->server->satisfy_all == 1) {
|
||||||
ctx->outcome = 0;
|
ctx->outcome = OUTCOME_DENY;
|
||||||
return NGX_DECLINED;
|
return NGX_DECLINED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1805,12 +1867,12 @@ ngx_http_auth_ldap_check_group(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *
|
|||||||
if (ctx->iteration > 0) {
|
if (ctx->iteration > 0) {
|
||||||
if (ctx->error_code == LDAP_COMPARE_TRUE) {
|
if (ctx->error_code == LDAP_COMPARE_TRUE) {
|
||||||
if (ctx->server->satisfy_all == 0) {
|
if (ctx->server->satisfy_all == 0) {
|
||||||
ctx->outcome = 1;
|
ctx->outcome = OUTCOME_ALLOW;
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
} else if (ctx->error_code == LDAP_COMPARE_FALSE || ctx->error_code == LDAP_NO_SUCH_ATTRIBUTE) {
|
} else if (ctx->error_code == LDAP_COMPARE_FALSE || ctx->error_code == LDAP_NO_SUCH_ATTRIBUTE) {
|
||||||
if (ctx->server->satisfy_all == 1) {
|
if (ctx->server->satisfy_all == 1) {
|
||||||
ctx->outcome = 0;
|
ctx->outcome = OUTCOME_DENY;
|
||||||
return NGX_DECLINED;
|
return NGX_DECLINED;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1823,11 +1885,7 @@ ngx_http_auth_ldap_check_group(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *
|
|||||||
/* Check next group */
|
/* Check next group */
|
||||||
if (ctx->iteration >= ctx->server->require_group->nelts) {
|
if (ctx->iteration >= ctx->server->require_group->nelts) {
|
||||||
/* No more groups */
|
/* No more groups */
|
||||||
if (ctx->server->satisfy_all == 0) {
|
return NGX_OK;
|
||||||
return NGX_DECLINED;
|
|
||||||
} else {
|
|
||||||
return NGX_OK;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ngx_http_auth_ldap_get_connection(ctx)) {
|
if (!ngx_http_auth_ldap_get_connection(ctx)) {
|
||||||
@@ -1837,7 +1895,7 @@ ngx_http_auth_ldap_check_group(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *
|
|||||||
ngx_str_t val;
|
ngx_str_t val;
|
||||||
values = ctx->server->require_group->elts;
|
values = ctx->server->require_group->elts;
|
||||||
if (ngx_http_complex_value(r, &values[ctx->iteration], &val) != NGX_OK) {
|
if (ngx_http_complex_value(r, &values[ctx->iteration], &val) != NGX_OK) {
|
||||||
ctx->outcome = -1;
|
ctx->outcome = OUTCOME_ERROR;
|
||||||
ngx_http_auth_ldap_return_connection(ctx->c);
|
ngx_http_auth_ldap_return_connection(ctx->c);
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
@@ -1857,7 +1915,7 @@ ngx_http_auth_ldap_check_group(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *
|
|||||||
if (rc != LDAP_SUCCESS) {
|
if (rc != LDAP_SUCCESS) {
|
||||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: ldap_compare_ext() failed (%d: %s)",
|
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: ldap_compare_ext() failed (%d: %s)",
|
||||||
rc, ldap_err2string(rc));
|
rc, ldap_err2string(rc));
|
||||||
ctx->outcome = -1;
|
ctx->outcome = OUTCOME_ERROR;
|
||||||
ngx_http_auth_ldap_return_connection(ctx->c);
|
ngx_http_auth_ldap_return_connection(ctx->c);
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
@@ -1890,7 +1948,7 @@ ngx_http_auth_ldap_check_bind(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *c
|
|||||||
if (rc != LDAP_SUCCESS) {
|
if (rc != LDAP_SUCCESS) {
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "http_auth_ldap: ldap_sasl_bind() failed (%d: %s)",
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "http_auth_ldap: ldap_sasl_bind() failed (%d: %s)",
|
||||||
rc, ldap_err2string(rc));
|
rc, ldap_err2string(rc));
|
||||||
ctx->outcome = -1;
|
ctx->outcome = OUTCOME_ERROR;
|
||||||
ngx_http_auth_ldap_return_connection(ctx->c);
|
ngx_http_auth_ldap_return_connection(ctx->c);
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
@@ -1906,10 +1964,10 @@ ngx_http_auth_ldap_check_bind(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t *c
|
|||||||
if (ctx->error_code != LDAP_SUCCESS) {
|
if (ctx->error_code != LDAP_SUCCESS) {
|
||||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "http_auth_ldap: User bind failed (%d: %s)",
|
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->error_code, ldap_err2string(ctx->error_code));
|
||||||
ctx->outcome = 0;
|
ctx->outcome = OUTCOME_DENY;
|
||||||
} else {
|
} else {
|
||||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: User bind successful");
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http_auth_ldap: User bind successful");
|
||||||
ctx->outcome = 1;
|
ctx->outcome = OUTCOME_ALLOW;
|
||||||
}
|
}
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
@@ -1933,7 +1991,7 @@ ngx_http_auth_ldap_recover_bind(ngx_http_request_t *r, ngx_http_auth_ldap_ctx_t
|
|||||||
if (rc != LDAP_SUCCESS) {
|
if (rc != LDAP_SUCCESS) {
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "http_auth_ldap: ldap_sasl_bind() failed (%d: %s)",
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "http_auth_ldap: ldap_sasl_bind() failed (%d: %s)",
|
||||||
rc, ldap_err2string(rc));
|
rc, ldap_err2string(rc));
|
||||||
ctx->outcome = -1;
|
ctx->outcome = OUTCOME_ERROR;
|
||||||
ngx_http_auth_ldap_return_connection(ctx->c);
|
ngx_http_auth_ldap_return_connection(ctx->c);
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user