You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
2.2 KiB
84 lines
2.2 KiB
"""Service to handle authentication."""
|
|
import re
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
from nacl import pwhash
|
|
from nacl.exceptions import InvalidkeyError
|
|
|
|
from atheneum import errors
|
|
from atheneum.model import User, UserToken
|
|
from atheneum.service import user_token_service
|
|
|
|
|
|
def validate_password_strength(proposed_password: str) -> str:
|
|
"""Validate that a password meets minimum strength requirements."""
|
|
# calculating the length
|
|
length_error = len(proposed_password) < 8
|
|
|
|
# searching for digits
|
|
digit_error = re.search(r"\d", proposed_password) is None
|
|
|
|
# searching for uppercase
|
|
uppercase_error = re.search(r"[A-Z]", proposed_password) is None
|
|
|
|
# searching for lowercase
|
|
lowercase_error = re.search(r"[a-z]", proposed_password) is None
|
|
|
|
if length_error or digit_error or uppercase_error or lowercase_error:
|
|
raise errors.ValidationError(
|
|
' '.join(['The password must be at least 8 characters long.',
|
|
'Contain one or more digits,',
|
|
'one or more uppercase characters,',
|
|
'and one or more lowercase characters']))
|
|
|
|
return proposed_password
|
|
|
|
|
|
def is_valid_password(user: User, password: str) -> bool:
|
|
"""
|
|
User password must pass pwhash verify.
|
|
|
|
:param user:
|
|
:param password:
|
|
:return:
|
|
"""
|
|
assert user
|
|
|
|
try:
|
|
return pwhash.verify(
|
|
user.password_hash.encode('utf8'), password.encode('utf8'))
|
|
except InvalidkeyError:
|
|
pass
|
|
return False
|
|
|
|
|
|
def is_valid_token(user_token: Optional[UserToken]) -> bool:
|
|
"""
|
|
Validate a token.
|
|
|
|
Token must be enabled and if it has an expiration, it must be greater
|
|
than now.
|
|
|
|
:param user_token:
|
|
:return:
|
|
"""
|
|
if user_token is None:
|
|
return False
|
|
if not user_token.enabled:
|
|
return False
|
|
if (user_token.expiration_time is not None
|
|
and user_token.expiration_time < datetime.utcnow()):
|
|
return False
|
|
return True
|
|
|
|
|
|
def logout(user_token: Optional[UserToken] = None) -> None:
|
|
"""
|
|
Remove a user_token associated with a client session.
|
|
|
|
:param user_token:
|
|
:return:
|
|
"""
|
|
if user_token is not None:
|
|
user_token_service.delete(user_token)
|