static ngx_int_t ngx_http_auth_request_handler(ngx_http_request_t *r) { ngx_table_elt_t *h, *ho; ngx_http_request_t *sr; ngx_http_post_subrequest_t *ps; ngx_http_auth_request_ctx_t *ctx; ngx_http_auth_request_conf_t *arcf; arcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_request_module); if (arcf->uri.len == 0) { return NGX_DECLINED; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "auth request handler"); ctx = ngx_http_get_module_ctx(r, ngx_http_auth_request_module); if (ctx != NULL) { if (!ctx->done) { return NGX_AGAIN; } /* * as soon as we are done - explicitly set variables to make * sure they will be available after internal redirects */ if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) { return NGX_ERROR; } /* return appropriate status */ if (ctx->status == NGX_HTTP_FORBIDDEN) { return ctx->status; } if (ctx->status == NGX_HTTP_UNAUTHORIZED) { sr = ctx->subrequest; h = sr->headers_out.www_authenticate; if (!h && sr->upstream) { h = sr->upstream->headers_in.www_authenticate; } if (h) { ho = ngx_list_push(&r->headers_out.headers); if (ho == NULL) { return NGX_ERROR; } *ho = *h; r->headers_out.www_authenticate = ho; } return ctx->status; } if (ctx->status >= NGX_HTTP_OK && ctx->status < NGX_HTTP_SPECIAL_RESPONSE) { return NGX_OK; } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "auth request unexpected status: %d", ctx->status); return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_request_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (ps == NULL) { return NGX_ERROR; } ps->handler = ngx_http_auth_request_done; ps->data = ctx; if (ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps, NGX_HTTP_SUBREQUEST_WAITED) != NGX_OK) { return NGX_ERROR; } /* * allocate fake request body to avoid attempts to read it and to make * sure real body file (if already read) won't be closed by upstream */ sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (sr->request_body == NULL) { return NGX_ERROR; } sr->header_only = 1; ctx->subrequest = sr; ngx_http_set_ctx(r, ctx, ngx_http_auth_request_module); return NGX_AGAIN; }
static ngx_int_t ngx_http_auth_request_handler(ngx_http_request_t *r) { ngx_uint_t i; ngx_int_t rc; ngx_list_part_t *part; ngx_table_elt_t *h, *hi; ngx_http_request_t *sr; ngx_http_post_subrequest_t *ps; ngx_http_auth_request_ctx_t *ctx; ngx_http_auth_request_conf_t *arcf; arcf = ngx_http_get_module_loc_conf(r, ngx_http_shibboleth_module); if (arcf->uri.len == 0) { return NGX_DECLINED; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request handler"); ctx = ngx_http_get_module_ctx(r, ngx_http_shibboleth_module); if (ctx != NULL) { if (!ctx->done) { return NGX_AGAIN; } /* * as soon as we are done - explicitly set variables to make * sure they will be available after internal redirects */ if (ngx_http_auth_request_set_variables(r, arcf, ctx) != NGX_OK) { return NGX_ERROR; } /* * Handle the subrequest * as per the FastCGI authorizer specification. */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer handler"); sr = ctx->subrequest; if (ctx->status == NGX_HTTP_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer allows access"); if (arcf->use_headers) { /* * 200 response may include headers prefixed with `Variable-`, * copy these into main request headers */ part = &sr->headers_out.headers.part; h = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; h = part->elts; i = 0; } if (h[i].hash == 0) { continue; } if (h[i].key.len >= 9 && ngx_strncasecmp(h[i].key.data, (u_char *) "Variable-", 9) == 0) { /* copy header into original request */ hi = ngx_list_push(&r->headers_in.headers); if (hi == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* Strip the Variable- prefix */ hi->key.len = h[i].key.len - 9; hi->key.data = h[i].key.data + 9; hi->hash = ngx_hash_key(hi->key.data, hi->key.len); hi->value = h[i].value; hi->lowcase_key = ngx_pnalloc(r->pool, hi->key.len); if (hi->lowcase_key == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_strlow(hi->lowcase_key, hi->key.data, hi->key.len); ngx_log_debug2( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer copied header: \"%V: %V\"", &hi->key, &hi->value); } } } else { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer not using headers"); } return NGX_OK; } /* * Unconditionally return subrequest response status, headers * and content as per FastCGI spec (section 6.3). * * The subrequest response body cannot be returned as Nginx does not * currently support NGX_HTTP_SUBREQUEST_IN_MEMORY. */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer returning sub-response"); /* copy status */ r->headers_out.status = sr->headers_out.status; /* copy headers */ part = &sr->headers_out.headers.part; h = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; h = part->elts; i = 0; } rc = ngx_http_set_output_header(r, h[i].key, h[i].value); if (rc == NGX_ERROR) { return NGX_ERROR; } ngx_log_debug2( NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "shib request authorizer returning header: \"%V: %V\"", &h[i].key, &h[i].value); } return ctx->status; } ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_auth_request_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ps = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (ps == NULL) { return NGX_ERROR; } ps->handler = ngx_http_auth_request_done; ps->data = ctx; if (ngx_http_subrequest(r, &arcf->uri, NULL, &sr, ps, NGX_HTTP_SUBREQUEST_WAITED) != NGX_OK) { return NGX_ERROR; } /* * allocate fake request body to avoid attempts to read it and to make * sure real body file (if already read) won't be closed by upstream */ sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (sr->request_body == NULL) { return NGX_ERROR; } /* * true FastCGI authorizers should always return the subrequest * response body but the Nginx FastCGI handler does not support * NGX_HTTP_SUBREQUEST_IN_MEMORY at present. */ sr->header_only = 1; ctx->subrequest = sr; ngx_http_set_ctx(r, ctx, ngx_http_shibboleth_module); return NGX_AGAIN; }