Slide 99
Slide 99 text
sub jwt {
std.log("Ready to perform some JWT magic");
if(cookie.isset("jwt_cookie")) {
#Extract header data from JWT
var.set("token", cookie.get("jwt_cookie"));
var.set("header", regsub(var.get("token"),"([^\.]+)\.[^\.]+\.[^\.]+","\1"));
var.set("type", regsub(digest.base64url_decode(var.get("header")),{"^.*?"typ"\s*:\s*"(\w+)".*?$"},"\1"));
var.set("algorithm", regsub(digest.base64url_decode(var.get("header")),{"^.*?"alg"\s*:\s*"(\w+)".*?$"},"\1"));
#Don't allow invalid JWT header
if(var.get("type") == "JWT" && var.get("algorithm") == "HS256") {
#Extract signature & payload data from JWT
var.set("rawPayload",regsub(var.get("token"),"[^\.]+\.([^\.]+)\.[^\.]+$","\1"));
var.set("signature",regsub(var.get("token"),"^[^\.]+\.[^\.]+\.([^\.]+)$","\1"));
var.set("currentSignature",digest.base64url_nopad_hex(digest.hmac_sha256(var.get("key"),var.get("header") + "." + var.get("rawPayload"))));
var.set("payload", digest.base64url_decode(var.get("rawPayload")));
var.set("exp",regsub(var.get("payload"),{"^.*?"exp"\s*:\s*([0-9]+).*?$"},"\1"));
var.set("jti",regsub(var.get("payload"),{"^.*?"jti"\s*:\s*"([a-z0-9A-Z_\-]+)".*?$"},"\1"));
var.set("userId",regsub(var.get("payload"),{"^.*?"uid"\s*:\s*"([0-9]+)".*?$"},"\1"));
var.set("roles",regsub(var.get("payload"),{"^.*?"roles"\s*:\s*"([a-z0-9A-Z_\-, ]+)".*?$"},"\1"));
#Only allow valid userId
if(var.get("userId") ~ "^\d+$") {
#Don't allow expired JWT
if(std.time(var.get("exp"),now) >= now) {
#SessionId should match JTI value from JWT
if(cookie.get(var.get("sessionCookie")) == var.get("jti")) {
#Don't allow invalid JWT signature
if(var.get("signature") == var.get("currentSignature")) {
#The sweet spot
set req.http.X-login="true";
} else {
std.log("JWT: signature doesn't match. Received: " + var.get("signature") + ", expected: " + var.get("currentSignature"));
}
} else {
std.log("JWT: session cookie doesn't match JTI." + var.get("sessionCookie") + ": " + cookie.get(var.get("sessionCookie")) + ", JTI:" + var.get("jti"));
}
} else {
std.log("JWT: token has expired");
}
} else {
std.log("UserId '"+ var.get("userId") +"', is not numeric");
}
} else {
std.log("JWT: type is not JWT or algorithm is not HS256");
}
std.log("JWT processing finished. UserId: " + var.get("userId") + ". X-Login: " + req.http.X-login);
}
#Look for full private content
if(req.url ~ "/node/2" && req.url !~ "^/user/login") {
if(req.http.X-login != "true") {
return(synth(302,"/user/login?destination=" + req.url));
}
}
}
Insert incomprehensible
Varnish VCL code here …