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>
649 lines
17 KiB
Markdown
649 lines
17 KiB
Markdown
# 🔐 ROA2WEB Shared Authentication System
|
|
|
|
Sistem de autentificare JWT partajat între toate aplicațiile din ecosistemul ROA2WEB, integrat cu Oracle Database și optimizat pentru aplicații FastAPI.
|
|
|
|
## 📋 Table of Contents
|
|
|
|
- [Features](#features)
|
|
- [Architecture](#architecture)
|
|
- [Quick Start](#quick-start)
|
|
- [Components](#components)
|
|
- [Integration Guide](#integration-guide)
|
|
- [Security Features](#security-features)
|
|
- [API Reference](#api-reference)
|
|
- [Testing](#testing)
|
|
- [Deployment](#deployment)
|
|
- [Troubleshooting](#troubleshooting)
|
|
|
|
## ✨ Features
|
|
|
|
### Core Features
|
|
- **JWT Authentication**: Secure token-based authentication cu access și refresh tokens
|
|
- **Oracle Database Integration**: Folosește `pack_drepturi.verificautilizator` pentru autentificare
|
|
- **Multi-Company Support**: Acces controlat la multiple firme/schemas Oracle
|
|
- **Permission System**: Sistem granular de permisiuni (read, write, admin, reports)
|
|
- **FastAPI Integration**: Dependencies și middleware native pentru FastAPI
|
|
- **Rate Limiting**: Protecție împotriva brute force attacks
|
|
- **Caching**: Cache inteligent pentru performanță optimă
|
|
|
|
### Security Features
|
|
- **Token Expiration**: Configurabil pentru access și refresh tokens
|
|
- **SQL Injection Protection**: Parametri legați în toate query-urile
|
|
- **Rate Limiting**: Configurabil per IP și endpoint
|
|
- **CORS Protection**: Configurare flexibilă pentru origins
|
|
- **Header Security**: Security headers automate
|
|
- **Token Blacklisting**: Suport pentru invalidarea token-urilor (în dezvoltare)
|
|
|
|
## 🏗️ Architecture
|
|
|
|
```
|
|
ROA2WEB Authentication Flow:
|
|
┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐
|
|
│ Client │───▶│ FastAPI │───▶│ JWT │───▶│ Oracle │
|
|
│ (Frontend) │ │ Application │ │ Handler │ │ Database │
|
|
└─────────────┘ └──────────────┘ └─────────────┘ └──────────────┘
|
|
│ │ │
|
|
▼ ▼ ▼
|
|
┌──────────────┐ ┌─────────────┐ ┌──────────────┐
|
|
│ Auth Service │ │ Middleware │ │ User Cache │
|
|
└──────────────┘ └─────────────┘ └──────────────┘
|
|
```
|
|
|
|
### Components Overview
|
|
|
|
```
|
|
shared/auth/
|
|
├── jwt_handler.py # JWT token creation și validation
|
|
├── auth_service.py # Oracle database integration
|
|
├── models.py # Pydantic models pentru data validation
|
|
├── middleware.py # FastAPI middleware pentru auto-authentication
|
|
├── dependencies.py # FastAPI dependencies pentru protected routes
|
|
├── routes.py # Pre-built authentication routes
|
|
├── test_auth.py # Comprehensive test suite
|
|
├── demo_app.py # Demo application cu examples
|
|
└── README.md # Această documentație
|
|
```
|
|
|
|
## 🚀 Quick Start
|
|
|
|
### 1. Environment Setup
|
|
|
|
```bash
|
|
# Copy și configurează environment variables
|
|
cp .env.example .env
|
|
|
|
# Edit .env cu configurările tale
|
|
JWT_SECRET_KEY=your-super-secret-jwt-key-change-in-production
|
|
ORACLE_USER=your_oracle_username
|
|
ORACLE_PASSWORD=your_oracle_password
|
|
ORACLE_DSN=your_oracle_connection_string
|
|
```
|
|
|
|
### 2. Basic Integration
|
|
|
|
```python
|
|
from fastapi import FastAPI, Depends
|
|
from roa2web.shared.auth import (
|
|
AuthenticationMiddleware, create_auth_router,
|
|
get_current_user, CurrentUser
|
|
)
|
|
from roa2web.shared.database import oracle_pool
|
|
|
|
app = FastAPI(title="My ROA2WEB App")
|
|
|
|
# Add authentication middleware
|
|
app.add_middleware(
|
|
AuthenticationMiddleware,
|
|
excluded_paths=["/", "/docs", "/health", "/auth/login"]
|
|
)
|
|
|
|
# Include authentication routes
|
|
auth_router = create_auth_router()
|
|
app.include_router(auth_router)
|
|
|
|
@app.on_event("startup")
|
|
async def startup():
|
|
await oracle_pool.initialize()
|
|
|
|
@app.get("/protected")
|
|
async def protected_endpoint(
|
|
current_user: CurrentUser = Depends(get_current_user)
|
|
):
|
|
return {"message": f"Hello {current_user.username}!"}
|
|
```
|
|
|
|
### 3. Test Authentication
|
|
|
|
```bash
|
|
# Start demo application
|
|
cd roa2web/shared/auth
|
|
python demo_app.py
|
|
|
|
# Open browser
|
|
open http://localhost:8000/docs
|
|
|
|
# Login prin Swagger UI cu credențialele Oracle
|
|
```
|
|
|
|
## 🧩 Components
|
|
|
|
### JWT Handler (`jwt_handler.py`)
|
|
|
|
Gestionează crearea, validarea și refresh-ul token-urilor JWT.
|
|
|
|
```python
|
|
from roa2web.shared.auth import jwt_handler
|
|
|
|
# Create access token
|
|
token = jwt_handler.create_access_token(
|
|
username="admin",
|
|
companies=["COMP1", "COMP2"],
|
|
permissions=["read", "write", "reports"]
|
|
)
|
|
|
|
# Verify token
|
|
token_data = jwt_handler.verify_token(token)
|
|
if token_data:
|
|
print(f"Valid token for user: {token_data.username}")
|
|
```
|
|
|
|
### Auth Service (`auth_service.py`)
|
|
|
|
Integrează cu Oracle Database pentru autentificare și management utilizatori.
|
|
|
|
```python
|
|
from roa2web.shared.auth import auth_service
|
|
|
|
# Authenticate user
|
|
success, token_response, error = await auth_service.authenticate_and_create_tokens(
|
|
"username", "password"
|
|
)
|
|
|
|
if success:
|
|
print(f"Access token: {token_response.access_token}")
|
|
else:
|
|
print(f"Authentication failed: {error}")
|
|
```
|
|
|
|
### FastAPI Dependencies (`dependencies.py`)
|
|
|
|
Oferă dependencies pentru protejarea endpoint-urilor.
|
|
|
|
```python
|
|
from fastapi import Depends
|
|
from roa2web.shared.auth import (
|
|
get_current_user, require_company_access,
|
|
require_permissions, PermissionType
|
|
)
|
|
|
|
@app.get("/admin-only")
|
|
async def admin_endpoint(
|
|
user: CurrentUser = Depends(require_permissions([PermissionType.ADMIN]))
|
|
):
|
|
return {"message": "Admin access granted"}
|
|
|
|
@app.get("/company/{company_code}/data")
|
|
async def company_data(
|
|
company_code: str,
|
|
user: CurrentUser = Depends(require_company_access(company_code))
|
|
):
|
|
return {"company": company_code, "data": "..."}
|
|
```
|
|
|
|
### Authentication Routes (`routes.py`)
|
|
|
|
Pre-built routes pentru operații de autentificare.
|
|
|
|
```python
|
|
from roa2web.shared.auth import create_auth_router
|
|
|
|
# Basic auth router
|
|
auth_router = create_auth_router()
|
|
app.include_router(auth_router)
|
|
|
|
# Auth router cu admin routes
|
|
auth_router_admin = create_auth_router(include_admin_routes=True)
|
|
app.include_router(auth_router_admin)
|
|
```
|
|
|
|
Available routes:
|
|
- `POST /auth/login` - User authentication
|
|
- `POST /auth/refresh` - Token refresh
|
|
- `POST /auth/logout` - User logout
|
|
- `GET /auth/me` - Current user info
|
|
- `GET /auth/companies` - User companies
|
|
- `GET /auth/status` - Authentication status
|
|
|
|
## 🔧 Integration Guide
|
|
|
|
### Full FastAPI Application
|
|
|
|
```python
|
|
from fastapi import FastAPI, Depends, HTTPException
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from contextlib import asynccontextmanager
|
|
|
|
from roa2web.shared.auth import (
|
|
AuthenticationMiddleware, create_auth_router,
|
|
get_current_user, require_company_access,
|
|
CurrentUser, PermissionType
|
|
)
|
|
from roa2web.shared.database import oracle_pool
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
# Startup
|
|
await oracle_pool.initialize()
|
|
yield
|
|
# Shutdown
|
|
await oracle_pool.close_pool()
|
|
|
|
app = FastAPI(
|
|
title="ROA2WEB Application",
|
|
lifespan=lifespan
|
|
)
|
|
|
|
# CORS
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["http://localhost:3000"],
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
# Authentication
|
|
app.add_middleware(
|
|
AuthenticationMiddleware,
|
|
excluded_paths=["/", "/docs", "/health"],
|
|
rate_limit_paths=["/auth/login"]
|
|
)
|
|
|
|
# Routes
|
|
auth_router = create_auth_router()
|
|
app.include_router(auth_router)
|
|
|
|
# Protected endpoints
|
|
@app.get("/")
|
|
async def public_endpoint():
|
|
return {"message": "Public endpoint"}
|
|
|
|
@app.get("/me")
|
|
async def my_info(current_user: CurrentUser = Depends(get_current_user)):
|
|
return current_user
|
|
|
|
@app.get("/company/{company_code}/invoices")
|
|
async def get_invoices(
|
|
company_code: str,
|
|
current_user: CurrentUser = Depends(require_company_access(company_code))
|
|
):
|
|
# Business logic here
|
|
return {"company": company_code, "invoices": []}
|
|
```
|
|
|
|
### Custom Permissions
|
|
|
|
```python
|
|
from roa2web.shared.auth import require_permissions, PermissionType
|
|
|
|
# Define custom permissions
|
|
class CustomPermissionType(str, Enum):
|
|
INVOICE_READ = "invoice_read"
|
|
INVOICE_WRITE = "invoice_write"
|
|
REPORT_EXPORT = "report_export"
|
|
|
|
# Use in endpoints
|
|
@app.get("/invoices")
|
|
async def get_invoices(
|
|
user: CurrentUser = Depends(require_permissions([CustomPermissionType.INVOICE_READ]))
|
|
):
|
|
return {"invoices": []}
|
|
```
|
|
|
|
### Company-Specific Endpoints
|
|
|
|
```python
|
|
from fastapi import Header
|
|
from roa2web.shared.auth import get_current_company_from_header
|
|
|
|
@app.get("/current-company-data")
|
|
async def get_current_company_data(
|
|
company_code: str = Depends(get_current_company_from_header),
|
|
current_user: CurrentUser = Depends(get_current_user)
|
|
):
|
|
# company_code is automatically extracted from X-Company-Code header
|
|
# and validated against user's accessible companies
|
|
return {"company": company_code, "data": "..."}
|
|
```
|
|
|
|
## 🔒 Security Features
|
|
|
|
### JWT Configuration
|
|
|
|
```python
|
|
# Environment variables
|
|
JWT_SECRET_KEY=your-super-secret-jwt-key-change-in-production
|
|
JWT_ALGORITHM=HS256
|
|
ACCESS_TOKEN_EXPIRE_MINUTES=30
|
|
REFRESH_TOKEN_EXPIRE_DAYS=7
|
|
```
|
|
|
|
### Rate Limiting
|
|
|
|
```python
|
|
from roa2web.shared.auth import RateLimiter, AuthenticationMiddleware
|
|
|
|
# Custom rate limiter
|
|
custom_rate_limiter = RateLimiter(
|
|
max_requests=10, # 10 requests
|
|
time_window=60 # per minute
|
|
)
|
|
|
|
app.add_middleware(
|
|
AuthenticationMiddleware,
|
|
rate_limit_paths=["/auth/login", "/auth/register"],
|
|
rate_limiter=custom_rate_limiter
|
|
)
|
|
```
|
|
|
|
### Security Headers
|
|
|
|
Middleware-ul adaugă automat header-e de securitate:
|
|
|
|
```
|
|
X-Content-Type-Options: nosniff
|
|
X-Frame-Options: DENY
|
|
X-XSS-Protection: 1; mode=block
|
|
```
|
|
|
|
## 📚 API Reference
|
|
|
|
### JWT Handler Methods
|
|
|
|
```python
|
|
class JWTHandler:
|
|
def create_access_token(username, companies, user_id=None, permissions=None) -> str
|
|
def create_refresh_token(username, user_id=None) -> str
|
|
def verify_token(token) -> Optional[TokenData]
|
|
def refresh_access_token(refresh_token, companies, permissions=None) -> Optional[str]
|
|
def create_token_response(username, companies, ...) -> TokenResponse
|
|
```
|
|
|
|
### Auth Service Methods
|
|
|
|
```python
|
|
class UserAuthService:
|
|
async def verify_user_credentials(username, password) -> bool
|
|
async def get_user_companies(username) -> List[str]
|
|
async def get_user_permissions(username, company) -> List[str]
|
|
async def authenticate_and_create_tokens(username, password) -> Tuple[bool, TokenResponse, str]
|
|
async def validate_user_company_access(username, company) -> bool
|
|
```
|
|
|
|
### FastAPI Dependencies
|
|
|
|
```python
|
|
# User dependencies
|
|
get_current_user() -> CurrentUser
|
|
get_optional_user() -> Optional[CurrentUser]
|
|
|
|
# Permission dependencies
|
|
require_permissions(permissions: List[PermissionType])
|
|
require_company_access(company_code: str)
|
|
require_company_and_permissions(company_code: str, permissions: List[PermissionType])
|
|
|
|
# Utility dependencies
|
|
get_current_company_from_header() -> str
|
|
```
|
|
|
|
## 🧪 Testing
|
|
|
|
### Running Tests
|
|
|
|
```bash
|
|
# Install test dependencies
|
|
pip install pytest pytest-asyncio httpx
|
|
|
|
# Run all tests
|
|
cd roa2web/shared/auth
|
|
python -m pytest test_auth.py -v
|
|
|
|
# Run specific test categories
|
|
python -m pytest test_auth.py::TestJWTHandler -v
|
|
python -m pytest test_auth.py::TestUserAuthService -v
|
|
python -m pytest test_auth.py::TestSecurityFeatures -v
|
|
|
|
# Run with coverage
|
|
python -m pytest test_auth.py --cov=. --cov-report=html
|
|
```
|
|
|
|
### Test Categories
|
|
|
|
- **Unit Tests**: JWT operations, auth service methods
|
|
- **Integration Tests**: Database integration, full auth flow
|
|
- **Security Tests**: Token tampering, SQL injection, rate limiting
|
|
- **Performance Tests**: Token creation/verification speed
|
|
|
|
### Demo Application
|
|
|
|
```bash
|
|
# Start demo app for manual testing
|
|
cd roa2web/shared/auth
|
|
python demo_app.py
|
|
|
|
# Available demo endpoints:
|
|
# http://localhost:8000/ - Home page cu documentație
|
|
# http://localhost:8000/docs - Swagger UI pentru testare
|
|
# http://localhost:8000/demo/* - Various demo endpoints
|
|
```
|
|
|
|
## 🚀 Deployment
|
|
|
|
### Production Configuration
|
|
|
|
```bash
|
|
# Strong JWT secret key
|
|
JWT_SECRET_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
|
|
|
|
# Shorter token expiration
|
|
ACCESS_TOKEN_EXPIRE_MINUTES=15
|
|
REFRESH_TOKEN_EXPIRE_DAYS=1
|
|
|
|
# Strict rate limiting
|
|
RATE_LIMIT_MAX_REQUESTS=3
|
|
RATE_LIMIT_TIME_WINDOW=300
|
|
|
|
# Secure headers
|
|
SECURE_SSL_REDIRECT=true
|
|
SESSION_COOKIE_SECURE=true
|
|
```
|
|
|
|
### Docker Integration
|
|
|
|
```dockerfile
|
|
# În Dockerfile-ul aplicației
|
|
FROM python:3.11-slim
|
|
|
|
WORKDIR /app
|
|
COPY requirements.txt .
|
|
RUN pip install -r requirements.txt
|
|
|
|
COPY . .
|
|
|
|
# Environment pentru container
|
|
ENV JWT_SECRET_KEY=${JWT_SECRET_KEY}
|
|
ENV ORACLE_USER=${ORACLE_USER}
|
|
ENV ORACLE_PASSWORD=${ORACLE_PASSWORD}
|
|
ENV ORACLE_DSN=${ORACLE_DSN}
|
|
|
|
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
|
```
|
|
|
|
### Health Checks
|
|
|
|
```python
|
|
@app.get("/health")
|
|
async def health_check():
|
|
# Test database connection
|
|
try:
|
|
async with oracle_pool.get_connection() as conn:
|
|
with conn.cursor() as cursor:
|
|
cursor.execute("SELECT 1 FROM DUAL")
|
|
db_status = "healthy"
|
|
except Exception as e:
|
|
db_status = f"error: {str(e)}"
|
|
|
|
return {
|
|
"status": "healthy" if db_status == "healthy" else "degraded",
|
|
"database": db_status,
|
|
"jwt": "functional",
|
|
"timestamp": datetime.now().isoformat()
|
|
}
|
|
```
|
|
|
|
## 🔧 Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
#### 1. "Invalid token" errors
|
|
|
|
```python
|
|
# Check JWT secret key consistency
|
|
print(f"JWT Secret: {os.getenv('JWT_SECRET_KEY')}")
|
|
|
|
# Verify token creation and validation
|
|
token = jwt_handler.create_access_token("test", ["COMP1"])
|
|
token_data = jwt_handler.verify_token(token)
|
|
print(f"Token valid: {token_data is not None}")
|
|
```
|
|
|
|
#### 2. Database connection errors
|
|
|
|
```python
|
|
# Test Oracle connection
|
|
try:
|
|
async with oracle_pool.get_connection() as conn:
|
|
with conn.cursor() as cursor:
|
|
cursor.execute("SELECT 1 FROM DUAL")
|
|
result = cursor.fetchone()
|
|
print("Database connection: OK")
|
|
except Exception as e:
|
|
print(f"Database error: {e}")
|
|
```
|
|
|
|
#### 3. Rate limiting issues
|
|
|
|
```python
|
|
# Check rate limiter stats
|
|
from roa2web.shared.auth import default_rate_limiter
|
|
|
|
client_ip = "192.168.1.1"
|
|
allowed = default_rate_limiter.is_allowed(client_ip)
|
|
reset_time = default_rate_limiter.get_reset_time(client_ip)
|
|
print(f"IP {client_ip} allowed: {allowed}, resets at: {reset_time}")
|
|
```
|
|
|
|
#### 4. Permission denied errors
|
|
|
|
```python
|
|
# Check user companies and permissions
|
|
companies = await auth_service.get_user_companies("username")
|
|
permissions = await auth_service.get_user_permissions("username", "COMP1")
|
|
print(f"User companies: {companies}")
|
|
print(f"User permissions: {permissions}")
|
|
```
|
|
|
|
### Debug Mode
|
|
|
|
```python
|
|
import logging
|
|
|
|
# Enable debug logging
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
# Specific loggers
|
|
logging.getLogger("roa2web.shared.auth").setLevel(logging.DEBUG)
|
|
```
|
|
|
|
### Environment Validation
|
|
|
|
```python
|
|
from roa2web.shared.utils.config import shared_config
|
|
|
|
# Validate configuration
|
|
print(f"Oracle User: {shared_config.oracle_user}")
|
|
print(f"JWT Secret set: {'***' if shared_config.jwt_secret_key else 'NOT SET'}")
|
|
print(f"Token expiry: {shared_config.access_token_expire_minutes} minutes")
|
|
```
|
|
|
|
## 📈 Performance Optimization
|
|
|
|
### Caching
|
|
|
|
```python
|
|
# Cache configuration
|
|
AUTH_CACHE_TTL_MINUTES=15 # User data cache TTL
|
|
|
|
# Monitor cache performance
|
|
stats = auth_service.get_cache_stats()
|
|
print(f"Cache hit ratio: {stats['cache_hit_ratio']:.2%}")
|
|
```
|
|
|
|
### Connection Pooling
|
|
|
|
```python
|
|
# Oracle pool configuration
|
|
DB_MIN_CONNECTIONS=2
|
|
DB_MAX_CONNECTIONS=10
|
|
DB_CONNECTION_INCREMENT=1
|
|
```
|
|
|
|
### Token Optimization
|
|
|
|
```python
|
|
# Optimize token size by limiting payload
|
|
token = jwt_handler.create_access_token(
|
|
username="user",
|
|
companies=["COMP1"], # Limit companies in token
|
|
permissions=["read"] # Essential permissions only
|
|
)
|
|
```
|
|
|
|
## 🤝 Contributing
|
|
|
|
Pentru contribuții la sistemul de autentificare:
|
|
|
|
1. **Fork repository-ul** și creează o ramură pentru feature
|
|
2. **Implementează schimbările** cu tests comprehensive
|
|
3. **Rulează toate testele** pentru a verifica compatibilitatea
|
|
4. **Actualizează documentația** dacă este necesar
|
|
5. **Creează Pull Request** cu descriere detaliată
|
|
|
|
### Development Setup
|
|
|
|
```bash
|
|
# Clone repository
|
|
git clone [repository-url]
|
|
cd roa-flask
|
|
|
|
# Setup environment
|
|
python -m venv venv
|
|
source venv/bin/activate # Linux/Mac
|
|
# or
|
|
venv\Scripts\activate # Windows
|
|
|
|
pip install -r requirements.txt
|
|
|
|
# Run tests
|
|
cd roa2web/shared/auth
|
|
python -m pytest test_auth.py -v
|
|
```
|
|
|
|
## 📜 License
|
|
|
|
Acest sistem de autentificare face parte din proiectul ROA2WEB și este disponibil sub aceleași condiții de licențiere ca și proiectul principal.
|
|
|
|
---
|
|
|
|
**ROA2WEB Authentication System v1.0.0**
|
|
*Secure, scalable, Oracle-integrated authentication pentru aplicații moderne* |