gateway/modules/routes/routeSecurityGoogle.py
ValueOn AG cf94b1115b ref
2025-05-26 07:04:30 +02:00

164 lines
No EOL
5.4 KiB
Python

"""
Routes for Google authentication.
"""
from fastapi import APIRouter, HTTPException, Request, Response, status, Depends
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
import logging
import json
from typing import Dict, Any, Optional
from datetime import datetime, timedelta
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import Flow
from google.auth.transport.requests import Request
from modules.shared.configuration import APP_CONFIG
from modules.interfaces.serviceAppClass import getInterface
from modules.interfaces.serviceAppModel import AuthAuthority
from modules.interfaces.serviceAppTokens import GoogleToken, saveToken
from modules.security.auth import getCurrentUser, limiter
# Configure logger
logger = logging.getLogger(__name__)
# Create router
router = APIRouter(
prefix="/api/google",
tags=["Security Google"],
responses={
404: {"description": "Not found"},
400: {"description": "Bad request"},
401: {"description": "Unauthorized"},
403: {"description": "Forbidden"},
500: {"description": "Internal server error"}
}
)
# Google OAuth configuration
CLIENT_ID = APP_CONFIG.get("Service_GOOGLE_CLIENT_ID")
CLIENT_SECRET = APP_CONFIG.get("Service_GOOGLE_CLIENT_SECRET")
REDIRECT_URI = APP_CONFIG.get("Service_GOOGLE_REDIRECT_URI")
SCOPES = [
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"
]
@router.get("/login")
@limiter.limit("5/minute")
async def login():
"""Initiate Google login"""
try:
# Create OAuth flow
flow = Flow.from_client_config(
{
"web": {
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"redirect_uris": [REDIRECT_URI]
}
},
scopes=SCOPES
)
# Generate auth URL
auth_url, _ = flow.authorization_url(
access_type="offline",
include_granted_scopes="true"
)
return RedirectResponse(auth_url)
except Exception as e:
logger.error(f"Error initiating Google login: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to initiate Google login: {str(e)}"
)
@router.get("/auth/callback")
async def auth_callback(code: str, request: Request):
"""Handle Google OAuth callback"""
try:
# Create OAuth flow
flow = Flow.from_client_config(
{
"web": {
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"redirect_uris": [REDIRECT_URI]
}
},
scopes=SCOPES,
redirect_uri=REDIRECT_URI
)
# Exchange code for token
flow.fetch_token(code=code)
credentials = flow.credentials
# Create token data
token_data = {
"access_token": credentials.token,
"refresh_token": credentials.refresh_token,
"token_type": credentials.token_type,
"expires_at": credentials.expiry.timestamp()
}
# Save token data
appInterface = getInterface()
saveToken(appInterface, "Google", token_data)
# Return success page with token data
return HTMLResponse(
content=f"""
<html>
<head><title>Authentication Successful</title></head>
<body>
<script>
if (window.opener) {{
window.opener.postMessage({{
type: 'google_auth_success',
access_token: {json.dumps(credentials.token)},
token_data: {json.dumps(token_data)}
}}, '*');
}}
setTimeout(() => window.close(), 1000);
</script>
</body>
</html>
"""
)
except Exception as e:
logger.error(f"Error in auth callback: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Authentication failed: {str(e)}"
)
@router.post("/logout")
@limiter.limit("30/minute")
async def logout(currentUser: Dict[str, Any] = Depends(getCurrentUser)):
"""Logout from Google"""
try:
# Get user interface
appInterface = getInterface()
# Revoke all sessions for the user
appInterface.revokeAllUserSessions(currentUser.get("id"))
return JSONResponse({
"message": "Successfully logged out from Google"
})
except Exception as e:
logger.error(f"Error during logout: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Logout failed: {str(e)}"
)