Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(auth): build authz middlware from FastAPI config #224

Merged
merged 2 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions bento_lib/auth/middleware/fastapi.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import re

from fastapi import Depends, FastAPI, Request, Response, status
from fastapi.responses import JSONResponse
Expand All @@ -8,6 +9,7 @@
from bento_lib.auth.middleware.base import BaseAuthMiddleware
from bento_lib.auth.permissions import Permission
from bento_lib.auth.resources import RESOURCE_EVERYTHING
from bento_lib.config.pydantic import BentoFastAPIBaseConfig
from bento_lib.responses.errors import http_error

__all__ = [
Expand All @@ -16,6 +18,24 @@


class FastApiAuthMiddleware(BaseAuthMiddleware):
@classmethod
def build_from_fastapi_pydantic_config(cls, config: BentoFastAPIBaseConfig, logger: logging.Logger, **kwargs):
"""
Build a FastAPI authorization middlware instance from a Bento Pydantic FastAPI config instance and a logger
instance. This automatically exempts the FastAPI-generated docs OpenAPI schema paths from requiring
authorization.
:param config: instance of the FastAPI subclass of the Bento Pydantic config class.
:param logger: A Python logger to instantiate the FastAPI authorization middlware with.
:param kwargs: Keyword arguments to pass to the FastAPI authorization middleware constructor.
:return: An instance of the authorization middleware.
"""
exempt_request_patterns = (
(r"GET", re.escape(config.service_docs_path)),
(r"GET", re.escape(config.service_openapi_path)),
*kwargs.pop("exempt_request_patterns", ()),
)
return cls.build_from_pydantic_config(config, logger, exempt_request_patterns=exempt_request_patterns, **kwargs)

def attach(self, app: FastAPI):
"""
Attach the middleware to an application. Must be called in order for requests to be checked.
Expand Down
14 changes: 13 additions & 1 deletion tests/test_platform_fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def get_403():
bento_authz_service_url="https://bento-auth.local",
cors_origins=("*",),
)
auth_middleware = FastApiAuthMiddleware.build_from_pydantic_config(
auth_middleware = FastApiAuthMiddleware.build_from_fastapi_pydantic_config(
app_test_auth_config,
logger,
include_request_patterns=authz_test_include_patterns,
Expand Down Expand Up @@ -327,6 +327,18 @@ def test_fastapi_auth_public(fastapi_client_auth: TestClient):
rd2 = r.json()
assert rd == rd2

# can get the FastAPI docs
r = fastapi_client_auth.get("/docs")
assert r.status_code == 200

# can get the OpenAPI schema
r = fastapi_client_auth.get("/openapi.json")
assert r.status_code == 200

# can post to the exempted post endpoint
r = fastapi_client_auth.post("/post-exempted", json=TEST_AUTHZ_VALID_POST_BODY)
assert r.status_code == 200

# can post to the public post endpoint
r = fastapi_client_auth.post("/post-public", json=TEST_AUTHZ_VALID_POST_BODY)
assert r.status_code == 200
Expand Down