diff --git a/lib/dl_app_api_base/dl_app_api_base/__init__.py b/lib/dl_app_api_base/dl_app_api_base/__init__.py index 64e69d66a..0b92d07df 100644 --- a/lib/dl_app_api_base/dl_app_api_base/__init__.py +++ b/lib/dl_app_api_base/dl_app_api_base/__init__.py @@ -8,8 +8,9 @@ HttpServerSettings, ) from .auth import ( - NoAuthChecker, - NoAuthResult, + AlwaysAllowAuthChecker, + AlwaysAllowAuthResult, + AlwaysDenyAuthChecker, OAuthChecker, OAuthCheckerSettings, OAuthResult, @@ -85,8 +86,9 @@ "RequestAuthCheckerProtocol", "OAuthChecker", "OAuthResult", - "NoAuthChecker", - "NoAuthResult", + "AlwaysAllowAuthChecker", + "AlwaysAllowAuthResult", + "AlwaysDenyAuthChecker", "RouteMatcher", "OAuthCheckerSettings", ] diff --git a/lib/dl_app_api_base/dl_app_api_base/app.py b/lib/dl_app_api_base/dl_app_api_base/app.py index 3b3ae03d3..b7f71c5c5 100644 --- a/lib/dl_app_api_base/dl_app_api_base/app.py +++ b/lib/dl_app_api_base/dl_app_api_base/app.py @@ -117,7 +117,7 @@ async def _get_request_auth_checkers( self, ) -> list[auth.RequestAuthCheckerProtocol]: return [ - auth.NoAuthChecker( + auth.AlwaysAllowAuthChecker( route_matchers=[ auth.RouteMatcher( path_regex=re.compile(r"^/api/v1/health/.*$"), diff --git a/lib/dl_app_api_base/dl_app_api_base/auth/__init__.py b/lib/dl_app_api_base/dl_app_api_base/auth/__init__.py index 3db006512..33e8b29b6 100644 --- a/lib/dl_app_api_base/dl_app_api_base/auth/__init__.py +++ b/lib/dl_app_api_base/dl_app_api_base/auth/__init__.py @@ -1,8 +1,9 @@ from .checkers import ( + AlwaysAllowAuthChecker, + AlwaysAllowAuthResult, + AlwaysDenyAuthChecker, BaseRequestAuthChecker, BaseRequestAuthResult, - NoAuthChecker, - NoAuthResult, OAuthChecker, OAuthCheckerSettings, OAuthResult, @@ -25,8 +26,9 @@ "BaseRequestAuthChecker", "RequestAuthCheckerProtocol", "BaseRequestAuthResult", - "NoAuthChecker", - "NoAuthResult", + "AlwaysAllowAuthChecker", + "AlwaysAllowAuthResult", + "AlwaysDenyAuthChecker", "OAuthChecker", "OAuthCheckerSettings", "OAuthResult", diff --git a/lib/dl_app_api_base/dl_app_api_base/auth/checkers/__init__.py b/lib/dl_app_api_base/dl_app_api_base/auth/checkers/__init__.py index c1c675769..6a7dcb312 100644 --- a/lib/dl_app_api_base/dl_app_api_base/auth/checkers/__init__.py +++ b/lib/dl_app_api_base/dl_app_api_base/auth/checkers/__init__.py @@ -1,12 +1,13 @@ +from .always_allow import ( + AlwaysAllowAuthChecker, + AlwaysAllowAuthResult, +) +from .always_deny import AlwaysDenyAuthChecker from .base import ( BaseRequestAuthChecker, BaseRequestAuthResult, RequestAuthCheckerProtocol, ) -from .no_auth import ( - NoAuthChecker, - NoAuthResult, -) from .oauth import ( OAuthChecker, OAuthCheckerSettings, @@ -18,9 +19,10 @@ "BaseRequestAuthChecker", "RequestAuthCheckerProtocol", "BaseRequestAuthResult", - "NoAuthChecker", - "NoAuthResult", + "AlwaysAllowAuthChecker", + "AlwaysAllowAuthResult", "OAuthChecker", "OAuthCheckerSettings", "OAuthResult", + "AlwaysDenyAuthChecker", ] diff --git a/lib/dl_app_api_base/dl_app_api_base/auth/checkers/always_allow.py b/lib/dl_app_api_base/dl_app_api_base/auth/checkers/always_allow.py new file mode 100644 index 000000000..599cd6fa6 --- /dev/null +++ b/lib/dl_app_api_base/dl_app_api_base/auth/checkers/always_allow.py @@ -0,0 +1,14 @@ +import aiohttp.web +import attr + +import dl_app_api_base.auth.checkers.base as auth_checkers_base + + +class AlwaysAllowAuthResult(auth_checkers_base.BaseRequestAuthResult): + ... + + +@attr.define(frozen=True, kw_only=True) +class AlwaysAllowAuthChecker(auth_checkers_base.BaseRequestAuthChecker): + async def check(self, request: aiohttp.web.Request) -> AlwaysAllowAuthResult: + return AlwaysAllowAuthResult() diff --git a/lib/dl_app_api_base/dl_app_api_base/auth/checkers/always_deny.py b/lib/dl_app_api_base/dl_app_api_base/auth/checkers/always_deny.py new file mode 100644 index 000000000..d4ac2061b --- /dev/null +++ b/lib/dl_app_api_base/dl_app_api_base/auth/checkers/always_deny.py @@ -0,0 +1,13 @@ +from typing import NoReturn + +import aiohttp.web +import attr + +import dl_app_api_base.auth.checkers.base as auth_checkers_base +import dl_app_api_base.auth.exc as auth_exc + + +@attr.define(frozen=True, kw_only=True) +class AlwaysDenyAuthChecker(auth_checkers_base.BaseRequestAuthChecker): + async def check(self, request: aiohttp.web.Request) -> NoReturn: + raise auth_exc.AuthFailureError("Always deny auth") diff --git a/lib/dl_app_api_base/dl_app_api_base/auth/checkers/no_auth.py b/lib/dl_app_api_base/dl_app_api_base/auth/checkers/no_auth.py deleted file mode 100644 index d639b3327..000000000 --- a/lib/dl_app_api_base/dl_app_api_base/auth/checkers/no_auth.py +++ /dev/null @@ -1,14 +0,0 @@ -import aiohttp.web -import attr - -import dl_app_api_base.auth.checkers.base as auth_checkers_base - - -class NoAuthResult(auth_checkers_base.BaseRequestAuthResult): - ... - - -@attr.define(frozen=True, kw_only=True) -class NoAuthChecker(auth_checkers_base.BaseRequestAuthChecker): - async def check(self, request: aiohttp.web.Request) -> NoAuthResult: - return NoAuthResult() diff --git a/lib/dl_app_api_base/dl_app_api_base_tests/unit/auth/middleware/test_no_auth.py b/lib/dl_app_api_base/dl_app_api_base_tests/unit/auth/middleware/test_always_allow.py similarity index 86% rename from lib/dl_app_api_base/dl_app_api_base_tests/unit/auth/middleware/test_no_auth.py rename to lib/dl_app_api_base/dl_app_api_base_tests/unit/auth/middleware/test_always_allow.py index eb9037b9b..d25e62df2 100644 --- a/lib/dl_app_api_base/dl_app_api_base_tests/unit/auth/middleware/test_no_auth.py +++ b/lib/dl_app_api_base/dl_app_api_base_tests/unit/auth/middleware/test_always_allow.py @@ -9,6 +9,6 @@ async def test_default( app_client: aiohttp.ClientSession, ) -> None: response = await app_client.get( - "/api/v1/no_auth/ping", + "/api/v1/always_allow/ping", ) assert response.status == http.HTTPStatus.OK diff --git a/lib/dl_app_api_base/dl_app_api_base_tests/unit/auth/middleware/test_always_deny.py b/lib/dl_app_api_base/dl_app_api_base_tests/unit/auth/middleware/test_always_deny.py new file mode 100644 index 000000000..f6ac77f39 --- /dev/null +++ b/lib/dl_app_api_base/dl_app_api_base_tests/unit/auth/middleware/test_always_deny.py @@ -0,0 +1,14 @@ +import http + +import aiohttp +import pytest + + +@pytest.mark.asyncio +async def test_default( + app_client: aiohttp.ClientSession, +) -> None: + response = await app_client.get( + "/api/v1/always_deny/ping", + ) + assert response.status == http.HTTPStatus.UNAUTHORIZED diff --git a/lib/dl_app_api_base/dl_app_api_base_tests/unit/conftest.py b/lib/dl_app_api_base/dl_app_api_base_tests/unit/conftest.py index 115260234..6526a0d0b 100644 --- a/lib/dl_app_api_base/dl_app_api_base_tests/unit/conftest.py +++ b/lib/dl_app_api_base/dl_app_api_base_tests/unit/conftest.py @@ -175,7 +175,7 @@ async def _get_request_auth_checkers( base_checkers = await super()._get_request_auth_checkers() return [ - dl_app_api_base.NoAuthChecker( + dl_app_api_base.AlwaysAllowAuthChecker( route_matchers=[ dl_app_api_base.RouteMatcher( path_regex=re.compile(r"^/api/v1/counter"), @@ -192,10 +192,18 @@ async def _get_request_auth_checkers( ) ], ), - dl_app_api_base.NoAuthChecker( + dl_app_api_base.AlwaysAllowAuthChecker( route_matchers=[ dl_app_api_base.RouteMatcher( - path_regex=re.compile(r"^/api/v1/no_auth/.*"), + path_regex=re.compile(r"^/api/v1/always_allow/.*"), + methods=frozenset(["GET"]), + ), + ], + ), + dl_app_api_base.AlwaysDenyAuthChecker( + route_matchers=[ + dl_app_api_base.RouteMatcher( + path_regex=re.compile(r"^/api/v1/always_deny/.*"), methods=frozenset(["GET"]), ), ], @@ -237,7 +245,12 @@ async def _get_aiohttp_app_routes( ), dl_app_api_base.Route( method="GET", - path="/api/v1/no_auth/ping", + path="/api/v1/always_allow/ping", + handler=PingHandler(), + ), + dl_app_api_base.Route( + method="GET", + path="/api/v1/always_deny/ping", handler=PingHandler(), ), ] diff --git a/lib/dl_app_api_base/dl_app_api_base_tests/unit/handlers/docs/expected_spec.json b/lib/dl_app_api_base/dl_app_api_base_tests/unit/handlers/docs/expected_spec.json index 9696dd02a..8a4008b03 100644 --- a/lib/dl_app_api_base/dl_app_api_base_tests/unit/handlers/docs/expected_spec.json +++ b/lib/dl_app_api_base/dl_app_api_base_tests/unit/handlers/docs/expected_spec.json @@ -253,7 +253,57 @@ } } }, - "/api/v1/no_auth/ping": { + "/api/v1/always_allow/ping": { + "get": { + "tags": [], + "summary": "", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "title": "Message", + "type": "string" + } + }, + "required": [ + "message" + ], + "title": "ResponseSchema", + "type": "object" + } + } + } + }, + "400": { + "content": { + "application/json": { + "schema": { + "properties": { + "message": { + "default": "Bad request", + "title": "Message", + "type": "string" + }, + "code": { + "default": "ERR.API.BAD_REQUEST", + "title": "Code", + "type": "string" + } + }, + "title": "BadRequestResponseSchema", + "type": "object" + } + } + } + } + } + } + }, + "/api/v1/always_deny/ping": { "get": { "tags": [], "summary": "",