From 4e79dcef00b9b85e858dfc26d368407d5b3f4011 Mon Sep 17 00:00:00 2001 From: jr conlin Date: Wed, 4 Oct 2017 11:40:35 -0700 Subject: [PATCH] feat: add Strict-Transport-Security header Closes #1031 --- autopush/config.py | 4 ++++ autopush/main_argparse.py | 4 ++++ autopush/tests/test_main.py | 1 + autopush/tests/test_web_base.py | 10 ++++++++++ autopush/web/base.py | 6 ++++++ 5 files changed, 25 insertions(+) diff --git a/autopush/config.py b/autopush/config.py index 09079ee9..6bf73a3b 100644 --- a/autopush/config.py +++ b/autopush/config.py @@ -170,6 +170,9 @@ class AutopushConfig(object): # Use the cryptography library use_cryptography = attrib(default=False) # type: bool + # Strict-Transport-Security max age (Default 1 year in secs) + sts_max_age = attrib(default=31536000) # type: int + def __attrs_post_init__(self): """Initialize the Settings object""" # Setup hosts/ports/urls @@ -315,6 +318,7 @@ def from_argparse(cls, ns, **kwargs): cert=ns.ssl_cert, dh_param=ns.ssl_dh_param ), + sts_max_age=ns.sts_max_age, **kwargs ) diff --git a/autopush/main_argparse.py b/autopush/main_argparse.py index 0eb22cb9..5325cd08 100644 --- a/autopush/main_argparse.py +++ b/autopush/main_argparse.py @@ -93,6 +93,10 @@ def add_shared_args(parser): help="Use the cryptography library vs. JOSE", action="store_true", default=False, env_var="USE_CRYPTOGRAPHY") + parser.add_argument('--sts_max_age', + help="Max Strict Transport Age in seconds", + type=int, default=31536000, + env_var="STS_MAX_AGE") # No ENV because this is for humans _add_external_router_args(parser) _obsolete_args(parser) diff --git a/autopush/tests/test_main.py b/autopush/tests/test_main.py index 319cbd9d..f8923990 100644 --- a/autopush/tests/test_main.py +++ b/autopush/tests/test_main.py @@ -260,6 +260,7 @@ class TestArg: memusage_port = None disable_simplepush = True use_cryptography = False + sts_max_age = 1234 def setUp(self): patchers = [ diff --git a/autopush/tests/test_web_base.py b/autopush/tests/test_web_base.py index cfc98280..e9ecdfe6 100644 --- a/autopush/tests/test_web_base.py +++ b/autopush/tests/test_web_base.py @@ -116,6 +116,16 @@ def test_cors_options(self): eq_(base._headers[ch3], self.CORS_HEADERS) eq_(base._headers[ch4], self.CORS_RESPONSE_HEADERS) + def test_sts_max_age_header(self): + args = {"api_ver": "v1", "token": "test"} + base = self.base + base.conf.sts_max_age = 86400 + base.prepare() + base.options(args) + sts_header = base._headers.get("Strict-Transport-Security") + ok_("max-age=86400" in sts_header) + ok_("includeSubDomains" in sts_header) + def test_write_error(self): """ Write error is triggered by sending the app a request with an invalid method (e.g. "put" instead of "PUT"). diff --git a/autopush/web/base.py b/autopush/web/base.py index 3335a8e2..00b1d0dd 100644 --- a/autopush/web/base.py +++ b/autopush/web/base.py @@ -163,6 +163,12 @@ def prepare(self): ",".join(self.cors_request_headers)) self.set_header("Access-Control-Expose-Headers", ",".join(self.cors_response_headers)) + if self.conf.sts_max_age: + self.set_header("Strict-Transport-Security", + ";".join([ + "max-age={}".format(self.conf.sts_max_age), + "includeSubDomains" + ])) ############################################################# # Cyclone HTTP Methods