ecodev-core 0.0.9__tar.gz → 0.0.10__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 ecodev-core might be problematic. Click here for more details.
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/PKG-INFO +1 -1
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/authentication.py +33 -17
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/pyproject.toml +1 -1
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/LICENSE.md +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/README.md +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/__init__.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/app_activity.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/app_rights.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/app_user.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/auth_configuration.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/backup.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/check_dependencies.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/custom_equal.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/db_connection.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/db_filters.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/db_insertion.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/db_retrieval.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/enum_utils.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/list_utils.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/logger.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/pandas_utils.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/permissions.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/pydantic_utils.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/read_write.py +0 -0
- {ecodev_core-0.0.9 → ecodev_core-0.0.10}/ecodev_core/safe_utils.py +0 -0
|
@@ -39,6 +39,7 @@ CONTEXT = CryptContext(schemes=['bcrypt'], deprecated='auto')
|
|
|
39
39
|
MONITORING = 'monitoring'
|
|
40
40
|
MONITORING_ERROR = 'Could not validate credentials. You need to be the monitoring user to call this'
|
|
41
41
|
INVALID_USER = 'Invalid User'
|
|
42
|
+
INVALID_TFA = 'Invalid TFA code'
|
|
42
43
|
ADMIN_ERROR = 'Could not validate credentials. You need admin rights to call this'
|
|
43
44
|
INVALID_CREDENTIALS = 'Invalid Credentials'
|
|
44
45
|
log = logger_get(__name__)
|
|
@@ -93,7 +94,7 @@ class JwtAuth(AuthenticationBackend):
|
|
|
93
94
|
return True if token else False
|
|
94
95
|
|
|
95
96
|
@staticmethod
|
|
96
|
-
def authorized(form:
|
|
97
|
+
def authorized(form: Any):
|
|
97
98
|
"""
|
|
98
99
|
Check that the user information contained in the form corresponds to an admin user
|
|
99
100
|
"""
|
|
@@ -122,9 +123,19 @@ class JwtAuth(AuthenticationBackend):
|
|
|
122
123
|
|
|
123
124
|
def attempt_to_log(user: str,
|
|
124
125
|
password: str,
|
|
125
|
-
session: Session
|
|
126
|
+
session: Session,
|
|
127
|
+
tfa_value: Optional[str] = None
|
|
128
|
+
) -> Union[Dict, HTTPException]:
|
|
126
129
|
"""
|
|
127
|
-
Factorized security logic. Ensure that the user is a legit one with a valid password
|
|
130
|
+
Factorized security logic. Ensure that the user is a legit one with a valid password.
|
|
131
|
+
If so, generate a token (with or without encoded tfa_value depending on whether this argument is
|
|
132
|
+
passed as an argument). If not, returns an HTTP exception with an intelligible error message.
|
|
133
|
+
|
|
134
|
+
Attributes are:
|
|
135
|
+
user: the user as expected to be found in the AppUser db
|
|
136
|
+
password: the plain password, to be compared with the hashed one in the AppUser db
|
|
137
|
+
session: db connection
|
|
138
|
+
tfa_value: if filled, add it encoded to the generated token
|
|
128
139
|
"""
|
|
129
140
|
selector = select(AppUser).where(col(AppUser.user) == user)
|
|
130
141
|
if not (db_user := session.exec(selector).first()):
|
|
@@ -134,54 +145,54 @@ def attempt_to_log(user: str,
|
|
|
134
145
|
log.warning('invalid user')
|
|
135
146
|
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=INVALID_CREDENTIALS)
|
|
136
147
|
|
|
137
|
-
return {'access_token': _create_access_token(data={'user_id': db_user.id}),
|
|
148
|
+
return {'access_token': _create_access_token(data={'user_id': db_user.id, 'tfa': tfa_value}),
|
|
138
149
|
'token_type': 'bearer'}
|
|
139
150
|
|
|
140
151
|
|
|
141
|
-
def is_authorized_user(token: str = Depends(SCHEME)) -> bool:
|
|
152
|
+
def is_authorized_user(token: str = Depends(SCHEME), tfa_value: Optional[str] = None) -> bool:
|
|
142
153
|
"""
|
|
143
154
|
Check if the passed token corresponds to an authorized user
|
|
144
155
|
"""
|
|
145
156
|
try:
|
|
146
|
-
return get_current_user(token) is not None
|
|
157
|
+
return get_current_user(token, tfa_value) is not None
|
|
147
158
|
except Exception:
|
|
148
159
|
return False
|
|
149
160
|
|
|
150
161
|
|
|
151
|
-
def safe_get_user(token: Dict) -> Union[AppUser, None]:
|
|
162
|
+
def safe_get_user(token: Dict, tfa: bool = False) -> Union[AppUser, None]:
|
|
152
163
|
"""
|
|
153
164
|
Safe method returning a user if one found given the passed token
|
|
154
165
|
"""
|
|
155
166
|
try:
|
|
156
|
-
return get_user(get_access_token(token))
|
|
167
|
+
return get_user(get_access_token(token), token['tfa'] if tfa else None)
|
|
157
168
|
except (HTTPException, AttributeError):
|
|
158
169
|
return None
|
|
159
170
|
|
|
160
171
|
|
|
161
|
-
def get_user(token: str = Depends(SCHEME)) -> AppUser:
|
|
172
|
+
def get_user(token: str = Depends(SCHEME), tfa_value: Optional[str] = None) -> AppUser:
|
|
162
173
|
"""
|
|
163
174
|
Retrieves (if it exists) the db user corresponding to the passed token
|
|
164
175
|
"""
|
|
165
|
-
if user := get_current_user(token):
|
|
176
|
+
if user := get_current_user(token, tfa_value):
|
|
166
177
|
return user
|
|
167
178
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=INVALID_CREDENTIALS,
|
|
168
179
|
headers={'WWW-Authenticate': 'Bearer'})
|
|
169
180
|
|
|
170
181
|
|
|
171
|
-
def get_current_user(token: str) -> Union[AppUser, None]:
|
|
182
|
+
def get_current_user(token: str, tfa_value: Optional[str] = None) -> Union[AppUser, None]:
|
|
172
183
|
"""
|
|
173
184
|
Retrieves (if it exists) a valid (meaning who has valid credentials) user from the db
|
|
174
185
|
"""
|
|
175
|
-
token = _verify_access_token(token)
|
|
186
|
+
token = _verify_access_token(token, tfa_value)
|
|
176
187
|
with Session(engine) as session:
|
|
177
188
|
return session.exec(select(AppUser).where(col(AppUser.id) == token.id)).first()
|
|
178
189
|
|
|
179
190
|
|
|
180
|
-
def is_admin_user(token: str = Depends(SCHEME)) -> AppUser:
|
|
191
|
+
def is_admin_user(token: str = Depends(SCHEME), tfa_value: Optional[str] = None) -> AppUser:
|
|
181
192
|
"""
|
|
182
193
|
Retrieves (if it exists) the admin (meaning who has valid credentials) user from the db
|
|
183
194
|
"""
|
|
184
|
-
if (user := get_current_user(token)) and user.permission == Permission.ADMIN:
|
|
195
|
+
if (user := get_current_user(token, tfa_value)) and user.permission == Permission.ADMIN:
|
|
185
196
|
return user
|
|
186
197
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=ADMIN_ERROR,
|
|
187
198
|
headers={'WWW-Authenticate': 'Bearer'})
|
|
@@ -197,22 +208,27 @@ def is_monitoring_user(token: str = Depends(SCHEME)) -> AppUser:
|
|
|
197
208
|
detail=MONITORING_ERROR, headers={'WWW-Authenticate': 'Bearer'})
|
|
198
209
|
|
|
199
210
|
|
|
200
|
-
def _create_access_token(data: Dict) -> str:
|
|
211
|
+
def _create_access_token(data: Dict, tfa_value: Optional[str] = None) -> str:
|
|
201
212
|
"""
|
|
202
213
|
Create an access token out of the passed data. Only called if credentials are valid
|
|
203
214
|
"""
|
|
204
215
|
to_encode = data.copy()
|
|
205
216
|
expire = datetime.now(timezone.utc) + timedelta(minutes=AUTH.access_token_expire_minutes)
|
|
206
|
-
to_encode
|
|
217
|
+
to_encode['exp'] = expire
|
|
218
|
+
if tfa_value:
|
|
219
|
+
to_encode['tfa'] = _hash_password(tfa_value)
|
|
207
220
|
return jwt.encode(to_encode, AUTH.secret_key, algorithm=AUTH.algorithm)
|
|
208
221
|
|
|
209
222
|
|
|
210
|
-
def _verify_access_token(token: str) -> TokenData:
|
|
223
|
+
def _verify_access_token(token: str, tfa_value: Optional[str] = None) -> TokenData:
|
|
211
224
|
"""
|
|
212
225
|
Retrieves the token data associated to the passed token if it contains valid credential info.
|
|
213
226
|
"""
|
|
214
227
|
try:
|
|
215
228
|
payload = jwt.decode(token, AUTH.secret_key, algorithms=[AUTH.algorithm])
|
|
229
|
+
if tfa_value and not _check_password(tfa_value, payload.get('tfa')):
|
|
230
|
+
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=INVALID_TFA,
|
|
231
|
+
headers={'WWW-Authenticate': 'Bearer'})
|
|
216
232
|
if (user_id := payload.get('user_id')) is None:
|
|
217
233
|
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=INVALID_USER,
|
|
218
234
|
headers={'WWW-Authenticate': 'Bearer'})
|
|
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
|