Skip to content

Commit

Permalink
Merge pull request #38 from mdsol/develop
Browse files Browse the repository at this point in the history
Develop => Master for 1.4.0
  • Loading branch information
ejinotti-mdsol authored Oct 5, 2022
2 parents 7801215 + 3ae28ce commit f08280d
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 220 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 1.4.0
- Add `MAuthWSGIMiddleware` for authenticating requests in WSGI frameworks like Flask.
- Remove `FlaskAuthenticator`.

# 1.3.0
- Add `MAuthASGIMiddleware` for authenticating requests in ASGI frameworks like FastAPI.
- Remove Support for EOL Python 3.6
Expand Down
41 changes: 24 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,30 +112,37 @@ authentic, status_code, message = authenticator.is_authentic()
app_uuid = authenticator.get_app_uuid()
```

#### Flask applications
#### WSGI Applications

You will need to create an application instance and initialize it with `FlaskAuthenticator`.
To specify routes that need to be authenticated use the `requires_authentication` decorator.
To apply to a WSGI application you should use the `MAuthWSGIMiddleware`. You
can make certain paths exempt from authentication by passing the `exempt`
option with a set of paths to exempt.

Here is an example for Flask. Note that requesting app's UUID and the
protocol version will be added to the request environment for successfully
authenticated requests.

```python
from flask import Flask
from mauth_client.flask_authenticator import FlaskAuthenticator, requires_authentication
from flask import Flask, request, jsonify
from mauth_client.consts import ENV_APP_UUID, ENV_PROTOCOL_VERSION
from mauth_client.middlewares import MAuthWSGIMiddleware

app = Flask("Some Sample App")
authenticator = FlaskAuthenticator()
authenticator.init_app(app)
app = Flask("MyApp")
app.wsgi_app = MAuthWSGIMiddleware(app.wsgi_app, exempt={"/app_status"})

@app.route("/some/private/route", methods=["GET"])
@requires_authentication
def private_route():
return "Wibble"
@app.get("/")
def root():
return jsonify({
"msg": "authenticated",
"app_uuid": request.environ[ENV_APP_UUID],
"protocol_version": request.environ[ENV_PROTOCOL_VERSION],
})

@app.route("/app_status", methods=["GET"])
def app_status():
return "OK"
@app.get("/app_status")
return "this route is exempt from authentication"
```

#### ASGI applications
#### ASGI Applications

To apply to an ASGI application you should use the `MAuthASGIMiddleware`. You
can make certain paths exempt from authentication by passing the `exempt`
Expand All @@ -147,7 +154,7 @@ authenticated requests.

```python
from fastapi import FastAPI, Request
from mauth_client.constants import ENV_APP_UUID, ENV_PROTOCOL_VERSION
from mauth_client.consts import ENV_APP_UUID, ENV_PROTOCOL_VERSION
from mauth_client.middlewares import MAuthASGIMiddleware

app = FastAPI()
Expand Down
1 change: 0 additions & 1 deletion mauth_client/flask_authenticator/__init__.py

This file was deleted.

81 changes: 0 additions & 81 deletions mauth_client/flask_authenticator/flask_authenticator.py

This file was deleted.

1 change: 1 addition & 0 deletions mauth_client/middlewares/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .asgi import MAuthASGIMiddleware
from .wsgi import MAuthWSGIMiddleware
62 changes: 62 additions & 0 deletions mauth_client/middlewares/wsgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import json
import logging

from mauth_client.authenticator import LocalAuthenticator
from mauth_client.config import Config
from mauth_client.consts import (
ENV_APP_UUID,
ENV_AUTHENTIC,
ENV_PROTOCOL_VERSION,
)

from mauth_client.signable import RequestSignable
from mauth_client.signed import Signed

logger = logging.getLogger("mauth_wsgi")


class MAuthWSGIMiddleware:
def __init__(self, app, exempt=None):
self._validate_configs()
self.app = app
self.exempt = exempt.copy() if exempt else set()

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

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

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

if is_authentic:
environ[ENV_APP_UUID] = signed.app_uuid
environ[ENV_AUTHENTIC] = True
environ[ENV_PROTOCOL_VERSION] = signed.protocol_version()
return self.app(environ, start_response)

start_response(status, [("content-type", "application/json")])
body = {"errors": {"mauth": [message]}}
return [json.dumps(body).encode("utf-8")]

def _validate_configs(self):
# Validate the client settings (APP_UUID, PRIVATE_KEY)
if not all([Config.APP_UUID, Config.PRIVATE_KEY]):
raise TypeError("MAuthWSGIMiddleware requires APP_UUID and PRIVATE_KEY")
# Validate the mauth settings (MAUTH_BASE_URL, MAUTH_API_VERSION)
if not all([Config.MAUTH_URL, Config.MAUTH_API_VERSION]):
raise TypeError("MAuthWSGIMiddleware requires MAUTH_URL and MAUTH_API_VERSION")

def _read_body(self, environ):
input = environ["wsgi.input"]
input.seek(0)
body = input.read()
input.seek(0)
return body
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mauth-client"
version = "1.3.0"
version = "1.4.0"
description = "MAuth Client for Python"
repository = "https://github.com/mdsol/mauth-client-python"
authors = ["Medidata Solutions <[email protected]>"]
Expand All @@ -13,10 +13,10 @@ classifiers = [
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Software Development :: Libraries :: Python Modules",
]
Expand Down
Empty file.
119 changes: 0 additions & 119 deletions tests/flask_authenticator/flask_authenticator_test.py

This file was deleted.

Loading

0 comments on commit f08280d

Please sign in to comment.