Skip to content

Commit

Permalink
Merge pull request #43 from mdsol/fix/wsgi-middleware-stop-using-werk…
Browse files Browse the repository at this point in the history
…zeug

[MCC-1058568] Remove `werkzeug` Presumption from WSGI Middleware
  • Loading branch information
ejinotti-mdsol authored Jun 15, 2023
2 parents d2c22ec + 6a77a20 commit cc956ff
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 6 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 1.5.1
- Fix `MAuthWSGIMiddleware` to no longer depend on `werkzeug` data in the request env.

# 1.5.0
- Replace `cchardet` with `charset-normalizer` to support Python 3.11

Expand Down
65 changes: 60 additions & 5 deletions mauth_client/middlewares/wsgi.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import json
import logging

from urllib.parse import quote

from mauth_client.authenticator import LocalAuthenticator
from mauth_client.config import Config
from mauth_client.consts import (
Expand All @@ -22,17 +24,17 @@ def __init__(self, app, exempt=None):
self.exempt = exempt.copy() if exempt else set()

def __call__(self, environ, start_response):
req = environ["werkzeug.request"]
path = environ.get("PATH_INFO", "")

if req.path in self.exempt:
if path in self.exempt:
return self.app(environ, start_response)

signable = RequestSignable(
method=req.method,
url=req.url,
method=environ["REQUEST_METHOD"],
url=self._extract_url(environ),
body=self._read_body(environ),
)
signed = Signed.from_headers(dict(req.headers))
signed = Signed.from_headers(self._extract_headers(environ))
authenticator = LocalAuthenticator(signable, signed, logger)
is_authentic, status, message = authenticator.is_authentic()

Expand Down Expand Up @@ -60,3 +62,56 @@ def _read_body(self, environ):
body = input.read()
input.seek(0)
return body

def _extract_headers(self, environ):
"""
Adapted from werkzeug package: https://github.com/pallets/werkzeug
"""
headers = {}

# don't care to titleize the header keys since
# the Signed class is just going to lowercase them
for k, v in environ.items():
if k.startswith("HTTP_") and k not in {
"HTTP_CONTENT_TYPE",
"HTTP_CONTENT_LENGTH",
}:
key = k[5:].replace("_", "-")
headers[key] = v
elif k in {"CONTENT_TYPE", "CONTENT_LENGTH"}:
key = k.replace("_", "-")
headers[key] = v

return headers

SAFE_CHARS = "!$&'()*+,/:;=@%"

def _extract_url(self, environ):
"""
Adapted from https://peps.python.org/pep-0333/#url-reconstruction
"""
scheme = environ["wsgi.url_scheme"]
url_parts = [scheme, "://"]
http_host = environ.get("HTTP_HOST")

if http_host:
url_parts.append(http_host)
else:
url_parts.append(environ["SERVER_NAME"])
port = environ["SERVER_PORT"]

if (scheme == "https" and port != 443) or (scheme != "https" and port != 80):
url_parts.append(f":{port}")

url_parts.append(
quote(environ.get("SCRIPT_NAME", ""), safe=self.SAFE_CHARS)
)
url_parts.append(
quote(environ.get("PATH_INFO", ""), safe=self.SAFE_CHARS)
)

qs = environ.get("QUERY_STRING")
if qs:
url_parts.append(f"?{quote(qs, safe=self.SAFE_CHARS)}")

return "".join(url_parts)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mauth-client"
version = "1.5.0"
version = "1.5.1"
description = "MAuth Client for Python"
repository = "https://github.com/mdsol/mauth-client-python"
authors = ["Medidata Solutions <support@mdsol.com>"]
Expand Down

0 comments on commit cc956ff

Please sign in to comment.