gateway/modules/services/serviceSecurity/mainServiceSecurity.py
2025-12-09 23:25:06 +01:00

128 lines
4.8 KiB
Python

"""
Security service for token management operations.
Provides centralized access to token refresh and management functionality.
"""
import logging
from typing import Optional, Callable
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, services):
"""Initialize security service with service center access.
Args:
services: Service center instance providing access to interfaces
"""
self.services = services
self._tokenManager = TokenManager()
def getFreshToken(self, connectionId: str, secondsBeforeExpiry: int = 30 * 60) -> Optional[Token]:
"""Get a fresh token for a connection, refreshing when expiring soon.
Reads the latest stored token via interface layer, then
uses ensureFreshToken to refresh if needed and persists the refreshed
token via interface layer.
Args:
connectionId: ID of the connection to get token for
secondsBeforeExpiry: Threshold window to proactively refresh (default: 30 minutes)
Returns:
Token object or None if not found/expired
"""
try:
# Use interface from services instead of getRootInterface()
interfaceDbApp = self.services.interfaceDbApp
token = interfaceDbApp.getConnectionToken(connectionId)
if not token:
return None
return self._tokenManager.ensureFreshToken(
token,
secondsBeforeExpiry=secondsBeforeExpiry,
saveCallback=lambda t: 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.
Args:
oldToken: Token object to refresh
Returns:
Refreshed Token object or None if refresh failed
"""
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.
Args:
token: Existing token to validate/refresh
secondsBeforeExpiry: Threshold window to proactively refresh (default: 30 minutes)
saveCallback: Optional function to persist a refreshed token
Returns:
A fresh token (refreshed or original) or None if refresh failed
"""
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.
Args:
refreshToken: Microsoft refresh token
userId: User ID owning the token
oldToken: Previous token object to preserve connection ID
Returns:
New Token object or None if refresh failed
"""
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.
Args:
refreshToken: Google refresh token
userId: User ID owning the token
oldToken: Previous token object to preserve connection ID
Returns:
New Token object or None if refresh failed
"""
try:
return self._tokenManager.refreshGoogleToken(refreshToken, userId, oldToken)
except Exception as e:
logger.error(f"refreshGoogleToken: Error refreshing Google token: {e}")
return None