| import hashlib, secrets |
| from datetime import datetime |
| from auth_repository import AuthRepository |
| from permissions import permissions_for_role, role_has_permission |
| from audit_logger import log_action |
| PREFIX = 'org_sk_live_' |
| def hash_key(raw_key): return hashlib.sha256(raw_key.encode('utf-8')).hexdigest() |
| def create_api_key(tenant_id, user_id, role='Admin', expires_at=None): |
| raw = PREFIX + secrets.token_urlsafe(32) |
| key_hash = hash_key(raw); key_id = 'key_' + secrets.token_hex(6); key_prefix = raw[:18] |
| repo = AuthRepository(); repo.seed_role_permissions() |
| rec = repo.create_api_key_record(key_id, tenant_id, user_id, role, key_prefix, key_hash, expires_at) |
| log_action(tenant_id, user_id, 'api_key_created', 'api_key', key_id, metadata={'role': role}) |
| return {'api_key': raw, 'record': rec} |
| def verify_api_key(raw_key): |
| rec = AuthRepository().get_api_key_by_hash(hash_key(raw_key)) |
| if not rec: return {'ok': False, 'error': 'invalid_api_key'} |
| if rec.get('expires_at') and rec['expires_at'] < datetime.utcnow().isoformat(): return {'ok': False, 'error': 'expired_api_key'} |
| repo = AuthRepository(); membership = repo.get_membership(rec['tenant_id'], rec['user_id']) |
| if not membership: return {'ok': False, 'error': 'no_active_membership'} |
| repo.touch_api_key(rec['key_id']) |
| principal = {'tenant_id': rec['tenant_id'], 'user_id': rec['user_id'], 'role': rec['role'], 'permissions': sorted(permissions_for_role(rec['role'])), 'key_id': rec['key_id']} |
| log_action(rec['tenant_id'], rec['user_id'], 'auth_success', 'api_key', rec['key_id']) |
| return {'ok': True, 'principal': principal} |
| def require_permission_principal(principal, permission): |
| ok = role_has_permission(principal.get('role'), permission) |
| if not ok: |
| log_action(principal.get('tenant_id','unknown'), principal.get('user_id','unknown'), 'permission_denied', 'permission', permission, outcome='failure') |
| return {'ok': False, 'error': 'permission_denied', 'permission': permission} |
| return {'ok': True} |
|
|