From 23bfeb8bf3835725e3b9a5cd0ad3382bfb95471f Mon Sep 17 00:00:00 2001 From: jrconlin Date: Thu, 10 Sep 2020 14:22:31 -0700 Subject: [PATCH] bug: enforce VAPID "aud" compliance. Closes: bug 1663922 --- autopush/tests/test_integration.py | 34 +++++++++++++++++++++++---- autopush/tests/test_web_validation.py | 9 +++---- autopush/web/webpush.py | 10 ++++++++ 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/autopush/tests/test_integration.py b/autopush/tests/test_integration.py index 058e54d1..c2882004 100644 --- a/autopush/tests/test_integration.py +++ b/autopush/tests/test_integration.py @@ -67,7 +67,7 @@ def setup_module(): def _get_vapid(key=None, payload=None): if not payload: - payload = {"aud": "https://pusher_origin.example.com", + payload = {"aud": "http://localhost", "exp": int(time.time()) + 86400, "sub": "mailto:admin@example.com"} if not key: @@ -781,7 +781,7 @@ def test_basic_delivery_with_invalid_vapid_exp(self): data = str(uuid.uuid4()) client = yield self.quick_register() vapid_info = _get_vapid( - payload={"aud": "https://pusher_origin.example.com", + payload={"aud": "http://localhost", "exp": '@', "sub": "mailto:admin@example.com"}) yield client.send_notification( @@ -790,7 +790,7 @@ def test_basic_delivery_with_invalid_vapid_exp(self): status=401) vapid_info = _get_vapid( - payload={"aud": "https://pusher_origin.example.com", + payload={"aud": "http://localhost", "exp": ['@'], "sub": "mailto:admin@example.com"}) yield client.send_notification( @@ -799,6 +799,30 @@ def test_basic_delivery_with_invalid_vapid_exp(self): status=401) yield self.shut_down(client) + @inlineCallbacks + def test_basic_delivery_with_invalid_vapid_aud(self): + data = str(uuid.uuid4()) + client = yield self.quick_register() + # try a different domain. + vapid_info = _get_vapid( + payload={"aud": "http://127.0.0.1", + "sub": "mailto:admin@example.com"}) + yield client.send_notification( + data=data, + vapid=vapid_info, + status=401) + + # try a different scheme + vapid_info = _get_vapid( + payload={"aud": "https://localhost", + "sub": "mailto:admin@example.com"}) + yield client.send_notification( + data=data, + vapid=vapid_info, + status=401) + yield self.shut_down(client) + + @inlineCallbacks def test_basic_delivery_with_invalid_vapid_auth(self): data = str(uuid.uuid4()) @@ -1522,7 +1546,7 @@ def test_webpush_monthly_rotation_no_channels(self): @inlineCallbacks def test_with_key(self): private_key = ecdsa.SigningKey.generate(curve=ecdsa.NIST256p) - claims = {"aud": "http://example.com", + claims = {"aud": "http://localhost", "exp": int(time.time()) + 86400, "sub": "a@example.com"} vapid = _get_vapid(private_key, claims) @@ -2065,6 +2089,8 @@ def _add_router(self): "app_id": "amzn1.application.StringOfStuff", "client_id": "amzn1.application-oa2-client.ev4nM0reStuff", "client_secret": "deadbeef0000decafbad1111", + "hostname": "localhost", + "endpoint_scheme": "http", } }, self.ep.db.metrics, diff --git a/autopush/tests/test_web_validation.py b/autopush/tests/test_web_validation.py index 6f64c3d2..cd9212a9 100644 --- a/autopush/tests/test_web_validation.py +++ b/autopush/tests/test_web_validation.py @@ -626,6 +626,7 @@ def _make_fut(self): from autopush.web.webpush import WebPushRequestSchema conf = AutopushConfig( hostname="localhost", + endpoint_scheme="http", statsd_host=None, ) db = test_db() @@ -666,7 +667,7 @@ def test_valid_vapid_crypto_header(self): schema = self._make_fut() header = {"typ": "JWT", "alg": "ES256"} - payload = {"aud": "https://pusher_origin.example.com", + payload = {"aud": "http://localhost", "exp": int(time.time()) + 86400, "sub": "mailto:admin@example.com"} @@ -698,7 +699,7 @@ def test_valid_vapid_crypto_header_webpush(self, use_crypto=False): schema.context["conf"].use_cryptography = use_crypto header = {"typ": "JWT", "alg": "ES256"} - payload = {"aud": "https://pusher_origin.example.com", + payload = {"aud": "http://localhost", "exp": int(time.time()) + 86400, "sub": "mailto:admin@example.com"} @@ -732,7 +733,7 @@ def test_valid_vapid_02_crypto_header_webpush(self): schema = self._make_fut() header = {"typ": "JWT", "alg": "ES256"} - payload = {"aud": "https://pusher_origin.example.com", + payload = {"aud": "http://localhost", "exp": int(time.time()) + 86400, "sub": "mailto:admin@example.com"} @@ -763,7 +764,7 @@ def test_valid_vapid_02_crypto_header_webpush_alt(self): schema = self._make_fut() header = {"typ": "JWT", "alg": "ES256"} - payload = {"aud": "https://pusher_origin.example.com", + payload = {"aud": "http://localhost", "exp": int(time.time()) + 86400, "sub": "mailto:admin@example.com"} diff --git a/autopush/web/webpush.py b/autopush/web/webpush.py index 2aa7aa59..79c22feb 100644 --- a/autopush/web/webpush.py +++ b/autopush/web/webpush.py @@ -425,6 +425,16 @@ def validate_auth(self, d): raise InvalidRequest("Invalid Authorization Header", status_code=401, errno=109, headers={"www-authenticate": PREF_SCHEME}) + if "aud" not in jwt: + raise InvalidRequest("Invalid bearer token: No Audience specified", + status_code=401, errno=109, + headers={"www-authenticate": PREF_SCHEME}) + if jwt['aud'] != "{}://{}".format( + self.context["conf"].endpoint_scheme or "http", + self.context["conf"].hostname): + raise InvalidRequest("Invalid bearer token: Invalid Audience Specified", + status_code=401, errno=109, + headers={"www-authenticate": PREF_SCHEME}) if "exp" not in jwt: raise InvalidRequest("Invalid bearer token: No expiration", status_code=401, errno=109,