Files
Marius Mutu f42eff71a6 Fix .gitignore and add missing authentication source files
This commit fixes overly broad .gitignore patterns that were excluding
important source code files from version control. Previously, wildcard
patterns like *auth*, *token*, *secret*, *connection*, and *credential*
were excluding ALL files containing these words, including critical
application code.

Changes:
- Updated .gitignore with specific patterns for sensitive config files
  (*.json, *.txt, *.yml, *.yaml extensions only)
- Removed broad wildcards that excluded source code files

Added missing source files:
- shared/auth/ (9 files): Complete authentication system
  - JWT handler, middleware, auth service, models, routes
- reports-app/backend/app/routers/auth.py: Authentication API router
- reports-app/backend/app/auth_middleware_wrapper.py: Middleware wrapper
- reports-app/frontend/src/stores/auth.js: Vue.js auth store
- reports-app/frontend/tests/: E2E tests and fixtures for auth
- reports-app/telegram-bot/app/auth/: Telegram auth linking module
- deployment/windows/scripts/Setup-ClaudeAuth.ps1: Windows deployment script
- security/secrets_scanner.py: Security scanning utility

These files are essential for the application to function and should
have been included in the initial commit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-25 15:02:28 +03:00

540 lines
18 KiB
Python

"""
FastAPI Demo App demonstrând sistemul de autentificare ROA2WEB
Această aplicație demonstrează integrarea completă a sistemului de autentificare:
- Login și logout cu Oracle database
- Protected routes cu JWT authentication
- Company-specific access control
- Permission-based authorization
- Rate limiting și security features
Funcționează ca:
1. Exemplu de integrare pentru dezvoltatori
2. Tool de testare pentru sistemul de autentificare
3. Demonstrație pentru managementul proiectului
Pentru a rula demo-ul:
1. Configurează variabilele de mediu în .env
2. Asigură-te că Oracle database este accesibil
3. Rulează: python demo_app.py
4. Acesează http://localhost:8000/docs pentru Swagger UI
"""
import asyncio
import logging
import sys
import os
from datetime import datetime
from typing import List, Optional
import uvicorn
from fastapi import FastAPI, Depends, HTTPException, Request, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse, JSONResponse
from contextlib import asynccontextmanager
# Adaugă calea pentru modulele shared
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
# Import modulele de autentificare
from .jwt_handler import jwt_handler
from .auth_service import auth_service
from .models import CurrentUser, LoginRequest, PermissionType
from .routes import create_auth_router
from .middleware import AuthenticationMiddleware, default_rate_limiter
from .dependencies import (
get_current_user, get_optional_user, require_company_access,
require_permissions, get_current_company_from_header
)
# Import componente shared
from database.oracle_pool import oracle_pool
from utils.config import shared_config
# Configurare logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""
Lifecycle events pentru demo app
"""
# Startup
logger.info("🚀 Starting ROA2WEB Authentication Demo")
try:
# Inițializează Oracle pool
await oracle_pool.initialize(
user=shared_config.oracle_user,
password=shared_config.oracle_password,
dsn=shared_config.oracle_dsn,
min_connections=2,
max_connections=5
)
logger.info("✅ Oracle connection pool initialized")
# Test database connection
async with oracle_pool.get_connection() as conn:
with conn.cursor() as cursor:
cursor.execute("SELECT 'Database connected successfully' FROM DUAL")
result = cursor.fetchone()
logger.info(f"✅ Database test: {result[0]}")
except Exception as e:
logger.error(f"❌ Startup error: {str(e)}")
logger.warning("Demo will continue but database features may not work")
yield
# Shutdown
logger.info("🛑 Shutting down ROA2WEB Authentication Demo")
try:
await oracle_pool.close_pool()
logger.info("✅ Oracle connection pool closed")
except Exception as e:
logger.error(f"❌ Shutdown error: {str(e)}")
# Crearea aplicației FastAPI
app = FastAPI(
title="ROA2WEB Authentication Demo",
description="""
Demonstrație completă a sistemului de autentificare ROA2WEB
Această aplicație demonstrează:
- JWT Authentication cu Oracle Database
- Protected routes și company access control
- Permission-based authorization
- Rate limiting și security features
- Integration patterns pentru aplicații ROA2WEB
""",
version="1.0.0",
docs_url="/docs",
redoc_url="/redoc",
lifespan=lifespan
)
# CORS pentru development
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000", "http://localhost:5173", "http://localhost:8080"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Authentication middleware
app.add_middleware(
AuthenticationMiddleware,
excluded_paths=["/", "/docs", "/redoc", "/openapi.json", "/health", "/demo", "/auth/login"],
rate_limit_paths=["/auth/login"],
rate_limiter=default_rate_limiter
)
# Include authentication router
auth_router = create_auth_router(include_admin_routes=True)
app.include_router(auth_router)
# =============================================================================
# DEMO ENDPOINTS
# =============================================================================
@app.get("/", response_class=HTMLResponse)
async def demo_home():
"""
Pagina principală cu informații despre demo
"""
html_content = """
<!DOCTYPE html>
<html>
<head>
<title>ROA2WEB Authentication Demo</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; background: #f5f5f5; }
.container { max-width: 800px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
h1 { color: #2c3e50; border-bottom: 3px solid #3498db; padding-bottom: 10px; }
h2 { color: #34495e; margin-top: 30px; }
.endpoint { background: #ecf0f1; padding: 15px; margin: 10px 0; border-radius: 5px; border-left: 4px solid #3498db; }
.method { font-weight: bold; color: #e74c3c; }
.protected { border-left-color: #f39c12; }
.public { border-left-color: #27ae60; }
code { background: #34495e; color: white; padding: 2px 6px; border-radius: 3px; }
.status { padding: 10px; margin: 15px 0; border-radius: 5px; }
.success { background: #d5edda; border: 1px solid #c3e6cb; color: #155724; }
.info { background: #d1ecf1; border: 1px solid #bee5eb; color: #0c5460; }
</style>
</head>
<body>
<div class="container">
<h1>🔐 ROA2WEB Authentication Demo</h1>
<div class="status info">
<strong>Status:</strong> Demo aplicație ROA2WEB Authentication System<br>
<strong>Versiune:</strong> 1.0.0<br>
<strong>Timp:</strong> """ + datetime.now().strftime("%Y-%m-%d %H:%M:%S") + """
</div>
<h2>📋 Endpoints Disponibile</h2>
<div class="endpoint public">
<div class="method">GET</div>
<strong>/docs</strong> - Swagger UI pentru testarea API-ului
</div>
<div class="endpoint public">
<div class="method">GET</div>
<strong>/health</strong> - Health check pentru aplicație și database
</div>
<div class="endpoint public">
<div class="method">POST</div>
<strong>/auth/login</strong> - Autentificare utilizator cu username/password
</div>
<div class="endpoint protected">
<div class="method">GET</div>
<strong>/auth/me</strong> - Informații utilizator curent (protejat)
</div>
<div class="endpoint protected">
<div class="method">GET</div>
<strong>/demo/protected</strong> - Endpoint protejat simplu
</div>
<div class="endpoint protected">
<div class="method">GET</div>
<strong>/demo/company/{company_code}</strong> - Endpoint cu verificare acces firmă
</div>
<div class="endpoint protected">
<div class="method">GET</div>
<strong>/demo/admin</strong> - Endpoint cu verificare admin permissions
</div>
<h2>🧪 Cum să testezi</h2>
<ol>
<li>Accesează <a href="/docs">/docs</a> pentru Swagger UI</li>
<li>Folosește <code>POST /auth/login</code> cu credențiale valide</li>
<li>Copiază <code>access_token</code> din răspuns</li>
<li>Click pe "Authorize" în Swagger UI și introdu: <code>Bearer YOUR_TOKEN</code></li>
<li>Testează endpoint-urile protejate</li>
</ol>
<h2>🔧 Configurare</h2>
<p>Pentru a funcționa complet, demo-ul necesită:</p>
<ul>
<li>Variabile de mediu configurate în <code>.env</code></li>
<li>Conexiune la Oracle Database</li>
<li>Utilizatori valizi în sistemul Oracle</li>
</ul>
<div class="status success">
<strong>💡 Tip:</strong> Pentru dezvoltare rapidă, vezi <code>demo_app.py</code>
pentru exemple de integrare a autentificării în aplicațiile tale FastAPI.
</div>
</div>
</body>
</html>
"""
return HTMLResponse(content=html_content)
@app.get("/health")
async def health_check():
"""
Health check complet pentru demo
"""
health_status = {
"service": "ROA2WEB Authentication Demo",
"status": "healthy",
"timestamp": datetime.now().isoformat(),
"version": "1.0.0"
}
# Test database connection
try:
async with oracle_pool.get_connection() as conn:
with conn.cursor() as cursor:
cursor.execute("SELECT 1 FROM DUAL")
cursor.fetchone()
health_status["database"] = "connected"
except Exception as e:
health_status["database"] = f"error: {str(e)}"
health_status["status"] = "degraded"
# Test JWT handler
try:
test_token = jwt_handler.create_access_token("healthcheck", ["TEST"])
token_data = jwt_handler.verify_token(test_token)
if token_data and token_data.username == "healthcheck":
health_status["jwt"] = "functional"
else:
health_status["jwt"] = "error: token verification failed"
health_status["status"] = "degraded"
except Exception as e:
health_status["jwt"] = f"error: {str(e)}"
health_status["status"] = "degraded"
# Authentication service status
try:
cache_stats = auth_service.get_cache_stats()
health_status["auth_cache"] = {
"total_entries": cache_stats["total_entries"],
"cache_hit_ratio": cache_stats["cache_hit_ratio"]
}
except Exception as e:
health_status["auth_cache"] = f"error: {str(e)}"
status_code = 200 if health_status["status"] == "healthy" else 503
return JSONResponse(content=health_status, status_code=status_code)
@app.get("/demo/public")
async def demo_public_endpoint():
"""
Endpoint public - nu necesită autentificare
"""
return {
"message": "Acesta este un endpoint public",
"authenticated": False,
"timestamp": datetime.now().isoformat(),
"info": "Acest endpoint poate fi accesat fără autentificare"
}
@app.get("/demo/optional-auth")
async def demo_optional_auth(
current_user: Optional[CurrentUser] = Depends(get_optional_user)
):
"""
Endpoint cu autentificare opțională
"""
if current_user:
return {
"message": f"Salut, {current_user.username}!",
"authenticated": True,
"user": current_user.username,
"companies": current_user.companies,
"timestamp": datetime.now().isoformat()
}
else:
return {
"message": "Acesta este un endpoint cu autentificare opțională",
"authenticated": False,
"timestamp": datetime.now().isoformat(),
"info": "Poți accesa și fără autentificare, dar cu token obții mai multe informații"
}
@app.get("/demo/protected")
async def demo_protected_endpoint(
current_user: CurrentUser = Depends(get_current_user)
):
"""
Endpoint protejat - necesită autentificare
"""
return {
"message": f"Bună ziua, {current_user.username}!",
"authenticated": True,
"user_info": {
"username": current_user.username,
"companies": current_user.companies,
"permissions": current_user.permissions,
"companies_count": len(current_user.companies)
},
"timestamp": datetime.now().isoformat(),
"info": "Acest endpoint necesită JWT token valid pentru acces"
}
@app.get("/demo/company/{company_code}")
async def demo_company_specific_endpoint(
company_code: str,
current_user: CurrentUser = Depends(require_company_access("")) # Will be overridden
):
"""
Endpoint cu verificare acces la firmă specifică
Demonstrează cum să verifici dacă utilizatorul are acces la o anumită firmă
"""
# Verificare manuală pentru demonstrație (în practică folosești dependency)
if company_code not in current_user.companies:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Nu aveți acces la firma {company_code}"
)
return {
"message": f"Acces permis la firma {company_code}",
"company_code": company_code,
"user": current_user.username,
"user_companies": current_user.companies,
"timestamp": datetime.now().isoformat(),
"info": "Utilizatorul are acces la această firmă"
}
@app.get("/demo/admin")
async def demo_admin_endpoint(
current_user: CurrentUser = Depends(require_permissions([PermissionType.ADMIN]))
):
"""
Endpoint cu verificare permisiuni admin
"""
return {
"message": f"Bună ziua, admin {current_user.username}!",
"admin_info": {
"username": current_user.username,
"permissions": current_user.permissions,
"companies": current_user.companies,
"admin_since": datetime.now().isoformat()
},
"system_stats": {
"total_companies": len(current_user.companies),
"demo_version": "1.0.0",
"auth_system": "ROA2WEB JWT"
},
"timestamp": datetime.now().isoformat(),
"info": "Acest endpoint necesită permisiuni de administrator"
}
@app.get("/demo/reports")
async def demo_reports_endpoint(
request: Request,
current_user: CurrentUser = Depends(require_permissions([PermissionType.REPORTS]))
):
"""
Endpoint pentru rapoarte - demonstrează integrarea cu header-ul Company
"""
# Obține company din header (X-Company-Code) sau folosește prima disponibilă
company_code = request.headers.get("X-Company-Code")
if not company_code:
company_code = current_user.companies[0] if current_user.companies else None
if not company_code:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Nu s-a specificat codul firmei (X-Company-Code header)"
)
if company_code not in current_user.companies:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Nu aveți acces la rapoartele firmei {company_code}"
)
# Simulează generarea unui raport
mock_report_data = {
"company_code": company_code,
"report_type": "demo_report",
"generated_by": current_user.username,
"generated_at": datetime.now().isoformat(),
"data": {
"total_invoices": 150,
"total_amount": 125000.50,
"paid_invoices": 120,
"outstanding_amount": 25000.00
}
}
return {
"message": f"Raport generat pentru firma {company_code}",
"report": mock_report_data,
"user_info": {
"username": current_user.username,
"permissions": current_user.permissions
},
"info": "Acesta este un exemplu de endpoint pentru rapoarte cu verificare company access"
}
@app.get("/demo/rate-limited")
async def demo_rate_limited_endpoint():
"""
Endpoint cu rate limiting pentru demonstrație
"""
return {
"message": "Acest endpoint are rate limiting aplicat",
"timestamp": datetime.now().isoformat(),
"info": "Încercați să faceți mai multe request-uri rapid pentru a vedea rate limiting-ul"
}
# =============================================================================
# DEMO UTILITIES
# =============================================================================
@app.get("/demo/token-info")
async def demo_token_info(
request: Request,
current_user: CurrentUser = Depends(get_current_user)
):
"""
Endpoint pentru afișarea informațiilor despre token-ul curent
"""
# Extrage token-ul din header
auth_header = request.headers.get("Authorization", "")
if auth_header.startswith("Bearer "):
token = auth_header[7:]
# Decodează token-ul pentru informații (fără verificare pentru demo)
payload = jwt_handler.decode_token_payload(token)
return {
"message": "Informații despre token-ul curent",
"token_info": {
"user": current_user.username,
"companies": current_user.companies,
"permissions": current_user.permissions,
"token_type": payload.get("type") if payload else "unknown",
"issued_at": payload.get("iat") if payload else None,
"expires_at": payload.get("exp") if payload else None
},
"timestamp": datetime.now().isoformat()
}
else:
return {
"error": "Nu s-a găsit token în header-ul Authorization"
}
# =============================================================================
# MAIN EXECUTION
# =============================================================================
def main():
"""
Funcția principală pentru rularea demo-ului
"""
print("🚀 Starting ROA2WEB Authentication Demo")
print("📋 Available endpoints:")
print(" • http://localhost:8000/ - Demo home page")
print(" • http://localhost:8000/docs - Swagger UI")
print(" • http://localhost:8000/health - Health check")
print(" • http://localhost:8000/demo/* - Demo endpoints")
print("")
print("💡 Pentru testare completă:")
print(" 1. Configurează .env cu credențialele Oracle")
print(" 2. Asigură-te că database-ul este accesibil")
print(" 3. Folosește /docs pentru testarea interactivă")
print("")
uvicorn.run(
"demo_app:app",
host="0.0.0.0",
port=8000,
reload=True,
log_level="info"
)
if __name__ == "__main__":
main()