Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.11 ]​[ nginx-1.14.2 ]​

0001 
0002 /*
0003  * Copyright (C) Maxim Dounin
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 typedef struct {
0014     ngx_str_t                 uri;
0015     ngx_array_t              *vars;
0016 } ngx_http_auth_request_conf_t;
0017 
0018 
0019 typedef struct {
0020     ngx_uint_t                done;
0021     ngx_uint_t                status;
0022     ngx_http_request_t       *subrequest;
0023 } ngx_http_auth_request_ctx_t;
0024 
0025 
0026 typedef struct {
0027     ngx_int_t                 index;
0028     ngx_http_complex_value_t  value;
0029     ngx_http_set_variable_pt  set_handler;
0030 } ngx_http_auth_request_variable_t;
0031 
0032 
0033 static ngx_int_t ngx_http_auth_request_handler(ngx_http_request_t *r);
0034 static ngx_int_t ngx_http_auth_request_done(ngx_http_request_t *r,
0035     void *data, ngx_int_t rc);
0036 static ngx_int_t ngx_http_auth_request_set_variables(ngx_http_request_t *r,
0037     ngx_http_auth_request_conf_t *arcf, ngx_http_auth_request_ctx_t *ctx);
0038 static ngx_int_t ngx_http_auth_request_variable(ngx_http_request_t *r,
0039     ngx_http_variable_value_t *v, uintptr_t data);
0040 static void *ngx_http_auth_request_create_conf(ngx_conf_t *cf);
0041 static char *ngx_http_auth_request_merge_conf(ngx_conf_t *cf,
0042     void *parent, void *child);
0043 static ngx_int_t ngx_http_auth_request_init(ngx_conf_t *cf);
0044 static char *ngx_http_auth_request(ngx_conf_t *cf, ngx_command_t *cmd,
0045     void *conf);
0046 static char *ngx_http_auth_request_set(ngx_conf_t *cf, ngx_command_t *cmd,
0047     void *conf);
0048 
0049 
0050 static ngx_command_t  ngx_http_auth_request_commands[] = {
0051 
0052     { ngx_string("auth_request"),
0053       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0054       ngx_http_auth_request,
0055       NGX_HTTP_LOC_CONF_OFFSET,
0056       0,
0057       NULL },
0058 
0059     { ngx_string("auth_request_set"),
0060       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
0061       ngx_http_auth_request_set,
0062       NGX_HTTP_LOC_CONF_OFFSET,
0063       0,
0064       NULL },
0065 
0066       ngx_null_command
0067 };
0068 
0069 
0070 static ngx_http_module_t  ngx_http_auth_request_module_ctx = {
0071     NULL,                                  /* preconfiguration */
0072     ngx_http_auth_request_init,            /* postconfiguration */
0073 
0074     NULL,                                  /* create main configuration */
0075     NULL,                                  /* init main configuration */
0076 
0077     NULL,                                  /* create server configuration */
0078     NULL,                                  /* merge server configuration */
0079 
0080     ngx_http_auth_request_create_conf,     /* create location configuration */
0081     ngx_http_auth_request_merge_conf       /* merge location configuration */
0082 };
0083 
0084 
0085 ngx_module_t  ngx_http_auth_request_module = {
0086     NGX_MODULE_V1,
0087     &ngx_http_auth_request_module_ctx,     /* module context */
0088     ngx_http_auth_request_commands,        /* module directives */
0089     NGX_HTTP_MODULE,                       /* module type */
0090     NULL,                                  /* init master */
0091     NULL,                                  /* init module */
0092     NULL,                                  /* init process */
0093     NULL,                                  /* init thread */
0094     NULL,                                  /* exit thread */
0095     NULL,                                  /* exit process */
0096     NULL,                                  /* exit master */
0097     NGX_MODULE_V1_PADDING
0098 };
0099 
0100 
0101 static ngx_int_t
0102 ngx_http_auth_request_handler(ngx_http_request_t *r)
0103 {
0104     ngx_table_elt_t               *h, *ho;
0105     ngx_http_request_t            *sr;
0106     ngx_http_post_subrequest_t    *ps;
0107     ngx_http_auth_request_ctx_t   *ctx;
0108     ngx_http_auth_request_conf_t  *arcf;
0109 
0110     arcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_request_module);
0111 
0112     if (arcf->uri.len == 0) {
0113         return NGX_DECLINED;
0114     }
0115 
0116     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0117                    "auth request handler");
0118 
0119     ctx = ngx_http_get_module_ctx(r, ngx_http_auth_request_module);
0120 
0121     if (ctx != NULL) {
0122         if (!ctx->done) {
0123             return NGX_AGAIN;
0124         }
0125 
0126         /*
0127          * as soon as we are done - explicitly set variables to make
0128          * sure they will be available after internal redirects
0129          */
0130 
0131         if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) {
0132             return NGX_ERROR;
0133         }
0134 
0135         /* return appropriate status */
0136 
0137         if (ctx->status == NGX_HTTP_FORBIDDEN) {
0138             return ctx->status;
0139         }
0140 
0141         if (ctx->status == NGX_HTTP_UNAUTHORIZED) {
0142             sr = ctx->subrequest;
0143 
0144             h = sr->headers_out.www_authenticate;
0145 
0146             if (!h && sr->upstream) {
0147                 h = sr->upstream->headers_in.www_authenticate;
0148             }
0149 
0150             if (h) {
0151                 ho = ngx_list_push(&r->headers_out.headers);
0152                 if (ho == NULL) {
0153                     return NGX_ERROR;
0154                 }
0155 
0156                 *ho = *h;
0157 
0158                 r->headers_out.www_authenticate = ho;
0159             }
0160 
0161             return ctx->status;
0162         }
0163 
0164         if (ctx->status >= NGX_HTTP_OK
0165             && ctx->status < NGX_HTTP_SPECIAL_RESPONSE)
0166         {
0167             return NGX_OK;
0168         }
0169 
0170         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0171                       "auth request unexpected status: %ui", ctx->status);
0172 
0173         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0174     }
0175 
0176     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_request_ctx_t));
0177     if (ctx == NULL) {
0178         return NGX_ERROR;
0179     }
0180 
0181     ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
0182     if (ps == NULL) {
0183         return NGX_ERROR;
0184     }
0185 
0186     ps->handler = ngx_http_auth_request_done;
0187     ps->data = ctx;
0188 
0189     if (ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps,
0190                             NGX_HTTP_SUBREQUEST_WAITED)
0191         != NGX_OK)
0192     {
0193         return NGX_ERROR;
0194     }
0195 
0196     /*
0197      * allocate fake request body to avoid attempts to read it and to make
0198      * sure real body file (if already read) won't be closed by upstream
0199      */
0200 
0201     sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
0202     if (sr->request_body == NULL) {
0203         return NGX_ERROR;
0204     }
0205 
0206     sr->header_only = 1;
0207 
0208     ctx->subrequest = sr;
0209 
0210     ngx_http_set_ctx(r, ctx, ngx_http_auth_request_module);
0211 
0212     return NGX_AGAIN;
0213 }
0214 
0215 
0216 static ngx_int_t
0217 ngx_http_auth_request_done(ngx_http_request_t *r, void *data, ngx_int_t rc)
0218 {
0219     ngx_http_auth_request_ctx_t   *ctx = data;
0220 
0221     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0222                    "auth request done s:%ui", r->headers_out.status);
0223 
0224     ctx->done = 1;
0225     ctx->status = r->headers_out.status;
0226 
0227     return rc;
0228 }
0229 
0230 
0231 static ngx_int_t
0232 ngx_http_auth_request_set_variables(ngx_http_request_t *r,
0233     ngx_http_auth_request_conf_t *arcf, ngx_http_auth_request_ctx_t *ctx)
0234 {
0235     ngx_str_t                          val;
0236     ngx_http_variable_t               *v;
0237     ngx_http_variable_value_t         *vv;
0238     ngx_http_auth_request_variable_t  *av, *last;
0239     ngx_http_core_main_conf_t         *cmcf;
0240 
0241     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0242                    "auth request set variables");
0243 
0244     if (arcf->vars == NULL) {
0245         return NGX_OK;
0246     }
0247 
0248     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
0249     v = cmcf->variables.elts;
0250 
0251     av = arcf->vars->elts;
0252     last = av + arcf->vars->nelts;
0253 
0254     while (av < last) {
0255         /*
0256          * explicitly set new value to make sure it will be available after
0257          * internal redirects
0258          */
0259 
0260         vv = &r->variables[av->index];
0261 
0262         if (ngx_http_complex_value(ctx->subrequest, &av->value, &val)
0263             != NGX_OK)
0264         {
0265             return NGX_ERROR;
0266         }
0267 
0268         vv->valid = 1;
0269         vv->not_found = 0;
0270         vv->data = val.data;
0271         vv->len = val.len;
0272 
0273         if (av->set_handler) {
0274             /*
0275              * set_handler only available in cmcf->variables_keys, so we store
0276              * it explicitly
0277              */
0278 
0279             av->set_handler(r, vv, v[av->index].data);
0280         }
0281 
0282         av++;
0283     }
0284 
0285     return NGX_OK;
0286 }
0287 
0288 
0289 static ngx_int_t
0290 ngx_http_auth_request_variable(ngx_http_request_t *r,
0291     ngx_http_variable_value_t *v, uintptr_t data)
0292 {
0293     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0294                    "auth request variable");
0295 
0296     v->not_found = 1;
0297 
0298     return NGX_OK;
0299 }
0300 
0301 
0302 static void *
0303 ngx_http_auth_request_create_conf(ngx_conf_t *cf)
0304 {
0305     ngx_http_auth_request_conf_t  *conf;
0306 
0307     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_request_conf_t));
0308     if (conf == NULL) {
0309         return NULL;
0310     }
0311 
0312     /*
0313      * set by ngx_pcalloc():
0314      *
0315      *     conf->uri = { 0, NULL };
0316      */
0317 
0318     conf->vars = NGX_CONF_UNSET_PTR;
0319 
0320     return conf;
0321 }
0322 
0323 
0324 static char *
0325 ngx_http_auth_request_merge_conf(ngx_conf_t *cf, void *parent, void *child)
0326 {
0327     ngx_http_auth_request_conf_t *prev = parent;
0328     ngx_http_auth_request_conf_t *conf = child;
0329 
0330     ngx_conf_merge_str_value(conf->uri, prev->uri, "");
0331     ngx_conf_merge_ptr_value(conf->vars, prev->vars, NULL);
0332 
0333     return NGX_CONF_OK;
0334 }
0335 
0336 
0337 static ngx_int_t
0338 ngx_http_auth_request_init(ngx_conf_t *cf)
0339 {
0340     ngx_http_handler_pt        *h;
0341     ngx_http_core_main_conf_t  *cmcf;
0342 
0343     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
0344 
0345     h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
0346     if (h == NULL) {
0347         return NGX_ERROR;
0348     }
0349 
0350     *h = ngx_http_auth_request_handler;
0351 
0352     return NGX_OK;
0353 }
0354 
0355 
0356 static char *
0357 ngx_http_auth_request(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0358 {
0359     ngx_http_auth_request_conf_t *arcf = conf;
0360 
0361     ngx_str_t        *value;
0362 
0363     if (arcf->uri.data != NULL) {
0364         return "is duplicate";
0365     }
0366 
0367     value = cf->args->elts;
0368 
0369     if (ngx_strcmp(value[1].data, "off") == 0) {
0370         arcf->uri.len = 0;
0371         arcf->uri.data = (u_char *) "";
0372 
0373         return NGX_CONF_OK;
0374     }
0375 
0376     arcf->uri = value[1];
0377 
0378     return NGX_CONF_OK;
0379 }
0380 
0381 
0382 static char *
0383 ngx_http_auth_request_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0384 {
0385     ngx_http_auth_request_conf_t *arcf = conf;
0386 
0387     ngx_str_t                         *value;
0388     ngx_http_variable_t               *v;
0389     ngx_http_auth_request_variable_t  *av;
0390     ngx_http_compile_complex_value_t   ccv;
0391 
0392     value = cf->args->elts;
0393 
0394     if (value[1].data[0] != '$') {
0395         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0396                            "invalid variable name \"%V\"", &value[1]);
0397         return NGX_CONF_ERROR;
0398     }
0399 
0400     value[1].len--;
0401     value[1].data++;
0402 
0403     if (arcf->vars == NGX_CONF_UNSET_PTR) {
0404         arcf->vars = ngx_array_create(cf->pool, 1,
0405                                       sizeof(ngx_http_auth_request_variable_t));
0406         if (arcf->vars == NULL) {
0407             return NGX_CONF_ERROR;
0408         }
0409     }
0410 
0411     av = ngx_array_push(arcf->vars);
0412     if (av == NULL) {
0413         return NGX_CONF_ERROR;
0414     }
0415 
0416     v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE);
0417     if (v == NULL) {
0418         return NGX_CONF_ERROR;
0419     }
0420 
0421     av->index = ngx_http_get_variable_index(cf, &value[1]);
0422     if (av->index == NGX_ERROR) {
0423         return NGX_CONF_ERROR;
0424     }
0425 
0426     if (v->get_handler == NULL) {
0427         v->get_handler = ngx_http_auth_request_variable;
0428         v->data = (uintptr_t) av;
0429     }
0430 
0431     av->set_handler = v->set_handler;
0432 
0433     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
0434 
0435     ccv.cf = cf;
0436     ccv.value = &value[2];
0437     ccv.complex_value = &av->value;
0438 
0439     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
0440         return NGX_CONF_ERROR;
0441     }
0442 
0443     return NGX_CONF_OK;
0444 }