Skip to content

Commit

Permalink
chore: surface event if proxy token mismatches (pypi#14499)
Browse files Browse the repository at this point in the history
  • Loading branch information
miketheman authored Sep 7, 2023
1 parent 34f6a0c commit 2d0e5ae
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 0 deletions.
27 changes: 27 additions & 0 deletions tests/unit/utils/test_wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import pretend
import pytest
import sentry_sdk

from sqlalchemy import type_coerce
from sqlalchemy.dialects.postgresql import INET
Expand Down Expand Up @@ -43,6 +44,32 @@ def test_skips_headers(self):
assert resp is response
assert app.calls == [pretend.call({}, start_response)]

def test_token_mismatch_sends_sentry(self, monkeypatch):
"""In the event someone submits the WAREHOUSE_TOKEN header with an
incorrect value, we send a Sentry.
"""
mock_set_context = pretend.call_recorder(lambda *a, **kw: None)
monkeypatch.setattr(sentry_sdk, "set_context", mock_set_context)
mock_capture_message = pretend.call_recorder(lambda *a, **kw: None)
monkeypatch.setattr(sentry_sdk, "capture_message", mock_capture_message)

response = pretend.stub()
app = pretend.call_recorder(lambda e, s: response)

environ = {"HTTP_WAREHOUSE_TOKEN": "NOPE"}
start_response = pretend.stub()

resp = wsgi.ProxyFixer(app, token="1234", ip_salt="pepa")(
environ, start_response
)

assert resp is response
assert app.calls == [pretend.call({}, start_response)]
assert mock_set_context.calls == [pretend.call("ProxyFixer", {"token": "NOPE"})]
assert mock_capture_message.calls == [
pretend.call("Invalid Proxy Token", level="warning")
]

def test_accepts_warehouse_headers(self):
response = pretend.stub()
app = pretend.call_recorder(lambda e, s: response)
Expand Down
15 changes: 15 additions & 0 deletions warehouse/utils/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

from typing import TYPE_CHECKING

import sentry_sdk

from sqlalchemy import type_coerce
from sqlalchemy.dialects.postgresql import INET
from sqlalchemy.exc import NoResultFound
Expand Down Expand Up @@ -66,11 +68,24 @@ def __call__(self, environ, start_response):
}

host = environ.get("HTTP_WAREHOUSE_HOST", "")

# If we're not getting headers from a trusted third party via the
# specialized Warehouse-* headers, then we'll fall back to looking at
# X-Forwarded-* headers, assuming that whatever we have in front of us
# will strip invalid ones.
else:
# If there IS a token, but it doesn't match, then tell us about it.
if request_token is not None and not hmac.compare_digest(
self.token, request_token
):
sentry_sdk.set_context(
self.__class__.__name__, {"token": request_token}
)
sentry_sdk.capture_message(
"Invalid Proxy Token",
level="warning",
)

proto = environ.get("HTTP_X_FORWARDED_PROTO", "")

# Special case: if we don't see a X-Forwarded-For, this may be a local
Expand Down

0 comments on commit 2d0e5ae

Please sign in to comment.