128 lines
4.8 KiB
Python
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.security.tokenManager 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
|
|
|