Auth request module

Hello!

Here is auth request module, it allows authorization based on
subrequest result. It works at access phase and therefore may be
nicely combined with other access modules (access, auth_basic) via
satisfy directive.

Example usage:

location /private/ {
    auth_request /auth;
    ...
}

location = /auth {
    proxy_pass ...
    proxy_set_header X-Original-Uri $request_uri;
    ...
}

To allow access backend should return 200, to disable - 401/403.

Further info is here:

http://mdounin.ru/hg/ngx_http_auth_request_module/
http://mdounin.ru/files/ngx_http_auth_request-0.1.tar.gz

MD5 (ngx_http_auth_request-0.1.tar.gz) =
c0ed1610097017813e6468e7cca28af7
SHA256 (ngx_http_auth_request-0.1.tar.gz) =
ccaafc2afa4b4c98dc2b7555fc61774cfbd4f98edca87eb172ae3ec36a49f263

Maxim D.

On Sun, Feb 28, 2010 at 3:00 AM, Maxim D. [email protected]
wrote:

Here is auth request module, it allows authorization based on
subrequest result. It works at access phase and therefore may be
nicely combined with other access modules (access, auth_basic) via
satisfy directive.

This is really awesome!

But too sad the ngx_eval module can’t work in subrequests itself so I
can not combine this with ngx_eval + ngx_drizzle + ngx_rds_json to do
mysql-based auth :slight_smile:

It’s mostly an issue in the ngx_eval, not your excellent
ngx_auth_request :wink: Our ngx_srcache module will also take advantage of
subrequests to do response caching.

For now, I’m using something like this for mysql-based login and it
works on my machine [1]:

location = /auth {
default_type ‘application/json’;
eval_subrequest_in_memory off;
eval $res {
set_quote_sql_str $user $arg_user;
set_quote_sql_str $pass $arg_pass;
set $sql ‘select count(*) res from users where name=$user
and passwd=$pass’;
drizzle_query $sql;
drizzle_pass backend;
rds_json on;
rds_json_content_type application/octet-stream;
}
if ($res ~ ‘“res”:1’) {
echo “Cool! you’re already logged in!”;
}
if ($res !~ ‘“res”:1’) {
return 403;
}
}

where the “backend” upstream name used in the drizzle_pass directive
is defined like this:

upstream backend {
    drizzle_server 127.0.0.1:3306 dbname=test
         password=some_pass user=monty protocol=mysql;
    drizzle_keepalive max=400 overflow=reject;
}

Then we can login the system by GET /auth?user=john&pass=some_pass.
Well, it’s just a naive demonstration. Hopefully I’m not too OT :stuck_out_tongue:

Cheers,
-agentzh

[1] Here we’re using my fork of ngx_eval module (
GitHub - openresty/nginx-eval-module: A module for evaluating memcached or proxy response into variable ) for two important
features: 1) capture outputs from arbitrary locations with output
filter support, 2) pass the parent request’s query string (or “args”)
into the eval block.

----- “agentzh” [email protected] wrote:

But too sad the ngx_eval module can’t work in subrequests itself so I
can not combine this with ngx_eval + ngx_drizzle + ngx_rds_json to do
mysql-based auth :slight_smile:

It’s mostly an issue in the ngx_eval, not your excellent
ngx_auth_request :wink:

What kind of issue is it?


Regards,
Valery K.

Spassiba Maxim !

Can we consume request body both in :

  • /auth url
  • and the latter private url

Best Marc

Posted at Nginx Forum:

On Mon, Mar 1, 2010 at 4:45 PM, Valery K. >> It’s mostly an
issue in the ngx_eval, not your excellent

ngx_auth_request :wink:

What kind of issue is it?

ngx_eval cannot be used in subrequests. Consider the following example:

location /foo {
    add_before_body /bah;
    #echo_location_async /bah;
    echo done;
}
location /bah {
    eval $foo {
        proxy_pass $scheme://127.0.0.1:$server_port/baz;
    }
    echo [$foo];
}
location /baz {
    echo baz;
}

Accessing /bah gives the correct output (using the git HEAD of your
repos):

[baz]

But accessing /foo results in a segfault. Here’s the gdb output:

Program received signal SIGSEGV, Segmentation fault.
memcpy () at …/sysdeps/i386/i686/memcpy.S:100
100 …/sysdeps/i386/i686/memcpy.S: No such file or directory.
in …/sysdeps/i386/i686/memcpy.S
Current language: auto
The current source language is “auto; currently asm”.
(gdb) bt
#0 memcpy () at …/sysdeps/i386/i686/memcpy.S:100
#1 0x0804fb6e in ngx_vslprintf (buf=0x3ffffafa <Address 0x3ffffafa
out of bounds>,
last=0xbffff3ac “\005”, fmt=0x80aaa1c “V?%V”", args=0xbffff3e4 “”)
at /usr/include/bits/string3.h:52
#2 0x0804be81 in ngx_log_error_core (level=805306387, log=0x80c6258,
err=527676,
fmt=0x64000000 <Address 0x64000000 out of bounds>) at
src/core/ngx_log.c:119
#3 0x88000075 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

By using ngx_echo module’s echo_location_async to issue the subrequest
gives identical segfault :slight_smile:

I haven’t tracked deep into the source but at least the lines starting
from ngx_http_eval_module.c:141 don’t like subrequests’ contexts.

Sorry for the delay. I was in Hangzhou for other business in the last
few weeks :stuck_out_tongue:

Cheers,
-agentzh

Hello!

On Thu, Mar 11, 2010 at 12:04:14PM -0500, amvtek wrote:

Spassiba Maxim !

Can we consume request body both in :

  • /auth url
  • and the latter private url

Short answer: no

Long answer:

Currently request body isn’t read by auth request. In fact it
specially prevents this from happening, as an attempt to read
request body from subrequest will cause SIGSEGV - nginx doesn’t
expect this to happen.

Moreover, as of now request body may be used only once if it
doesn’t fit into memory, as first successful upstream request will
close temporary file used to buffer it. This may even cause
problems in nginx with official modules (e.g. ssi returned by
backend and ssi subrequests).

I’m not sure how to fix this properly. For now I tend to think
that only main request should be allowed to work with request body
and subrequest should always ignore it.

Maxim D.

Thanks Maxim,
I think I get it now, request ‘body’ can be consumed at most one time,
this is a design decision which aims at protecting system ressources.

Best,
Marc

Posted at Nginx Forum: