Forum: NGINX Can nginx support FastCGI Authorizers?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
lhmwzy (Guest)
on 2008-12-27 14:41
(Received via mailing list)
I search the wiki of nginx,but can't find any thing about FastCGI
Authorizers.
can or How to use FastCGI Authorizers under nginx?
lhmwzy (Guest)
on 2008-12-27 14:47
(Received via mailing list)
see also : http://www.fastcgi.com/devkit/doc/fcgi-spec.html
......
 6.3 Authorizer

An Authorizer FastCGI application receives all the information
associated with an HTTP request and generates an
authorized/unauthorized decision. In case of an authorized decision
the Authorizer can also associate name-value pairs with the HTTP
request; when giving an unauthorized decision the Authorizer sends a
complete response to the HTTP client.

Since CGI/1.1 defines a perfectly good way to represent the
information associated with an HTTP request, Authorizers use the same
representation:

    * The Authorizer application receives HTTP request information
from the Web server on the FCGI_PARAMS stream, in the same format as a
Responder. The Web server does not send CONTENT_LENGTH, PATH_INFO,
PATH_TRANSLATED, and SCRIPT_NAME headers.

    * The Authorizer application sends stdout and stderr data in the
same manner as a Responder. The CGI/1.1 response status specifies the
disposition of the request. If the application sends status 200 (OK),
the Web server allows access. Depending upon its configuration the Web
server may proceed with other access checks, including requests to
other Authorizers.

      An Authorizer application's 200 response may include headers
whose names are prefixed with Variable-. These headers communicate
name-value pairs from the application to the Web server. For instance,
the response header

              Variable-AUTH_METHOD: database lookup

      transmits the value "database lookup" with name AUTH-METHOD. The
server associates such name-value pairs with the HTTP request and
includes them in subsequent CGI or FastCGI requests performed in
processing the HTTP request. When the application gives a 200
response, the server ignores response headers whose names aren't
prefixed with Variable- prefix, and ignores any response content.

      For Authorizer response status values other than "200" (OK), the
Web server denies access and sends the response status, headers, and
content back to the HTTP client.
......


2008/12/27 lhmwzy <removed_email_address@domain.invalid>:
Maxim D. (Guest)
on 2008-12-27 21:39
(Received via mailing list)
Hello!

On Sat, Dec 27, 2008 at 08:30:09PM +0800, lhmwzy wrote:

> I search the wiki of nginx,but can't find any thing about FastCGI Authorizers.
> can or How to use FastCGI Authorizers under nginx?

Only FastCGI responder role is supported.

Maxim D.
lhmwzy (Guest)
on 2008-12-28 03:15
(Received via mailing list)
hmm....
Has Igor  any plan to support FastCGI Authorizers?

2008/12/28 Maxim D. <removed_email_address@domain.invalid>:
André Cruz (Guest)
on 2008-12-29 12:04
(Received via mailing list)
+1 for FastCGI Authorizers. This way we can use nginx with a
Shibboleth SP.

André Cruz
lhmwzy (Guest)
on 2009-01-06 16:27
(Received via mailing list)
Has Igor any play for this?

2008/12/29 André Cruz <removed_email_address@domain.invalid>:
André Cruz (Guest)
on 2009-01-06 17:02
(Received via mailing list)
I don't think so. I've had no feedback on this.
Bryon Roche (Guest)
on 2009-01-09 03:16
(Received via mailing list)
On Tue, 06 Jan 2009 14:52:24 +0000, André Cruz wrote:

> I don't think so. I've had no feedback on this.
Couldn't you use a per or lua or wsgi hook in the mean time?  I believe
those can handle auth, correct? otherwise, there's always the source..
I'm pretty sure you could do it with a module, although you may need to
implement new hooks into request processing, as if you want to integrate
it with libevent (i.e. smartly), you will probably need to add the hooks
into a request to wait on authorizers.

/K
André Cruz (Guest)
on 2009-01-09 12:08
(Received via mailing list)
On Jan 9, 2009, at 1:05 , Bryon Roche wrote:

> On Tue, 06 Jan 2009 14:52:24 +0000, André Cruz wrote:
>
>> I don't think so. I've had no feedback on this.
> Couldn't you use a per or lua or wsgi hook in the mean time?  I
> believe
> those can handle auth, correct? otherwise,

Maybe, but the applications that I would like to use only support fcgi
authorizers.

> there's always the source..
> I'm pretty sure you could do it with a module, although you may need
> to
> implement new hooks into request processing, as if you want to
> integrate
> it with libevent (i.e. smartly), you will probably need to add the
> hooks
> into a request to wait on authorizers.

This is probably better done in the fastcgi module itself. After all,
it is a part of the fcgi specification that is not implemented.

Andr
Igor C. (Guest)
on 2009-01-12 12:29
André Cruz wrote:

> This is probably better done in the fastcgi module itself. After all,
> it is a part of the fcgi specification that is not implemented.

I've thought about this in the past and wondered whether the best way to
do it would be with a module along the lines of "auth_fastcgi". Is this
viable? Does anyone have any general views on how such a module would
need to be structured?

Cheers,
Igor C.
Igor S. (Guest)
on 2009-01-12 12:49
(Received via mailing list)
On Sun, Dec 28, 2008 at 09:03:55AM +0800, lhmwzy wrote:

> hmm....
> Has Igor  any plan to support FastCGI Authorizers?

Currently there is no plans to support this.
Initually FastCGI support was written to meet PHP FastCGI support.
And PHP may be FastCGI Responder only.

Do other FastCGI servers support FastCGI Authorizer role?
André Cruz (Guest)
on 2009-01-12 13:29
(Received via mailing list)
Apache and lighttpd both do authorizer mode. Don't know about others...
lhmwzy (Guest)
on 2009-01-12 13:31
(Received via mailing list)
lighttpd web server and zeus web server both support FastCGI
Authorizers.
FastCGI servers? what's your mean?

2009/1/12 Igor S. <removed_email_address@domain.invalid>:
Igor S. (Guest)
on 2009-01-12 13:44
(Received via mailing list)
On Mon, Jan 12, 2009 at 07:24:09PM +0800, lhmwzy wrote:

> lighttpd web server and zeus web server both support FastCGI Authorizers.
> FastCGI servers? what's your mean?

I mean FastCGI-backend - PHP, Django, etc.
nginx, lighty, Zeus, and Apache are just proxies that convert a HTTP
request
to FastCGI one and pass the request to a real FastCGI-server for
processing.
lhmwzy (Guest)
on 2009-01-12 13:47
(Received via mailing list)
You can look at the way how lighttpd implements FastCGI Authorizers.

2009/1/12 Igor C. <removed_email_address@domain.invalid>:
lhmwzy (Guest)
on 2009-01-12 14:00
(Received via mailing list)
I use FastCGI Authorizers to exam the valid of user and protect some
especial directory.
I use perl to implement it.
the script:

#!/usr/bin/perl

use strict;

use DBI;
use FCGI;

use constant PATH_NEVER  => 0;
use constant PATH_MAYBE  => 1;
use constant PATH_ALWAYS => 2;

# normally, I would abstract this stuff out into a sitewide config
module,
# but for didactic reasons, I'll just define some constants here:
use constant COOKIE_NAME => 'AUTH_TOKEN';
use constant DBI_DSN     =>
'dbi:mysql:hostname=DBHOSTNAME;database=DBNAME';
use constant DBI_USR     => 'monty';
use constant DBI_PWD     => 'widenius';

use constant AUTH_ERR => -1;
use constant AUTH_NOK =>  0;
use constant AUTH_OK  =>  1;

use constant AUTH_QUERY => <<AQ_SQL;
select count(*) as authorized
from   login_table
where  user  = ?
and    token = ?
and    expiry > unix_timestamp()
AQ_SQL
use vars qw($DBH $STH $N);

sub _init ();
sub _exit ();
sub authorized ($$$);
sub get_login_cookie ();
sub query_decode (;@);

_init();

for ($N = 0; FCGI::accept() >= 0; $N++)
{
    # check the path to see if we want/need to authorize access:
    my $path_auth = check_path($ENV{REQUEST_URI});

    if($path_auth == PATH_MAYBE)
    {
        my $auth = undef();
        my $user;
        my $token;
        my $cookie;

        # get the login cookie and decompose it into user + token:
        # cookie format: USERNAME:OPAQUETOKENFROMDB
        $cookie = get_login_cookie();
        ($user,$token) = split(/:/,$cookie,2);

        # check to see if an unexpired entry exists in the db:
        $auth = authorized($STH, $user, $token);

        if($auth == AUTH_OK)
        {
            # return 200 Ok, and set the AUTH_USER_NAME env variable
            # in case there is a dynamic content generator:
            # variables you want to set for the requested script/page
            # need to be prefixed w. the string 'Variable-',
            # or they will be passed back to the client, not the server.
            print(STDOUT "Status: 200 Authorized\r\n");
            print(STDOUT "Variable-AUTH_USER_NAME: $user\r\n");
            print(STDOUT "\r\n");
        }
        elsif($auth == AUTH_NOK)
        {
            # Not authorized.
            # You can make your login page the default
            # 401 page with the htaccess ErrorDocument 401 directive:
            print(STDOUT "Status: 401 Not Authorized\r\n");
            print(STDOUT "WWW-Authenticate: basic realm=\"foo\"\r\n");
            print(STDOUT "\r\n");
        }
        else
        {
            # Waah. Something blew up.
            print(STDOUT "Status: 500 Internal Auth Error\r\n");
            print(STDOUT "\r\n");
        }
    }
    elsif($path_auth == PATH_NEVER)
    {
        # we never allow anyone in to these:
        print(STDOUT "Status: 403 Denied\r\n");
        print(STDOUT "\r\n");
    }
    elsif($path_auth == PATH_ALWAYS)
    {
        # these we don't really care about, just let them in.
        # your error pages, icon, etc should all fall into this
        # category, as should your login page:
        print(STDOUT "Status: 200 Ok\r\n");
        print(STDOUT "\r\n");
    }
    else
    {
        # This should not be able to happen: If it does,
        # your site needs attention from you:
        print(STDOUT "Status: 500 Internal Auth Error\r\n");
        print(STDOUT "\r\n");
    }
}

_exit();

##############

# Access rules, first match wins:

# /auth/login.cgi is always allowed
# /share/* and /icons/* are always allowed
# /lib/*   and /auth/*  are always disallowed
# anything else must be explicitly authorized

sub check_path ($)
{
    my $uri = $_[0];

    #warn("check_path($_[0])\n");

    if ($uri =~ m@/auth/login.cgi@){ return PATH_ALWAYS }
    if ($uri =~ m@/share/|/icons/@){ return PATH_ALWAYS }
    if ($uri =~ m@/lib/|/auth/@)   { return PATH_NEVER  }

    return PATH_MAYBE;
}


sub authorized ($$$)
{
    my $rv;
    my $row;
    my $sth  = $_[0];

    my $user  = $_[1];
    my $token = $_[2];

    if(!$sth->execute($user,$token))
    {
        warn("DBI error: ", $sth->errstr(), "\n");
        return AUTH_ERR;
    }

    if($row = $sth->fetchrow_arrayref())
    {
        # only interested in one column in this case
        $rv = $row->[0] ? AUTH_OK : AUTH_NOK;
    }
    else
    {
        warn("DBI error: ", $sth->errstr(), "\n");
        $rv = AUTH_ERR;
    }

    # paranoia: empty out the sql result buffer, just in case
    # so that it's clean for the next invocation
    while ($sth->{Active}) { $sth->fetchrow_arrayref() }

    return $rv;
}

# open a database connection and prepare the query
sub _init ()
{
    $DBH = DBI->connect(DBI_DSN, DBI_USR, DBI_PWD)
      || die("DBI->connect() failed: $DBI::errstr\n");

    $STH = $DBH->prepare(AUTH_QUERY)
      || die("prepare(AUTH_QUERY) failed: ",$DBH->errstr(),"\n");
}

# clean up and close down
sub _exit ()
{
    $STH->finish();
    $DBH->disconnect();
}

# extract a login cookie from the headers:
# the assumption is made here that any... unusual characters
# in the cookie have been %XX encoded:
sub get_login_cookie ()
{
    my $cval  = undef();

    if(exists($ENV{HTTP_COOKIE}))
    {
        my @cookie = split(/; /,$ENV{HTTP_COOKIE});

      COOKIE:
        foreach my $ck (@cookie)
        {
            my($n, $v) = query_decode(split(/=/,$ck,2));

            if($n eq COOKIE_NAME) { $cval = $v; last COOKIE }
        }
    }

    return $cval;
}

# %XX decode a string or strings:
sub query_decode (;@)
{
    my @str = @_;
    my $item;

    foreach $item (@str)
    {
        $item =~ tr/+/ /;
        $item =~ s/\%([A-F\d]{2})/chr(hex($1))/gei;
    }

    return wantarray ? (@str) : $str[0];
}

END

/* mysql login table create statement */
create table login_table (token  char(32) not null,
                          user   char(32) not null,
                          expiry int(11)  not null)



2009/1/12 Igor S. <removed_email_address@domain.invalid>:
André Cruz (Guest)
on 2009-01-12 14:14
(Received via mailing list)
On Jan 12, 2009, at 11:34 , Igor S. wrote:

> processing.
If you mean applications that take advantage of fastcgi authorizers I
know that at least Shibboleth (Internet2's Single-Sign on solution)
uses it. In fact it's the only way to use nginx as a Service Provider
frontend.

Andr
Igor C. (Guest)
on 2009-01-12 14:28
lhmwzy wrote:
> You can look at the way how lighttpd implements FastCGI Authorizers.
>
> 2009/1/12 Igor C. <removed_email_address@domain.invalid>:

Thanks for the reply. I was thinking about how to do it in terms of
nginx module architecture?

Cheers
IC
lhmwzy (Guest)
on 2009-01-12 15:04
(Received via mailing list)
I don't know c and can't help you to program.
But I look forward to hearing your success.

2009/1/12 Igor C. <removed_email_address@domain.invalid>:
Igor C. (Guest)
on 2009-01-12 16:49
lhmwzy wrote:
> I don't know c and can't help you to program.
> But I look forward to hearing your success.

Thanks, it's something I'm interested in doing (time permitting,
obviously) but as my C is rusty and my experience with nginx's module
interface limited, I would like to validate an approach before embarking
on it.

cheers
IC
Igor S. (Guest)
on 2009-01-12 18:09
(Received via mailing list)
On Mon, Jan 12, 2009 at 01:28:47PM +0100, Igor C. wrote:

> lhmwzy wrote:
> > You can look at the way how lighttpd implements FastCGI Authorizers.
> >
> > 2009/1/12 Igor C. <removed_email_address@domain.invalid>:
>
> Thanks for the reply. I was thinking about how to do it in terms of
> nginx module architecture?

nginx has special access phase where ngx_http_access_module and
ngx_http_auth_basic_module work. However, implementing FastCGI auth is
not
too easy task.
Igor C. (Guest)
on 2009-01-13 02:06
Igor S. wrote:
> On Mon, Jan 12, 2009 at 01:28:47PM +0100, Igor C. wrote:
>
>> lhmwzy wrote:
>> > You can look at the way how lighttpd implements FastCGI Authorizers.
>> >
>> > 2009/1/12 Igor C. <removed_email_address@domain.invalid>:
>>
>> Thanks for the reply. I was thinking about how to do it in terms of
>> nginx module architecture?
>
> nginx has special access phase where ngx_http_access_module and
> ngx_http_auth_basic_module work. However, implementing FastCGI auth is
> not
> too easy task.

No, I'm sure it's not! :-)

Thanks Igor.

IC
André Cruz (Guest)
on 2009-05-07 15:07
(Received via mailing list)
On Jan 13, 2009, at 0:06 , Igor C. wrote:

>> ngx_http_auth_basic_module work. However, implementing FastCGI auth
>> is
>> not
>> too easy task.
>
> No, I'm sure it's not! :-)
>
> Thanks Igor.

Has there been any progress regarding FastCGI Authorizers support in
nginx?

Best regards,
André Cruz
André Cruz (Guest)
on 2009-05-07 15:25
(Received via mailing list)
On Jan 13, 2009, at 0:06 , Igor C. wrote:

>> ngx_http_auth_basic_module work. However, implementing FastCGI auth
>> is
>> not
>> too easy task.
>
> No, I'm sure it's not! :-)
>
> Thanks Igor.

Has there been any progress regarding FastCGI Authorizers support in
nginx?

Best regards,
André Cruz
This topic is locked and can not be replied to.