jamlib 3.0.0b12.dev3__tar.gz → 3.0.0b13__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.
- {jamlib-3.0.0b12.dev3/src/jamlib.egg-info → jamlib-3.0.0b13}/PKG-INFO +1 -1
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/pyproject.toml +1 -1
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/__init__.py +1 -1
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/exceptions/__init__.py +8 -1
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/exceptions/plugins.py +13 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/ext/litestar/__init__.py +3 -1
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/ext/litestar/plugins.py +56 -10
- jamlib-3.0.0b13/src/jam/ext/starlette/__init__.py +18 -0
- jamlib-3.0.0b13/src/jam/ext/starlette/backends.py +153 -0
- jamlib-3.0.0b13/src/jam/ext/starlette/objects.py +53 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/jwt/__algorithms__.py +5 -1
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13/src/jamlib.egg-info}/PKG-INFO +1 -1
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jamlib.egg-info/SOURCES.txt +2 -2
- jamlib-3.0.0b12.dev3/src/jam/ext/starlette/__init__.py +0 -12
- jamlib-3.0.0b12.dev3/src/jam/ext/starlette/auth_backends.py +0 -143
- jamlib-3.0.0b12.dev3/src/jam/ext/starlette/value.py +0 -18
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/LICENSE.md +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/README.md +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/setup.cfg +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/__base__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/__base_encoder__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/__deprecated__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/__base__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/instance.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/jwt/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/oauth2/__base__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/oauth2/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/oauth2/builtin/github.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/oauth2/builtin/google.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/oauth2/client.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/sessions/__base__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/sessions/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/sessions/json.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/aio/sessions/redis.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/encoders.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/exceptions/base.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/exceptions/jwt.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/exceptions/oauth2.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/exceptions/paseto.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/exceptions/sessions.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/ext/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/ext/fastapi/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/ext/flask/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/ext/flask/extensions.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/ext/litestar/middleware.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/ext/litestar/objects.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/instance.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/jwt/__base__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/jwt/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/jwt/__types__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/jwt/lists/__abc_list_repo__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/jwt/lists/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/jwt/lists/json.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/jwt/lists/redis.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/jwt/module.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/jwt/utils.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/logger.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/oauth2/__base__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/oauth2/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/oauth2/builtin/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/oauth2/builtin/github.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/oauth2/builtin/gitlab.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/oauth2/builtin/google.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/oauth2/builtin/yandex.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/oauth2/client.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/otp/__base__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/otp/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/otp/hotp.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/otp/totp.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/paseto/__base__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/paseto/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/paseto/utils.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/paseto/v1.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/paseto/v2.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/paseto/v3.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/paseto/v4.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/py.typed +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/sessions/__base__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/sessions/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/sessions/json.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/sessions/redis.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/tests/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/tests/clients.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/tests/fakers.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/__init__.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/aes.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/await_maybe.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/basic_auth.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/config_maker.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/ed.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/otp_keys.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/rsa.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/salt_hash.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/symmetric.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/xchacha20poly1305.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jam/utils/xor.py +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jamlib.egg-info/dependency_links.txt +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jamlib.egg-info/requires.txt +0 -0
- {jamlib-3.0.0b12.dev3 → jamlib-3.0.0b13}/src/jamlib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jamlib
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.0b13
|
|
4
4
|
Summary: Simple and universal library for authorization.
|
|
5
5
|
Author-email: Makridenko Adrian <adrianmakridenko@duck.com>, Ksenia Travnikova <kseniatravnikova@duck.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -36,7 +36,12 @@ from .paseto import (
|
|
|
36
36
|
JamPASETOInvalidTokenFormat
|
|
37
37
|
)
|
|
38
38
|
|
|
39
|
-
from .plugins import
|
|
39
|
+
from .plugins import (
|
|
40
|
+
JamLitestarPluginConfigError,
|
|
41
|
+
JamLitestarPluginError,
|
|
42
|
+
JamStarlettePluginConfigError,
|
|
43
|
+
JamStarlettePluginError
|
|
44
|
+
)
|
|
40
45
|
|
|
41
46
|
from .sessions import (
|
|
42
47
|
JamSessionNotFound,
|
|
@@ -67,6 +72,8 @@ __all__ = [
|
|
|
67
72
|
"JamPASTOKeyVerificationError",
|
|
68
73
|
"JamLitestarPluginConfigError",
|
|
69
74
|
"JamLitestarPluginError",
|
|
75
|
+
"JamStarlettePluginConfigError",
|
|
76
|
+
"JamStarlettePluginError",
|
|
70
77
|
"JamSessionNotFound",
|
|
71
78
|
"JamSessionEmptyAESKey",
|
|
72
79
|
]
|
|
@@ -15,3 +15,16 @@ class JamLitestarPluginError(JamError):
|
|
|
15
15
|
|
|
16
16
|
default_message = "An error occurred for a litestar plugin."
|
|
17
17
|
default_code = "jam.plugin.litestar"
|
|
18
|
+
|
|
19
|
+
class JamStarlettePluginConfigError(JamConfigurationError):
|
|
20
|
+
"""Exception raised when a configuration error occurs for a starlette plugin."""
|
|
21
|
+
|
|
22
|
+
default_message = "Configuration error occurred for a starlette plugin."
|
|
23
|
+
default_code = "jam.configuration.plugin.starlette"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class JamStarlettePluginError(JamError):
|
|
27
|
+
"""Exception raised when an error occurs for a starlette plugin."""
|
|
28
|
+
|
|
29
|
+
default_message = "An error occurred for a starlette plugin."
|
|
30
|
+
default_code = "jam.plugin.starlette"
|
|
@@ -16,7 +16,8 @@ from .plugins import (
|
|
|
16
16
|
BasePlugin,
|
|
17
17
|
JamJWTPlugin,
|
|
18
18
|
JamSessionPlugin,
|
|
19
|
-
JamPASETOPlugin
|
|
19
|
+
JamPASETOPlugin,
|
|
20
|
+
JamOAuth2Plugin,
|
|
20
21
|
)
|
|
21
22
|
|
|
22
23
|
__all__ = [
|
|
@@ -27,4 +28,5 @@ __all__ = [
|
|
|
27
28
|
"JamJWTPlugin",
|
|
28
29
|
"JamSessionPlugin",
|
|
29
30
|
"JamPASETOPlugin",
|
|
31
|
+
"JamOAuth2Plugin",
|
|
30
32
|
]
|
|
@@ -17,6 +17,7 @@ from jam.ext.litestar.middleware import (
|
|
|
17
17
|
)
|
|
18
18
|
from jam.ext.litestar.objects import BaseUser
|
|
19
19
|
from jam.jwt import JWT
|
|
20
|
+
from jam.oauth2 import create_instance as create_oauth2
|
|
20
21
|
from jam.paseto import create_instance as create_paseto
|
|
21
22
|
from jam.utils.config_maker import GENERIC_POINTER, __config_maker__
|
|
22
23
|
|
|
@@ -25,23 +26,34 @@ class BasePlugin(InitPlugin):
|
|
|
25
26
|
"""Base Litestar plugin."""
|
|
26
27
|
|
|
27
28
|
MODULE: Callable
|
|
28
|
-
|
|
29
|
+
MIDDLEWARE: type[BaseMiddleware]
|
|
29
30
|
_DI_KEY: str
|
|
30
31
|
_CONFIG_KEY: str
|
|
31
32
|
|
|
32
33
|
def _setup_config(self, config: dict[str, Any]) -> None:
|
|
33
34
|
self._auth = self.MODULE(**config)
|
|
34
35
|
|
|
35
|
-
def __init__(
|
|
36
|
+
def __init__(
|
|
36
37
|
self,
|
|
37
38
|
config: dict[str, Any] | str | None = None,
|
|
38
39
|
pointer: str = GENERIC_POINTER,
|
|
39
40
|
cookie_name: str | None = None,
|
|
40
41
|
header_name: str | None = None,
|
|
41
42
|
middleware: bool = True,
|
|
42
|
-
|
|
43
|
+
user: type[BaseUser] | None = None,
|
|
43
44
|
**kwargs,
|
|
44
45
|
) -> None:
|
|
46
|
+
"""Initialize the plugin.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
config (dict[str, Any] | str | None): Jam config as path/to/file or dict.
|
|
50
|
+
pointer (str): Config pointer
|
|
51
|
+
cookie_name (str | None): Cookie name to read token
|
|
52
|
+
header_name (str | None): Header name to read token
|
|
53
|
+
middleware (bool): Use middleware?
|
|
54
|
+
user (type[BaseUser]): User for request state. See: DOCUMENTATION
|
|
55
|
+
**kwargs: Config arguments if config=None
|
|
56
|
+
"""
|
|
45
57
|
if middleware and (not cookie_name and not header_name):
|
|
46
58
|
raise JamLitestarPluginConfigError(
|
|
47
59
|
message="Cookie name and header name cannot be both None.",
|
|
@@ -50,11 +62,11 @@ class BasePlugin(InitPlugin):
|
|
|
50
62
|
"header_name": header_name,
|
|
51
63
|
},
|
|
52
64
|
)
|
|
53
|
-
if middleware and not
|
|
65
|
+
if middleware and not user:
|
|
54
66
|
raise JamLitestarPluginConfigError(
|
|
55
67
|
message="Middleware user cannot be None when middleware is True.",
|
|
56
68
|
details={
|
|
57
|
-
"middleware_user":
|
|
69
|
+
"middleware_user": user,
|
|
58
70
|
},
|
|
59
71
|
)
|
|
60
72
|
|
|
@@ -67,11 +79,11 @@ class BasePlugin(InitPlugin):
|
|
|
67
79
|
self._middleware = None
|
|
68
80
|
|
|
69
81
|
if middleware:
|
|
70
|
-
_middleware = self.
|
|
82
|
+
_middleware = self.MIDDLEWARE
|
|
71
83
|
_middleware.COOKIE_NAME = cookie_name
|
|
72
84
|
_middleware.HEADER_NAME = header_name
|
|
73
85
|
_middleware.AUTH_MODULE = self._auth
|
|
74
|
-
_middleware.USER =
|
|
86
|
+
_middleware.USER = user # type: ignore
|
|
75
87
|
self._middleware = _middleware
|
|
76
88
|
|
|
77
89
|
def on_app_init(self, app_config: AppConfig) -> AppConfig: # noqa
|
|
@@ -88,7 +100,7 @@ class JamJWTPlugin(BasePlugin):
|
|
|
88
100
|
"""JWT plugin for litestar."""
|
|
89
101
|
|
|
90
102
|
MODULE = JWT
|
|
91
|
-
|
|
103
|
+
MIDDLEWARE = JWTMiddleware
|
|
92
104
|
_DI_KEY = "jwt"
|
|
93
105
|
_CONFIG_KEY = "jwt"
|
|
94
106
|
|
|
@@ -97,7 +109,7 @@ class JamSessionPlugin(BasePlugin):
|
|
|
97
109
|
"""Sessions plugin for litestar."""
|
|
98
110
|
|
|
99
111
|
MODULE = staticmethod(create_session)
|
|
100
|
-
|
|
112
|
+
MIDDLEWARE = SessionMiddleware
|
|
101
113
|
_DI_KEY = "session"
|
|
102
114
|
_CONFIG_KEY = "sessions"
|
|
103
115
|
|
|
@@ -106,6 +118,40 @@ class JamPASETOPlugin(BasePlugin):
|
|
|
106
118
|
"""PASETO plugin for litestar."""
|
|
107
119
|
|
|
108
120
|
MODULE = staticmethod(create_paseto)
|
|
109
|
-
|
|
121
|
+
MIDDLEWARE = PASETOMiddleware
|
|
110
122
|
_DI_KEY = "paseto"
|
|
111
123
|
_CONFIG_KEY = "paseto"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class JamOAuth2Plugin(BasePlugin):
|
|
127
|
+
"""OAuth2 plugin for litestar."""
|
|
128
|
+
|
|
129
|
+
MODULE = staticmethod(create_oauth2)
|
|
130
|
+
_DI_KEY = "oauth2"
|
|
131
|
+
_CONFIG_KEY = "oauth2"
|
|
132
|
+
|
|
133
|
+
def __init__(
|
|
134
|
+
self,
|
|
135
|
+
config: str | dict[str, Any] | None = None,
|
|
136
|
+
pointer: str = GENERIC_POINTER,
|
|
137
|
+
**kwargs,
|
|
138
|
+
) -> None:
|
|
139
|
+
"""Initialize the OAuth2 plugin.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
config (dict[str, Any] | str | None): Jam config as path/to/file or dict.
|
|
143
|
+
pointer (str): Config pointer
|
|
144
|
+
**kwargs: Config arguments if config=None
|
|
145
|
+
"""
|
|
146
|
+
_config: dict[str, Any] | None = (
|
|
147
|
+
__config_maker__(config, pointer) if config else None
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
params = _config.pop(self._CONFIG_KEY) if _config else kwargs
|
|
151
|
+
self._setup_config(params)
|
|
152
|
+
|
|
153
|
+
def on_app_init(self, app_config: AppConfig) -> AppConfig: # noqa
|
|
154
|
+
app_config.dependencies[self._DI_KEY] = Provide(
|
|
155
|
+
lambda: self._auth, sync_to_thread=True
|
|
156
|
+
)
|
|
157
|
+
return app_config
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
"""Starlette integration.
|
|
4
|
+
|
|
5
|
+
Starlette docs: https://starlette.dev
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .objects import BaseUser, SimpleUser
|
|
9
|
+
from .backends import JWTBackend, SessionBackend, PASETOBackend
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"BaseUser",
|
|
14
|
+
"SimpleUser",
|
|
15
|
+
"JWTBackend",
|
|
16
|
+
"SessionBackend",
|
|
17
|
+
"PASETOBackend",
|
|
18
|
+
]
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from starlette.authentication import (
|
|
7
|
+
AuthCredentials,
|
|
8
|
+
AuthenticationBackend,
|
|
9
|
+
UnauthenticatedUser,
|
|
10
|
+
)
|
|
11
|
+
from starlette.authentication import BaseUser as StarletteBaseUser
|
|
12
|
+
from starlette.requests import HTTPConnection
|
|
13
|
+
|
|
14
|
+
from jam.aio.sessions import create_instance as create_session
|
|
15
|
+
from jam.exceptions import JamStarlettePluginConfigError
|
|
16
|
+
from jam.ext.starlette.objects import BaseUser, SimpleUser
|
|
17
|
+
from jam.jwt import JWT
|
|
18
|
+
from jam.paseto import create_instance as create_paseto
|
|
19
|
+
from jam.utils.config_maker import GENERIC_POINTER, __config_maker__
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BaseBackend(AuthenticationBackend):
|
|
23
|
+
"""Base Jam backend."""
|
|
24
|
+
|
|
25
|
+
MODULE: Callable
|
|
26
|
+
_CONFIG_KEY: str
|
|
27
|
+
|
|
28
|
+
def __init__( # noqa
|
|
29
|
+
self,
|
|
30
|
+
config: str | dict[str, Any] | None = None,
|
|
31
|
+
pointer: str = GENERIC_POINTER,
|
|
32
|
+
cookie_name: str | None = None,
|
|
33
|
+
header_name: str | None = None,
|
|
34
|
+
user: type[BaseUser] = SimpleUser,
|
|
35
|
+
**kwargs,
|
|
36
|
+
) -> None:
|
|
37
|
+
if not cookie_name and not header_name:
|
|
38
|
+
raise JamStarlettePluginConfigError(
|
|
39
|
+
message="cookie_name or header_name must be provided.",
|
|
40
|
+
details={
|
|
41
|
+
"cookie_name": cookie_name,
|
|
42
|
+
"header_name": header_name,
|
|
43
|
+
},
|
|
44
|
+
)
|
|
45
|
+
self._cookie_name = cookie_name
|
|
46
|
+
self._header_name = header_name
|
|
47
|
+
self._user = user
|
|
48
|
+
self._config_setup(config, pointer, kwargs)
|
|
49
|
+
|
|
50
|
+
def _get_auth_token(self, connection: HTTPConnection) -> str | None:
|
|
51
|
+
if self._cookie_name:
|
|
52
|
+
token = connection.cookies.get(self._cookie_name, None)
|
|
53
|
+
elif self._header_name:
|
|
54
|
+
token_bear = connection.headers.get(self._header_name, None)
|
|
55
|
+
if token_bear:
|
|
56
|
+
token = token_bear.split("Bearer ")[1] # noqa: E701
|
|
57
|
+
else:
|
|
58
|
+
token = None # noqa: E701
|
|
59
|
+
else:
|
|
60
|
+
raise JamStarlettePluginConfigError(
|
|
61
|
+
message="cookie_name or header_name must be provided.",
|
|
62
|
+
details={
|
|
63
|
+
"cookie_name": self._cookie_name,
|
|
64
|
+
"header_name": self._header_name,
|
|
65
|
+
},
|
|
66
|
+
)
|
|
67
|
+
return token
|
|
68
|
+
|
|
69
|
+
def _config_setup(
|
|
70
|
+
self,
|
|
71
|
+
config: dict[str, Any] | str | None,
|
|
72
|
+
pointer: str,
|
|
73
|
+
kwargs: dict[str, Any],
|
|
74
|
+
) -> None:
|
|
75
|
+
try:
|
|
76
|
+
if config:
|
|
77
|
+
config_ = __config_maker__(config, pointer)[self._CONFIG_KEY]
|
|
78
|
+
self._auth = self.MODULE(**config_)
|
|
79
|
+
else:
|
|
80
|
+
self._auth = self.MODULE(**kwargs)
|
|
81
|
+
except Exception as e:
|
|
82
|
+
raise JamStarlettePluginConfigError(
|
|
83
|
+
message="Error while building auth modile.",
|
|
84
|
+
details={
|
|
85
|
+
"module": self.MODULE.__str__,
|
|
86
|
+
"config": {
|
|
87
|
+
"config": config,
|
|
88
|
+
"pointer": pointer,
|
|
89
|
+
"kwargs": kwargs,
|
|
90
|
+
},
|
|
91
|
+
"config_key": self._CONFIG_KEY,
|
|
92
|
+
"error": str(e),
|
|
93
|
+
},
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class JWTBackend(BaseBackend):
|
|
98
|
+
"""JWT Backend for litestar."""
|
|
99
|
+
|
|
100
|
+
MODULE = JWT
|
|
101
|
+
_CONFIG_KEY = "jwt"
|
|
102
|
+
|
|
103
|
+
async def authenticate( # noqa
|
|
104
|
+
self, conn: HTTPConnection
|
|
105
|
+
) -> tuple[AuthCredentials, StarletteBaseUser] | None:
|
|
106
|
+
setattr(conn.state, "jwt", self._auth)
|
|
107
|
+
token = self._get_auth_token(conn)
|
|
108
|
+
if token:
|
|
109
|
+
data = self._auth.decode(token)
|
|
110
|
+
user = self._user.from_payload(data)
|
|
111
|
+
return AuthCredentials(["authenticated"]), user
|
|
112
|
+
|
|
113
|
+
return AuthCredentials(None), UnauthenticatedUser()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class SessionBackend(BaseBackend):
|
|
117
|
+
"""Session backend."""
|
|
118
|
+
|
|
119
|
+
MODULE = staticmethod(create_session)
|
|
120
|
+
_CONFIG_KEY = "sessions"
|
|
121
|
+
|
|
122
|
+
async def authenticate( # noqa
|
|
123
|
+
self, conn: HTTPConnection
|
|
124
|
+
) -> tuple[AuthCredentials, StarletteBaseUser] | None:
|
|
125
|
+
setattr(conn.state, "session", self._auth)
|
|
126
|
+
session_id = self._get_auth_token(conn)
|
|
127
|
+
if session_id:
|
|
128
|
+
data = await self._auth.get(session_id)
|
|
129
|
+
if data:
|
|
130
|
+
user = self._user.from_payload(data)
|
|
131
|
+
return AuthCredentials(["authenticated"]), user
|
|
132
|
+
|
|
133
|
+
return AuthCredentials(None), UnauthenticatedUser()
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class PASETOBackend(BaseBackend):
|
|
137
|
+
"""PASETO auth backend."""
|
|
138
|
+
|
|
139
|
+
MODULE = staticmethod(create_paseto)
|
|
140
|
+
_CONFIG_KEY = "paseto"
|
|
141
|
+
|
|
142
|
+
async def authenticate( # noqa
|
|
143
|
+
self, conn: HTTPConnection
|
|
144
|
+
) -> tuple[AuthCredentials, StarletteBaseUser] | None:
|
|
145
|
+
setattr(conn.state, "paseto", self._auth)
|
|
146
|
+
token = self._get_auth_token(conn)
|
|
147
|
+
if token:
|
|
148
|
+
data = self._auth.decode(token)
|
|
149
|
+
if data:
|
|
150
|
+
user = self._user.from_payload(data)
|
|
151
|
+
return AuthCredentials(["authenticated"]), user
|
|
152
|
+
|
|
153
|
+
return AuthCredentials(None), UnauthenticatedUser()
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, TypeVar
|
|
6
|
+
|
|
7
|
+
from starlette.authentication import BaseUser as StarletteBaseUser
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
User = TypeVar("User", bound="BaseUser")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BaseUser(ABC, StarletteBaseUser):
|
|
14
|
+
"""BaseUser with builder from payload."""
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def from_payload(cls, payload: dict[str, Any]) -> User:
|
|
19
|
+
"""Create instance by payload.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
payload (dict[str, Any]): Payload from auth
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
```python
|
|
26
|
+
|
|
27
|
+
class MyUser(JamBaseUser):
|
|
28
|
+
id: int
|
|
29
|
+
username: str
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def from_payload(cls, payload):
|
|
33
|
+
return cls(
|
|
34
|
+
id=payload["id"],
|
|
35
|
+
username=payload["username"]
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
payload = jwt.decode(token)
|
|
39
|
+
user = MyUser.from_payload(payload)
|
|
40
|
+
```
|
|
41
|
+
"""
|
|
42
|
+
raise NotImplementedError
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass(slots=True)
|
|
46
|
+
class SimpleUser(BaseUser):
|
|
47
|
+
"""Simple user with payload only."""
|
|
48
|
+
|
|
49
|
+
payload: dict[str, Any]
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def from_payload(cls, payload: dict[str, Any]): # noqa
|
|
53
|
+
return cls(payload=payload)
|
|
@@ -100,7 +100,11 @@ class BaseAlgorithm(ABC):
|
|
|
100
100
|
from pathlib import Path
|
|
101
101
|
|
|
102
102
|
path = Path(data)
|
|
103
|
-
|
|
103
|
+
try:
|
|
104
|
+
is_file = path.is_file()
|
|
105
|
+
except OSError:
|
|
106
|
+
is_file = False
|
|
107
|
+
return path.read_bytes() if is_file else data.encode()
|
|
104
108
|
|
|
105
109
|
def _load_private_key(
|
|
106
110
|
self, key_bytes: bytes | None, key_obj: Any | None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jamlib
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.0b13
|
|
4
4
|
Summary: Simple and universal library for authorization.
|
|
5
5
|
Author-email: Makridenko Adrian <adrianmakridenko@duck.com>, Ksenia Travnikova <kseniatravnikova@duck.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -41,8 +41,8 @@ src/jam/ext/litestar/middleware.py
|
|
|
41
41
|
src/jam/ext/litestar/objects.py
|
|
42
42
|
src/jam/ext/litestar/plugins.py
|
|
43
43
|
src/jam/ext/starlette/__init__.py
|
|
44
|
-
src/jam/ext/starlette/
|
|
45
|
-
src/jam/ext/starlette/
|
|
44
|
+
src/jam/ext/starlette/backends.py
|
|
45
|
+
src/jam/ext/starlette/objects.py
|
|
46
46
|
src/jam/jwt/__algorithms__.py
|
|
47
47
|
src/jam/jwt/__base__.py
|
|
48
48
|
src/jam/jwt/__init__.py
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
from typing import Any
|
|
4
|
-
|
|
5
|
-
from starlette.authentication import (
|
|
6
|
-
AuthCredentials,
|
|
7
|
-
AuthenticationBackend,
|
|
8
|
-
AuthenticationError,
|
|
9
|
-
BaseUser,
|
|
10
|
-
)
|
|
11
|
-
from starlette.requests import HTTPConnection
|
|
12
|
-
|
|
13
|
-
from jam.__base__ import BaseJam
|
|
14
|
-
from jam.utils.await_maybe import await_maybe
|
|
15
|
-
|
|
16
|
-
from .value import Payload
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class JWTBackend(AuthenticationBackend):
|
|
20
|
-
"""JWT Backend for Starlette AuthenticationMiddleware."""
|
|
21
|
-
|
|
22
|
-
def __init__(
|
|
23
|
-
self,
|
|
24
|
-
jam: BaseJam,
|
|
25
|
-
cookie_name: str | None = None,
|
|
26
|
-
header_name: str | None = "Authorization",
|
|
27
|
-
) -> None:
|
|
28
|
-
"""Constructor.
|
|
29
|
-
|
|
30
|
-
Args:
|
|
31
|
-
jam (BaseJam): Jam instance
|
|
32
|
-
cookie_name (str | None): Access token cookie name
|
|
33
|
-
header_name (str | None): Access token header name
|
|
34
|
-
"""
|
|
35
|
-
self._jam = jam
|
|
36
|
-
self.cookie_name = cookie_name
|
|
37
|
-
self.header_name = header_name
|
|
38
|
-
self.__use_list = bool(getattr(self._jam.jwt, "list", False))
|
|
39
|
-
|
|
40
|
-
async def authenticate(
|
|
41
|
-
self, conn: HTTPConnection
|
|
42
|
-
) -> tuple[AuthCredentials, BaseUser] | None:
|
|
43
|
-
"""Starlette authentication handler."""
|
|
44
|
-
logger = self._jam._logger
|
|
45
|
-
token = None
|
|
46
|
-
|
|
47
|
-
logger.debug("JWTBackend: Attempting to extract token from request")
|
|
48
|
-
if self.cookie_name:
|
|
49
|
-
token = conn.cookies.get(self.cookie_name)
|
|
50
|
-
if token:
|
|
51
|
-
logger.debug(f"Token found in cookie '{self.cookie_name}'")
|
|
52
|
-
|
|
53
|
-
if not token and self.header_name:
|
|
54
|
-
header = conn.headers.get(self.header_name)
|
|
55
|
-
if header and header.startswith("Bearer "):
|
|
56
|
-
token = header.split("Bearer ")[1]
|
|
57
|
-
logger.debug(f"Token found in header '{self.header_name}'")
|
|
58
|
-
|
|
59
|
-
if not token:
|
|
60
|
-
logger.debug("No token found in request")
|
|
61
|
-
return None
|
|
62
|
-
|
|
63
|
-
logger.debug(
|
|
64
|
-
f"Verifying JWT token (length: {len(token)} chars), check_list={self.__use_list}"
|
|
65
|
-
)
|
|
66
|
-
try:
|
|
67
|
-
payload: dict[str, Any] = await await_maybe(
|
|
68
|
-
self._jam.jwt_verify_token(
|
|
69
|
-
token=token, check_exp=True, check_list=self.__use_list
|
|
70
|
-
)
|
|
71
|
-
)
|
|
72
|
-
logger.debug(
|
|
73
|
-
f"JWT token verified successfully, payload keys: {list(payload.keys())}"
|
|
74
|
-
)
|
|
75
|
-
except Exception as e:
|
|
76
|
-
logger.warning(f"Token verify error: {e}")
|
|
77
|
-
raise AuthenticationError("Token verification failed.")
|
|
78
|
-
|
|
79
|
-
return AuthCredentials(["authenticated"]), Payload(payload=payload)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
class SessionBackend(AuthenticationBackend):
|
|
83
|
-
"""Sessions backend for starlette."""
|
|
84
|
-
|
|
85
|
-
def __init__(
|
|
86
|
-
self,
|
|
87
|
-
jam: BaseJam,
|
|
88
|
-
cookie_name: str | None = "sessionId",
|
|
89
|
-
header_name: str | None = None,
|
|
90
|
-
) -> None:
|
|
91
|
-
"""Constructor.
|
|
92
|
-
|
|
93
|
-
Args:
|
|
94
|
-
jam (BaseJam): Jam instance
|
|
95
|
-
cookie_name (str | None): Session id cookie name
|
|
96
|
-
header_name (str | None): Session id header name
|
|
97
|
-
"""
|
|
98
|
-
self._jam = jam
|
|
99
|
-
self.cookie_name = cookie_name
|
|
100
|
-
self.header_name = header_name
|
|
101
|
-
|
|
102
|
-
async def authenticate(
|
|
103
|
-
self, conn: HTTPConnection
|
|
104
|
-
) -> tuple[AuthCredentials, BaseUser] | None:
|
|
105
|
-
"""Starlette authentication handler."""
|
|
106
|
-
logger = self._jam._logger
|
|
107
|
-
session_id = None
|
|
108
|
-
|
|
109
|
-
logger.debug(
|
|
110
|
-
"SessionBackend: Attempting to extract session ID from request"
|
|
111
|
-
)
|
|
112
|
-
if self.cookie_name:
|
|
113
|
-
session_id = conn.cookies.get(self.cookie_name)
|
|
114
|
-
if session_id:
|
|
115
|
-
logger.debug(f"Session ID found in cookie '{self.cookie_name}'")
|
|
116
|
-
|
|
117
|
-
if not session_id and self.header_name:
|
|
118
|
-
header = conn.headers.get(self.header_name)
|
|
119
|
-
if header and header.startswith("Bearer "):
|
|
120
|
-
session_id = header.split("Bearer ")[1]
|
|
121
|
-
logger.debug(f"Session ID found in header '{self.header_name}'")
|
|
122
|
-
|
|
123
|
-
if not session_id:
|
|
124
|
-
logger.debug("No session ID found in request")
|
|
125
|
-
return None
|
|
126
|
-
|
|
127
|
-
logger.debug(f"Getting session data for session ID: {session_id}")
|
|
128
|
-
try:
|
|
129
|
-
payload: dict[str, Any] | None = await await_maybe( # type: ignore[arg-type]
|
|
130
|
-
self._jam.session_get(session_id) # type: ignore[arg-type]
|
|
131
|
-
)
|
|
132
|
-
if payload:
|
|
133
|
-
logger.debug(
|
|
134
|
-
f"Session data retrieved successfully, keys: {list(payload.keys())}"
|
|
135
|
-
)
|
|
136
|
-
else:
|
|
137
|
-
logger.debug(f"Session {session_id} not found")
|
|
138
|
-
# TODO: Return unauthized user
|
|
139
|
-
except Exception as e:
|
|
140
|
-
logger.warning(f"Session retrieval error: {e}")
|
|
141
|
-
raise AuthenticationError("Token verification failed.")
|
|
142
|
-
|
|
143
|
-
return AuthCredentials(["authenticated"]), Payload(payload=payload)
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
from typing import Any
|
|
4
|
-
|
|
5
|
-
from starlette.authentication import BaseUser
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Payload(BaseUser):
|
|
9
|
-
"""Auth payload."""
|
|
10
|
-
|
|
11
|
-
def __init__(self, payload: dict[str, Any] | None):
|
|
12
|
-
"""Auth payload."""
|
|
13
|
-
self.payload = payload
|
|
14
|
-
|
|
15
|
-
@property
|
|
16
|
-
def is_authenticated(self) -> bool:
|
|
17
|
-
"""Auth checker."""
|
|
18
|
-
return True
|
|
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
|
|
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
|