-
-
Save andrewwiik/3dcb9c028b15bf359ae1053b8e8f94b9 to your computer and use it in GitHub Desktop.
Google Auth VCL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import blob; | |
| import http; | |
| import urlplus; | |
| import kvstore; | |
| import json; | |
| import jwt; | |
| import str; | |
| import headerplus; | |
| import cookieplus; | |
| sub vcl_init { | |
| new gauth_config = kvstore.init(); | |
| gauth_config.set("client_id", "174207094618-5a1knqdlr1fqr1krt4akmj8240vj71o2.apps.googleusercontent.com"); | |
| gauth_config.set("client_secret", "Xh7qJvhPCP2AlHYeZHO4uIUp"); | |
| gauth_config.set("callback_path", "/api/auth/google/callback"); | |
| gauth_config.set("auth_cookie", "auth_cookie"); | |
| gauth_config.set("signing_secret", "test123"); | |
| gauth_config.set("scope", "email profile"); | |
| gauth_config.set("allowed_domain", "varnish-software.com"); | |
| new gauth_cookie_jwt_reader = jwt.reader(); | |
| new gauth_cookie_jwt_writer = jwt.writer(); | |
| } | |
| sub gauth_handle_start { | |
| # Get URL to Redirect to after successful auth | |
| set req.http.X-InternalGAuth-Referrer-URL = "https://" + req.http.Host + urlplus.url_get(); | |
| # Get CallbackURL to pass to Google Auth | |
| set req.http.X-InternalGAuth-Callback-URL = "https://" + req.http.Host + gauth_config.get("callback_path"); | |
| # Setup Redirect URL | |
| urlplus.parse("/o/oauth2/v2/auth"); | |
| urlplus.query_add("response_type", "code"); | |
| urlplus.query_add("prompt", "select_account"); | |
| urlplus.query_add("access_type", "offline"); | |
| urlplus.query_add("redirect_uri", blob.transcode(encoded=req.http.X-InternalGAuth-Callback-URL, encoding=URL)); | |
| urlplus.query_add("scope", blob.transcode(encoded=gauth_config.get("scope"), encoding=URL)); | |
| urlplus.query_add("client_id", gauth_config.get("client_id")); | |
| urlplus.query_add("state", blob.transcode(encoded=req.http.X-InternalGAuth-Referrer-URL, encoding=URL)); | |
| set req.http.X-InternalGAuth-Redirect = "https://accounts.google.com" + urlplus.as_string(); | |
| urlplus.parse(req.url); | |
| return (synth(667, req.http.X-InternalGAuth-Redirect)); | |
| } | |
| sub gauth_get_access_token { | |
| set req.http.X-InternalGAuth-GAuth-Token = "error"; | |
| # Initialize Post Request | |
| http.init(1); | |
| http.req_set_method(1, "POST"); | |
| http.req_set_url(1, "https://oauth2.googleapis.com/token"); | |
| http.req_set_header(1, "Host", "oauth2.googleapis.com"); | |
| http.req_set_header(1, "Content-Type", "application/x-www-form-urlencoded"); | |
| # Build Post Body | |
| set req.http.X-InternalGAuth-Post-Body = "code=" + req.http.X-InternalGAuth-Callback-Code; | |
| set req.http.X-InternalGAuth-Post-Body = req.http.X-InternalGAuth-Post-Body + "&client_id=" + gauth_config.get("client_id") + "&client_secret=" + gauth_config.get("client_secret"); | |
| set req.http.X-InternalGAuth-Full-URL = "https://" + req.http.Host + urlplus.url_get(); | |
| set req.http.X-InternalGAuth-Post-Body = req.http.X-InternalGAuth-Post-Body + "&redirect_uri=" + blob.transcode(encoded=req.http.X-InternalGAuth-Full-URL, encoding=URL); | |
| set req.http.X-InternalGAuth-Post-Body = req.http.X-InternalGAuth-Post-Body + "&grant_type=authorization_code"; | |
| http.req_set_sparam(1, "POSTFIELDS", req.http.X-InternalGAuth-Post-Body); | |
| # Send Data | |
| http.req_send(1); | |
| http.resp_wait(1); | |
| if (http.resp_get_status(1) == 200) { | |
| # Get Authorization Token | |
| json.parse(http.resp_get_body(1)); | |
| if (!json.is_valid() || !json.is_object()) { | |
| set req.http.X-InternalGAuth-GAuth-Token = "error"; | |
| } else { | |
| set req.http.X-InternalGAuth-GAuth-Token = json.get("access_token", "error"); | |
| } | |
| } else { | |
| set req.http.X-InternalGAuth-GAuth-Token = "error"; | |
| } | |
| } | |
| sub gauth_get_profile { | |
| set req.http.X-InternalGAuth-GAuth-Profile = "error"; | |
| # Get User's Google Profile | |
| # Setup Request | |
| http.init(2); | |
| http.req_set_method(2, "GET"); | |
| http.req_set_url(2, "https://www.googleapis.com/oauth2/v3/userinfo"); | |
| http.req_set_header(2, "Host", "www.googleapis.com"); | |
| http.req_set_header(2, "Authorization", "Bearer " + req.http.X-InternalGAuth-GAuth-Token); | |
| # Send Request | |
| http.req_send(2); | |
| http.resp_wait(2); | |
| # Analyse Response | |
| if (http.resp_get_status(2) == 200) { | |
| set req.http.X-InternalGAuth-GAuth-Profile = http.resp_get_body(2); | |
| } else { | |
| set req.http.X-InternalGAuth-GAuth-Profile = "error"; | |
| } | |
| } | |
| sub gauth_set_cookie { | |
| gauth_cookie_jwt_writer.set_alg("HS256"); | |
| gauth_cookie_jwt_writer.set_exp(now + 24h); | |
| gauth_cookie_jwt_writer.set_payload(req.http.X-InternalGAuth-GAuth-Profile); | |
| set req.http.X-InternalGAuth-Set-Auth-Cookie = gauth_cookie_jwt_writer.generate(gauth_config.get("signing_secret")); | |
| set req.http.X-InternalGAuth-Final-Redirect = blob.transcode(encoded=req.http.X-InternalGAuth-Callback-State, decoding=URL); | |
| return (synth(667, req.http.X-InternalGAuth-Final-Redirect)); | |
| } | |
| sub gauth_handle_callback { | |
| # Get callback data from URL | |
| set req.http.X-InternalGAuth-Callback-Code = urlplus.query_get("code", "error"); | |
| set req.http.X-InternalGAuth-Callback-State = urlplus.query_get("state"); | |
| # Did we get an auth code | |
| if (req.http.X-InternalGAuth-Callback-Code == "error") { | |
| return (synth(503, "No Auth Code Given")); | |
| } | |
| call gauth_get_access_token; | |
| if (req.http.X-InternalGAuth-GAuth-Token == "error") { | |
| return (synth(503, "Failed to get Authorization Bearer Token")); | |
| } | |
| call gauth_get_profile; | |
| if (req.http.X-InternalGAuth-GAuth-Profile == "error") { | |
| return (synth(503, "Failed to get User's Profile")); | |
| } | |
| call gauth_set_cookie; | |
| } | |
| sub gauth_handle { | |
| if (urlplus.url_get() == gauth_config.get("callback_path")) { | |
| # Callback URL for Google OAuth | |
| call gauth_handle_callback; | |
| } else { | |
| # Start the Authentication Process | |
| call gauth_handle_start; | |
| } | |
| } | |
| sub gauth_check_allowed_user { | |
| json.parse(gauth_cookie_jwt_reader.get_payload()); | |
| set req.http.X-InternalGAuth-Email = json.get("email", "error"); | |
| if (req.http.X-InternalGAuth-Email == "error") { | |
| set req.http.X-InternalGAuth-Wipe-Cookie = "YES"; | |
| return (synth(503, "Not Authorized to Access this Resource")); | |
| } | |
| if (!str.endswith(req.http.X-InternalGAuth-Email, "@" + gauth_config.get("allowed_domain"))) { | |
| set req.http.X-InternalGAuth-Wipe-Cookie = "YES"; | |
| return (synth(503, "Not Authorized to Access this Resource")); | |
| } | |
| } | |
| sub gauth_check { | |
| set req.http.X-InternalGAuth-Auth-Cookie = cookieplus.get(gauth_config.get("auth_cookie"), "error"); | |
| # No Auth Cookie was present, we need to authenticate | |
| if (req.http.X-InternalGAuth-Auth-Cookie == "error") { | |
| call gauth_handle; | |
| } | |
| # Setup Auth Cookie JWT Reader | |
| gauth_cookie_jwt_reader.set_key(gauth_config.get("signing_secret")); | |
| if (gauth_cookie_jwt_reader.parse(req.http.X-InternalGAuth-Auth-Cookie)) { | |
| if (!gauth_cookie_jwt_reader.verify("HS256")) { | |
| # JWT Auth Cookie was expired | |
| call gauth_handle; | |
| } else { | |
| call gauth_check_allowed_user; | |
| } | |
| } else { | |
| # Did not have valid JWT Auth Cookie | |
| call gauth_handle; | |
| } | |
| # headerplus.init(req); | |
| # headerplus.delete_regex("^X-InternalGAuth-"); | |
| # headerplus.write(); | |
| # They are Authenticated | |
| } | |
| sub vcl_synth { | |
| if (resp.status == 667) { | |
| if (req.http.X-InternalGAuth-Set-Auth-Cookie) { | |
| cookieplus.setcookie_add(gauth_config.get("auth_cookie"), req.http.X-InternalGAuth-Set-Auth-Cookie, 24h, req.http.Host, "/", true, true); | |
| cookieplus.setcookie_write(); | |
| } | |
| set resp.http.location = resp.reason; | |
| set resp.reason = "Moved"; | |
| set resp.status = 302; | |
| return (deliver); | |
| } | |
| if (resp.status == 503) { | |
| if (req.http.X-InternalGAuth-Wipe-Cookie == "YES") { | |
| cookieplus.setcookie_add(gauth_config.get("auth_cookie"), "", -1h, req.http.Host, "/", true, true); | |
| cookieplus.setcookie_write(resp.http.Set-Cookie); | |
| } | |
| } | |
| } | |
| sub vcl_recv { | |
| call gauth_check; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment