81 lines
3.3 KiB
Python
81 lines
3.3 KiB
Python
# Copyright (c) 2025 Patrick Motsch
|
|
# All rights reserved.
|
|
"""
|
|
Security service for token management operations.
|
|
Core service - not requested by features directly.
|
|
"""
|
|
|
|
import logging
|
|
from typing import Optional, Callable, Any
|
|
|
|
from modules.datamodels.datamodelSecurity import Token
|
|
from modules.auth import TokenManager
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SecurityService:
|
|
"""Security service providing token management operations."""
|
|
|
|
def __init__(self, context: Any, get_service: Callable[[str], Any]):
|
|
"""Initialize with service center context and resolver."""
|
|
self._context = context
|
|
self._get_service = get_service
|
|
self._tokenManager = TokenManager()
|
|
from modules.interfaces.interfaceDbApp import getInterface as getAppInterface
|
|
self._interfaceDbApp = getAppInterface(
|
|
context.user,
|
|
mandateId=context.mandate_id,
|
|
)
|
|
|
|
def getFreshToken(self, connectionId: str, secondsBeforeExpiry: int = 30 * 60) -> Optional[Token]:
|
|
"""Get a fresh token for a connection, refreshing when expiring soon."""
|
|
try:
|
|
token = self._interfaceDbApp.getConnectionToken(connectionId)
|
|
if not token:
|
|
return None
|
|
return self._tokenManager.ensureFreshToken(
|
|
token,
|
|
secondsBeforeExpiry=secondsBeforeExpiry,
|
|
saveCallback=lambda t: self._interfaceDbApp.saveConnectionToken(t)
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"getFreshToken: Error fetching or refreshing token for connection {connectionId}: {e}")
|
|
return None
|
|
|
|
def refreshToken(self, oldToken: Token) -> Optional[Token]:
|
|
"""Refresh an expired token using the appropriate OAuth service."""
|
|
try:
|
|
return self._tokenManager.refreshToken(oldToken)
|
|
except Exception as e:
|
|
logger.error(f"refreshToken: Error refreshing token: {e}")
|
|
return None
|
|
|
|
def ensureFreshToken(self, token: Token, *, secondsBeforeExpiry: int = 30 * 60,
|
|
saveCallback: Optional[Callable[[Token], None]] = None) -> Optional[Token]:
|
|
"""Ensure a token is fresh; refresh if expiring within threshold."""
|
|
try:
|
|
return self._tokenManager.ensureFreshToken(
|
|
token,
|
|
secondsBeforeExpiry=secondsBeforeExpiry,
|
|
saveCallback=saveCallback
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"ensureFreshToken: Error ensuring fresh token: {e}")
|
|
return None
|
|
|
|
def refreshMicrosoftToken(self, refreshToken: str, userId: str, oldToken: Token) -> Optional[Token]:
|
|
"""Refresh Microsoft OAuth token using refresh token."""
|
|
try:
|
|
return self._tokenManager.refreshMicrosoftToken(refreshToken, userId, oldToken)
|
|
except Exception as e:
|
|
logger.error(f"refreshMicrosoftToken: Error refreshing Microsoft token: {e}")
|
|
return None
|
|
|
|
def refreshGoogleToken(self, refreshToken: str, userId: str, oldToken: Token) -> Optional[Token]:
|
|
"""Refresh Google OAuth token using refresh token."""
|
|
try:
|
|
return self._tokenManager.refreshGoogleToken(refreshToken, userId, oldToken)
|
|
except Exception as e:
|
|
logger.error(f"refreshGoogleToken: Error refreshing Google token: {e}")
|
|
return None
|