the37lab-authlib 0.1.1751357568__tar.gz → 0.1.1756367559__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.
Potentially problematic release.
This version of the37lab-authlib might be problematic. Click here for more details.
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/PKG-INFO +38 -1
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/README.md +37 -0
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/pyproject.toml +1 -1
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib/auth.py +44 -3
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib/db.py +21 -4
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib.egg-info/PKG-INFO +38 -1
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/setup.cfg +0 -0
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib/__init__.py +0 -0
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib/decorators.py +0 -0
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib/exceptions.py +0 -0
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib/models.py +0 -0
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib.egg-info/SOURCES.txt +0 -0
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib.egg-info/dependency_links.txt +0 -0
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib.egg-info/requires.txt +0 -0
- {the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: the37lab_authlib
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1756367559
|
|
4
4
|
Summary: Python SDK for the Authlib
|
|
5
5
|
Author-email: the37lab <info@the37lab.com>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -39,6 +39,12 @@ A Python authentication library that provides JWT, OAuth2, and API token authent
|
|
|
39
39
|
- [Setup](#setup)
|
|
40
40
|
- [Database Setup](#database-setup)
|
|
41
41
|
- [Running Tests](#running-tests)
|
|
42
|
+
- [API Token Override for Testing](#api-token-override-for-testing)
|
|
43
|
+
- [Usage](#usage)
|
|
44
|
+
- [Warning](#warning)
|
|
45
|
+
- [User Override for Testing](#user-override-for-testing)
|
|
46
|
+
- [Usage](#usage-1)
|
|
47
|
+
- [Warning](#warning-1)
|
|
42
48
|
|
|
43
49
|
## Installation
|
|
44
50
|
|
|
@@ -211,3 +217,34 @@ python -m authlib.cli db init
|
|
|
211
217
|
```bash
|
|
212
218
|
pytest
|
|
213
219
|
```
|
|
220
|
+
|
|
221
|
+
## API Token Override for Testing
|
|
222
|
+
|
|
223
|
+
For testing purposes, you can bypass the database and provide a static mapping of API tokens to usernames using the `api_tokens` argument to `AuthManager` or the `{PREFIX}API_TOKENS` environment variable.
|
|
224
|
+
|
|
225
|
+
### Usage
|
|
226
|
+
|
|
227
|
+
- **Constructor argument:**
|
|
228
|
+
```python
|
|
229
|
+
AuthManager(api_tokens={"token1": "user1", "token2": "user2"})
|
|
230
|
+
```
|
|
231
|
+
- **Environment variable:**
|
|
232
|
+
Set `{PREFIX}API_TOKENS` to a comma-separated list of `token:username` pairs, e.g.:
|
|
233
|
+
```
|
|
234
|
+
export MYAPP_API_TOKENS="token1:user1,token2:user2"
|
|
235
|
+
```
|
|
236
|
+
Replace `MYAPP` with your environment prefix.
|
|
237
|
+
|
|
238
|
+
**Warning:** This method is intended only for testing and development. Do not use this approach in production environments.
|
|
239
|
+
|
|
240
|
+
## User Override for Testing
|
|
241
|
+
|
|
242
|
+
For testing purposes, you can force all authentication to return a specific user by setting the `{PREFIX}USER_OVERRIDE` environment variable:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
export MYAPP_USER_OVERRIDE="testuser"
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
If set, all requests will be authenticated as the specified user, regardless of any tokens or credentials provided. This cannot be combined with `api_tokens` or `db_dsn`.
|
|
249
|
+
|
|
250
|
+
**Warning:** This method is intended only for testing and development. Do not use this approach in production environments.
|
|
@@ -22,6 +22,12 @@ A Python authentication library that provides JWT, OAuth2, and API token authent
|
|
|
22
22
|
- [Setup](#setup)
|
|
23
23
|
- [Database Setup](#database-setup)
|
|
24
24
|
- [Running Tests](#running-tests)
|
|
25
|
+
- [API Token Override for Testing](#api-token-override-for-testing)
|
|
26
|
+
- [Usage](#usage)
|
|
27
|
+
- [Warning](#warning)
|
|
28
|
+
- [User Override for Testing](#user-override-for-testing)
|
|
29
|
+
- [Usage](#usage-1)
|
|
30
|
+
- [Warning](#warning-1)
|
|
25
31
|
|
|
26
32
|
## Installation
|
|
27
33
|
|
|
@@ -194,3 +200,34 @@ python -m authlib.cli db init
|
|
|
194
200
|
```bash
|
|
195
201
|
pytest
|
|
196
202
|
```
|
|
203
|
+
|
|
204
|
+
## API Token Override for Testing
|
|
205
|
+
|
|
206
|
+
For testing purposes, you can bypass the database and provide a static mapping of API tokens to usernames using the `api_tokens` argument to `AuthManager` or the `{PREFIX}API_TOKENS` environment variable.
|
|
207
|
+
|
|
208
|
+
### Usage
|
|
209
|
+
|
|
210
|
+
- **Constructor argument:**
|
|
211
|
+
```python
|
|
212
|
+
AuthManager(api_tokens={"token1": "user1", "token2": "user2"})
|
|
213
|
+
```
|
|
214
|
+
- **Environment variable:**
|
|
215
|
+
Set `{PREFIX}API_TOKENS` to a comma-separated list of `token:username` pairs, e.g.:
|
|
216
|
+
```
|
|
217
|
+
export MYAPP_API_TOKENS="token1:user1,token2:user2"
|
|
218
|
+
```
|
|
219
|
+
Replace `MYAPP` with your environment prefix.
|
|
220
|
+
|
|
221
|
+
**Warning:** This method is intended only for testing and development. Do not use this approach in production environments.
|
|
222
|
+
|
|
223
|
+
## User Override for Testing
|
|
224
|
+
|
|
225
|
+
For testing purposes, you can force all authentication to return a specific user by setting the `{PREFIX}USER_OVERRIDE` environment variable:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
export MYAPP_USER_OVERRIDE="testuser"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
If set, all requests will be authenticated as the specified user, regardless of any tokens or credentials provided. This cannot be combined with `api_tokens` or `db_dsn`.
|
|
232
|
+
|
|
233
|
+
**Warning:** This method is intended only for testing and development. Do not use this approach in production environments.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "the37lab_authlib"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.1756367559"
|
|
8
8
|
description = "Python SDK for the Authlib"
|
|
9
9
|
authors = [{name = "the37lab", email = "info@the37lab.com"}]
|
|
10
10
|
dependencies = ["flask", "psycopg2-binary", "pyjwt", "python-dotenv", "requests", "authlib", "bcrypt"]
|
{the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib/auth.py
RENAMED
|
@@ -11,12 +11,14 @@ import bcrypt
|
|
|
11
11
|
import logging
|
|
12
12
|
import os
|
|
13
13
|
from functools import wraps
|
|
14
|
+
from isodate import parse_duration
|
|
14
15
|
|
|
15
16
|
logging.basicConfig(level=logging.DEBUG)
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
18
19
|
class AuthManager:
|
|
19
|
-
def __init__(self, app=None, db_dsn=None, jwt_secret=None, oauth_config=None, id_type='integer', environment_prefix=None):
|
|
20
|
+
def __init__(self, app=None, db_dsn=None, jwt_secret=None, oauth_config=None, id_type='integer', environment_prefix=None, api_tokens=None):
|
|
21
|
+
self.user_override = None
|
|
20
22
|
if environment_prefix:
|
|
21
23
|
prefix = environment_prefix.upper() + '_'
|
|
22
24
|
db_dsn = os.getenv(f'{prefix}DATABASE_URL')
|
|
@@ -29,6 +31,25 @@ class AuthManager:
|
|
|
29
31
|
'client_id': google_client_id,
|
|
30
32
|
'client_secret': google_client_secret
|
|
31
33
|
}
|
|
34
|
+
api_tokens_env = os.getenv(f'{prefix}API_TOKENS')
|
|
35
|
+
if api_tokens_env:
|
|
36
|
+
api_tokens = {}
|
|
37
|
+
for entry in api_tokens_env.split(','):
|
|
38
|
+
if ':' in entry:
|
|
39
|
+
key, user = entry.split(':', 1)
|
|
40
|
+
api_tokens[key.strip()] = user.strip()
|
|
41
|
+
user_override_env = os.getenv(f'{prefix}USER_OVERRIDE')
|
|
42
|
+
if user_override_env:
|
|
43
|
+
self.user_override = user_override_env
|
|
44
|
+
else:
|
|
45
|
+
prefix = ''
|
|
46
|
+
|
|
47
|
+
self.expiry_time = parse_duration(os.getenv(f'{prefix}JWT_TOKEN_EXPIRY_TIME', 'PT1H'))
|
|
48
|
+
if self.user_override and (api_tokens or db_dsn):
|
|
49
|
+
raise ValueError('Cannot set user_override together with api_tokens or db_dsn')
|
|
50
|
+
if api_tokens and db_dsn:
|
|
51
|
+
raise ValueError('Cannot set both api_tokens and db_dsn')
|
|
52
|
+
self.api_tokens = api_tokens or None
|
|
32
53
|
self.db = Database(db_dsn, id_type=id_type) if db_dsn else None
|
|
33
54
|
self.jwt_secret = jwt_secret
|
|
34
55
|
self.oauth_config = oauth_config or {}
|
|
@@ -61,6 +82,18 @@ class AuthManager:
|
|
|
61
82
|
return redirect_uri
|
|
62
83
|
|
|
63
84
|
def _validate_api_token(self, api_token):
|
|
85
|
+
if self.api_tokens is not None:
|
|
86
|
+
username = self.api_tokens.get(api_token)
|
|
87
|
+
if not username:
|
|
88
|
+
raise AuthError('Invalid API token')
|
|
89
|
+
# Return a minimal user dict
|
|
90
|
+
return {
|
|
91
|
+
'id': username,
|
|
92
|
+
'username': username,
|
|
93
|
+
'email': '',
|
|
94
|
+
'real_name': username,
|
|
95
|
+
'roles': []
|
|
96
|
+
}
|
|
64
97
|
try:
|
|
65
98
|
parsed = ApiToken.parse_token(api_token)
|
|
66
99
|
with self.db.get_cursor() as cur:
|
|
@@ -109,6 +142,14 @@ class AuthManager:
|
|
|
109
142
|
raise AuthError('Invalid token format')
|
|
110
143
|
|
|
111
144
|
def _authenticate_request(self):
|
|
145
|
+
if self.user_override:
|
|
146
|
+
return {
|
|
147
|
+
'id': self.user_override,
|
|
148
|
+
'username': self.user_override,
|
|
149
|
+
'email': '',
|
|
150
|
+
'real_name': self.user_override,
|
|
151
|
+
'roles': []
|
|
152
|
+
}
|
|
112
153
|
auth_header = request.headers.get('Authorization')
|
|
113
154
|
api_token = request.headers.get('X-API-Token')
|
|
114
155
|
|
|
@@ -451,12 +492,12 @@ class AuthManager:
|
|
|
451
492
|
def _create_token(self, user):
|
|
452
493
|
payload = {
|
|
453
494
|
'sub': str(user['id']),
|
|
454
|
-
'exp': datetime.utcnow() +
|
|
495
|
+
'exp': datetime.utcnow() + self.expiry_time,
|
|
455
496
|
'iat': datetime.utcnow()
|
|
456
497
|
}
|
|
457
498
|
logger.debug(f"Creating token with payload: {payload}")
|
|
458
499
|
token = jwt.encode(payload, self.jwt_secret, algorithm='HS256')
|
|
459
|
-
logger.
|
|
500
|
+
logger.info(f"Created token: {token}")
|
|
460
501
|
return token
|
|
461
502
|
|
|
462
503
|
def _create_refresh_token(self, user):
|
{the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib/db.py
RENAMED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
import psycopg2
|
|
2
2
|
from psycopg2.extras import RealDictCursor
|
|
3
|
+
from psycopg2 import pool
|
|
3
4
|
from contextlib import contextmanager
|
|
4
5
|
from .models import UUIDGenerator, IntegerGenerator
|
|
5
6
|
|
|
6
7
|
class Database:
|
|
7
|
-
def __init__(self, dsn, id_type='uuid'):
|
|
8
|
+
def __init__(self, dsn, id_type='uuid', min_conn=1, max_conn=10):
|
|
8
9
|
self.dsn = dsn
|
|
9
10
|
self.id_generator = UUIDGenerator() if id_type == 'uuid' else IntegerGenerator()
|
|
10
11
|
self.id_type = id_type
|
|
12
|
+
self.min_conn = min_conn
|
|
13
|
+
self.max_conn = max_conn
|
|
14
|
+
self._pool = None
|
|
15
|
+
self._init_pool()
|
|
11
16
|
self._init_db()
|
|
12
17
|
|
|
18
|
+
def _init_pool(self):
|
|
19
|
+
self._pool = pool.ThreadedConnectionPool(
|
|
20
|
+
self.min_conn,
|
|
21
|
+
self.max_conn,
|
|
22
|
+
self.dsn,
|
|
23
|
+
cursor_factory=RealDictCursor
|
|
24
|
+
)
|
|
25
|
+
|
|
13
26
|
def _init_db(self):
|
|
14
27
|
with self.get_connection() as conn:
|
|
15
28
|
with conn.cursor() as cur:
|
|
@@ -54,7 +67,7 @@ class Database:
|
|
|
54
67
|
|
|
55
68
|
@contextmanager
|
|
56
69
|
def get_connection(self):
|
|
57
|
-
conn =
|
|
70
|
+
conn = self._pool.getconn()
|
|
58
71
|
try:
|
|
59
72
|
yield conn
|
|
60
73
|
conn.commit()
|
|
@@ -62,7 +75,7 @@ class Database:
|
|
|
62
75
|
conn.rollback()
|
|
63
76
|
raise
|
|
64
77
|
finally:
|
|
65
|
-
|
|
78
|
+
self._pool.putconn(conn)
|
|
66
79
|
|
|
67
80
|
@contextmanager
|
|
68
81
|
def get_cursor(self):
|
|
@@ -71,4 +84,8 @@ class Database:
|
|
|
71
84
|
yield cur
|
|
72
85
|
|
|
73
86
|
def get_id_generator(self):
|
|
74
|
-
return self.id_generator
|
|
87
|
+
return self.id_generator
|
|
88
|
+
|
|
89
|
+
def close(self):
|
|
90
|
+
if self._pool:
|
|
91
|
+
self._pool.closeall()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: the37lab_authlib
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1756367559
|
|
4
4
|
Summary: Python SDK for the Authlib
|
|
5
5
|
Author-email: the37lab <info@the37lab.com>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -39,6 +39,12 @@ A Python authentication library that provides JWT, OAuth2, and API token authent
|
|
|
39
39
|
- [Setup](#setup)
|
|
40
40
|
- [Database Setup](#database-setup)
|
|
41
41
|
- [Running Tests](#running-tests)
|
|
42
|
+
- [API Token Override for Testing](#api-token-override-for-testing)
|
|
43
|
+
- [Usage](#usage)
|
|
44
|
+
- [Warning](#warning)
|
|
45
|
+
- [User Override for Testing](#user-override-for-testing)
|
|
46
|
+
- [Usage](#usage-1)
|
|
47
|
+
- [Warning](#warning-1)
|
|
42
48
|
|
|
43
49
|
## Installation
|
|
44
50
|
|
|
@@ -211,3 +217,34 @@ python -m authlib.cli db init
|
|
|
211
217
|
```bash
|
|
212
218
|
pytest
|
|
213
219
|
```
|
|
220
|
+
|
|
221
|
+
## API Token Override for Testing
|
|
222
|
+
|
|
223
|
+
For testing purposes, you can bypass the database and provide a static mapping of API tokens to usernames using the `api_tokens` argument to `AuthManager` or the `{PREFIX}API_TOKENS` environment variable.
|
|
224
|
+
|
|
225
|
+
### Usage
|
|
226
|
+
|
|
227
|
+
- **Constructor argument:**
|
|
228
|
+
```python
|
|
229
|
+
AuthManager(api_tokens={"token1": "user1", "token2": "user2"})
|
|
230
|
+
```
|
|
231
|
+
- **Environment variable:**
|
|
232
|
+
Set `{PREFIX}API_TOKENS` to a comma-separated list of `token:username` pairs, e.g.:
|
|
233
|
+
```
|
|
234
|
+
export MYAPP_API_TOKENS="token1:user1,token2:user2"
|
|
235
|
+
```
|
|
236
|
+
Replace `MYAPP` with your environment prefix.
|
|
237
|
+
|
|
238
|
+
**Warning:** This method is intended only for testing and development. Do not use this approach in production environments.
|
|
239
|
+
|
|
240
|
+
## User Override for Testing
|
|
241
|
+
|
|
242
|
+
For testing purposes, you can force all authentication to return a specific user by setting the `{PREFIX}USER_OVERRIDE` environment variable:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
export MYAPP_USER_OVERRIDE="testuser"
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
If set, all requests will be authenticated as the specified user, regardless of any tokens or credentials provided. This cannot be combined with `api_tokens` or `db_dsn`.
|
|
249
|
+
|
|
250
|
+
**Warning:** This method is intended only for testing and development. Do not use this approach in production environments.
|
|
File without changes
|
{the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{the37lab_authlib-0.1.1751357568 → the37lab_authlib-0.1.1756367559}/src/the37lab_authlib/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|