Allow specifying the full user DN to avoid searching the LDAP

The configuration can now contain a directive like this
  require valid_user cn=$remote_user,dc=example,dc=com
which will result in the bind as the respective user to be the
only command sent to the server, skipping the search request.
main
Jiri Hruska 12 years ago
parent a043544e2d
commit bd4959918c
  1. 236
      ngx_http_auth_ldap_module.c

@ -43,6 +43,7 @@ typedef struct {
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_http_auth_ldap_server_t;
@ -373,14 +374,20 @@ 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* rule = NULL;
ngx_http_complex_value_t* target = NULL;
ngx_http_compile_complex_value_t ccv;
value = cf->args->elts;
if (ngx_strcmp(value[1].data, "valid_user") == 0) {
server->require_valid_user = 1;
return NGX_CONF_OK;
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));
@ -388,7 +395,7 @@ ngx_http_auth_ldap_parse_require(ngx_conf_t *cf, ngx_http_auth_ldap_server_t *se
return NGX_CONF_ERROR;
}
}
rule = ngx_array_push(server->require_user);
target = ngx_array_push(server->require_user);
} else if (ngx_strcmp(value[1].data, "group") == 0) {
if (server->require_group == NULL) {
server->require_group = ngx_array_create(cf->pool, 4, sizeof(ngx_http_complex_value_t));
@ -396,17 +403,17 @@ ngx_http_auth_ldap_parse_require(ngx_conf_t *cf, ngx_http_auth_ldap_server_t *se
return NGX_CONF_ERROR;
}
}
rule = ngx_array_push(server->require_group);
target = ngx_array_push(server->require_group);
}
if (rule == NULL) {
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 = rule;
ccv.complex_value = target;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
@ -560,7 +567,8 @@ static ngx_int_t ngx_http_auth_ldap_authenticate_against_server(ngx_http_request
int rc;
LDAP *ld;
LDAPMessage *searchResult;
char *dn;
char* ldn = NULL;
ngx_str_t dn;
u_char *p, *filter;
ngx_http_complex_value_t *value;
ngx_uint_t i;
@ -593,129 +601,139 @@ static ngx_int_t ngx_http_auth_ldap_authenticate_against_server(ngx_http_request
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "LDAP: Bind successful", NULL);
/// Create filter for search users by uid
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);
if (server->require_valid_user_dn.value.data != NULL) {
// Construct user DN
if (ngx_http_complex_value(r, &server->require_valid_user_dn, &dn) != NGX_OK) {
ldap_unbind_s(ld);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
} else {
/// Create filter for search users by uid
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);
p = ngx_sprintf(filter, "(&%s(%s=%V))",
ludpp->lud_filter != NULL ? ludpp->lud_filter : "(objectClass=*)",
ludpp->lud_attrs[0], &r->headers_in.user);
*p = 0;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "LDAP: filter %s", (const char*) filter);
/// Search the directory
rc = ldap_search_ext_s(ld, ludpp->lud_dn, ludpp->lud_scope, (const char*) filter, NULL, 0, NULL, NULL, &timeOut, 0,
&searchResult);
if (rc != LDAP_SUCCESS) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "LDAP: ldap_search_ext_s: %d, %s", rc, ldap_err2string(rc));
ldap_msgfree(searchResult);
ldap_unbind_s(ld);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
p = ngx_sprintf(filter, "(&%s(%s=%V))", ludpp->lud_filter != NULL ? ludpp->lud_filter : "(objectClass=*)", ludpp->lud_attrs[0], &r->headers_in.user);
*p = 0;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "LDAP: filter %s", (const char*) filter);
if (ldap_count_entries(ld, searchResult) > 0) {
ldn = ldap_get_dn(ld, searchResult);
}
ldap_msgfree(searchResult);
/// Search the directory
rc = ldap_search_ext_s(ld, ludpp->lud_dn, ludpp->lud_scope, (const char*) filter, NULL, 0, NULL, NULL, &timeOut, 0,
&searchResult);
if (!ldn) {
ldap_unbind_s(ld);
return 0;
}
if (rc != LDAP_SUCCESS) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "LDAP: ldap_search_ext_s: %d, %s", rc, ldap_err2string(rc));
ldap_msgfree(searchResult);
ldap_unbind_s(ld);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
dn.data = (u_char*) ldn;
dn.len = ngx_strlen(ldn);
}
if (ldap_count_entries(ld, searchResult) > 0) {
dn = ldap_get_dn(ld, searchResult);
if (dn != NULL) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "LDAP: result DN %s", dn);
/// Check require user
if (server->require_user != NULL) {
value = server->require_user->elts;
for (i = 0; i < server->require_user->nelts; i++) {
ngx_str_t val;
if (ngx_http_complex_value(r, &value[i], &val) != NGX_OK) {
ldap_memfree(dn);
ldap_msgfree(searchResult);
ldap_unbind_s(ld);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "LDAP: compare with: %V", &val);
if (ngx_strncmp(val.data, dn, val.len) == 0) {
pass = 1;
if (server->satisfy_all == 0) {
break;
}
} else {
if (server->satisfy_all == 1) {
ldap_memfree(dn);
ldap_msgfree(searchResult);
ldap_unbind_s(ld);
return 0;
}
}
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "LDAP: result DN %V", &dn);
/// Check require user
if (server->require_user != NULL) {
value = server->require_user->elts;
for (i = 0; i < server->require_user->nelts; i++) {
ngx_str_t val;
if (ngx_http_complex_value(r, &value[i], &val) != NGX_OK) {
ldap_memfree(ldn);
ldap_unbind_s(ld);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
/// Check require group
if (server->require_group != NULL) {
if (server->group_attribute_dn == 1) {
bvalue.bv_val = dn;
bvalue.bv_len = ngx_strlen(dn);
} else {
bvalue.bv_val = (char*) r->headers_in.user.data;
bvalue.bv_len = r->headers_in.user.len;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "LDAP: compare with: %V", &val);
if (val.len == dn.len && ngx_memcmp(val.data, dn.data, val.len) == 0) {
pass = 1;
if (server->satisfy_all == 0) {
break;
}
} else {
if (server->satisfy_all == 1) {
ldap_memfree(ldn);
ldap_unbind_s(ld);
return 0;
}
}
}
}
value = server->require_group->elts;
/// Check require group
if (server->require_group != NULL) {
if (server->group_attribute_dn == 1) {
bvalue.bv_val = (char*) dn.data;
bvalue.bv_len = dn.len;
} else {
bvalue.bv_val = (char*) r->headers_in.user.data;
bvalue.bv_len = r->headers_in.user.len;
}
for (i = 0; i < server->require_group->nelts; i++) {
ngx_str_t val;
if (ngx_http_complex_value(r, &value[i], &val) != NGX_OK) {
ldap_memfree(dn);
ldap_msgfree(searchResult);
ldap_unbind_s(ld);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
value = server->require_group->elts;
for (i = 0; i < server->require_group->nelts; i++) {
ngx_str_t val;
if (ngx_http_complex_value(r, &value[i], &val) != NGX_OK) {
ldap_memfree(ldn);
ldap_unbind_s(ld);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "LDAP: group compare with: %V", &val);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "LDAP: group compare with: %V", &val);
rc = ldap_compare_ext_s(ld, (const char*) val.data, (const char*) server->group_attribute.data,
&bvalue, NULL, NULL);
rc = ldap_compare_ext_s(ld, (const char*) val.data, (const char*) server->group_attribute.data,
&bvalue, NULL, NULL);
/*if (rc != LDAP_COMPARE_TRUE && rc != LDAP_COMPARE_FALSE && rc != LDAP_NO_SUCH_ATTRIBUTE) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "LDAP: ldap_search_ext_s: %d, %s", rc,
ldap_err2string(rc));
ldap_memfree(ldn);
ldap_unbind_s(ld);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}*/
/*if (rc != LDAP_COMPARE_TRUE && rc != LDAP_COMPARE_FALSE && rc != LDAP_NO_SUCH_ATTRIBUTE ) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "LDAP: ldap_search_ext_s: %d, %s", rc,
ldap_err2string(rc));
ldap_memfree(dn);
ldap_msgfree(searchResult);
ldap_unbind_s(ld);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}*/
if (rc == LDAP_COMPARE_TRUE) {
pass = 1;
if (server->satisfy_all == 0) {
break;
}
} else {
if (server->satisfy_all == 1) {
pass = 0;
break;
}
}
if (rc == LDAP_COMPARE_TRUE) {
pass = 1;
if (server->satisfy_all == 0) {
break;
}
}
/// Check valid user
if ( pass != 0 || (server->require_valid_user == 1 && server->satisfy_all == 0 && pass == 0)) {
/// Bind user to the server
rc = ldap_simple_bind_s(ld, dn, (const char *) r->headers_in.passwd.data);
if (rc != LDAP_SUCCESS) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "LDAP: ldap_simple_bind_s error: %d, %s", rc,
ldap_err2string(rc));
} else {
if (server->satisfy_all == 1) {
pass = 0;
} else {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "LDAP: User bind successful", NULL);
if (server->require_valid_user == 1) pass = 1;
break;
}
}
}
}
/// Check valid user
if (pass != 0 || (server->require_valid_user == 1 && server->satisfy_all == 0 && pass == 0)) {
/// Bind user to the server
rc = ldap_simple_bind_s(ld, (const char *) dn.data, (const char *) r->headers_in.passwd.data);
if (rc != LDAP_SUCCESS) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "LDAP: ldap_simple_bind_s error: %d, %s", rc,
ldap_err2string(rc));
pass = 0;
} else {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "LDAP: User bind successful", NULL);
if (server->require_valid_user == 1) pass = 1;
}
ldap_memfree(dn);
}
ldap_msgfree(searchResult);
ldap_memfree(ldn);
ldap_unbind_s(ld);
return pass;

Loading…
Cancel
Save