feat: add logs
This commit is contained in:
@@ -25,8 +25,16 @@ class PassKycCommand:
|
|||||||
|
|
||||||
|
|
||||||
async def __call__(self,user_id: str) -> BeorgKycCreateResponse:
|
async def __call__(self,user_id: str) -> BeorgKycCreateResponse:
|
||||||
|
self._logger.info(f'KYC session creation started for user {user_id}')
|
||||||
|
self._logger.info(f'KYC Beorg identification request started for user {user_id}')
|
||||||
result = await self._beorg_service.create_identification(client_user_token=user_id)
|
result = await self._beorg_service.create_identification(client_user_token=user_id)
|
||||||
|
self._logger.info(
|
||||||
|
f'KYC Beorg identification request finished for user {user_id} '
|
||||||
|
f'status={result.status} user_token={result.user_token} client_user_token={result.client_user_token}'
|
||||||
|
)
|
||||||
expires_at = _utc_now() + timedelta(seconds=KYC_SESSION_TTL)
|
expires_at = _utc_now() + timedelta(seconds=KYC_SESSION_TTL)
|
||||||
|
self._logger.info(f'KYC session expiration calculated for user {user_id} ttl={KYC_SESSION_TTL} expires_at={expires_at.isoformat()}')
|
||||||
|
self._logger.info(f'KYC session database save started for user {user_id}')
|
||||||
async with self._unit_of_work as unit_of_work:
|
async with self._unit_of_work as unit_of_work:
|
||||||
await unit_of_work.kyc_repository.create_started_session(
|
await unit_of_work.kyc_repository.create_started_session(
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
@@ -37,7 +45,8 @@ class PassKycCommand:
|
|||||||
expires_at=expires_at,
|
expires_at=expires_at,
|
||||||
error=result.error,
|
error=result.error,
|
||||||
)
|
)
|
||||||
self._logger.info(f'KYC started for user {user_id}')
|
self._logger.info(f'KYC session database save finished for user {user_id}')
|
||||||
|
self._logger.info(f'KYC session creation finished for user {user_id}')
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class JwtService(IJwtService):
|
|||||||
self._key_store = key_store
|
self._key_store = key_store
|
||||||
|
|
||||||
async def decode_access_token(self, token: str) -> AccessTokenPayload:
|
async def decode_access_token(self, token: str) -> AccessTokenPayload:
|
||||||
|
self._logger.info('JWT access token decode started')
|
||||||
payload = await self._decode_and_verify(token)
|
payload = await self._decode_and_verify(token)
|
||||||
|
|
||||||
if payload.get('type') != 'access':
|
if payload.get('type') != 'access':
|
||||||
@@ -20,7 +21,7 @@ class JwtService(IJwtService):
|
|||||||
raise InvalidTokenException('Invalid token type')
|
raise InvalidTokenException('Invalid token type')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return AccessTokenPayload(
|
result = AccessTokenPayload(
|
||||||
sub=str(payload['sub']),
|
sub=str(payload['sub']),
|
||||||
type='access',
|
type='access',
|
||||||
sid=str(payload['sid']),
|
sid=str(payload['sid']),
|
||||||
@@ -30,6 +31,8 @@ class JwtService(IJwtService):
|
|||||||
iss=payload.get('iss'),
|
iss=payload.get('iss'),
|
||||||
aud=payload.get('aud'),
|
aud=payload.get('aud'),
|
||||||
)
|
)
|
||||||
|
self._logger.info(f'JWT access token decode completed user_id={result.sub} sid={result.sid}')
|
||||||
|
return result
|
||||||
except KeyError as exception:
|
except KeyError as exception:
|
||||||
self._logger.warning(f'Access token missing claim error={str(exception)}')
|
self._logger.warning(f'Access token missing claim error={str(exception)}')
|
||||||
raise InvalidTokenException(f'Missing token claim: {exception}')
|
raise InvalidTokenException(f'Missing token claim: {exception}')
|
||||||
@@ -37,6 +40,7 @@ class JwtService(IJwtService):
|
|||||||
async def _decode_and_verify(self, token: str) -> dict:
|
async def _decode_and_verify(self, token: str) -> dict:
|
||||||
kid: str | None = None
|
kid: str | None = None
|
||||||
try:
|
try:
|
||||||
|
self._logger.debug('JWT header parsing started')
|
||||||
header = jwt.get_unverified_header(token)
|
header = jwt.get_unverified_header(token)
|
||||||
|
|
||||||
kid = header.get('kid')
|
kid = header.get('kid')
|
||||||
@@ -49,6 +53,7 @@ class JwtService(IJwtService):
|
|||||||
self._logger.warning(f'JWT invalid algorithm kid={kid} received_alg={received_alg} expected_alg={settings.JWT_ALGORITHM}')
|
self._logger.warning(f'JWT invalid algorithm kid={kid} received_alg={received_alg} expected_alg={settings.JWT_ALGORITHM}')
|
||||||
raise InvalidTokenException('Invalid token algorithm')
|
raise InvalidTokenException('Invalid token algorithm')
|
||||||
|
|
||||||
|
self._logger.debug(f'JWT public key lookup started kid={kid}')
|
||||||
public_pem = await self._key_store.get_public_key_for_kid(str(kid))
|
public_pem = await self._key_store.get_public_key_for_kid(str(kid))
|
||||||
|
|
||||||
if not public_pem:
|
if not public_pem:
|
||||||
@@ -60,6 +65,7 @@ class JwtService(IJwtService):
|
|||||||
self._logger.warning(f'JWT unknown kid kid={kid}')
|
self._logger.warning(f'JWT unknown kid kid={kid}')
|
||||||
raise InvalidTokenException('Unknown token kid')
|
raise InvalidTokenException('Unknown token kid')
|
||||||
|
|
||||||
|
self._logger.debug(f'JWT signature verification started kid={kid}')
|
||||||
options = {
|
options = {
|
||||||
'verify_signature': True,
|
'verify_signature': True,
|
||||||
'verify_exp': True,
|
'verify_exp': True,
|
||||||
@@ -91,6 +97,7 @@ class JwtService(IJwtService):
|
|||||||
self._logger.warning(f'JWT missing type claim kid={kid}')
|
self._logger.warning(f'JWT missing type claim kid={kid}')
|
||||||
raise InvalidTokenException('Missing token claim: type')
|
raise InvalidTokenException('Missing token claim: type')
|
||||||
|
|
||||||
|
self._logger.info(f'JWT signature verification completed kid={kid} user_id={payload.get("sub")} sid={payload.get("sid")}')
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
except ExpiredSignatureError as exception:
|
except ExpiredSignatureError as exception:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from src.application.contracts import IJwtService
|
|||||||
from src.application.domain.exceptions import InvalidTokenException,NotAuthenticatedException
|
from src.application.domain.exceptions import InvalidTokenException,NotAuthenticatedException
|
||||||
from src.application.domain.dto import AccessTokenPayload, AuthContext
|
from src.application.domain.dto import AccessTokenPayload, AuthContext
|
||||||
from src.presentation.dependencies import get_jwt_service
|
from src.presentation.dependencies import get_jwt_service
|
||||||
|
from src.presentation.dependencies.logger import get_logger
|
||||||
|
|
||||||
|
|
||||||
def _extract_access_token(request: Request) -> str | None:
|
def _extract_access_token(request: Request) -> str | None:
|
||||||
@@ -25,12 +26,17 @@ async def require_access_token(
|
|||||||
request: Request,
|
request: Request,
|
||||||
jwt_service: IJwtService = Depends(get_jwt_service),
|
jwt_service: IJwtService = Depends(get_jwt_service),
|
||||||
) -> AuthContext:
|
) -> AuthContext:
|
||||||
|
logger = get_logger()
|
||||||
|
logger.info(f'JWT auth started path={request.url.path}')
|
||||||
token = _extract_access_token(request)
|
token = _extract_access_token(request)
|
||||||
if not token:
|
if not token:
|
||||||
|
logger.warning(f'JWT auth failed path={request.url.path} reason=missing_token')
|
||||||
raise NotAuthenticatedException()
|
raise NotAuthenticatedException()
|
||||||
|
|
||||||
payload: AccessTokenPayload = await jwt_service.decode_access_token(token)
|
payload: AccessTokenPayload = await jwt_service.decode_access_token(token)
|
||||||
if payload.type != 'access':
|
if payload.type != 'access':
|
||||||
|
logger.warning(f'JWT auth failed path={request.url.path} user_id={payload.sub} reason=invalid_token_type type={payload.type}')
|
||||||
raise InvalidTokenException('Invalid token type')
|
raise InvalidTokenException('Invalid token type')
|
||||||
|
|
||||||
|
logger.info(f'JWT auth completed path={request.url.path} user_id={payload.sub} sid={payload.sid}')
|
||||||
return AuthContext(user_id=payload.sub, sid=payload.sid, token=payload)
|
return AuthContext(user_id=payload.sub, sid=payload.sid, token=payload)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from typing import Callable, Awaitable, Any, Optional, Annotated
|
|||||||
from fastapi import Request, Header
|
from fastapi import Request, Header
|
||||||
from src.application.domain.exceptions import CsrfRequestRequiredException
|
from src.application.domain.exceptions import CsrfRequestRequiredException
|
||||||
from src.infrastructure.security import CsrfService
|
from src.infrastructure.security import CsrfService
|
||||||
|
from src.presentation.dependencies.logger import get_logger
|
||||||
|
|
||||||
|
|
||||||
def csrf_protect(
|
def csrf_protect(
|
||||||
@@ -31,6 +32,7 @@ def csrf_protect(
|
|||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
async def wrapper(*args, **kwargs):
|
async def wrapper(*args, **kwargs):
|
||||||
|
logger = get_logger()
|
||||||
request: Request | None = kwargs.get('request')
|
request: Request | None = kwargs.get('request')
|
||||||
if request is None:
|
if request is None:
|
||||||
for arg in args:
|
for arg in args:
|
||||||
@@ -39,8 +41,10 @@ def csrf_protect(
|
|||||||
break
|
break
|
||||||
|
|
||||||
if request is None:
|
if request is None:
|
||||||
|
logger.warning('CSRF check failed reason=missing_request')
|
||||||
raise CsrfRequestRequiredException()
|
raise CsrfRequestRequiredException()
|
||||||
|
|
||||||
|
logger.info(f'CSRF check started path={request.url.path}')
|
||||||
csrf = CsrfService()
|
csrf = CsrfService()
|
||||||
|
|
||||||
cookie_token, _ = csrf.extract(request.cookies, request.headers)
|
cookie_token, _ = csrf.extract(request.cookies, request.headers)
|
||||||
@@ -50,6 +54,7 @@ def csrf_protect(
|
|||||||
csrf.verify_pair(cookie_token, header_token, expected_subject)
|
csrf.verify_pair(cookie_token, header_token, expected_subject)
|
||||||
|
|
||||||
kwargs.pop('x_csrf_token', None)
|
kwargs.pop('x_csrf_token', None)
|
||||||
|
logger.info(f'CSRF check completed path={request.url.path}')
|
||||||
return await func(*args, **kwargs)
|
return await func(*args, **kwargs)
|
||||||
|
|
||||||
wrapper.__signature__ = sig.replace(parameters=params)
|
wrapper.__signature__ = sig.replace(parameters=params)
|
||||||
|
|||||||
Reference in New Issue
Block a user