Last active
June 4, 2019 11:12
-
-
Save FND/80d591c9a9762376869556787c623883 to your computer and use it in GitHub Desktop.
SSI with nginx
This file contains 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
# http://editorconfig.org | |
root = true | |
[*] | |
charset = utf-8 | |
end_of_line = lf | |
insert_final_newline = true | |
trim_trailing_whitespace = true | |
max_line_length = 80 | |
indent_style = tab | |
indent_size = 4 | |
[*.{md,py}] | |
indent_style = space | |
[COMMIT_EDITMSG] | |
trim_trailing_whitespace = false | |
max_line_length = 72 | |
indent_style = space |
This file contains 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
#!/usr/bin/env python3 | |
import sys | |
HOST = "localhost" | |
PORT = int(sys.argv[1]) | |
ROOT_URI = "/" | |
AUTH_URI = "/auth" | |
NAV_URI = "/nav" | |
FRAGMENT_PREFIX = "/_fragment" | |
COOKIE_FIELD = "token" | |
JWT = ("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" + | |
".eyJmb28iOiJiYXIifQ" + | |
".VAoRL1IU0nOguxURF2ZcKR0SGKE1gCbqwyh8u2MLAyY") | |
FRAGMENT_TYPE = "text/html; fragment=true" | |
DOCUMENT = """<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>%(title)s</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<style> | |
nav { | |
margin-left: 1em; | |
border: 1px solid #DCA; | |
padding: 0.5em; | |
background-color: #FEFFCD; | |
} | |
nav p, | |
nav ul { | |
margin: 0; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>%(title)s</h1> | |
<p>welcome, %(username)s</p> | |
<pre>%(request_details)s</pre> | |
<a href="%(auth_uri)s">toggle authentication</a> | |
<!--# include virtual="%(embed_uri)s" --> | |
<p>EOF</p> | |
</body> | |
</html> | |
""" | |
FRAGMENT = """ | |
<nav> | |
<p>browsing as %(username)s</p> | |
<pre>%(request_details)s</pre> | |
<ul> | |
<li>foo</li> | |
<li>bar</li> | |
<li>baz</li> | |
</ul> | |
</nav> | |
""" | |
def handler(environ, start_response): | |
method = environ["REQUEST_METHOD"] | |
uri = environ.get("PATH_INFO", "") | |
accept = environ.get("HTTP_ACCEPT") | |
cookie = environ.get("HTTP_COOKIE") | |
user = environ.get("HTTP_X_USER") | |
if uri == AUTH_URI: | |
origin = environ.get("HTTP_REFERER", ROOT_URI) | |
value = ("%s=void; expires=Thu, 01 Jan 1970 00:00:00 GMT" % COOKIE_FIELD | |
if cookie else "%s=%s" % (COOKIE_FIELD, JWT)) | |
start_response("302 Found", | |
[("Set-Cookie", value), ("Location", origin)]) | |
return "" | |
start_response("200 OK", [("Content-Type", "text/html"), | |
("Cache-Control", "no-cache, must-revalidate, max-age=0")]) | |
embed_uri = FRAGMENT_PREFIX + NAV_URI | |
data = { | |
"request_details": "\n".join([ | |
"🔗 %s" % uri, | |
"⛓️ %s" % embed_uri, | |
"📄 %s" % accept, | |
"🍪 %s" % (cookie or "N/A"), | |
"👤 %s" % (user or "N/A") | |
]), | |
"username": "admin" if user else "anonymous" | |
} | |
html = FRAGMENT % data if accept == FRAGMENT_TYPE else DOCUMENT % { | |
**data, | |
"title": "Hello World", | |
"auth_uri": AUTH_URI, | |
"embed_uri": embed_uri | |
} | |
return uft8(html) | |
def uft8(*args): | |
return (txt.encode("utf-8") for txt in args) | |
if __name__ == "__main__": | |
from wsgiref.simple_server import make_server | |
srv = make_server(HOST, PORT, handler) | |
print("→ http://%s:%s" % (HOST, PORT)) | |
srv.serve_forever() |
This file contains 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
local authr = {} | |
local jwt = require "resty.jwt" | |
local cjson = require "cjson" | |
local ngx = ngx | |
-- TODO: use environment variables | |
local auth_uri = "/auth" | |
local cookie_field = "token" | |
local jwt_key = "lua-resty-jwt" | |
function authr.access_handler() | |
if ngx.var.uri == auth_uri then -- FIXME: hacky workaround; brittle? | |
return | |
end | |
-- retrieve JWT from cookie, otherwise abort | |
local cookie = ngx.var["cookie_" .. cookie_field] | |
if not cookie then | |
return ngx.redirect(auth_uri) | |
end | |
-- retrieve payload from JWT, otherwise abort | |
-- TODO: | |
-- * ensure `is_not_expired` | |
-- * LRU cache? | |
local token = jwt:verify(jwt_key, cookie) | |
if not token.valid or not token.verified then | |
return ngx.redirect(auth_uri) | |
end | |
ngx.req.set_header("X-USER", cjson.encode(token.payload)) | |
-- NB: ideally we'd avoid exposing these (not all) cookies to upstream | |
-- applications, but it's not worth the parsing hassle | |
end | |
return authr |
This file contains 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
FROM openresty/openresty:stretch-fat | |
RUN opm get cdbattags/lua-resty-jwt | |
COPY ./nginx.conf /usr/local/openresty/nginx/conf/nginx.conf | |
COPY ./nginx.default.conf /etc/nginx/conf.d/default.conf | |
COPY ./authr.lua /usr/local/openresty/lualib/authr.lua |
This file contains 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
worker_processes 1; | |
events { | |
worker_connections 1024; | |
} | |
http { | |
init_by_lua_block { | |
authr = require "authr" | |
} | |
server { | |
location /_fragment/ { | |
rewrite ^/_fragment/(.*)$ /$1 break; | |
proxy_pass http://host.docker.internal:9999; | |
proxy_set_header Host $host; | |
proxy_set_header Accept "text/html; fragment=true"; | |
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |
proxy_set_header X-Forwarded-Proto $scheme; | |
} | |
location / { | |
ssi on; | |
access_by_lua_block { | |
authr.access_handler() | |
} | |
proxy_pass http://host.docker.internal:9999; | |
proxy_set_header Host $host; | |
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |
proxy_set_header X-Forwarded-Proto $scheme; | |
} | |
} | |
} |
This file contains 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
server { | |
listen 80; | |
server_name localhost; | |
} |
This file contains 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
#!/usr/bin/env bash | |
host_port="8080" | |
vm_port="80" # cf. nginx.conf | |
app_port="9999" # cf. nginx.conf | |
echo "----" | |
echo "starting application and reverse proxy → http://localhost:$host_port" | |
echo "----" | |
./app "$app_port" & | |
app_pid="$!" | |
docker build -t nginxy ./ | |
docker run -p "$host_port:$vm_port" nginxy | |
kill $app_pid # it appears Python ignores SIGINT ¯\_(ツ)_/¯ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment