sanic-security 1.15.2__py3-none-any.whl → 1.16.0__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 +18 -23
- sanic_security/authorization.py +44 -18
- sanic_security/configuration.py +9 -0
- sanic_security/exceptions.py +5 -3
- sanic_security/models.py +73 -70
- sanic_security/oauth.py +239 -0
- sanic_security/test/server.py +75 -28
- sanic_security/test/tests.py +25 -10
- sanic_security/utils.py +11 -7
- sanic_security/verification.py +1 -4
- {sanic_security-1.15.2.dist-info → sanic_security-1.16.0.dist-info}/METADATA +133 -47
- sanic_security-1.16.0.dist-info/RECORD +17 -0
- {sanic_security-1.15.2.dist-info → sanic_security-1.16.0.dist-info}/WHEEL +1 -1
- sanic_security-1.15.2.dist-info/RECORD +0 -16
- {sanic_security-1.15.2.dist-info → sanic_security-1.16.0.dist-info}/LICENSE +0 -0
- {sanic_security-1.15.2.dist-info → sanic_security-1.16.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: sanic-security
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.16.0
|
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/
|
@@ -17,11 +17,12 @@ License-File: LICENSE
|
|
17
17
|
Requires-Dist: tortoise-orm>=0.17.0
|
18
18
|
Requires-Dist: pyjwt>=1.7.0
|
19
19
|
Requires-Dist: captcha>=0.4
|
20
|
-
Requires-Dist: pillow>=9.5.0
|
21
20
|
Requires-Dist: argon2-cffi>=20.1.0
|
22
21
|
Requires-Dist: sanic>=21.3.0
|
22
|
+
Provides-Extra: oauth
|
23
|
+
Requires-Dist: httpx-oauth>=0.16.1; extra == "oauth"
|
23
24
|
Provides-Extra: dev
|
24
|
-
Requires-Dist: httpx; extra == "dev"
|
25
|
+
Requires-Dist: httpx-oauth; extra == "dev"
|
25
26
|
Requires-Dist: black; extra == "dev"
|
26
27
|
Requires-Dist: blacken-docs; extra == "dev"
|
27
28
|
Requires-Dist: pdoc3; extra == "dev"
|
@@ -62,6 +63,7 @@ Requires-Dist: cryptography>=3.3.1; extra == "crypto"
|
|
62
63
|
* [Installation](#installation)
|
63
64
|
* [Configuration](#configuration)
|
64
65
|
* [Usage](#usage)
|
66
|
+
* [OAuth](#oauth)
|
65
67
|
* [Authentication](#authentication)
|
66
68
|
* [CAPTCHA](#captcha)
|
67
69
|
* [Two-step Verification](#two-step-verification)
|
@@ -79,6 +81,7 @@ Requires-Dist: cryptography>=3.3.1; extra == "crypto"
|
|
79
81
|
Sanic Security is an authentication, authorization, and verification library designed for use with the
|
80
82
|
[Sanic](https://github.com/huge-success/sanic) framework.
|
81
83
|
|
84
|
+
* OAuth2 integration
|
82
85
|
* Login, registration, and authentication with refresh mechanisms
|
83
86
|
* Role based authorization with wildcard permissions
|
84
87
|
* Image & audio CAPTCHA
|
@@ -102,7 +105,7 @@ pip3 install sanic-security
|
|
102
105
|
|
103
106
|
* Install the Sanic Security pip package with the `cryptography` dependency included.
|
104
107
|
|
105
|
-
If you
|
108
|
+
If you're planning on encoding or decoding JWTs using certain digital signature algorithms (like RSA or ECDSA which use
|
106
109
|
the public secret and private secret), you will need to install the `cryptography` library. This can be installed explicitly, or
|
107
110
|
as an extra requirement.
|
108
111
|
|
@@ -110,7 +113,17 @@ as an extra requirement.
|
|
110
113
|
pip3 install sanic-security[crypto]
|
111
114
|
````
|
112
115
|
|
113
|
-
*
|
116
|
+
* Install the Sanic Security pip package with the `httpx-oauth` dependency included.
|
117
|
+
|
118
|
+
If you're planning on utilizing OAuth, you will need to install the `httpx-oauth` library. This can be installed explicitly, or
|
119
|
+
as an extra requirement.
|
120
|
+
|
121
|
+
```shell
|
122
|
+
pip3 install sanic-security[oauth]
|
123
|
+
````
|
124
|
+
|
125
|
+
* Update Sanic Security if already installed.
|
126
|
+
|
114
127
|
```shell
|
115
128
|
pip3 install sanic-security --upgrade
|
116
129
|
```
|
@@ -138,41 +151,119 @@ You can load environment variables with a different prefix via `config.load_envi
|
|
138
151
|
|
139
152
|
* Default configuration values:
|
140
153
|
|
141
|
-
| Key | Value | Description
|
142
|
-
|
143
|
-
| **SECRET** | This is a big secret. Shhhhh | The secret used for generating and signing JWTs. This should be a string unique to your application. Keep it safe.
|
144
|
-
| **PUBLIC_SECRET** | None | The secret used for verifying and decoding JWTs and can be publicly shared. This should be a string unique to your application.
|
145
|
-
| **
|
146
|
-
| **
|
147
|
-
| **
|
148
|
-
| **
|
149
|
-
| **
|
150
|
-
| **
|
151
|
-
| **
|
152
|
-
| **
|
153
|
-
| **
|
154
|
-
| **
|
155
|
-
| **
|
156
|
-
| **
|
157
|
-
| **
|
158
|
-
| **
|
159
|
-
| **
|
160
|
-
| **
|
154
|
+
| Key | Value | Description |
|
155
|
+
|---------------------------------------|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
156
|
+
| **SECRET** | This is a big secret. Shhhhh | The secret used for generating and signing JWTs. This should be a string unique to your application. Keep it safe. |
|
157
|
+
| **PUBLIC_SECRET** | None | The secret used for verifying and decoding JWTs and can be publicly shared. This should be a string unique to your application. |
|
158
|
+
| **OAUTH_CLIENT** | None | The client ID provided by the OAuth provider, this is used to identify the application making the OAuth request. |
|
159
|
+
| **OAUTH_SECRET** | None | The client secret provided by the OAuth provider, this is used in conjunction with the client ID to authenticate the application. |
|
160
|
+
| **SESSION_SAMESITE** | Strict | The SameSite attribute of session cookies. |
|
161
|
+
| **SESSION_SECURE** | True | The Secure attribute of session cookies. |
|
162
|
+
| **SESSION_HTTPONLY** | True | The HttpOnly attribute of session cookies. HIGHLY recommended that you do not turn this off, unless you know what you are doing. |
|
163
|
+
| **SESSION_DOMAIN** | None | The Domain attribute of session cookies. |
|
164
|
+
| **SESSION_ENCODING_ALGORITHM** | HS256 | The algorithm used to encode and decode session JWT's. |
|
165
|
+
| **SESSION_PREFIX** | tkn | Prefix attached to the beginning of session cookies. |
|
166
|
+
| **MAX_CHALLENGE_ATTEMPTS** | 3 | The maximum amount of session challenge attempts allowed. |
|
167
|
+
| **CAPTCHA_SESSION_EXPIRATION** | 180 | The amount of seconds till captcha session expiration on creation. Setting to 0 will disable expiration. |
|
168
|
+
| **CAPTCHA_FONT** | captcha-font.ttf | The file path to the font being used for captcha generation. Several fonts can be used by separating them via comma. |
|
169
|
+
| **CAPTCHA_VOICE** | captcha-voice/ | The directory of the voice library being used for audio captcha generation. |
|
170
|
+
| **TWO_STEP_SESSION_EXPIRATION** | 300 | The amount of seconds till two-step session expiration on creation. Setting to 0 will disable expiration. |
|
171
|
+
| **AUTHENTICATION_SESSION_EXPIRATION** | 86400 | The amount of seconds till authentication session expiration on creation. Setting to 0 will disable expiration. |
|
172
|
+
| **AUTHENTICATION_REFRESH_EXPIRATION** | 604800 | The amount of seconds till authentication refresh expiration. Setting to 0 will disable refresh mechanism. |
|
173
|
+
| **ALLOW_LOGIN_WITH_USERNAME** | False | Allows login via username; unique constraint is disabled when set to false. |
|
174
|
+
| **INITIAL_ADMIN_EMAIL** | admin@example.com | Email used when creating the initial admin account. |
|
175
|
+
| **INITIAL_ADMIN_PASSWORD** | admin123 | Password used when creating the initial admin account. |
|
161
176
|
|
162
177
|
## Usage
|
163
178
|
|
164
179
|
Sanic Security's authentication and verification functionality is session based. A new session will be created for the user after the user logs in or requests some form of verification (two-step, captcha). The session data is then encoded into a JWT and stored on a cookie on the user’s browser. The session cookie is then sent
|
165
180
|
along with every subsequent request. The server can then compare the session stored on the cookie against the session information stored in the database to verify user’s identity and send a response with the corresponding state.
|
166
181
|
|
167
|
-
* Initialize
|
182
|
+
* Initialize Sanic Security as follows:
|
168
183
|
```python
|
169
184
|
initialize_security(app)
|
185
|
+
initialize_oauth(app) # Remove if not utilizing OAuth
|
170
186
|
if __name__ == "__main__":
|
171
187
|
app.run(host="127.0.0.1", port=8000, workers=1, debug=True)
|
172
188
|
```
|
173
189
|
|
174
190
|
The tables in the below examples represent example [request form-data](https://sanicframework.org/en/guide/basics/request.html#form).
|
175
191
|
|
192
|
+
## OAuth
|
193
|
+
|
194
|
+
OAuth2 provides users with a familiar experience by having them register/login using their existing credentials from other trusted services (such as Google, Discord, etc.).
|
195
|
+
|
196
|
+
This feature is designed to complement existing authentication protocols by linking a Sanic Security account with the user's OAuth credentials. As a result, developers can leverage all of Sanic Security's capabilities including robust session handling and account management.
|
197
|
+
|
198
|
+
* Define OAuth clients
|
199
|
+
|
200
|
+
You can [utilize various OAuth clients](https://frankie567.github.io/httpx-oauth/reference/httpx_oauth.clients/) based on your needs or [customize one](https://frankie567.github.io/httpx-oauth/usage/).
|
201
|
+
ID and secret should be stored and referenced via configuration.
|
202
|
+
|
203
|
+
```python
|
204
|
+
discord_oauth = DiscordOAuth2(
|
205
|
+
"1325594509043830895",
|
206
|
+
"WNMYbkDJjGlC0ej60qM-50tC9mMy0EXa",
|
207
|
+
)
|
208
|
+
google_oauth = GoogleOAuth2(
|
209
|
+
"480512993828-e2e9tqtl2b8or62hc4l7hpoh478s3ni1.apps.googleusercontent.com",
|
210
|
+
"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",
|
211
|
+
)
|
212
|
+
```
|
213
|
+
|
214
|
+
* Redirect to authorization URL
|
215
|
+
|
216
|
+
```python
|
217
|
+
@app.route("api/security/oauth", methods=["GET", "POST"])
|
218
|
+
async def on_oauth_request(request):
|
219
|
+
return redirect(
|
220
|
+
await oauth_url(
|
221
|
+
google_oauth, "http://localhost:8000/api/security/oauth/callback"
|
222
|
+
)
|
223
|
+
)
|
224
|
+
```
|
225
|
+
|
226
|
+
* Handle OAuth callback
|
227
|
+
|
228
|
+
```python
|
229
|
+
@app.get("api/security/oauth/callback")
|
230
|
+
async def on_oauth_callback(request):
|
231
|
+
token_info, authentication_session = await oauth_callback(
|
232
|
+
request, google_oauth, "http://localhost:8000/api/security/oauth/callback"
|
233
|
+
)
|
234
|
+
response = json(
|
235
|
+
"Authorization successful.",
|
236
|
+
{"token_info": token_info, "auth_session": authentication_session.json},
|
237
|
+
)
|
238
|
+
oauth_encode(response, token_info)
|
239
|
+
authentication_session.encode(response)
|
240
|
+
return response
|
241
|
+
```
|
242
|
+
|
243
|
+
* Get access token
|
244
|
+
|
245
|
+
```python
|
246
|
+
@app.get("api/security/oauth/token")
|
247
|
+
async def on_oauth_token(request):
|
248
|
+
token_info = await decode_oauth(request, google_oauth)
|
249
|
+
return json(
|
250
|
+
"Access token retrieved.",
|
251
|
+
token_info,
|
252
|
+
)
|
253
|
+
```
|
254
|
+
|
255
|
+
* Requires access token (This method is not called directly and instead used as a decorator)
|
256
|
+
|
257
|
+
```python
|
258
|
+
@app.get("api/security/oauth/token")
|
259
|
+
@requires_oauth(google_oauth)
|
260
|
+
async def on_oauth_token(request):
|
261
|
+
return json(
|
262
|
+
"Access token retrieved.",
|
263
|
+
request.ctx.oauth,
|
264
|
+
)
|
265
|
+
```
|
266
|
+
|
176
267
|
## Authentication
|
177
268
|
|
178
269
|
* Registration (With two-step account verification)
|
@@ -324,7 +415,9 @@ or you can download/create your own and specify its path in the configuration.
|
|
324
415
|
@app.get("api/security/captcha")
|
325
416
|
async def on_captcha_img_request(request):
|
326
417
|
captcha_session = await request_captcha(request)
|
327
|
-
response =
|
418
|
+
response = raw(
|
419
|
+
captcha_session.get_image(), content_type="image/jpeg"
|
420
|
+
) # Captcha: LJ0F3U
|
328
421
|
captcha_session.encode(response)
|
329
422
|
return response
|
330
423
|
```
|
@@ -334,8 +427,12 @@ async def on_captcha_img_request(request):
|
|
334
427
|
```python
|
335
428
|
@app.get("api/security/captcha/audio")
|
336
429
|
async def on_captcha_audio_request(request):
|
337
|
-
captcha_session = await
|
338
|
-
|
430
|
+
captcha_session = await request_captcha(request)
|
431
|
+
response = raw(
|
432
|
+
captcha_session.get_audio(), content_type="audio/mpeg"
|
433
|
+
) # Captcha: LJ0F3U
|
434
|
+
captcha_session.encode(response)
|
435
|
+
return response
|
339
436
|
```
|
340
437
|
|
341
438
|
* Attempt CAPTCHA
|
@@ -366,7 +463,7 @@ async def on_captcha(request):
|
|
366
463
|
|
367
464
|
## Two-step Verification
|
368
465
|
|
369
|
-
Two-step verification should be integrated with other custom functionalities, such as
|
466
|
+
Two-step verification should be integrated with other custom functionalities, such as forgot password recovery.
|
370
467
|
|
371
468
|
* Request Two-step Verification
|
372
469
|
|
@@ -447,8 +544,10 @@ Wildcard permissions support the concept of multiple levels or parts. For exampl
|
|
447
544
|
await assign_role(
|
448
545
|
"Chat Room Moderator",
|
449
546
|
account,
|
450
|
-
"channels:view,delete, voice:*, account:suspend,mute",
|
451
547
|
"Can read and delete messages in all chat rooms, suspend and mute accounts, and control voice chat.",
|
548
|
+
"channels:view,delete",
|
549
|
+
"voice:*",
|
550
|
+
"account:suspend,mute",
|
452
551
|
)
|
453
552
|
```
|
454
553
|
|
@@ -467,7 +566,7 @@ async def on_check_perms(request):
|
|
467
566
|
|
468
567
|
```python
|
469
568
|
@app.post("api/security/perms")
|
470
|
-
@
|
569
|
+
@requires_permission("channels:view", "voice:*")
|
471
570
|
async def on_check_perms(request):
|
472
571
|
return text("Account is authorized.")
|
473
572
|
```
|
@@ -485,7 +584,7 @@ async def on_check_roles(request):
|
|
485
584
|
|
486
585
|
```python
|
487
586
|
@app.post("api/security/roles")
|
488
|
-
@
|
587
|
+
@requires_role("Chat Room Moderator")
|
489
588
|
async def on_check_roles(request):
|
490
589
|
return text("Account is authorized.")
|
491
590
|
```
|
@@ -582,16 +681,3 @@ Distributed under the MIT License. See `LICENSE` for more information.
|
|
582
681
|
* PATCH version when you make backwards compatible bug fixes.
|
583
682
|
|
584
683
|
[https://semver.org/](https://semver.org/)
|
585
|
-
|
586
|
-
<!-- MARKDOWN LINKS & IMAGES -->
|
587
|
-
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
588
|
-
[contributors-shield]: https://img.shields.io/github/contributors/sunset-developer/sanic-security.svg?style=flat-square
|
589
|
-
[contributors-url]: https://github.com/sunset-developer/sanic-security/graphs/contributors
|
590
|
-
[forks-shield]: https://img.shields.io/github/forks/sunset-developer/sanic-security.svg?style=flat-square
|
591
|
-
[forks-url]: https://github.com/sunset-developer/sanic-security/network/members
|
592
|
-
[stars-shield]: https://img.shields.io/github/stars/sunset-developer/sanic-security.svg?style=flat-square
|
593
|
-
[stars-url]: https://github.com/sunset-developer/sanic-security/stargazers
|
594
|
-
[issues-shield]: https://img.shields.io/github/issues/sunset-developer/sanic-security.svg?style=flat-square
|
595
|
-
[issues-url]: https://github.com/sunset-developer/sanic-security/issues
|
596
|
-
[license-shield]: https://img.shields.io/github/license/sunset-developer/sanic-security.svg?style=flat-square
|
597
|
-
[license-url]: https://github.com/sunset-developer/sanic-security/blob/master/LICENSE
|
@@ -0,0 +1,17 @@
|
|
1
|
+
sanic_security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
sanic_security/authentication.py,sha256=dogkcRsZH81WqKMqvwnDXN44ANCOuZsuuTGeo3di0c4,12985
|
3
|
+
sanic_security/authorization.py,sha256=ssq58w4vLv4YsNt40ufxHVyCeNzVDby3UcOYOEeTnI4,8428
|
4
|
+
sanic_security/configuration.py,sha256=2kWC4CZXvWR1wtBaqkMl58IA0VzxhI2ZbBTqd7LS_fE,6305
|
5
|
+
sanic_security/exceptions.py,sha256=RCYrDUgczwH_Uz2A__z1zCc8iKKbt2YSBdNTQUaMykc,5381
|
6
|
+
sanic_security/models.py,sha256=Ote83cdLUTpNWOMaY1uM04yDmst5_DamPEMFcSSmdks,22161
|
7
|
+
sanic_security/oauth.py,sha256=Wnd-jqC3uIi-fi4cV15_gmhXTi2FyuY9NAwKG5FxLr8,8398
|
8
|
+
sanic_security/utils.py,sha256=WlPOEEQGcfZk-GbPNu6OiysNXAo9mw80TitDV7XxWMc,3762
|
9
|
+
sanic_security/verification.py,sha256=0pBoGBVGsyTFNLHI0lyz640Y1f8fnKjLjA8zHzXutqM,8660
|
10
|
+
sanic_security/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
+
sanic_security/test/server.py,sha256=opZGmoLuNZgZR2WHzu5WnWecniRnUu-nheqQsrhau5I,13313
|
12
|
+
sanic_security/test/tests.py,sha256=h6v3N1YhvENNA0eC-RqJK1sqGe2gFeKAMPJu7hjceqc,22570
|
13
|
+
sanic_security-1.16.0.dist-info/LICENSE,sha256=sXlJs9_mG-dCkPfWsDnuzydJWagS82E2gYtkVH9enHA,1100
|
14
|
+
sanic_security-1.16.0.dist-info/METADATA,sha256=d9uGtSKHAiUtmZev-_kjjfTYWCcAKQ1s4RchCUPWPBc,25648
|
15
|
+
sanic_security-1.16.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
16
|
+
sanic_security-1.16.0.dist-info/top_level.txt,sha256=ZybkhHXSjfzhmv8XeqLvnNmLmv21Z0oPX6Ep4DJN8b0,15
|
17
|
+
sanic_security-1.16.0.dist-info/RECORD,,
|
@@ -1,16 +0,0 @@
|
|
1
|
-
sanic_security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
sanic_security/authentication.py,sha256=3Pit1B4PN_MRvwAlhYPHl_6DGD9JVpdPjgjiyKQJanM,13145
|
3
|
-
sanic_security/authorization.py,sha256=jAxfDT9cHN_zpMKcA3oYFZ5Eu2KItnMJZ7oPcqmMwrw,7537
|
4
|
-
sanic_security/configuration.py,sha256=_E66ts5g9t_XHW9ZAnr48rWVcZmGNu_DWGDxm_AVVWE,5681
|
5
|
-
sanic_security/exceptions.py,sha256=9zISLyAvP6qN8sNR8e5qxKP__FA4NLIXCun_fEKndOw,5297
|
6
|
-
sanic_security/models.py,sha256=1gMoPnzA9cpJaZXJ1GtgAzsXxGO-rts-f3YyVgcd7lY,22475
|
7
|
-
sanic_security/utils.py,sha256=Il5MjFzVe975yx_CV2HV_LVQYl2W3XYDRGtCG5CQA8Q,3531
|
8
|
-
sanic_security/verification.py,sha256=9bi8-NZ8GE3rcuELZ63yh18zDg8RxvxGPkhAu5SzLn0,8692
|
9
|
-
sanic_security/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
sanic_security/test/server.py,sha256=RjL9Kfvkfqpm5TXWwFQKKa0J4hfTKgwI6U0s_TAKO8w,11984
|
11
|
-
sanic_security/test/tests.py,sha256=bW5fHJfsCrg8eBmcSqVMLm0R5XRL1ou-XJJRgz09GOE,21993
|
12
|
-
sanic_security-1.15.2.dist-info/LICENSE,sha256=sXlJs9_mG-dCkPfWsDnuzydJWagS82E2gYtkVH9enHA,1100
|
13
|
-
sanic_security-1.15.2.dist-info/METADATA,sha256=PNjYIu36zcUqehxfO0Zg7X98CwHSzGbPc1FYXsXo7qs,23247
|
14
|
-
sanic_security-1.15.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
15
|
-
sanic_security-1.15.2.dist-info/top_level.txt,sha256=ZybkhHXSjfzhmv8XeqLvnNmLmv21Z0oPX6Ep4DJN8b0,15
|
16
|
-
sanic_security-1.15.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|