jamlib 3.2.0rc0__tar.gz → 3.3.0__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.
Files changed (136) hide show
  1. {jamlib-3.2.0rc0/src/jamlib.egg-info → jamlib-3.3.0}/PKG-INFO +7 -3
  2. {jamlib-3.2.0rc0 → jamlib-3.3.0}/README.md +6 -2
  3. {jamlib-3.2.0rc0 → jamlib-3.3.0}/pyproject.toml +1 -1
  4. jamlib-3.3.0/src/jam/__defaults__.py +21 -0
  5. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/__init__.py +1 -1
  6. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/__base__.py +8 -0
  7. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/instance.py +21 -9
  8. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/sessions/__base__.py +5 -1
  9. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/exceptions/__init__.py +20 -0
  10. jamlib-3.3.0/src/jam/exceptions/saml.py +66 -0
  11. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/flask/extensions.py +2 -0
  12. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/litestar/middleware.py +7 -7
  13. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/litestar/objects.py +2 -5
  14. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/litestar/plugins.py +3 -0
  15. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/starlette/backends.py +2 -0
  16. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/starlette/objects.py +5 -6
  17. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/__algorithms__.py +9 -0
  18. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/__base__.py +16 -11
  19. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/jwe.py +2 -0
  20. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/jwk.py +0 -9
  21. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/jws.py +5 -1
  22. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/jwt.py +64 -35
  23. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/lists/redis.py +5 -3
  24. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/paseto/v1.py +4 -0
  25. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/paseto/v2.py +4 -0
  26. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/paseto/v3.py +4 -0
  27. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/paseto/v4.py +4 -0
  28. jamlib-3.3.0/src/jam/saml/__base__.py +577 -0
  29. jamlib-3.3.0/src/jam/saml/__init__.py +129 -0
  30. jamlib-3.3.0/src/jam/saml/binding.py +188 -0
  31. jamlib-3.3.0/src/jam/saml/encryption.py +244 -0
  32. jamlib-3.3.0/src/jam/saml/metadata.py +211 -0
  33. jamlib-3.3.0/src/jam/saml/saml.py +1943 -0
  34. jamlib-3.3.0/src/jam/saml/signature.py +287 -0
  35. jamlib-3.3.0/src/jam/saml/types.py +185 -0
  36. jamlib-3.3.0/src/jam/saml/xml.py +174 -0
  37. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/sessions/__base__.py +5 -1
  38. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/tests/clients.py +271 -53
  39. jamlib-3.3.0/src/jam/tests/fakers.py +187 -0
  40. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/config_maker.py +15 -0
  41. {jamlib-3.2.0rc0 → jamlib-3.3.0/src/jamlib.egg-info}/PKG-INFO +7 -3
  42. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jamlib.egg-info/SOURCES.txt +11 -0
  43. jamlib-3.2.0rc0/src/jam/tests/fakers.py +0 -102
  44. {jamlib-3.2.0rc0 → jamlib-3.3.0}/LICENSE.md +0 -0
  45. {jamlib-3.2.0rc0 → jamlib-3.3.0}/setup.cfg +0 -0
  46. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/__base__.py +0 -0
  47. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/__base_encoder__.py +0 -0
  48. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/__deprecated__.py +0 -0
  49. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/__init__.py +0 -0
  50. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/jwt/__init__.py +0 -0
  51. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/oauth2/__base__.py +0 -0
  52. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/oauth2/__init__.py +0 -0
  53. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/oauth2/builtin/__init__.py +0 -0
  54. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/oauth2/builtin/github.py +0 -0
  55. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/oauth2/builtin/gitlab.py +0 -0
  56. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/oauth2/builtin/google.py +0 -0
  57. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/oauth2/builtin/yandex.py +0 -0
  58. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/oauth2/client.py +0 -0
  59. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/sessions/__init__.py +0 -0
  60. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/sessions/json.py +0 -0
  61. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/aio/sessions/redis.py +0 -0
  62. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/cli/__init__.py +0 -0
  63. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/cli/cli.py +0 -0
  64. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/cli/commands/__init__.py +0 -0
  65. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/cli/commands/keys.py +0 -0
  66. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/cli/commands/password.py +0 -0
  67. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/encoders.py +0 -0
  68. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/exceptions/base.py +0 -0
  69. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/exceptions/jose.py +0 -0
  70. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/exceptions/jwt.py +0 -0
  71. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/exceptions/oauth2.py +0 -0
  72. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/exceptions/paseto.py +0 -0
  73. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/exceptions/plugins.py +0 -0
  74. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/exceptions/sessions.py +0 -0
  75. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/__init__.py +0 -0
  76. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/fastapi/__init__.py +0 -0
  77. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/flask/__init__.py +0 -0
  78. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/flask/objects.py +0 -0
  79. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/litestar/__init__.py +0 -0
  80. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/ext/starlette/__init__.py +0 -0
  81. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/instance.py +0 -0
  82. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/__init__.py +0 -0
  83. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/lists/__base__.py +0 -0
  84. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/lists/__init__.py +0 -0
  85. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/lists/json.py +0 -0
  86. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/lists/memory.py +0 -0
  87. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jose/utils.py +0 -0
  88. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jwt/__algorithms__.py +0 -0
  89. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jwt/__base__.py +0 -0
  90. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jwt/__init__.py +0 -0
  91. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jwt/__types__.py +0 -0
  92. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jwt/lists/__base__.py +0 -0
  93. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jwt/lists/__init__.py +0 -0
  94. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jwt/lists/json.py +0 -0
  95. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jwt/lists/redis.py +0 -0
  96. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jwt/module.py +0 -0
  97. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/jwt/utils.py +0 -0
  98. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/logger.py +0 -0
  99. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/oauth2/__base__.py +0 -0
  100. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/oauth2/__init__.py +0 -0
  101. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/oauth2/builtin/__init__.py +0 -0
  102. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/oauth2/builtin/github.py +0 -0
  103. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/oauth2/builtin/gitlab.py +0 -0
  104. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/oauth2/builtin/google.py +0 -0
  105. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/oauth2/builtin/yandex.py +0 -0
  106. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/oauth2/client.py +0 -0
  107. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/otp/__base__.py +0 -0
  108. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/otp/__init__.py +0 -0
  109. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/otp/hotp.py +0 -0
  110. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/otp/totp.py +0 -0
  111. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/paseto/__base__.py +0 -0
  112. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/paseto/__init__.py +0 -0
  113. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/paseto/utils.py +0 -0
  114. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/plugins/__base__.py +0 -0
  115. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/plugins/__init__.py +0 -0
  116. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/py.typed +0 -0
  117. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/sessions/__init__.py +0 -0
  118. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/sessions/json.py +0 -0
  119. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/sessions/redis.py +0 -0
  120. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/tests/__init__.py +0 -0
  121. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/__init__.py +0 -0
  122. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/aes.py +0 -0
  123. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/await_maybe.py +0 -0
  124. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/basic_auth.py +0 -0
  125. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/ed.py +0 -0
  126. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/otp_keys.py +0 -0
  127. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/rsa.py +0 -0
  128. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/salt_hash.py +0 -0
  129. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/symmetric.py +0 -0
  130. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/version_check.py +0 -0
  131. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/xchacha20poly1305.py +0 -0
  132. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jam/utils/xor.py +0 -0
  133. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jamlib.egg-info/dependency_links.txt +0 -0
  134. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jamlib.egg-info/entry_points.txt +0 -0
  135. {jamlib-3.2.0rc0 → jamlib-3.3.0}/src/jamlib.egg-info/requires.txt +0 -0
  136. {jamlib-3.2.0rc0 → jamlib-3.3.0}/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.2.0rc0
3
+ Version: 3.3.0
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
@@ -62,6 +62,8 @@ Dynamic: license-file
62
62
  [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/lyaguxafrog/jam)
63
63
  [![GitHub License](https://img.shields.io/github/license/lyaguxafrog/jam)](https://github.com/lyaguxafrog/jam/blob/master/LICENSE.md)
64
64
 
65
+ **Jam (Jam Auth Module)** - A universal auth* combine that provides popular auth mechanisms strictly according to the specification.
66
+
65
67
  * Documentation: [jam.makridenko.ru](https://jam.makridenko.ru)
66
68
  * Changelog: [CHANGELOG.md](https://github.com/lyaguxafrog/jam/blob/master/CHANGELOG.md)
67
69
 
@@ -77,7 +79,7 @@ from jam import Jam
77
79
 
78
80
  jam = Jam(config="config.toml")
79
81
 
80
- jwt = jam.jwt_create({"user": 1})
82
+ jwt = jam.jwt_encode(payload={"user": 1})
81
83
  session_id = jam.session_create(session_key="username", data={"user": 1})
82
84
  otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
83
85
  ```
@@ -85,11 +87,12 @@ otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
85
87
  ## Why Jam?
86
88
  Jam is a library that provides the most popular AUTH* mechanisms right out of the box.
87
89
 
88
- * [JOSE](https://jam.makridenko.ru/usage/jose/index/)
90
+ * [JOSE](https://jam.makridenko.ru/usage/jose/)
89
91
  * [PASETO](https://jam.makridenko.ru/usage/paseto/)
90
92
  * [Server side sessions](https://jam.makridenko.ru/usage/sessions/)
91
93
  * [OTP](https://jam.makridenko.ru/usage/otp/)
92
94
  * [OAuth2](https://jam.makridenko.ru/usage/oauth2/)
95
+ * [SAML](https://jam.makridenko.ru/usage/saml/)
93
96
 
94
97
  ### Framework integrations
95
98
 
@@ -115,5 +118,6 @@ Here is a comparison with other libraries:
115
118
  | Server side sessions | ✅ | ✅ | ❌ | ❌ | ❌ |
116
119
  | OTP | ✅ | ❌ | ❌ | ❌ | ✅ |
117
120
  | OAuth2 | ✅ | ✅ | ❌ | ✅ | ❌ |
121
+ | SAML 2.0 | ✅ | ❌ | ❌ | ❌ | ❌ |
118
122
  | Flexible config | ✅ | ❌ | ❌ | ❌ | ❌ |
119
123
  | Modularity | ✅ | ❌ | ❌ | ❌ | ❌ |
@@ -9,6 +9,8 @@
9
9
  [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/lyaguxafrog/jam)
10
10
  [![GitHub License](https://img.shields.io/github/license/lyaguxafrog/jam)](https://github.com/lyaguxafrog/jam/blob/master/LICENSE.md)
11
11
 
12
+ **Jam (Jam Auth Module)** - A universal auth* combine that provides popular auth mechanisms strictly according to the specification.
13
+
12
14
  * Documentation: [jam.makridenko.ru](https://jam.makridenko.ru)
13
15
  * Changelog: [CHANGELOG.md](https://github.com/lyaguxafrog/jam/blob/master/CHANGELOG.md)
14
16
 
@@ -24,7 +26,7 @@ from jam import Jam
24
26
 
25
27
  jam = Jam(config="config.toml")
26
28
 
27
- jwt = jam.jwt_create({"user": 1})
29
+ jwt = jam.jwt_encode(payload={"user": 1})
28
30
  session_id = jam.session_create(session_key="username", data={"user": 1})
29
31
  otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
30
32
  ```
@@ -32,11 +34,12 @@ otp_code = jam.otp_code(secret="3DB7FOAOFBCI3WFDRE7EPF43CA")
32
34
  ## Why Jam?
33
35
  Jam is a library that provides the most popular AUTH* mechanisms right out of the box.
34
36
 
35
- * [JOSE](https://jam.makridenko.ru/usage/jose/index/)
37
+ * [JOSE](https://jam.makridenko.ru/usage/jose/)
36
38
  * [PASETO](https://jam.makridenko.ru/usage/paseto/)
37
39
  * [Server side sessions](https://jam.makridenko.ru/usage/sessions/)
38
40
  * [OTP](https://jam.makridenko.ru/usage/otp/)
39
41
  * [OAuth2](https://jam.makridenko.ru/usage/oauth2/)
42
+ * [SAML](https://jam.makridenko.ru/usage/saml/)
40
43
 
41
44
  ### Framework integrations
42
45
 
@@ -62,5 +65,6 @@ Here is a comparison with other libraries:
62
65
  | Server side sessions | ✅ | ✅ | ❌ | ❌ | ❌ |
63
66
  | OTP | ✅ | ❌ | ❌ | ❌ | ✅ |
64
67
  | OAuth2 | ✅ | ✅ | ❌ | ✅ | ❌ |
68
+ | SAML 2.0 | ✅ | ❌ | ❌ | ❌ | ❌ |
65
69
  | Flexible config | ✅ | ❌ | ❌ | ❌ | ❌ |
66
70
  | Modularity | ✅ | ❌ | ❌ | ❌ | ❌ |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "jamlib"
3
- version = "3.2.0rc0"
3
+ version = "3.3.0"
4
4
  description = "Simple and universal library for authorization."
5
5
  authors = [
6
6
  {name = "Makridenko Adrian",email = "adrianmakridenko@duck.com"},
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from dataclasses import dataclass
4
+ import os
5
+
6
+
7
+ @dataclass(slots=True, frozen=True)
8
+ class DEFAULTS:
9
+ """Jam defaults vars."""
10
+
11
+ DEBUG: bool = os.getenv("JAM_DEBUG", "False") == "True"
12
+ """Debug flag. Use only while developing jam module."""
13
+
14
+ TEMP_DIR: str = os.getenv("JAM_TMP_DIR", "/tmp/jam/")
15
+ """tmp directory for storing temporary files and blobs."""
16
+
17
+ ENABLE_PLUGINS: bool = os.getenv("JAM_ENABLE_PLUGINS", "1") == "0"
18
+ """Enabling experimental plugin features."""
19
+
20
+
21
+ defaults = DEFAULTS()
@@ -10,5 +10,5 @@ from jam.__base__ import BaseJam
10
10
  from jam.instance import Jam
11
11
 
12
12
 
13
- __version__ = "3.2.0rc0"
13
+ __version__ = "3.3.0"
14
14
  __all__ = ["Jam", "BaseJam"]
@@ -4,6 +4,7 @@ from abc import abstractmethod
4
4
  from typing import Any
5
5
 
6
6
  from jam.__base__ import BaseJam
7
+ from jam.__deprecated__ import deprecated
7
8
  from jam.aio.oauth2.__base__ import BaseAsyncOAuth2Client
8
9
  from jam.aio.sessions.__base__ import BaseAsyncSessionModule
9
10
  from jam.jose.__base__ import BaseJWE, BaseJWS
@@ -21,11 +22,17 @@ class BaseAsyncJam(BaseJam):
21
22
  jwe: BaseJWE | None = None # type: ignore[override]
22
23
 
23
24
  @abstractmethod
25
+ @deprecated(
26
+ "This method is deprecated; the JWT payload is generated automatically in accordance with the specification."
27
+ )
24
28
  async def jwt_make_payload( # type: ignore[override]
25
29
  self, exp: int | None, data: dict[str, Any]
26
30
  ) -> dict[str, Any]:
27
31
  """Make JWT-specific payload.
28
32
 
33
+ !!! Deprecated
34
+ This method is deprecated; the JWT payload is generated automatically in accordance with the specification.
35
+
29
36
  Args:
30
37
  exp (int | None): Token expire, if None -> use default
31
38
  data (dict[str, Any]): Data to payload
@@ -36,6 +43,7 @@ class BaseAsyncJam(BaseJam):
36
43
  raise NotImplementedError
37
44
 
38
45
  @abstractmethod
46
+ @deprecated("Use jam.jwt_encode")
39
47
  async def jwt_create( # type: ignore[override]
40
48
  self, payload: dict[str, Any]
41
49
  ) -> str:
@@ -1,10 +1,10 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- import datetime
4
3
  import time
5
4
  from typing import Any
6
5
  import uuid
7
6
 
7
+ from jam.__deprecated__ import deprecated
8
8
  from jam.aio.__base__ import BaseAsyncJam
9
9
  from jam.exceptions import (
10
10
  JamConfigurationError,
@@ -30,11 +30,17 @@ class Jam(BaseAsyncJam):
30
30
  "otp": "jam.otp.__base__.OTPConfig",
31
31
  }
32
32
 
33
+ @deprecated(
34
+ "This method is deprecated; the JWT payload is generated automatically in accordance with the specification."
35
+ )
33
36
  async def jwt_make_payload(
34
37
  self, exp: int | None, data: dict[str, Any]
35
38
  ) -> dict[str, Any]:
36
39
  """Make JWT-specific payload.
37
40
 
41
+ !!! Deprecated
42
+ This method is deprecated; the JWT payload is generated automatically in accordance with the specification.
43
+
38
44
  Args:
39
45
  exp (int | None): Token expire
40
46
  data (dict[str, Any]): Data to payload
@@ -42,17 +48,22 @@ class Jam(BaseAsyncJam):
42
48
  Returns:
43
49
  dict[str, Any]: Payload
44
50
  """
51
+ now = time.time()
45
52
  payload = {
46
- "iat": datetime.datetime.now().timestamp(),
47
- "exp": (datetime.datetime.now().timestamp() + exp) if exp else None,
53
+ "iat": now,
54
+ "exp": (now + exp) if exp else None,
48
55
  "jti": str(uuid.uuid4()),
49
56
  }
50
57
  payload = payload | data
51
58
  return payload
52
59
 
60
+ @deprecated("Use jam.jwt_encode")
53
61
  async def jwt_create(self, payload: dict[str, Any]) -> str:
54
62
  """Create JWT token.
55
63
 
64
+ !!! Deprecated
65
+ Use Jam.jwt_encode
66
+
56
67
  Args:
57
68
  payload (dict[str, Any]): Data payload
58
69
 
@@ -244,7 +255,10 @@ class Jam(BaseAsyncJam):
244
255
  """
245
256
  assert self.jwe is not None
246
257
  self._logger.debug(f"Encrypting data with JWE, header: {header}")
247
- token = self.jwe.encrypt(data, header)
258
+ token = self.jwe.encrypt(
259
+ self._serializer.dumps(data) if isinstance(data, dict) else data,
260
+ header,
261
+ )
248
262
  self._logger.debug(f"JWE token created, length: {len(token)}")
249
263
  return token
250
264
 
@@ -369,8 +383,8 @@ class Jam(BaseAsyncJam):
369
383
  async def otp_uri(
370
384
  self,
371
385
  secret: str,
372
- name: str | None = None,
373
- issuer: str | None = None,
386
+ name: str,
387
+ issuer: str,
374
388
  counter: int | None = None,
375
389
  ) -> str:
376
390
  """Generates an otpauth:// URI for Google Authenticator.
@@ -388,9 +402,7 @@ class Jam(BaseAsyncJam):
388
402
  assert self._otp is not None
389
403
  return self._otp(
390
404
  secret=secret, digits=self.otp.digits, digest=self.otp.digest
391
- ).provisioning_uri(
392
- name=name or "", issuer=issuer or "", counter=counter
393
- )
405
+ ).provisioning_uri(name=name, issuer=issuer, counter=counter)
394
406
 
395
407
  async def otp_verify_code(
396
408
  self,
@@ -7,9 +7,11 @@ from uuid import uuid4
7
7
 
8
8
  from cryptography.fernet import Fernet
9
9
 
10
- from jam.encoders import BaseEncoder, JsonEncoder
10
+ from jam.__base_encoder__ import BaseEncoder
11
+ from jam.encoders import JsonEncoder
11
12
  from jam.exceptions import JamSessionEmptyAESKey
12
13
  from jam.logger import BaseLogger
14
+ from jam.utils.config_maker import __key_loader__
13
15
 
14
16
 
15
17
  class BaseAsyncSessionModule(ABC):
@@ -32,6 +34,8 @@ class BaseAsyncSessionModule(ABC):
32
34
  raise JamSessionEmptyAESKey
33
35
  if is_session_crypt:
34
36
  assert session_aes_secret is not None
37
+ if isinstance(session_aes_secret, str):
38
+ session_aes_secret = __key_loader__(session_aes_secret)
35
39
  self._code_session_key = Fernet(session_aes_secret)
36
40
 
37
41
  def __encode_session_id__(self, data: str) -> str:
@@ -45,6 +45,17 @@ from .sessions import (
45
45
  JamSessionEmptyAESKey,
46
46
  JamSessionNotFound,
47
47
  )
48
+ from .saml import (
49
+ JamSAMLError,
50
+ JamSAMLExpired,
51
+ JamSAMLNotYetValid,
52
+ JamSAMLInvalidAudience,
53
+ JamSAMLInvalidIssuer,
54
+ JamSAMLEmptyPrivateKey,
55
+ JamSAMLEmptyPublicKey,
56
+ JamSAMLUnsupportedAlgorithm,
57
+ JamSAMLValidationError,
58
+ )
48
59
 
49
60
 
50
61
  __all__ = [
@@ -81,4 +92,13 @@ __all__ = [
81
92
  "JamStarlettePluginError",
82
93
  "JamSessionNotFound",
83
94
  "JamSessionEmptyAESKey",
95
+ "JamSAMLError",
96
+ "JamSAMLExpired",
97
+ "JamSAMLNotYetValid",
98
+ "JamSAMLInvalidAudience",
99
+ "JamSAMLInvalidIssuer",
100
+ "JamSAMLEmptyPrivateKey",
101
+ "JamSAMLEmptyPublicKey",
102
+ "JamSAMLUnsupportedAlgorithm",
103
+ "JamSAMLValidationError",
84
104
  ]
@@ -0,0 +1,66 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from .base import JamConfigurationError, JamError, JamValidationError
4
+
5
+
6
+ class JamSAMLError(JamError):
7
+ default_message = "SAML error occurred."
8
+ default_code = "saml.error"
9
+
10
+
11
+ class JamSAMLExpired(JamError):
12
+ default_message = "SAML assertion has expired."
13
+ default_code = "saml.assertion_expired"
14
+
15
+
16
+ class JamSAMLNotYetValid(JamError):
17
+ default_message = "SAML assertion is not yet valid."
18
+ default_code = "saml.assertion_not_yet_valid"
19
+
20
+
21
+ class JamSAMLInvalidAudience(JamError):
22
+ default_message = "SAML assertion audience validation failed."
23
+ default_code = "saml.invalid_audience"
24
+
25
+
26
+ class JamSAMLInvalidIssuer(JamError):
27
+ default_message = "SAML assertion issuer validation failed."
28
+ default_code = "saml.invalid_issuer"
29
+
30
+
31
+ class JamSAMLEmptyPrivateKey(JamConfigurationError):
32
+ default_message = "For SAML signing, you must specify `private_key`."
33
+ default_code = "saml.config.empty_private_key"
34
+
35
+
36
+ class JamSAMLEmptyPublicKey(JamConfigurationError):
37
+ default_message = "For SAML verification, you must specify `public_key`."
38
+ default_code = "saml.config.empty_public_key"
39
+
40
+
41
+ class JamSAMLUnsupportedAlgorithm(JamConfigurationError):
42
+ default_message = "Unsupported SAML algorithm."
43
+ default_code = "saml.config.unsupported_algorithm"
44
+
45
+
46
+ class JamSAMLValidationError(JamValidationError):
47
+ default_message = "SAML assertion validation failed."
48
+ default_code = "saml.validation.assertion_error"
49
+
50
+
51
+ class JamSAMLInvalidRecipient(JamError):
52
+ default_message = (
53
+ "SAML assertion SubjectConfirmationData Recipient "
54
+ "does not match the expected ACS URL."
55
+ )
56
+ default_code = "saml.invalid_recipient"
57
+
58
+
59
+ class JamSAMLReplayDetected(JamError):
60
+ default_message = "SAML message ID has already been consumed (replay attack)."
61
+ default_code = "saml.replay_detected"
62
+
63
+
64
+ class JamSAMLSOAPError(JamError):
65
+ default_message = "SAML SOAP/artifact resolution failed."
66
+ default_code = "saml.soap_error"
@@ -89,6 +89,8 @@ class BaseAuthExtension(BaseExtension):
89
89
  _config: dict[str, Any] | None = (
90
90
  __config_maker__(config, pointer) if config else None
91
91
  )
92
+ if _config and _config.get("jose", None) and self.MODULE == create_jwt:
93
+ _config = _config["jose"]
92
94
 
93
95
  params = _config.pop(self._CONFIG_KEY) if _config else kwargs
94
96
  super().__init__(app=app, **params)
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- from collections.abc import Callable
3
+ from typing import Any
4
4
 
5
5
  from litestar.connection import ASGIConnection
6
6
  from litestar.middleware import (
@@ -18,7 +18,7 @@ from jam.paseto import BasePASETO
18
18
  class BaseMiddleware(AbstractAuthenticationMiddleware):
19
19
  """Base Jam middleware for litestar."""
20
20
 
21
- AUTH_MODULE: Callable
21
+ AUTH_MODULE: Any
22
22
  HEADER_NAME: str | None
23
23
  COOKIE_NAME: str | None
24
24
  BEARER: bool = False
@@ -95,7 +95,7 @@ class SessionMiddleware(BaseMiddleware):
95
95
  if not data:
96
96
  return AuthenticationResult(None, auth=token_model)
97
97
  user = self.USER.from_payload(data)
98
- return AuthenticationResult(user, token)
98
+ return AuthenticationResult(user=user, auth=token_model)
99
99
  except Exception as e:
100
100
  raise JamLitestarPluginError(message=str(e))
101
101
 
@@ -113,10 +113,10 @@ class PASETOMiddleware(BaseMiddleware):
113
113
  if not token:
114
114
  return AuthenticationResult(None, auth=token_model)
115
115
  try:
116
- data = self.AUTH_MODULE.decode(token)
117
- if not data:
116
+ result = self.AUTH_MODULE.decode(token)
117
+ if not result:
118
118
  return AuthenticationResult(None, auth=token_model)
119
- user = self.USER.from_payload(data)
120
- return AuthenticationResult(user, token)
119
+ user = self.USER.from_payload(result[0])
120
+ return AuthenticationResult(user=user, auth=token_model)
121
121
  except Exception as e:
122
122
  raise JamLitestarPluginError(message=str(e))
@@ -4,10 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  from abc import ABC, abstractmethod
6
6
  from dataclasses import dataclass
7
- from typing import Any, TypeVar
8
-
9
-
10
- User = TypeVar("User", bound="BaseUser")
7
+ from typing import Any
11
8
 
12
9
 
13
10
  @dataclass(slots=True)
@@ -23,7 +20,7 @@ class BaseUser(ABC):
23
20
 
24
21
  @classmethod
25
22
  @abstractmethod
26
- def from_payload(cls, payload: dict[str, Any]) -> User:
23
+ def from_payload(cls, payload: dict[str, Any]) -> BaseUser:
27
24
  """Build model from payload.
28
25
 
29
26
  Args:
@@ -76,6 +76,9 @@ class BasePlugin(InitPlugin):
76
76
  __config_maker__(config, pointer) if config else None
77
77
  )
78
78
 
79
+ # FIXME: Make config wrapper
80
+ if _config and _config.get("jose", None) and self.MODULE == create_jwt:
81
+ _config = _config["jose"]
79
82
  params = _config.pop(self._CONFIG_KEY) if _config else kwargs
80
83
  self._setup_config(params)
81
84
  self._middleware = None
@@ -81,6 +81,8 @@ class BaseBackend(AuthenticationBackend):
81
81
  try:
82
82
  if config:
83
83
  config_ = __config_maker__(config, pointer)[self._CONFIG_KEY]
84
+ if config_.get("jose", None) and self.MODULE == create_jwt:
85
+ config_ = config_["jose"]
84
86
  self._auth = self.MODULE(**config_)
85
87
  else:
86
88
  self._auth = self.MODULE(**kwargs)
@@ -1,21 +1,20 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  from abc import ABC, abstractmethod
4
6
  from dataclasses import dataclass
5
- from typing import Any, TypeVar
7
+ from typing import Any
6
8
 
7
9
  from starlette.authentication import BaseUser as StarletteBaseUser
8
10
 
9
11
 
10
- User = TypeVar("User", bound="BaseUser")
11
-
12
-
13
12
  class BaseUser(ABC, StarletteBaseUser):
14
13
  """BaseUser with builder from payload."""
15
14
 
16
15
  @classmethod
17
16
  @abstractmethod
18
- def from_payload(cls, payload: dict[str, Any]) -> User:
17
+ def from_payload(cls, payload: dict[str, Any]) -> BaseUser:
19
18
  """Create instance by payload.
20
19
 
21
20
  Args:
@@ -49,7 +48,7 @@ class SimpleUser(BaseUser):
49
48
  payload: dict[str, Any]
50
49
 
51
50
  @classmethod
52
- def from_payload(cls, payload: dict[str, Any]): # noqa
51
+ def from_payload(cls, payload: dict[str, Any]) -> SimpleUser: # noqa
53
52
  return cls(payload=payload)
54
53
 
55
54
  def is_authenticated(self) -> bool: # type: ignore # noqa
@@ -112,6 +112,8 @@ class BaseAlgorithm(ABC):
112
112
  except OSError:
113
113
  is_file = False
114
114
  return path.read_bytes() if is_file else data.encode()
115
+ if isinstance(data, rsa.RSAPrivateKey | ec.EllipticCurvePrivateKey):
116
+ data = data.public_key()
115
117
  return data.public_bytes(
116
118
  encoding=serialization.Encoding.PEM,
117
119
  format=serialization.PublicFormat.SubjectPublicKeyInfo,
@@ -602,6 +604,11 @@ class BaseKeyAlgorithm(ABC):
602
604
  if hasattr(self._key, "private_key"):
603
605
  return self._key.private_key()
604
606
 
607
+ if isinstance(
608
+ self._key, rsa.RSAPrivateKey | ec.EllipticCurvePrivateKey
609
+ ):
610
+ return self._key
611
+
605
612
  key_bytes = self._load_key_data(self._key)
606
613
  return serialization.load_pem_private_key(
607
614
  key_bytes, password=self._password
@@ -620,6 +627,8 @@ class BaseKeyAlgorithm(ABC):
620
627
  except OSError:
621
628
  is_file = False
622
629
  return path.read_bytes() if is_file else data.encode()
630
+ if isinstance(data, rsa.RSAPrivateKey | ec.EllipticCurvePrivateKey):
631
+ data = data.public_key()
623
632
  return data.public_bytes(
624
633
  encoding=serialization.Encoding.PEM,
625
634
  format=serialization.PublicFormat.SubjectPublicKeyInfo,
@@ -73,34 +73,39 @@ class BaseJWT(ABC):
73
73
  @abstractmethod
74
74
  def encrypt(
75
75
  self,
76
- payload: dict[str, Any] | str,
76
+ plaintext: bytes | str | dict[str, Any],
77
77
  header: dict[str, Any] | None = None,
78
78
  ) -> str:
79
- """Encrypt payload using JWE.
79
+ """Encrypt plaintext.
80
80
 
81
- Creates JWE or JWS+JWE token (sign then encrypt).
81
+ Produces JWE Compact Serialization:
82
+ BASE64URL(header).BASE64URL(encrypted_key).BASE64URL(iv).BASE64URL(ciphertext).BASE64URL(tag)
82
83
 
83
84
  Args:
84
- payload: Data to encrypt. If dict, will be JSON encoded.
85
- header: Additional JWE header.
85
+ plaintext: Data to encrypt. If str, will be encoded to UTF-8.
86
+ If dict, will be JSON encoded.
87
+ header: JWE header (must include 'alg' and 'enc').
86
88
 
87
89
  Returns:
88
- str: Encrypted JWT (JWE or JWS+JWE).
90
+ JWE compact serialization string.
91
+
92
+ Raises:
93
+ JamJWEEncryptionError: If encryption fails.
89
94
  """
90
95
  raise NotImplementedError
91
96
 
92
97
  @abstractmethod
93
- def decrypt(self, token: str) -> dict[str, Any]:
94
- """Decrypt JWE or JWS+JWE token.
98
+ def decrypt(self, token: str) -> dict[str, Any] | bytes:
99
+ """Decrypt JWE token.
95
100
 
96
101
  Args:
97
- token: Encrypted JWT token.
102
+ token: JWE compact serialization string.
98
103
 
99
104
  Returns:
100
- dict[str, Any]: Decrypted payload.
105
+ bytes: Decrypted plaintext.
101
106
 
102
107
  Raises:
103
- ValueError: If token is invalid or decryption fails.
108
+ JamJWEDecryptionError: If decryption fails.
104
109
  """
105
110
  raise NotImplementedError
106
111
 
@@ -66,6 +66,8 @@ class JWE(BaseJWE):
66
66
 
67
67
  self._alg = alg.upper()
68
68
  self._enc = enc.upper()
69
+ if isinstance(key, JWKClass):
70
+ key = key._to_keylike()
69
71
  self._key = key
70
72
  self._password = password
71
73
  self._serializer = serializer
@@ -56,9 +56,6 @@ class JWKRSA(JWKCommon, total=False):
56
56
  ... }
57
57
  """
58
58
 
59
- kty: Literal["RSA"]
60
- """Key Type. Fixed to "RSA"."""
61
-
62
59
  n: str
63
60
  """RSA modulus n. The modulus value for the RSA public key."""
64
61
 
@@ -98,9 +95,6 @@ class JWKEC(JWKCommon, total=False):
98
95
  ... }
99
96
  """
100
97
 
101
- kty: Literal["EC"]
102
- """Key Type. Fixed to "EC"."""
103
-
104
98
  crv: Literal["P-256", "P-384", "P-521"]
105
99
  """Elliptic curve name. The curve on which the key is based."""
106
100
 
@@ -126,9 +120,6 @@ class JWKOct(JWKCommon, total=False):
126
120
  ... }
127
121
  """
128
122
 
129
- kty: Literal["oct"]
130
- """Key Type. Fixed to "oct"."""
131
-
132
123
  k: str
133
124
  """Key value. The base64url-encoded symmetric key value."""
134
125
 
@@ -15,6 +15,7 @@ from jam.jose.__algorithms__ import (
15
15
  from jam.jose.__base__ import BaseJWS
16
16
  from jam.jose.utils import __base64url_decode__, __base64url_encode__
17
17
  from jam.logger import BaseLogger, logger
18
+ from jam.utils.config_maker import __key_loader__
18
19
 
19
20
 
20
21
  if TYPE_CHECKING:
@@ -46,6 +47,9 @@ class JWS(BaseJWS):
46
47
  self._alg = alg.upper()
47
48
  self._validate_algorithm(self._alg)
48
49
 
50
+ if isinstance(key, str):
51
+ key = __key_loader__(key)
52
+
49
53
  if isinstance(key, JWKClass):
50
54
  key = key._to_keylike()
51
55
 
@@ -80,7 +84,7 @@ class JWS(BaseJWS):
80
84
  def serialize_compact(
81
85
  self,
82
86
  protected: dict[str, Any],
83
- payload: bytes | str,
87
+ payload: bytes | str | dict[str, Any],
84
88
  ) -> str:
85
89
  """Create JWS Compact Serialization.
86
90