mirror of
https://github.com/mainnika/nginx-auth-ldap.git
synced 2026-06-13 02:13:36 +00:00
Merge pull request #100 from victorhahncastell/master
Provide SSL certificate verification
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2011-2013 Valery Komarov <komarov@valerka.net>
|
* Copyright (C) 2011-2013 Valery Komarov <komarov@valerka.net>
|
||||||
* Copyright (C) 2013 Jiri Hruska <jirka@fud.cz>
|
* Copyright (C) 2013 Jiri Hruska <jirka@fud.cz>
|
||||||
|
* Copyright (C) 2015 Victor Hahn Castell <victor.hahn@flexoptix.net>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
|||||||
@@ -71,3 +71,52 @@ And add required servers in correct order into your location/server directive:
|
|||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
## 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 ceritificate 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.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ typedef struct {
|
|||||||
ngx_str_t group_attribute;
|
ngx_str_t group_attribute;
|
||||||
ngx_flag_t group_attribute_dn;
|
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_group; /* array of ngx_http_complex_value_t */
|
||||||
ngx_array_t *require_user; /* 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_flag_t require_valid_user;
|
||||||
@@ -378,6 +382,12 @@ 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, "ssl_check_cert") == 0 && ngx_strcmp(value[1].data, "on") == 0) {
|
||||||
|
server->ssl_check_cert = 1;
|
||||||
|
} 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,connect_timeout)
|
||||||
else CONF_MSEC_VALUE(cf,value,server,reconnect_timeout)
|
else CONF_MSEC_VALUE(cf,value,server,reconnect_timeout)
|
||||||
@@ -1129,7 +1139,7 @@ ngx_http_auth_ldap_dummy_write_handler(ngx_event_t *wev)
|
|||||||
|
|
||||||
|
|
||||||
#if (NGX_OPENSSL)
|
#if (NGX_OPENSSL)
|
||||||
/* Make sure the event hendlers are activated. */
|
/* Make sure the event handlers are activated. */
|
||||||
static ngx_int_t
|
static ngx_int_t
|
||||||
ngx_http_auth_ldap_restore_handlers(ngx_connection_t *conn)
|
ngx_http_auth_ldap_restore_handlers(ngx_connection_t *conn)
|
||||||
{
|
{
|
||||||
@@ -1212,23 +1222,45 @@ ngx_http_auth_ldap_connection_established(ngx_http_auth_ldap_connection_t *c)
|
|||||||
|
|
||||||
#if (NGX_OPENSSL)
|
#if (NGX_OPENSSL)
|
||||||
static void
|
static void
|
||||||
ngx_http_auth_ldap_ssl_handshake_handler(ngx_connection_t *conn)
|
ngx_http_auth_ldap_ssl_handshake_handler(ngx_connection_t *conn, ngx_flag_t validate)
|
||||||
{
|
{
|
||||||
ngx_http_auth_ldap_connection_t *c;
|
ngx_http_auth_ldap_connection_t *c;
|
||||||
|
|
||||||
c = conn->data;
|
c = conn->data;
|
||||||
|
|
||||||
if (conn->ssl->handshaked) {
|
if (conn->ssl->handshaked) {
|
||||||
conn->read->handler = &ngx_http_auth_ldap_read_handler;
|
// verify remote certificate
|
||||||
ngx_http_auth_ldap_restore_handlers(conn);
|
X509 *cert = SSL_get_peer_certificate(conn->ssl->connection);
|
||||||
ngx_http_auth_ldap_connection_established(c);
|
long verified = SSL_get_verify_result(conn->ssl->connection);
|
||||||
return;
|
|
||||||
|
if (!validate || (cert && verified == X509_V_OK) ) { // everything fine
|
||||||
|
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 { // smells fishy
|
||||||
|
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
||||||
|
"http_auth_ldap: Remote side presented invalid SSL certificate: error %l, %s",
|
||||||
|
verified, X509_verify_cert_error_string(verified));
|
||||||
|
ngx_http_auth_ldap_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: SSL handshake failed");
|
ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: SSL handshake failed");
|
||||||
ngx_http_auth_ldap_close_connection(c);
|
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
|
static void
|
||||||
ngx_http_auth_ldap_ssl_handshake(ngx_http_auth_ldap_connection_t *c)
|
ngx_http_auth_ldap_ssl_handshake(ngx_http_auth_ldap_connection_t *c)
|
||||||
{
|
{
|
||||||
@@ -1243,14 +1275,45 @@ ngx_http_auth_ldap_ssl_handshake(ngx_http_auth_ldap_connection_t *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
c->log->action = "SSL handshaking to LDAP server";
|
c->log->action = "SSL handshaking to LDAP server";
|
||||||
|
ngx_connection_t *transport = c->conn.connection;
|
||||||
|
|
||||||
rc = ngx_ssl_handshake(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) {
|
||||||
|
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));
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int setcode = SSL_CTX_set_default_verify_paths(transport->ssl->connection->ctx);
|
||||||
|
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) {
|
if (rc == NGX_AGAIN) {
|
||||||
c->conn.connection->ssl->handler = &ngx_http_auth_ldap_ssl_handshake_handler;
|
transport->ssl->handler = callback;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngx_http_auth_ldap_ssl_handshake_handler(c->conn.connection);
|
(*callback)(transport);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user