bae705aa97
- Add NFC ePassport roadmap (ICAO 9303, eIDAS) - Add TensorFlow.js edge face detection (BlazeFace) - Add structured audit logger (GDPR-compliant) - Risk scoring support Part of KYC Apple Native UX v1.1.0
152 lines
4.7 KiB
Python
152 lines
4.7 KiB
Python
"""
|
|
Authentication and Authorization
|
|
JWT-based auth with role-based access control
|
|
"""
|
|
|
|
from datetime import datetime, timedelta
|
|
from typing import Optional, Dict, List
|
|
from enum import Enum
|
|
import jwt
|
|
from fastapi import HTTPException, Security
|
|
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
|
|
|
|
|
class UserRole(str, Enum):
|
|
"""User roles"""
|
|
ADMIN = "admin"
|
|
MUNICIPALITY = "municipality"
|
|
PROPERTY_OWNER = "property_owner"
|
|
INFRASTRUCTURE_OWNER = "infrastructure_owner"
|
|
INSURANCE = "insurance"
|
|
BANK = "bank"
|
|
RETAIL = "retail"
|
|
ZOOMER = "zoomer"
|
|
READONLY = "readonly"
|
|
|
|
|
|
class Permission(str, Enum):
|
|
"""Permissions"""
|
|
READ_OBSERVATIONS = "read:observations"
|
|
WRITE_OBSERVATIONS = "write:observations"
|
|
READ_ANALYTICS = "read:analytics"
|
|
WRITE_ANALYTICS = "write:analytics"
|
|
READ_DECISIONS = "read:decisions"
|
|
WRITE_DECISIONS = "write:decisions"
|
|
READ_ADMIN = "read:admin"
|
|
WRITE_ADMIN = "write:admin"
|
|
MANAGE_USERS = "manage:users"
|
|
MANAGE_SYSTEM = "manage:system"
|
|
|
|
|
|
# Role permissions mapping
|
|
ROLE_PERMISSIONS = {
|
|
UserRole.ADMIN: [p for p in Permission],
|
|
UserRole.MUNICIPALITY: [
|
|
Permission.READ_OBSERVATIONS,
|
|
Permission.WRITE_OBSERVATIONS,
|
|
Permission.READ_ANALYTICS,
|
|
Permission.READ_DECISIONS,
|
|
Permission.WRITE_DECISIONS
|
|
],
|
|
UserRole.PROPERTY_OWNER: [
|
|
Permission.READ_OBSERVATIONS,
|
|
Permission.READ_ANALYTICS,
|
|
Permission.READ_DECISIONS
|
|
],
|
|
UserRole.INFRASTRUCTURE_OWNER: [
|
|
Permission.READ_OBSERVATIONS,
|
|
Permission.WRITE_OBSERVATIONS,
|
|
Permission.READ_ANALYTICS,
|
|
Permission.READ_DECISIONS,
|
|
Permission.WRITE_DECISIONS
|
|
],
|
|
UserRole.INSURANCE: [
|
|
Permission.READ_OBSERVATIONS,
|
|
Permission.READ_ANALYTICS,
|
|
Permission.READ_DECISIONS
|
|
],
|
|
UserRole.BANK: [
|
|
Permission.READ_OBSERVATIONS,
|
|
Permission.READ_ANALYTICS,
|
|
Permission.READ_DECISIONS
|
|
],
|
|
UserRole.RETAIL: [
|
|
Permission.READ_OBSERVATIONS,
|
|
Permission.READ_ANALYTICS,
|
|
Permission.READ_DECISIONS
|
|
],
|
|
UserRole.ZOOMER: [
|
|
Permission.READ_OBSERVATIONS,
|
|
Permission.WRITE_OBSERVATIONS
|
|
],
|
|
UserRole.READONLY: [
|
|
Permission.READ_OBSERVATIONS,
|
|
Permission.READ_ANALYTICS
|
|
]
|
|
}
|
|
|
|
|
|
class AuthManager:
|
|
"""Authentication and authorization manager"""
|
|
|
|
def __init__(self, secret_key: str, algorithm: str = "HS256"):
|
|
self.secret_key = secret_key
|
|
self.algorithm = algorithm
|
|
self.security = HTTPBearer()
|
|
|
|
def create_token(self, user_id: str, role: UserRole, expires_hours: int = 24) -> str:
|
|
"""Create JWT token"""
|
|
payload = {
|
|
"sub": user_id,
|
|
"role": role.value,
|
|
"permissions": [p.value for p in ROLE_PERMISSIONS[role]],
|
|
"iat": datetime.utcnow(),
|
|
"exp": datetime.utcnow() + timedelta(hours=expires_hours)
|
|
}
|
|
|
|
return jwt.encode(payload, self.secret_key, algorithm=self.algorithm)
|
|
|
|
def verify_token(self, token: str) -> Dict:
|
|
"""Verify JWT token"""
|
|
try:
|
|
payload = jwt.decode(token, self.secret_key, algorithms=[self.algorithm])
|
|
return payload
|
|
except jwt.ExpiredSignatureError:
|
|
raise HTTPException(status_code=401, detail="Token expired")
|
|
except jwt.InvalidTokenError:
|
|
raise HTTPException(status_code=401, detail="Invalid token")
|
|
|
|
def get_current_user(self, credentials: HTTPAuthorizationCredentials = Security(HTTPBearer())):
|
|
"""Get current user from token"""
|
|
token = credentials.credentials
|
|
return self.verify_token(token)
|
|
|
|
def require_permission(self, permission: Permission):
|
|
"""Require specific permission"""
|
|
def checker(credentials: HTTPAuthorizationCredentials = Security(HTTPBearer())):
|
|
token = credentials.credentials
|
|
payload = self.verify_token(token)
|
|
|
|
user_permissions = payload.get("permissions", [])
|
|
if permission.value not in user_permissions:
|
|
raise HTTPException(
|
|
status_code=403,
|
|
detail=f"Permission denied: {permission.value}"
|
|
)
|
|
|
|
return payload
|
|
|
|
return checker
|
|
|
|
def has_permission(self, user_payload: Dict, permission: Permission) -> bool:
|
|
"""Check if user has permission"""
|
|
user_permissions = user_payload.get("permissions", [])
|
|
return permission.value in user_permissions
|
|
|
|
|
|
# Initialize auth manager
|
|
import os
|
|
auth_manager = AuthManager(
|
|
secret_key=os.getenv("JWT_SECRET", "iom_jwt_secret")
|
|
)
|