Hello,

I try to use vouch-proxy and varnish (v7) together to build a authorisation
proxy. vouch-proxy is written to work with nginx ngx_http_auth_request_module

https://github.com/vouch/vouch-proxy
https://nginx.org/en/docs/http/ngx_http_auth_request_module.html

Idea:

inspired from 
https://web.archive.org/web/20121124064818/https://adayinthelifeof.nl/2012/07/06/using-varnish-to-offload-and-cache-your-oauth-requests/

- use varnish request restart feature
- intercept original client request and make a GET request to vouch-proxy
validate endpoint
- when validated restore the original request and do a restart 

in detail:

# vcl_recv
#   restarts == 0
#       save req method, url, Content-Length, Content-Type in var
#       method := GET
#       url := /validate
#       backend := vouch-proxy
#       remove Content-Length, Content-Type
#   restarts > 0
#       check vouch-proxy headers (roles, groups)
#
# vcl_deliver
#   resp == vouch-proxy,GET,/validate,200
#       restore req method, url, Content-Length, Content-Type from var
#       forward vouch-proxy response headers to req
#       restart (original) req

see attached common-vouch-proxy.vcl

It works for client requests without request body (GET, HEAD, …) but not for
POST, PUT, …. POST, PUT run in timeouts, so I think the request body is lost in
the restarted request. Why is the body gone after restart?

I think it should work with the curl vmod but this is not integrated yet.

Thank you very much in advance
tom

-- 
Tom Anheyer
Senior Developer

BerlinOnline Stadtportal GmbH & Co. KG
Stefan-Heym-Platz 1
10365 Berlin
Germany

Tel.: +49 30 2327-5210
Fax: +49 30 5771180-95
E-Mail: [email protected]

berlin.de | berlinonline.net

Amtsgericht Berlin-Charlottenburg, HRA 31951
Sitz der Gesellschaft: Berlin,
Deutschland
USt-IdNr.: DE219483549

Persönlich haftender Gesellschafter:
BerlinOnline Stadtportalbeteiligungsges. mbH
Amtsgericht Berlin-Charlottenburg, HRB 79077
Sitz der Gesellschaft: Berlin, Deutschland

Geschäftsführung: Olf Dziadek, Andreas Mängel
Amtierender Vorsitzender des Aufsichtsrates: Lothar Sattler
#
# authorisisation proxy using vouch-proxy
#
# Idea:
#
# vcl_recv
#   restarts == 0
#       save client req method, url, Content-Length, Content-Type in var
#       method := GET
#       url := /validate
#       backend := vouch-proxy
#       remove Content-Length, Content-Type
#   restarts > 0
#       check vouch-proxy headers (roles, groups)
#
# vcl_deliver
#   resp == vouch-proxy,GET,/validate,200
#       restore req method, url, Content-Length, Content-Type from var
#       forward vouch-proxy response headers to req
#       restart (client) req
#
# Links:
#   - 
https://web.archive.org/web/20121124064818/https://adayinthelifeof.nl/2012/07/06/using-varnish-to-offload-and-cache-your-oauth-requests/
#   - https://github.com/vouch/vouch-proxy
#   - https://nginx.org/en/docs/http/ngx_http_auth_request_module.html
#
# Usage:
#   in vcl_recv
#
#       var.set_backend("vouch_proxy", …);
#
#       call vouch_proxy_auth;
#       if (req.http.X-Vouch-Claims-Roles !~ {""…""}) {
#           # missing role
#           return(synth(403, "Forbidden"));
#       }


sub choose_vouch_proxy {
    if (req.http.host ~ "^vouch.") {
        set req.backend_hint = var.get_backend("vouch_proxy");
        return(pass);
    }
}


sub vouch_proxy_auth {
    if (req.restarts == 0 && var.get_backend("vouch_proxy") != default) {
        # original request from external client
        # - remove X-Vouch-Success header to ensure header is set correctly
        if (req.http.X-Vouch-Success) {
            unset req.http.X-Vouch-Success;
        }
        # - we have to check authorisisation
        if (cookie.get("VouchCookie")) {
            # existing vouch-proxy authorisisation session
            # - intercept request
            # - send request to /validate endpoint
            if (! req.http.Content-Length || req.method !~ 
"^(?:POST|PUT|PATCH|DELETE)$") {
                # send validate request for all requests without body
                # (Workaround for POST, PUT, …)
                if (req.method != "GET") {
                    var.set_string("req.method", req.method);
                    set req.method = "GET";
                }
                set req.url = "/__vouch_proxy/validate";
                if (req.http.Content-Length) {
                    var.set_string("req.http.Content-Length", 
req.http.Content-Length);
                    unset req.http.Content-Length;
                }
                if (req.http.Content-Type) {
                    var.set_string("req.http.Content-Type", 
req.http.Content-Type);
                    unset req.http.Content-Type;
                }
                var.set_int("allow_cache_with_cookie", 1);
                set req.backend_hint = var.get_backend("vouch_proxy");
                return(hash);
            }
        } else {
            # missing authorisisation session
            # - redirect to OIDC login
            return(synth(308, var.get_string("vouch_vhost") + 
"/__vouch_proxy/login?url=https://"; + req.http.X-Portal + req.http.X-Url));
        }
    }
}

sub vcl_recv {
    if (false) {
        call choose_vouch_proxy;
        call vouch_proxy_auth;
    }
}

sub vcl_hash {
    if (req.url == "/__vouch_proxy/validate") {
        # hash the OIDC validation request for current user
        hash_data(req.http.host);
        hash_data(req.url);
        hash_data(cookie.get("VouchCookie"));
        hash_data(client.identity);
        return (lookup);
    }
}

sub vcl_backend_response {
    if (bereq.url ~ "^/__vouch_proxy" && beresp.status != 200) {
        # negative TTL for failed requests
        set beresp.ttl = 5s;
    }
}

sub vcl_deliver {
    if (req.restarts == 0 && req.url == "/__vouch_proxy/validate") {
        if (resp.status == 200) {
            if (var.get_string("req.method")) {
                set req.method = var.get_string("req.method");
            }
            set req.url = req.http.X-Url;
            if (req.http.host != req.http.X-Portal) {
                set req.http.host = req.http.X-Portal;
            }
            if (var.get_string("req.http.Content-Type")) {
                set req.http.Content-Type = 
var.get_string("req.http.Content-Type");
            }
            if (var.get_string("req.http.Content-Length")) {
                set req.http.Content-Length = 
var.get_string("req.http.Content-Length");
            }
            #
            # forward vouch validate response headers to application backend 
request
            #
            if (resp.http.X-Vouch-User) {
                set req.http.X-Vouch-User = resp.http.X-Vouch-User;
            }
            if (resp.http.X-Vouch-Success) {
                set req.http.X-Vouch-Success = resp.http.X-Vouch-Success;
            }
            if (resp.http.X-Vouch-Claims-Groups) {
                set req.http.X-Vouch-Claims-Groups = 
resp.http.X-Vouch-Claims-Groups;
            }
            if (resp.http.X-Vouch-Claims-Locale) {
                set req.http.X-Vouch-Claims-Locale = 
resp.http.X-Vouch-Claims-Locale;
            }
            if (resp.http.X-Vouch-Claims-Preferred-Username) {
                set req.http.X-Vouch-Claims-Preferred-Username = 
resp.http.X-Vouch-Claims-Preferred-Username;
            }
            if (resp.http.X-Vouch-Claims-Roles) {
                set req.http.X-Vouch-Claims-Roles = 
resp.http.X-Vouch-Claims-Roles;
            }
            return(restart);
        } else {
            return(synth(308, var.get_string("vouch_vhost") + 
"/__vouch_proxy/login?url=https://"; + req.http.X-Portal + req.http.X-Url));
        }
    }
}
_______________________________________________
varnish-misc mailing list
[email protected]
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-misc

Reply via email to