I have a service which acts as both a rate limiter and access filter.
The service responds with a 200 status and a body like
{ "limited":false, "allow":true }
I have the following example
http {
access_log /dev/stdout;
js_import gateway.js;
server {
server_name localhost;
listen 8000;
listen [::]:8000;
# potential filter here <-
location /foo/ {
# potential filter here <-
proxy_set_header Special "imspecial";
proxy_pass http://backend:9000/;
}
}
I would like to add some sort of auth filter at the server level, or at each location block.
Is it possible to invoke a function like
function my_filter(request) {
request.subrequest("/check-access", {
body: JSON.stringify(body),
method: "POST",
})
.then((reply) => {
var body = JSON.parse(reply.responseBody);
if (body["limited"]===true) {
request.return(429, JSON.stringify({"foo": "special response body here etc"}));
}
if (body["allow"]===false) {
request.return(401, JSON.stringify({"foo": "special response body here etc"}));
}
// do nothing, continue on to the proxy pass
})
// imagine error handling here for subrequest
}
It seems I cannot; both call js_content and proxy_pass right after in the same location block.
Ive tried all sorts of combinations to the point I cannot remember each of them, any help would be greatly appreciated.
@tylerhjones
Hi!
It seems I cannot; both call js_content and proxy_pass right after in the same location block.
looks like it can be achieved by hacking a auth_request:
location = /auth {
js_content test.auth;
}
location @access_denied {
js_content test.access_denied;
}
location /secure {
auth_request /auth;
auth_request_set $x_auth_status "$x_auth_status";
auth_request_set $x_auth_response "$x_auth_response";
error_page 403 = @access_denied;
proxy_pass http://127.0.0.1:10000/content;
}
location /content {
return 200 "Welcome";
}
function auth(r) {
var x = (Math.random() * 1000) & 2;
switch (x) {
case 0:
r.return(204);
return;
case 1:
r.variables['x_auth_status'] = 429;
r.variables['x_auth_response'] = `Rate limit, ${new Date()}`;
break;
case 2:
r.variables['x_auth_status'] = 401;
r.variables['x_auth_response'] = `Auth required, ${new Date()}`;
break;
}
r.return(403);
}
function access_denied(r) {
var status = +r.variables['x_auth_status'];
var response = r.variables['x_auth_response'];
r.return(status, response);
}
@tylerhjones we are planning to add js body filter in the near term future.
@drsm Thank you so much for this example.
Is x_auth_status special in some way?
When I attempt to set extra values
e.g.
r.variables['try-after'] = "1234"; // <- new value;
r.variables['x_auth_status'] = 429;
r.variables['x_auth_response'] = `Rate limit, ${new Date()}`;
I get an error
[error] 29#29: *1 js: Error: variable not found
馃う馃徎 nvm, forgot to define the variable first auth_request_set $try_after "$try_after";
resolved
Most helpful comment
@tylerhjones
Hi!
looks like it can be achieved by hacking a
auth_request: