Commits

David Beitey  committed 3d865a7

Add initial FastCGI authorizer support.

  • Participants
  • Parent commits a29d748

Comments (0)

Files changed (2)

 Auth request module for nginx.
 
-This module allows authorization based on subrequest result.  Once subrequest
-returns 2xx status - access is allowed, on 401 or 403 - disabled with
-appropriate status.  Anything else is considered to be an error.
+This module allows authorization based on a subrequest result.  Once 
+a subrequest returns 2xx status - access is allowed; on 401 or 403 - 
+access is disabled with an appropriate status.  
 
-For 401 status WWW-Authenticate header from subrequest response will be
-passed to client.
+For 401 statuses, the WWW-Authenticate header from the subrequest response 
+will be passed to client.
 
-Module works at access phase and therefore may be combined nicely with other
+All other subrequest response statuses are considered to be an error, unless
+the `authorizer=on` flag is supplied, in which case the module will
+return the subrequest's response status and headers. This mostly follows
+the FastCGI Authorizer specification, with the exception of the processing
+of the request and response bodies.  Further information follows below.
+
+The module works at access phase and therefore may be combined nicely with other
 access modules (access, auth_basic) via satisfy directive.
 
 Configuration directives:
 
-    auth_request <uri>|off
+    auth_request <uri>|off [flags]
 
         Context: http, server, location
         Default: off
         Switches auth request module on and sets uri which will be asked for
         authorization.
 
+        Flags may be configured to modify the behaviour of the module as
+        follows:
+        
+         * authorizer=on - Configures the auth request module to explicitly
+           return the status, headers, and content of the response resulting
+           from the sub-request to the configured uri.
+ 
+           This option allows a uri to conform to the FastCGI Authorizer
+           specification; see http://www.fastcgi.com/drupal/node/22#S6.3.
+           The one (potentially significant) caveat is that due to the way
+           Nginx operates at present with regards to subrequests (what
+           an Authorizer effectively requires), the request body will *not* be
+           forwarded to the authorizer, and similarly, the response body from
+           the authorizer will *not* be returned to the client. 
+
+           Configured URIs are not restricted to using a FastCGI backend
+           to generate a response, however.  This may be useful during
+           testing or otherwise, as you can use Nginx's built in ``return``
+           and ``rewrite`` directives to produce a suitable response.
+
     auth_request_set <variable> <value>
 
         Context: http, server, location
 
     location /private/ {
         auth_request /auth;
+        auth_request_set $my_variable $upstream_http_subrequest_uri;
         ...
     }
 
         proxy_pass_request_body off;
         proxy_set_header Content-Length "";
         proxy_set_header X-Original-URI $request_uri;
+        add_header Subrequest-URI $request_uri;
     }
 
 Note: it is not currently possible to use proxy_cache/proxy_store (and 

File ngx_http_auth_request_module.c

 
 typedef struct {
     ngx_str_t                 uri;
+    ngx_uint_t                authorizer;
     ngx_array_t              *vars;
 } ngx_http_auth_request_conf_t;
 
 static ngx_command_t  ngx_http_auth_request_commands[] = {
 
     { ngx_string("auth_request"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_http_auth_request,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
 static ngx_int_t
 ngx_http_auth_request_handler(ngx_http_request_t *r)
 {
-    ngx_table_elt_t               *h, *ho;
+    ngx_uint_t                    i;
+    ngx_list_part_t               *part;
+    ngx_table_elt_t               *h, *ho, *hi;
     ngx_http_request_t            *sr;
     ngx_http_post_subrequest_t    *ps;
     ngx_http_auth_request_ctx_t   *ctx;
             return NGX_ERROR;
         }
 
+        /*
+         * if authorizer mode is configured, handle the subrequest
+         * as per the FastCGI authorizer specification.
+         */ 
+        if (arcf->authorizer) {
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "auth request authorizer handler");
+            sr = ctx->subrequest;
+
+            if (ctx->status == NGX_HTTP_OK) {
+                /* 
+                 * 200 response may include headers prefixed with `Variable-`
+                 * back into initial headers
+                 */
+                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "auth request authorizer allows access");
+
+                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 (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->value = h[i].value;
+
+                        ngx_log_debug2(
+                          NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                          "auth request authorizer copied header: \"%V: %V\"",
+                          &hi->key, &hi->value);
+                    }
+                }
+                
+                return NGX_OK;
+            }
+
+            /* 
+             * Unconditionally return subrequest response status, headers 
+             * and content.
+             */
+            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                           "auth request authorizer returning sub-response");
+
+            r->headers_out = sr->headers_out;
+            return ctx->status;
+        }
+
         /* return appropriate status */
 
         if (ctx->status == NGX_HTTP_FORBIDDEN) {
         return NGX_ERROR;
     }
 
+    /* 
+     * true FastCGI authorizers should conditionally return the subrequest 
+     * response body but the FastCGI handler does not support
+     * NGX_HTTP_SUBREQUEST_IN_MEMORY at present.
+     */
     sr->header_only = 1;
 
     ctx->subrequest = sr;
 {
     ngx_http_auth_request_conf_t *arcf = conf;
 
-    ngx_str_t        *value;
+    ngx_uint_t       i;
+    ngx_str_t        *value, s;
 
     if (arcf->uri.data != NULL) {
         return "is duplicate";
 
     arcf->uri = value[1];
 
+    for (i = 2; i < cf->args->nelts; i++) {
+
+        if (ngx_strncmp(value[i].data, "authorizer=", 11) == 0) {
+            s.len = value[i].len - 11;
+            s.data = value[i].data + 11;
+            if (ngx_strcmp(s.data, "on") == 0) {
+                arcf->authorizer = 1;
+            }
+        }
+    }
+
+
     return NGX_CONF_OK;
 }