sanic-security 1.13.0__py3-none-any.whl → 1.13.2__py3-none-any.whl
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.
- sanic_security/authentication.py +7 -3
- sanic_security/authorization.py +8 -4
- sanic_security/models.py +1 -0
- sanic_security/test/server.py +1 -1
- sanic_security/verification.py +34 -3
- {sanic_security-1.13.0.dist-info → sanic_security-1.13.2.dist-info}/METADATA +5 -4
- sanic_security-1.13.2.dist-info/RECORD +16 -0
- {sanic_security-1.13.0.dist-info → sanic_security-1.13.2.dist-info}/WHEEL +1 -1
- sanic_security-1.13.0.dist-info/RECORD +0 -16
- {sanic_security-1.13.0.dist-info → sanic_security-1.13.2.dist-info}/LICENSE +0 -0
- {sanic_security-1.13.0.dist-info → sanic_security-1.13.2.dist-info}/top_level.txt +0 -0
sanic_security/authentication.py
CHANGED
@@ -86,6 +86,7 @@ async def register(
|
|
86
86
|
verified=verified,
|
87
87
|
disabled=disabled,
|
88
88
|
)
|
89
|
+
logger.info(f"Client {get_ip(request)} has registered account {account.id}.")
|
89
90
|
return account
|
90
91
|
|
91
92
|
|
@@ -128,7 +129,7 @@ async def login(
|
|
128
129
|
request, account, requires_second_factor=require_second_factor
|
129
130
|
)
|
130
131
|
logger.info(
|
131
|
-
f"Client {get_ip(request)} has logged
|
132
|
+
f"Client {get_ip(request)} has logged in with authentication session {authentication_session.id}."
|
132
133
|
)
|
133
134
|
return authentication_session
|
134
135
|
except VerifyMismatchError:
|
@@ -159,8 +160,7 @@ async def logout(request: Request) -> AuthenticationSession:
|
|
159
160
|
authentication_session.active = False
|
160
161
|
await authentication_session.save(update_fields=["active"])
|
161
162
|
logger.info(
|
162
|
-
f"Client {get_ip(request)} has logged out
|
163
|
-
else f"of account {authentication_session.bearer.id}"} with authentication session {authentication_session.id}."
|
163
|
+
f"Client {get_ip(request)} has logged out with authentication session {authentication_session.id}."
|
164
164
|
)
|
165
165
|
return authentication_session
|
166
166
|
|
@@ -193,6 +193,10 @@ async def fulfill_second_factor(request: Request) -> AuthenticationSession:
|
|
193
193
|
await two_step_session.check_code(request.form.get("code"))
|
194
194
|
authentication_session.requires_second_factor = False
|
195
195
|
await authentication_session.save(update_fields=["requires_second_factor"])
|
196
|
+
logger.info(
|
197
|
+
f"Client {get_ip(request)} has fulfilled authentication session {authentication_session.id} "
|
198
|
+
"second factor."
|
199
|
+
)
|
196
200
|
return authentication_session
|
197
201
|
|
198
202
|
|
sanic_security/authorization.py
CHANGED
@@ -59,6 +59,9 @@ async def check_permissions(
|
|
59
59
|
"""
|
60
60
|
authentication_session = await authenticate(request)
|
61
61
|
if authentication_session.anonymous:
|
62
|
+
logger.warning(
|
63
|
+
f"Client {get_ip(request)} attempted an unauthorized action anonymously."
|
64
|
+
)
|
62
65
|
raise AnonymousError()
|
63
66
|
roles = await authentication_session.bearer.roles.filter(deleted=False).all()
|
64
67
|
for role in roles:
|
@@ -68,8 +71,7 @@ async def check_permissions(
|
|
68
71
|
if fnmatch(required_permission, role_permission):
|
69
72
|
return authentication_session
|
70
73
|
logger.warning(
|
71
|
-
f"Client {get_ip(request)} with account {authentication_session.bearer.id}
|
72
|
-
"attempted action."
|
74
|
+
f"Client {get_ip(request)} with account {authentication_session.bearer.id} attempted an unauthorized action. "
|
73
75
|
)
|
74
76
|
raise AuthorizationError("Insufficient permissions required for this action.")
|
75
77
|
|
@@ -98,14 +100,16 @@ async def check_roles(request: Request, *required_roles: str) -> AuthenticationS
|
|
98
100
|
"""
|
99
101
|
authentication_session = await authenticate(request)
|
100
102
|
if authentication_session.anonymous:
|
103
|
+
logger.warning(
|
104
|
+
f"Client {get_ip(request)} attempted an unauthorized action anonymously."
|
105
|
+
)
|
101
106
|
raise AnonymousError()
|
102
107
|
roles = await authentication_session.bearer.roles.filter(deleted=False).all()
|
103
108
|
for role in roles:
|
104
109
|
if role.name in required_roles:
|
105
110
|
return authentication_session
|
106
111
|
logger.warning(
|
107
|
-
f"Client {get_ip(request)} with account {authentication_session.bearer.id}
|
108
|
-
"attempted action."
|
112
|
+
f"Client {get_ip(request)} with account {authentication_session.bearer.id} attempted an unauthorized action. "
|
109
113
|
)
|
110
114
|
raise AuthorizationError("Insufficient roles required for this action.")
|
111
115
|
|
sanic_security/models.py
CHANGED
@@ -336,6 +336,7 @@ class Session(BaseModel):
|
|
336
336
|
"id": self.id,
|
337
337
|
"date_created": str(self.date_created),
|
338
338
|
"expiration_date": str(self.expiration_date),
|
339
|
+
"bearer": self.bearer.id if isinstance(self.bearer, Account) else None,
|
339
340
|
"ip": self.ip,
|
340
341
|
},
|
341
342
|
security_config.SECRET,
|
sanic_security/test/server.py
CHANGED
sanic_security/verification.py
CHANGED
@@ -1,18 +1,21 @@
|
|
1
1
|
import functools
|
2
2
|
from contextlib import suppress
|
3
3
|
|
4
|
+
from sanic.log import logger
|
4
5
|
from sanic.request import Request
|
5
6
|
|
6
7
|
from sanic_security.exceptions import (
|
7
8
|
JWTDecodeError,
|
8
9
|
NotFoundError,
|
9
10
|
VerifiedError,
|
11
|
+
MaxedOutChallengeError,
|
10
12
|
)
|
11
13
|
from sanic_security.models import (
|
12
14
|
Account,
|
13
15
|
TwoStepSession,
|
14
16
|
CaptchaSession,
|
15
17
|
)
|
18
|
+
from sanic_security.utils import get_ip
|
16
19
|
|
17
20
|
"""
|
18
21
|
Copyright (c) 2020-present Nicholas Aidan Stewart
|
@@ -89,7 +92,16 @@ async def two_step_verification(request: Request) -> TwoStepSession:
|
|
89
92
|
two_step_session = await TwoStepSession.decode(request)
|
90
93
|
two_step_session.validate()
|
91
94
|
two_step_session.bearer.validate()
|
92
|
-
|
95
|
+
try:
|
96
|
+
await two_step_session.check_code(request.form.get("code"))
|
97
|
+
except MaxedOutChallengeError as e:
|
98
|
+
logger.warning(
|
99
|
+
f"Client {get_ip(request)} has exceeded maximum two-step session {two_step_session.id} challenge attempts."
|
100
|
+
)
|
101
|
+
raise e
|
102
|
+
logger.info(
|
103
|
+
f"Client {get_ip(request)} has completed two-step session {two_step_session.id} challenge."
|
104
|
+
)
|
93
105
|
return two_step_session
|
94
106
|
|
95
107
|
|
@@ -153,9 +165,19 @@ async def verify_account(request: Request) -> TwoStepSession:
|
|
153
165
|
if two_step_session.bearer.verified:
|
154
166
|
raise VerifiedError()
|
155
167
|
two_step_session.validate()
|
156
|
-
|
168
|
+
try:
|
169
|
+
await two_step_session.check_code(request.form.get("code"))
|
170
|
+
except MaxedOutChallengeError as e:
|
171
|
+
logger.warning(
|
172
|
+
f"Client {get_ip(request)} has exceeded maximum two-step session {two_step_session.id} challenge attempts "
|
173
|
+
"during account verification."
|
174
|
+
)
|
175
|
+
raise e
|
157
176
|
two_step_session.bearer.verified = True
|
158
177
|
await two_step_session.bearer.save(update_fields=["verified"])
|
178
|
+
logger.info(
|
179
|
+
f"Client {get_ip(request)} has verified account {two_step_session.bearer.id}."
|
180
|
+
)
|
159
181
|
return two_step_session
|
160
182
|
|
161
183
|
|
@@ -197,7 +219,16 @@ async def captcha(request: Request) -> CaptchaSession:
|
|
197
219
|
"""
|
198
220
|
captcha_session = await CaptchaSession.decode(request)
|
199
221
|
captcha_session.validate()
|
200
|
-
|
222
|
+
try:
|
223
|
+
await captcha_session.check_code(request.form.get("captcha"))
|
224
|
+
except MaxedOutChallengeError as e:
|
225
|
+
logger.warning(
|
226
|
+
f"Client {get_ip(request)} has exceeded maximum captcha session {captcha_session.id} challenge attempts."
|
227
|
+
)
|
228
|
+
raise e
|
229
|
+
logger.info(
|
230
|
+
f"Client {get_ip(request)} has completed captcha session {captcha_session.id} challenge."
|
231
|
+
)
|
201
232
|
return captcha_session
|
202
233
|
|
203
234
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sanic-security
|
3
|
-
Version: 1.13.
|
3
|
+
Version: 1.13.2
|
4
4
|
Summary: An async security library for the Sanic framework.
|
5
5
|
Author-email: Aidan Stewart <me@na-stewart.com>
|
6
6
|
Project-URL: Documentation, https://security.na-stewart.com/
|
@@ -64,7 +64,7 @@ Requires-Dist: cryptography; extra == "dev"
|
|
64
64
|
* [Usage](#usage)
|
65
65
|
* [Authentication](#authentication)
|
66
66
|
* [Captcha](#captcha)
|
67
|
-
* [Two-
|
67
|
+
* [Two-step Verification](#two-step-verification)
|
68
68
|
* [Authorization](#authorization)
|
69
69
|
* [Testing](#testing)
|
70
70
|
* [Tortoise](#tortoise)
|
@@ -79,10 +79,11 @@ Requires-Dist: cryptography; extra == "dev"
|
|
79
79
|
Sanic Security is an authentication, authorization, and verification library designed for use with [Sanic](https://github.com/huge-success/sanic).
|
80
80
|
|
81
81
|
* Login, registration, and authentication with refresh mechanisms
|
82
|
+
* Role based authorization with wildcard permissions
|
82
83
|
* Two-factor authentication
|
83
|
-
* Captcha
|
84
84
|
* Two-step verification
|
85
|
-
*
|
85
|
+
* Captcha
|
86
|
+
* Logging
|
86
87
|
|
87
88
|
Visit [security.na-stewart.com](https://security.na-stewart.com) for documentation.
|
88
89
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
sanic_security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
sanic_security/authentication.py,sha256=h0Yq2hWFv1GZoqhPQBmoJnqywGQd6fOYu7zyaqfv6wQ,14432
|
3
|
+
sanic_security/authorization.py,sha256=1SHx4cU_ibC0o_nEDDYURH_l_K6Q66M0SLzpRQrsIXc,7534
|
4
|
+
sanic_security/configuration.py,sha256=br2hI3MHsTBh3yfPer5f3bkKSWfQdCeqfLqWmaDNVoM,5510
|
5
|
+
sanic_security/exceptions.py,sha256=JiCaBR2kjE1Cj0fc_08y-32fqJJXa_1UCw205T4_RTY,5493
|
6
|
+
sanic_security/models.py,sha256=l3cO5-S1bmE0tqhFXBC9z4IWTCnYNeRvw1VzIFLeaHE,22363
|
7
|
+
sanic_security/utils.py,sha256=XAUNalcTi53qTz0D8xiDyDyRlq7Z7ffNBzUONJZqe90,2705
|
8
|
+
sanic_security/verification.py,sha256=js2PkqJU6o46atslJ76n-_cYoY5iz5fbyiV0OFwoySo,8668
|
9
|
+
sanic_security/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
+
sanic_security/test/server.py,sha256=79HaNIH1skWTrh2gIbh8WWVNxvYqPA5GlQ8AqRaCsXQ,12094
|
11
|
+
sanic_security/test/tests.py,sha256=bW5fHJfsCrg8eBmcSqVMLm0R5XRL1ou-XJJRgz09GOE,21993
|
12
|
+
sanic_security-1.13.2.dist-info/LICENSE,sha256=sXlJs9_mG-dCkPfWsDnuzydJWagS82E2gYtkVH9enHA,1100
|
13
|
+
sanic_security-1.13.2.dist-info/METADATA,sha256=mcHljpRvZGGTk_hRi2Sf-lqF-QyZIrhn_lNZGkbNjUI,23011
|
14
|
+
sanic_security-1.13.2.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
|
15
|
+
sanic_security-1.13.2.dist-info/top_level.txt,sha256=ZybkhHXSjfzhmv8XeqLvnNmLmv21Z0oPX6Ep4DJN8b0,15
|
16
|
+
sanic_security-1.13.2.dist-info/RECORD,,
|
@@ -1,16 +0,0 @@
|
|
1
|
-
sanic_security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
sanic_security/authentication.py,sha256=ZY4WJDUXbwDdaH_2Ovc9gkR1jCgw52yB9enYp_1LypM,14334
|
3
|
-
sanic_security/authorization.py,sha256=XbRrnsx-Yqpiemf3bn_djIYIe1khdnfToB7DsBheLtk,7338
|
4
|
-
sanic_security/configuration.py,sha256=br2hI3MHsTBh3yfPer5f3bkKSWfQdCeqfLqWmaDNVoM,5510
|
5
|
-
sanic_security/exceptions.py,sha256=JiCaBR2kjE1Cj0fc_08y-32fqJJXa_1UCw205T4_RTY,5493
|
6
|
-
sanic_security/models.py,sha256=v3tJyL420HEdZXqJCq9uPPSivuYXuQNtqf9QC9wF0TU,22274
|
7
|
-
sanic_security/utils.py,sha256=XAUNalcTi53qTz0D8xiDyDyRlq7Z7ffNBzUONJZqe90,2705
|
8
|
-
sanic_security/verification.py,sha256=ebT7QaytHAsw-IKA13W9wyCoqoBAYKgmFA1QJ80N2bE,7476
|
9
|
-
sanic_security/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
sanic_security/test/server.py,sha256=DmwP5dBs2Sq2qk4UZgWbAqzm96YXvLGI9jWeqzluy_c,12082
|
11
|
-
sanic_security/test/tests.py,sha256=bW5fHJfsCrg8eBmcSqVMLm0R5XRL1ou-XJJRgz09GOE,21993
|
12
|
-
sanic_security-1.13.0.dist-info/LICENSE,sha256=sXlJs9_mG-dCkPfWsDnuzydJWagS82E2gYtkVH9enHA,1100
|
13
|
-
sanic_security-1.13.0.dist-info/METADATA,sha256=VeYHXoqKPrbNAfub2NW3RT78Rt1WSUBCKj2gVJrHplE,23000
|
14
|
-
sanic_security-1.13.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
15
|
-
sanic_security-1.13.0.dist-info/top_level.txt,sha256=ZybkhHXSjfzhmv8XeqLvnNmLmv21Z0oPX6Ep4DJN8b0,15
|
16
|
-
sanic_security-1.13.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|