navigator-auth 0.17.2__tar.gz → 0.17.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/PKG-INFO +1 -1
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/auth.py +5 -6
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/api.py +4 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/django.py +4 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/token.py +4 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/troc.py +4 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/decorators.py +193 -3
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/recovery.py +5 -8
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/version.py +1 -1
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth.egg-info/PKG-INFO +1 -1
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/CHANGES.rst +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/LICENSE +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/MANIFEST.in +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/Makefile +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/README.md +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/Makefile +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/api.rst +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/authors.rst +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/changelog.rst +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/changes.rst +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/code-of-conduct.rst +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/conf.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/config.rst +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/index.rst +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/make.bat +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/policies.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/requirements-dev.txt +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/requirements.txt +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/security.rst +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/docs/settings.rst +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/audit.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/context.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/decorators.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/errors.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/guardian.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/middleware.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/pdp.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/policies/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/policies/abstract.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/policies/environment.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/policies/evaluator.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/policies/file.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/policies/obj.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/policies/policy.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/policies/resource_policy.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/policies/resources.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/policyhandler.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/storages/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/storages/abstract.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/storages/db.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/storages/pg.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/authorizations/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/authorizations/abstract.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/authorizations/allow_hosts.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/authorizations/hosts.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/authorizations/useragent.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/abstract.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/adfs.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/attributes/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/attributes/abstract.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/attributes/internal.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/azure.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/basic.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/external.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/github.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/google.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/idp/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/idp/code.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/jwksutils.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/noauth.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/oauth.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/oauth2/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/oauth2/backend.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/oauth2/client_backend.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/oauth2/code_backend.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/oauth2/ddl.sql +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/oauth2/models.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/okta.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/saml.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/conf.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/exceptions.c +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/exceptions.pxd +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/exceptions.pyx +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/groups.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/handler.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/model.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/partners.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/permissions.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/userattrs.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/users/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/users/passwd.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/users/session.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/handlers/users/user.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/identities.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/libs/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/libs/cipher.cpp +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/libs/cipher.pyx +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/libs/json.cpp +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/libs/json.pyx +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/libs/parser.cpp +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/libs/parser.pyx +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/middlewares/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/middlewares/abstract.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/middlewares/apikey.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/middlewares/django.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/middlewares/jwt.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/middlewares/security.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/middlewares/token.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/middlewares/troc.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/models.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/py.typed +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/responses.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/storages/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/storages/abstract.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/storages/postgres.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/storages/redis.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/templates.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/uv.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth.egg-info/SOURCES.txt +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth.egg-info/dependency_links.txt +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth.egg-info/requires.txt +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth.egg-info/top_level.txt +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/pyproject.toml +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/setup.cfg +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/setup.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/tests/__init__.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/tests/test_allowed.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/tests/test_login.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/tests/test_policy.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/tests/test_policy_conditions.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/tests/test_policy_evaluation.py +0 -0
- {navigator_auth-0.17.2 → navigator_auth-0.17.3}/tests/test_policy_object.py +0 -0
|
@@ -700,7 +700,6 @@ class AuthHandler:
|
|
|
700
700
|
# avoid authorization backend on OPTION method:
|
|
701
701
|
if request.method == hdrs.METH_OPTIONS:
|
|
702
702
|
return True
|
|
703
|
-
|
|
704
703
|
# Check for explicit exclude list matches
|
|
705
704
|
for pattern in exclude_list:
|
|
706
705
|
if fnmatch.fnmatch(request.path, pattern):
|
|
@@ -749,19 +748,19 @@ class AuthHandler:
|
|
|
749
748
|
"""
|
|
750
749
|
if await self.verify_exceptions(request):
|
|
751
750
|
return await handler(request)
|
|
752
|
-
|
|
751
|
+
self.logger.debug(":: AUTH MIDDLEWARE ::")
|
|
753
752
|
try:
|
|
754
753
|
token = await self._idp.get_payload(request)
|
|
755
754
|
_, payload = self._idp.decode_token(code=token)
|
|
756
755
|
except Forbidden as err:
|
|
757
|
-
|
|
756
|
+
self.logger.error(
|
|
758
757
|
f"Auth Middleware: Access Denied: {err}"
|
|
759
758
|
)
|
|
760
759
|
raise self.Unauthorized(
|
|
761
760
|
reason=err.message
|
|
762
761
|
) from err
|
|
763
762
|
except AuthExpired as err:
|
|
764
|
-
|
|
763
|
+
self.logger.error(
|
|
765
764
|
f"Auth Middleware: Credentials expired: {err}"
|
|
766
765
|
)
|
|
767
766
|
raise self.Unauthorized(
|
|
@@ -778,7 +777,7 @@ class AuthHandler:
|
|
|
778
777
|
try:
|
|
779
778
|
session = await get_session(request, payload, new=False)
|
|
780
779
|
except Exception as err:
|
|
781
|
-
|
|
780
|
+
self.logger.error(str(err))
|
|
782
781
|
if not session and AUTH_CREDENTIALS_REQUIRED is True:
|
|
783
782
|
raise self.Unauthorized(
|
|
784
783
|
reason="There is no Session or Authentication is missing"
|
|
@@ -787,7 +786,7 @@ class AuthHandler:
|
|
|
787
786
|
request.user = await self.get_session_user(session)
|
|
788
787
|
request["authenticated"] = True
|
|
789
788
|
except Exception as ex: # pylint: disable=W0703
|
|
790
|
-
|
|
789
|
+
self.logger.error(f"Missing User Object from Session: {ex}")
|
|
791
790
|
elif self.secure_cookies is True:
|
|
792
791
|
session = await get_session(request, None, new=False)
|
|
793
792
|
if not session and AUTH_CREDENTIALS_REQUIRED is True:
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Navigator Authentication using an API Token.
|
|
4
4
|
description: Single API Token Authentication
|
|
5
5
|
"""
|
|
6
|
+
from aiohttp import hdrs
|
|
6
7
|
from collections.abc import Callable, Awaitable
|
|
7
8
|
import orjson
|
|
8
9
|
from aiohttp import web
|
|
@@ -223,6 +224,9 @@ class APIKeyAuth(BaseAuthBackend):
|
|
|
223
224
|
) -> web.StreamResponse:
|
|
224
225
|
request.user = None
|
|
225
226
|
# avoid check system routes
|
|
227
|
+
# avoid authorization backend on OPTION method:
|
|
228
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
229
|
+
return await handler(request)
|
|
226
230
|
if await self.verify_exceptions(request):
|
|
227
231
|
return await handler(request)
|
|
228
232
|
try:
|
|
@@ -4,6 +4,7 @@ Navigator Authentication using Django Session Backend
|
|
|
4
4
|
description: read the Django session from Redis Backend
|
|
5
5
|
and decrypt, after that, a session will be created.
|
|
6
6
|
"""
|
|
7
|
+
from aiohttp import hdrs
|
|
7
8
|
import base64
|
|
8
9
|
import logging
|
|
9
10
|
from collections.abc import Callable, Awaitable
|
|
@@ -226,6 +227,9 @@ class DjangoAuth(BaseAuthBackend):
|
|
|
226
227
|
Basic Auth Middleware.
|
|
227
228
|
Description: Basic Authentication for NoAuth, Basic, Token and Django.
|
|
228
229
|
"""
|
|
230
|
+
# avoid authorization backend on OPTION method:
|
|
231
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
232
|
+
return await handler(request)
|
|
229
233
|
# avoid check system routes
|
|
230
234
|
if await self.verify_exceptions(request):
|
|
231
235
|
return await handler(request)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Navigator Authentication using an API Token for partners.
|
|
4
4
|
description: Single API Token Authentication
|
|
5
5
|
"""
|
|
6
|
+
from aiohttp import hdrs
|
|
6
7
|
from collections.abc import Callable, Awaitable
|
|
7
8
|
import jwt
|
|
8
9
|
from aiohttp import web
|
|
@@ -177,6 +178,9 @@ class TokenAuth(BaseAuthBackend):
|
|
|
177
178
|
Token Auth Middleware.
|
|
178
179
|
Description: Token Middleware.
|
|
179
180
|
"""
|
|
181
|
+
# avoid authorization backend on OPTION method:
|
|
182
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
183
|
+
return await handler(request)
|
|
180
184
|
# avoid check system routes
|
|
181
185
|
if await self.verify_exceptions(request):
|
|
182
186
|
return await handler(request)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Troc Authentication using RNC algorithm.
|
|
4
4
|
"""
|
|
5
|
+
from aiohttp import hdrs
|
|
5
6
|
from typing import Optional
|
|
6
7
|
from collections.abc import Awaitable, Callable
|
|
7
8
|
from aiohttp import web
|
|
@@ -220,6 +221,9 @@ class TrocToken(BaseAuthBackend):
|
|
|
220
221
|
Partner Auth Middleware.
|
|
221
222
|
Description: Basic Authentication for Partner Token Auth.
|
|
222
223
|
"""
|
|
224
|
+
# avoid authorization backend on OPTION method:
|
|
225
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
226
|
+
return await handler(request)
|
|
223
227
|
# avoid check system routes
|
|
224
228
|
if await self.verify_exceptions(request):
|
|
225
229
|
return await handler(request)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from functools import wraps
|
|
2
2
|
import inspect
|
|
3
|
-
from typing import Any, TypeVar
|
|
3
|
+
from typing import Any, TypeVar
|
|
4
4
|
from collections.abc import Callable, Awaitable
|
|
5
5
|
from aiohttp import web, hdrs
|
|
6
6
|
from aiohttp.abc import AbstractView
|
|
7
7
|
from navigator_session import get_session
|
|
8
8
|
from .exceptions import AuthException
|
|
9
|
-
from .conf import AUTH_SESSION_OBJECT
|
|
9
|
+
from .conf import AUTH_SESSION_OBJECT
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
F = TypeVar("F", bound=Callable[..., Any])
|
|
@@ -45,7 +45,7 @@ def allow_anonymous(handler: F) -> F:
|
|
|
45
45
|
is not required for this endpoint.
|
|
46
46
|
|
|
47
47
|
Args:
|
|
48
|
-
|
|
48
|
+
handler: The handler function or class-based view to decorate.
|
|
49
49
|
|
|
50
50
|
Returns:
|
|
51
51
|
Callable: The decorated handler that allows anonymous access.
|
|
@@ -77,6 +77,9 @@ def user_session() -> Callable[[F], F]:
|
|
|
77
77
|
@wraps(handler)
|
|
78
78
|
async def _wrap(*args, **kwargs) -> web.StreamResponse:
|
|
79
79
|
request = args[0] if isinstance(args[0], web.Request) else args[-1]
|
|
80
|
+
# avoid check on OPTION method:
|
|
81
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
82
|
+
return await handler(*args, **kwargs)
|
|
80
83
|
session = await get_session(request, new=False)
|
|
81
84
|
try:
|
|
82
85
|
user = session.decode("user")
|
|
@@ -95,6 +98,9 @@ def user_session() -> Callable[[F], F]:
|
|
|
95
98
|
@wraps(method)
|
|
96
99
|
async def wrapped_method(self, *args, **kwargs):
|
|
97
100
|
request = self.request
|
|
101
|
+
# avoid check on OPTION method:
|
|
102
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
103
|
+
return await method(self, *args, **kwargs)
|
|
98
104
|
session = await get_session(request, new=False)
|
|
99
105
|
try:
|
|
100
106
|
user = session.decode("user")
|
|
@@ -138,6 +144,9 @@ def is_authenticated(content_type: str = "application/json") -> Callable[[F], F]
|
|
|
138
144
|
request = args[-1]
|
|
139
145
|
if request is None or not isinstance(request, web.Request):
|
|
140
146
|
raise ValueError(f"web.Request was not found in arguments. {handler!s}")
|
|
147
|
+
# avoid check on OPTION method:
|
|
148
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
149
|
+
return await handler(*args, **kwargs)
|
|
141
150
|
if request.get("authenticated", False):
|
|
142
151
|
return await handler(*args, **kwargs)
|
|
143
152
|
else:
|
|
@@ -167,6 +176,9 @@ def is_authenticated(content_type: str = "application/json") -> Callable[[F], F]
|
|
|
167
176
|
@wraps(method)
|
|
168
177
|
async def wrapped_method(self, *args, **kwargs):
|
|
169
178
|
request = self.request
|
|
179
|
+
# avoid check on OPTION method:
|
|
180
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
181
|
+
return await method(self, *args, **kwargs)
|
|
170
182
|
if request.get("authenticated", False):
|
|
171
183
|
return await method(self, *args, **kwargs)
|
|
172
184
|
app = request.app
|
|
@@ -209,6 +221,9 @@ def allowed_groups(groups: list, content_type: str = "application/json") -> Call
|
|
|
209
221
|
raise ValueError(
|
|
210
222
|
f"web.Request was not found in arguments. {handler!s}"
|
|
211
223
|
)
|
|
224
|
+
# avoid check on OPTION method:
|
|
225
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
226
|
+
return await handler(*args, **kwargs)
|
|
212
227
|
if request.get("authenticated", False) is False:
|
|
213
228
|
# check credentials:
|
|
214
229
|
raise web.HTTPUnauthorized(
|
|
@@ -261,6 +276,9 @@ def allowed_programs(
|
|
|
261
276
|
request = args[-1]
|
|
262
277
|
if request is None:
|
|
263
278
|
raise ValueError(f"web.Request was not found in arguments. {handler!s}")
|
|
279
|
+
# avoid check on OPTION method:
|
|
280
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
281
|
+
return await handler(*args, **kwargs)
|
|
264
282
|
if not request.get("authenticated", False):
|
|
265
283
|
raise web.HTTPUnauthorized(
|
|
266
284
|
reason=f"Access Denied to Handler {handler!s}",
|
|
@@ -296,6 +314,9 @@ def allowed_programs(
|
|
|
296
314
|
request = self.request
|
|
297
315
|
if request is None:
|
|
298
316
|
raise ValueError(f"web.Request was not found in arguments. {method!s}")
|
|
317
|
+
# avoid check on OPTION method:
|
|
318
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
319
|
+
return await method(self, *args, **kwargs)
|
|
299
320
|
if not request.get("authenticated", False):
|
|
300
321
|
raise web.HTTPUnauthorized(
|
|
301
322
|
reason=f"Access Denied to Handler {method!s}",
|
|
@@ -350,6 +371,9 @@ def apikey_required(content_type: str = "application/json") -> Callable:
|
|
|
350
371
|
request = args[-1]
|
|
351
372
|
if request is None:
|
|
352
373
|
raise ValueError(f"web.Request was not found in arguments. {handler!s}")
|
|
374
|
+
# avoid check on OPTION method:
|
|
375
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
376
|
+
return await handler(*args, **kwargs)
|
|
353
377
|
app = request.app
|
|
354
378
|
try:
|
|
355
379
|
auth = app["auth"]
|
|
@@ -390,6 +414,9 @@ def apikey_required(content_type: str = "application/json") -> Callable:
|
|
|
390
414
|
request = self.request
|
|
391
415
|
if request is None:
|
|
392
416
|
raise ValueError(f"web.Request was not found in arguments. {method!s}")
|
|
417
|
+
# avoid check on OPTION method:
|
|
418
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
419
|
+
return await method(self, *args, **kwargs)
|
|
393
420
|
app = request.app
|
|
394
421
|
try:
|
|
395
422
|
auth = app["auth"]
|
|
@@ -450,6 +477,9 @@ def allowed_organizations(
|
|
|
450
477
|
request = args[-1]
|
|
451
478
|
if request is None:
|
|
452
479
|
raise ValueError(f"web.Request was not found in arguments. {handler!s}")
|
|
480
|
+
# avoid check on OPTION method:
|
|
481
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
482
|
+
return await handler(*args, **kwargs)
|
|
453
483
|
if not request.get("authenticated", False):
|
|
454
484
|
raise web.HTTPUnauthorized(
|
|
455
485
|
reason=f"Access Denied to Handler {handler!s}",
|
|
@@ -481,6 +511,9 @@ def allowed_organizations(
|
|
|
481
511
|
request = self.request
|
|
482
512
|
if request is None:
|
|
483
513
|
raise ValueError(f"web.Request was not found in arguments. {method!s}")
|
|
514
|
+
# avoid check on OPTION method:
|
|
515
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
516
|
+
return await method(self, *args, **kwargs)
|
|
484
517
|
if not request.get("authenticated", False):
|
|
485
518
|
raise web.HTTPUnauthorized(
|
|
486
519
|
reason=f"Access Denied to Handler {method!s}",
|
|
@@ -517,3 +550,160 @@ def allowed_organizations(
|
|
|
517
550
|
return _wrap_function(handler)
|
|
518
551
|
|
|
519
552
|
return _wrapper
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def is_restricted(
|
|
556
|
+
users: list = None, groups: list = None, content_type: str = "application/json"
|
|
557
|
+
) -> Callable:
|
|
558
|
+
"""
|
|
559
|
+
Restrict access to specific Users or Groups.
|
|
560
|
+
Logic:
|
|
561
|
+
- If 'users' is provided, current user MUST be in the list.
|
|
562
|
+
- If 'groups' is provided, current user MUST have at least one group in the list.
|
|
563
|
+
- If both are provided, BOTH conditions must be met (Intersection).
|
|
564
|
+
"""
|
|
565
|
+
def _wrap_function(handler):
|
|
566
|
+
@wraps(handler)
|
|
567
|
+
async def _wrapped(*args, **kwargs) -> web.StreamResponse:
|
|
568
|
+
# For function-based handlers, assume request is the last argument.
|
|
569
|
+
request = args[-1]
|
|
570
|
+
if request is None:
|
|
571
|
+
raise ValueError(f"web.Request was not found in arguments. {handler!s}")
|
|
572
|
+
# check on OPTION method:
|
|
573
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
574
|
+
return await handler(*args, **kwargs)
|
|
575
|
+
if not request.get("authenticated", False):
|
|
576
|
+
raise web.HTTPUnauthorized(
|
|
577
|
+
reason=f"Access Denied to Handler {handler!s}",
|
|
578
|
+
headers={
|
|
579
|
+
hdrs.CONTENT_TYPE: content_type,
|
|
580
|
+
hdrs.CONNECTION: "keep-alive",
|
|
581
|
+
},
|
|
582
|
+
)
|
|
583
|
+
# 1. Get Session
|
|
584
|
+
session = await get_session(request)
|
|
585
|
+
# 2. Extract User Info
|
|
586
|
+
username = None
|
|
587
|
+
user_groups = set()
|
|
588
|
+
try:
|
|
589
|
+
# Try getting from cached session dict
|
|
590
|
+
userinfo = session[AUTH_SESSION_OBJECT]
|
|
591
|
+
username = userinfo.get("username")
|
|
592
|
+
if "groups" in userinfo:
|
|
593
|
+
user_groups = set(userinfo["groups"])
|
|
594
|
+
except KeyError:
|
|
595
|
+
# Fallback to decoding the User object
|
|
596
|
+
try:
|
|
597
|
+
user = session.decode("user")
|
|
598
|
+
username = getattr(user, "username", None)
|
|
599
|
+
if hasattr(user, "groups"):
|
|
600
|
+
for g in user.groups:
|
|
601
|
+
if hasattr(g, "group"):
|
|
602
|
+
user_groups.add(g.group)
|
|
603
|
+
elif hasattr(g, "group_name"):
|
|
604
|
+
user_groups.add(g.group_name)
|
|
605
|
+
except (AttributeError, TypeError, RuntimeError):
|
|
606
|
+
pass
|
|
607
|
+
# 3. Check Constraints
|
|
608
|
+
# User Check
|
|
609
|
+
if users is not None:
|
|
610
|
+
if not username or username not in users:
|
|
611
|
+
raise web.HTTPUnauthorized(
|
|
612
|
+
reason="Access Denied",
|
|
613
|
+
headers={
|
|
614
|
+
hdrs.CONTENT_TYPE: content_type,
|
|
615
|
+
hdrs.CONNECTION: "keep-alive",
|
|
616
|
+
},
|
|
617
|
+
)
|
|
618
|
+
# Group Check
|
|
619
|
+
if groups is not None:
|
|
620
|
+
# user_groups must have intersection with allowed groups
|
|
621
|
+
if user_groups.isdisjoint(groups):
|
|
622
|
+
raise web.HTTPUnauthorized(
|
|
623
|
+
reason="Access Denied",
|
|
624
|
+
headers={
|
|
625
|
+
hdrs.CONTENT_TYPE: content_type,
|
|
626
|
+
hdrs.CONNECTION: "keep-alive",
|
|
627
|
+
},
|
|
628
|
+
)
|
|
629
|
+
return await handler(*args, **kwargs)
|
|
630
|
+
return _wrapped
|
|
631
|
+
|
|
632
|
+
def _wrap_method(method):
|
|
633
|
+
@wraps(method)
|
|
634
|
+
async def _wrapped(self, *args, **kwargs) -> web.StreamResponse:
|
|
635
|
+
request = self.request
|
|
636
|
+
if request is None:
|
|
637
|
+
raise ValueError(f"web.Request was not found in arguments. {method!s}")
|
|
638
|
+
# check on OPTION method:
|
|
639
|
+
if request.method == hdrs.METH_OPTIONS:
|
|
640
|
+
return await method(self, *args, **kwargs)
|
|
641
|
+
if not request.get("authenticated", False):
|
|
642
|
+
raise web.HTTPUnauthorized(
|
|
643
|
+
reason=f"Access Denied to Handler {method!s}",
|
|
644
|
+
headers={
|
|
645
|
+
hdrs.CONTENT_TYPE: content_type,
|
|
646
|
+
hdrs.CONNECTION: "keep-alive",
|
|
647
|
+
},
|
|
648
|
+
)
|
|
649
|
+
# 1. Get Session
|
|
650
|
+
session = await get_session(request)
|
|
651
|
+
# 2. Extract User Info
|
|
652
|
+
username = None
|
|
653
|
+
user_groups = set()
|
|
654
|
+
try:
|
|
655
|
+
# Try getting from cached session dict
|
|
656
|
+
userinfo = session[AUTH_SESSION_OBJECT]
|
|
657
|
+
username = userinfo.get("username")
|
|
658
|
+
if "groups" in userinfo:
|
|
659
|
+
user_groups = set(userinfo["groups"])
|
|
660
|
+
except KeyError:
|
|
661
|
+
# Fallback to decoding the User object
|
|
662
|
+
try:
|
|
663
|
+
user = session.decode("user")
|
|
664
|
+
username = getattr(user, "username", None)
|
|
665
|
+
if hasattr(user, "groups"):
|
|
666
|
+
for g in user.groups:
|
|
667
|
+
if hasattr(g, "group"):
|
|
668
|
+
user_groups.add(g.group)
|
|
669
|
+
elif hasattr(g, "group_name"):
|
|
670
|
+
user_groups.add(g.group_name)
|
|
671
|
+
except (AttributeError, TypeError, RuntimeError):
|
|
672
|
+
pass
|
|
673
|
+
# 3. Check Constraints
|
|
674
|
+
# User Check
|
|
675
|
+
if users is not None:
|
|
676
|
+
if not username or username not in users:
|
|
677
|
+
raise web.HTTPUnauthorized(
|
|
678
|
+
reason="Access Denied",
|
|
679
|
+
headers={
|
|
680
|
+
hdrs.CONTENT_TYPE: content_type,
|
|
681
|
+
hdrs.CONNECTION: "keep-alive",
|
|
682
|
+
},
|
|
683
|
+
)
|
|
684
|
+
# Group Check
|
|
685
|
+
if groups is not None:
|
|
686
|
+
# user_groups must have intersection with allowed groups
|
|
687
|
+
if user_groups.isdisjoint(groups):
|
|
688
|
+
raise web.HTTPUnauthorized(
|
|
689
|
+
reason="Access Denied",
|
|
690
|
+
headers={
|
|
691
|
+
hdrs.CONTENT_TYPE: content_type,
|
|
692
|
+
hdrs.CONNECTION: "keep-alive",
|
|
693
|
+
},
|
|
694
|
+
)
|
|
695
|
+
return await method(self, *args, **kwargs)
|
|
696
|
+
return _wrapped
|
|
697
|
+
|
|
698
|
+
def _wrapper(handler: F):
|
|
699
|
+
# If the handler is a class-based view (subclass of AbstractView), wrap each HTTP method.
|
|
700
|
+
if inspect.isclass(handler) and issubclass(handler, AbstractView):
|
|
701
|
+
for method_name in hdrs.METH_ALL:
|
|
702
|
+
method = getattr(handler, method_name.lower(), None)
|
|
703
|
+
if method is not None and callable(method):
|
|
704
|
+
setattr(handler, method_name.lower(), _wrap_method(method))
|
|
705
|
+
return handler
|
|
706
|
+
else:
|
|
707
|
+
return _wrap_function(handler)
|
|
708
|
+
|
|
709
|
+
return _wrapper
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
import secrets
|
|
3
|
+
import asyncio
|
|
3
4
|
import logging
|
|
4
5
|
import importlib
|
|
5
6
|
from typing import Optional
|
|
6
7
|
from aiohttp import web
|
|
8
|
+
from aiohttp_cors import CorsViewMixin
|
|
7
9
|
try:
|
|
8
10
|
import redis.asyncio as redis
|
|
9
11
|
except ImportError:
|
|
@@ -11,13 +13,9 @@ except ImportError:
|
|
|
11
13
|
from navconfig import config
|
|
12
14
|
from navigator_auth.conf import (
|
|
13
15
|
REDIS_URL,
|
|
14
|
-
AUTH_USER_MODEL
|
|
15
|
-
AUTH_PWD_DIGEST,
|
|
16
|
-
AUTH_PWD_ALGORITHM,
|
|
17
|
-
AUTH_PWD_LENGTH
|
|
16
|
+
AUTH_USER_MODEL
|
|
18
17
|
)
|
|
19
18
|
from navigator_auth.libs.json import json_decoder
|
|
20
|
-
from navigator_auth.exceptions import UserNotFound
|
|
21
19
|
from navigator_auth.responses import JSONResponse
|
|
22
20
|
|
|
23
21
|
class RecoveryTokenStorage:
|
|
@@ -47,7 +45,7 @@ class RecoveryTokenStorage:
|
|
|
47
45
|
key = f"{self.prefix}{token}"
|
|
48
46
|
await self.redis.delete(key)
|
|
49
47
|
|
|
50
|
-
class ForgotPasswordHandler(web.View):
|
|
48
|
+
class ForgotPasswordHandler(web.View, CorsViewMixin):
|
|
51
49
|
async def post(self):
|
|
52
50
|
data = await self.request.json()
|
|
53
51
|
email = data.get('email')
|
|
@@ -104,9 +102,8 @@ class ForgotPasswordHandler(web.View):
|
|
|
104
102
|
logging.exception(f"Error in ForgotPasswordHandler: {e}")
|
|
105
103
|
return web.HTTPInternalServerError(reason="Internal Server Error")
|
|
106
104
|
|
|
107
|
-
import asyncio
|
|
108
105
|
|
|
109
|
-
class ResetPasswordHandler(web.View):
|
|
106
|
+
class ResetPasswordHandler(web.View, CorsViewMixin):
|
|
110
107
|
async def post(self):
|
|
111
108
|
data = await self.request.json()
|
|
112
109
|
token = data.get('token')
|
|
@@ -7,7 +7,7 @@ __title__ = "navigator_auth"
|
|
|
7
7
|
__description__ = (
|
|
8
8
|
"Navigator Auth is an Authentication/Authorization Toolkit for aiohttp."
|
|
9
9
|
)
|
|
10
|
-
__version__ = "0.17.
|
|
10
|
+
__version__ = "0.17.3" # pragma: no cover
|
|
11
11
|
__author__ = "Jesus Lara"
|
|
12
12
|
__author_email__ = "jesuslarag@gmail.com"
|
|
13
13
|
__copyright__ = "Copyright (c) 2019-2025 Jesus Lara"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/abac/policies/resource_policy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/authorizations/allow_hosts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/attributes/__init__.py
RENAMED
|
File without changes
|
{navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/attributes/abstract.py
RENAMED
|
File without changes
|
{navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/attributes/internal.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/oauth2/client_backend.py
RENAMED
|
File without changes
|
{navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth/backends/oauth2/code_backend.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{navigator_auth-0.17.2 → navigator_auth-0.17.3}/navigator_auth.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|