-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
partially fixes #2063 This will allow us to add permissions checks to our API calls. Currently it does not require a valid JWT, but if one exists will store the "sub" field such that the user's id can be checked against our user table to establish permissions.
- Loading branch information
EC2 Default User
committed
Jan 7, 2025
1 parent
a0b418d
commit 361b3d4
Showing
6 changed files
with
101 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
- bump: patch | ||
changes: | ||
changed: | ||
- Updated PolicyEngine US to 1.168.1. | ||
- API now checks for authenticated user, but only prints access errors rather than failing. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
from flask import Flask, g | ||
from werkzeug.local import LocalProxy | ||
from authlib.integrations.flask_oauth2 import ResourceProtector | ||
|
||
|
||
def configure(app: Flask, require_auth: ResourceProtector): | ||
""" | ||
Configure the application to attempt to get and validate a bearer token. | ||
If there is a token and it's valid the user id is added to the request context | ||
which can be accessed via get_user_id | ||
Otherwise, the request is accepted but get_user_id returns None | ||
This supports our current auth model where only user-specific actions are restricted and | ||
then only to allow the user | ||
""" | ||
|
||
# If the user is authenticated then get the user id from the token | ||
# And add it to the flask request context. | ||
@app.before_request | ||
def get_user(): | ||
try: | ||
token = require_auth.acquire_token() | ||
print(f"Validated JWT for sub {g.authlib_server_oauth2_token.sub}") | ||
except Exception as ex: | ||
print(f"Unable to parse a valid bearer token from request: {ex}") | ||
|
||
|
||
def get_user() -> None | str: | ||
# I didn't see this documented anywhere, but if you look at the source code | ||
# the validator stores the token in the flask global context under this name. | ||
if "authlib_server_oauth2_token" not in g: | ||
print( | ||
"authlib_server_oauth2_token is not in the flask global context. Please make sure you called 'configure' on the app" | ||
) | ||
return None | ||
if "sub" not in g.authlib_server_oauth2_token: | ||
print( | ||
"ERROR: authlib_server_oauth2_token does not contain a sub field. The JWT validator should force this to be true." | ||
) | ||
return None | ||
return g.authlib_server_oauth2_token.sub |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# As defined by https://auth0.com/docs/quickstart/backend/python/interactive | ||
import json | ||
from urllib.request import urlopen | ||
|
||
from authlib.oauth2.rfc7523 import JWTBearerTokenValidator | ||
from authlib.jose.rfc7517.jwk import JsonWebKey | ||
|
||
|
||
class Auth0JWTBearerTokenValidator(JWTBearerTokenValidator): | ||
def __init__( | ||
self, | ||
audience="https://api.policyengine.org/", | ||
): | ||
issuer = "https://policyengine.uk.auth0.com/" | ||
jsonurl = urlopen( | ||
f"https://policyengine.uk.auth0.com/.well-known/jwks.json" | ||
) | ||
public_key = JsonWebKey.import_key_set(json.loads(jsonurl.read())) | ||
super(Auth0JWTBearerTokenValidator, self).__init__(public_key) | ||
self.claims_options = { | ||
"exp": {"essential": True}, | ||
"aud": {"essential": True, "value": audience}, | ||
"iss": {"essential": True, "value": issuer}, | ||
# Provides the user id as we currently use it. | ||
"sub": {"essential": True}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ | |
"streamlit", | ||
"werkzeug", | ||
"Flask-Caching>=2,<3", | ||
"Authlib", | ||
], | ||
extras_require={ | ||
"dev": [ | ||
|