Skip to content

Instantly share code, notes, and snippets.

@swichers
Created August 1, 2018 22:22
Show Gist options
  • Save swichers/a850557aca488970d6fc3efe47e581ed to your computer and use it in GitHub Desktop.
Save swichers/a850557aca488970d6fc3efe47e581ed to your computer and use it in GitHub Desktop.
Varnish VCL for checking authorization against a different page and then forcing a cached response.
vcl 4.0;
# !!Important!! Do not use this if your authenticated response can vary
# between users or roles.
# Note: This is only useful if the following things are true:
# * Access to the jsonapi endpoints is restricted to authorized users only.
# * jsonapi request results will be the same for all authorized users. No
# customized or filtered results based on role or other access checks.
# Note: Was implemented and tested as an include file. Priority of includes
# does matter. Example:
#
# vcl 4.0;
# include "jsonapi.vcl"
# include "base.vcl"
# include "debug.vcl"
sub vcl_recv {
if (req.restarts == 0) {
# Remove our auth header if Varnish wasn't responsible for adding it.
unset req.http.X-JSON-Authed;
}
# Special handling to ping the lightweight JSONAPI auth check endpoint
# instead of potentially hitting heavy endpoints on each check. This does
# not cut the number of web requests but can potentially save substantial
# time in the response.
#
# We only want our extra handling to process URLs below the /jsonapi/ path.
if (req.url ~ "^/jsonapi/.+$") {
# If our API auth header is missing then we need to ping the auth check
# endpoint to verify this user can actually access JSONAPI resources.
if (!req.http.X-JSON-Authed) {
set req.http.X-Original-URL = req.url;
set req.url = "/jsonapi";
return (pass);
}
elseif (req.http.X-JSON-Authed == "true") {
return (hash);
}
# Authed was FALSE or some other issue.
return (synth(403, "Access denied"));
}
}
sub vcl_deliver {
# We need the additional check for X-Original-URL to make sure direct access
# to /jsonapi still works without causing a redirect loop.
if (req.url == "/jsonapi" && req.http.X-Original-URL) {
# Fail open if there was a server error.
if (resp.status >= 500 && resp.status < 600) {
set req.http.X-JSON-Authed = "true";
}
else if (resp.status == 200) {
set req.http.X-JSON-Authed = "true";
}
else if (resp.status == 401) {
return (deliver);
}
else {
set req.http.X-JSON-Authed = "false";
}
# Continue the original request with our new header.
set req.url = req.http.X-Original-URL;
unset req.http.X-Original-URL;
return (restart);
}
}
sub vcl_backend_response {
if (bereq.url ~ "^/jsonapi/.+") {
if (beresp.status == 200 || beresp.status == 302) {
# Strip out parts of the response that will always block caching.
unset beresp.http.Set-Cookie;
unset beresp.http.Authorization;
unset beresp.http.Cookie;
# TODO: Custom handler on Drupal side that will set this information.
set beresp.http.Cache-Control = "max-age=900, public";
set beresp.ttl = 15m;
return (deliver);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment