Reverse proxy for a resource that requires authentication based on Cookie? How?

749 views
Skip to first unread message

Grigory Ptashko

unread,
Jun 24, 2018, 4:40:11 PM6/24/18
to openresty-en
Hello.

I want to use openresty as a reverse proxy for an https resource
that requires form authentication. I want openresty to behave like this:

  1. A user sends a request to openresty.
  2. Openresty sends this request to my https resource.
  3. If the resource answers with 200 then Openresty gives the response back to the user.
  4. If the resource answers with 401 then Openresty must submit a POST-request with a login and a password (they will be specified in the nginx.conf).
  5. After successful authentication the https resource sends back the Set-Cookie header from which all subsequent requests to the resource must have in the Cookie header.

In other words openresty must authenticate if needed and use
the Cookie on further requests to the resource. But it must not
authenticate on every user request. Just in case the resource
answers with 401.

Can anyone tell me the steps to make it work? I mean I will
write a script in Lua but I don't understand the generic pattern
in terms of nginx-lua phases (access, content, etc).


Thank you!

Christian Battaglia

unread,
Jun 25, 2018, 12:26:17 PM6/25/18
to openresty-en

Grigory Ptashko

unread,
Jun 25, 2018, 12:51:16 PM6/25/18
to openresty-en
This is a great library! But it doesn't do what I need.

In my scenario there is no access phase.
There is only the content phase during which the proxied resource
might answer with 401. And in this case I have to authenticate, save the Cookie
and use it in all subsequent requests to the proxied resource.

I think I'm getting closer to understanding how to implement this.
One thing that I cannot understand is how to implement a critical section in Lua
for authenticating and saving the Cookie.
The authentication request must be only one and after it is successful all other
request might proceed to the proxied resource with the Cookie saved from the
authentication request.

jona...@findmeon.com

unread,
Jun 26, 2018, 1:08:35 AM6/26/18
to openresty-en
this http client was released for openresty a few weeks ago  https://groups.google.com/forum/#!topic/openresty-en/0EYZv6qxqDI

it can handle what you want.  the older http client would too, but this one would probably make it easier.

Grigory Ptashko

unread,
Jun 26, 2018, 4:47:11 AM6/26/18
to openresty-en
I'm definitely going to try this library. I'm already close to implementing the script.

Piotr Przybylski

unread,
Jun 26, 2018, 3:50:01 PM6/26/18
to openresty-en
Or, if you want to use nginx proxy, you can abuse proxy_intercept_errors and error_page directives, using something like this (not tested, but should get my point across):

lua_shared_dict data 1m;

server {
  set $auth_cookie "";

  location / {
    access_by_lua_block {
      ngx.var.cookie = ngx.shared.data:get("auth_cookie")
    }

    proxy_intercept_errors on;
    error_page 401 @handle_401;

    proxy_set_header Cookie $auth_cookie;
    proxy_pass http://...
  }

  location @handle_401 {
    rewrite_by_lua_block {
      -- use some HTTP library to acquire cookie, save it in ngx.shared.data
      return ngx.exec(ngx.var.uri)
    }
  }
}


That way a typical request will be handled by nginx proxy + a bit of Lua to set that $auth_cookie variable. Of course a solution without redirects, built only with a Lua HTTP library, will be much easier to reason about, and if it meets your requirements I recommend going with simpler option.

Grigory Ptashko

unread,
Jun 27, 2018, 3:33:22 AM6/27/18
to openresty-en
Do I get it right that in

@handle_401

after the successful authentication and calling the

return ngx.exec(ngx.var.uri)

nginx will re-execute the "location /" block?

Piotr Przybylski

unread,
Jun 27, 2018, 12:23:45 PM6/27/18
to openresty-en
It should, and if not you can always create another internal block with proxy. Just remember to check what happens when you get into "401 -> request -> 401 ->..." loop. I haven't tested returning to /, but I'm using internal redirects for some custom logic in my proxy (replying only for cached requests, heavily customized error responses that depend on request conditions etc.).

Grigory Ptashko

unread,
Jun 29, 2018, 2:58:08 AM6/29/18
to openresty-en
Piotr, thank you for the hint! I did it your way. But the ngx.exec did not work actually! Instead I used the proxy_pass in the 401 handler.
The behaviour is exactly what I need now. Here's my config:

http {
  lua_package_path '/var/app/?.lua;;';

  server {
    set $auth_cookie "";

    location @handle_401 {
      rewrite_by_lua_block {
        local auth = require("auth")
        local is_auth = auth.auth()

        if not is_auth then
          return ngx.exit(ngx.HTTP_UNAUTHORIZED)
        else
          ngx.var.auth_cookie = auth.auth_cookie
        end
      }

      proxy_set_header Cookie $auth_cookie;
      more_clear_headers "Set-Cookie";

      proxy_pass <THE RESOURCE>
    }

    location / {
      access_by_lua_block {
        local auth = require("auth")
        local is_auth = auth.auth()
      }

      proxy_intercept_errors on;
      error_page 401 = @handle_401;

      proxy_set_header Cookie $auth_cookie;
      more_clear_headers "Set-Cookie";

      proxy_pass <THE RESOURCE>
    }
  }
}
Reply all
Reply to author
Forward
0 new messages