kailash 0.3.2__py3-none-any.whl → 0.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kailash/__init__.py +33 -1
- kailash/access_control/__init__.py +129 -0
- kailash/access_control/managers.py +461 -0
- kailash/access_control/rule_evaluators.py +467 -0
- kailash/access_control_abac.py +825 -0
- kailash/config/__init__.py +27 -0
- kailash/config/database_config.py +359 -0
- kailash/database/__init__.py +28 -0
- kailash/database/execution_pipeline.py +499 -0
- kailash/middleware/__init__.py +306 -0
- kailash/middleware/auth/__init__.py +33 -0
- kailash/middleware/auth/access_control.py +436 -0
- kailash/middleware/auth/auth_manager.py +422 -0
- kailash/middleware/auth/jwt_auth.py +477 -0
- kailash/middleware/auth/kailash_jwt_auth.py +616 -0
- kailash/middleware/communication/__init__.py +37 -0
- kailash/middleware/communication/ai_chat.py +989 -0
- kailash/middleware/communication/api_gateway.py +802 -0
- kailash/middleware/communication/events.py +470 -0
- kailash/middleware/communication/realtime.py +710 -0
- kailash/middleware/core/__init__.py +21 -0
- kailash/middleware/core/agent_ui.py +890 -0
- kailash/middleware/core/schema.py +643 -0
- kailash/middleware/core/workflows.py +396 -0
- kailash/middleware/database/__init__.py +63 -0
- kailash/middleware/database/base.py +113 -0
- kailash/middleware/database/base_models.py +525 -0
- kailash/middleware/database/enums.py +106 -0
- kailash/middleware/database/migrations.py +12 -0
- kailash/{api/database.py → middleware/database/models.py} +183 -291
- kailash/middleware/database/repositories.py +685 -0
- kailash/middleware/database/session_manager.py +19 -0
- kailash/middleware/mcp/__init__.py +38 -0
- kailash/middleware/mcp/client_integration.py +585 -0
- kailash/middleware/mcp/enhanced_server.py +576 -0
- kailash/nodes/__init__.py +27 -3
- kailash/nodes/admin/__init__.py +42 -0
- kailash/nodes/admin/audit_log.py +794 -0
- kailash/nodes/admin/permission_check.py +864 -0
- kailash/nodes/admin/role_management.py +823 -0
- kailash/nodes/admin/security_event.py +1523 -0
- kailash/nodes/admin/user_management.py +944 -0
- kailash/nodes/ai/a2a.py +24 -7
- kailash/nodes/ai/ai_providers.py +248 -40
- kailash/nodes/ai/embedding_generator.py +11 -11
- kailash/nodes/ai/intelligent_agent_orchestrator.py +99 -11
- kailash/nodes/ai/llm_agent.py +436 -5
- kailash/nodes/ai/self_organizing.py +85 -10
- kailash/nodes/ai/vision_utils.py +148 -0
- kailash/nodes/alerts/__init__.py +26 -0
- kailash/nodes/alerts/base.py +234 -0
- kailash/nodes/alerts/discord.py +499 -0
- kailash/nodes/api/auth.py +287 -6
- kailash/nodes/api/rest.py +151 -0
- kailash/nodes/auth/__init__.py +17 -0
- kailash/nodes/auth/directory_integration.py +1228 -0
- kailash/nodes/auth/enterprise_auth_provider.py +1328 -0
- kailash/nodes/auth/mfa.py +2338 -0
- kailash/nodes/auth/risk_assessment.py +872 -0
- kailash/nodes/auth/session_management.py +1093 -0
- kailash/nodes/auth/sso.py +1040 -0
- kailash/nodes/base.py +344 -13
- kailash/nodes/base_cycle_aware.py +4 -2
- kailash/nodes/base_with_acl.py +1 -1
- kailash/nodes/code/python.py +283 -10
- kailash/nodes/compliance/__init__.py +9 -0
- kailash/nodes/compliance/data_retention.py +1888 -0
- kailash/nodes/compliance/gdpr.py +2004 -0
- kailash/nodes/data/__init__.py +22 -2
- kailash/nodes/data/async_connection.py +469 -0
- kailash/nodes/data/async_sql.py +757 -0
- kailash/nodes/data/async_vector.py +598 -0
- kailash/nodes/data/readers.py +767 -0
- kailash/nodes/data/retrieval.py +360 -1
- kailash/nodes/data/sharepoint_graph.py +397 -21
- kailash/nodes/data/sql.py +94 -5
- kailash/nodes/data/streaming.py +68 -8
- kailash/nodes/data/vector_db.py +54 -4
- kailash/nodes/enterprise/__init__.py +13 -0
- kailash/nodes/enterprise/batch_processor.py +741 -0
- kailash/nodes/enterprise/data_lineage.py +497 -0
- kailash/nodes/logic/convergence.py +31 -9
- kailash/nodes/logic/operations.py +14 -3
- kailash/nodes/mixins/__init__.py +8 -0
- kailash/nodes/mixins/event_emitter.py +201 -0
- kailash/nodes/mixins/mcp.py +9 -4
- kailash/nodes/mixins/security.py +165 -0
- kailash/nodes/monitoring/__init__.py +7 -0
- kailash/nodes/monitoring/performance_benchmark.py +2497 -0
- kailash/nodes/rag/__init__.py +284 -0
- kailash/nodes/rag/advanced.py +1615 -0
- kailash/nodes/rag/agentic.py +773 -0
- kailash/nodes/rag/conversational.py +999 -0
- kailash/nodes/rag/evaluation.py +875 -0
- kailash/nodes/rag/federated.py +1188 -0
- kailash/nodes/rag/graph.py +721 -0
- kailash/nodes/rag/multimodal.py +671 -0
- kailash/nodes/rag/optimized.py +933 -0
- kailash/nodes/rag/privacy.py +1059 -0
- kailash/nodes/rag/query_processing.py +1335 -0
- kailash/nodes/rag/realtime.py +764 -0
- kailash/nodes/rag/registry.py +547 -0
- kailash/nodes/rag/router.py +837 -0
- kailash/nodes/rag/similarity.py +1854 -0
- kailash/nodes/rag/strategies.py +566 -0
- kailash/nodes/rag/workflows.py +575 -0
- kailash/nodes/security/__init__.py +19 -0
- kailash/nodes/security/abac_evaluator.py +1411 -0
- kailash/nodes/security/audit_log.py +103 -0
- kailash/nodes/security/behavior_analysis.py +1893 -0
- kailash/nodes/security/credential_manager.py +401 -0
- kailash/nodes/security/rotating_credentials.py +760 -0
- kailash/nodes/security/security_event.py +133 -0
- kailash/nodes/security/threat_detection.py +1103 -0
- kailash/nodes/testing/__init__.py +9 -0
- kailash/nodes/testing/credential_testing.py +499 -0
- kailash/nodes/transform/__init__.py +10 -2
- kailash/nodes/transform/chunkers.py +592 -1
- kailash/nodes/transform/processors.py +484 -14
- kailash/nodes/validation.py +321 -0
- kailash/runtime/access_controlled.py +1 -1
- kailash/runtime/async_local.py +41 -7
- kailash/runtime/docker.py +1 -1
- kailash/runtime/local.py +474 -55
- kailash/runtime/parallel.py +1 -1
- kailash/runtime/parallel_cyclic.py +1 -1
- kailash/runtime/testing.py +210 -2
- kailash/security.py +1 -1
- kailash/utils/migrations/__init__.py +25 -0
- kailash/utils/migrations/generator.py +433 -0
- kailash/utils/migrations/models.py +231 -0
- kailash/utils/migrations/runner.py +489 -0
- kailash/utils/secure_logging.py +342 -0
- kailash/workflow/__init__.py +16 -0
- kailash/workflow/cyclic_runner.py +3 -4
- kailash/workflow/graph.py +70 -2
- kailash/workflow/resilience.py +249 -0
- kailash/workflow/templates.py +726 -0
- {kailash-0.3.2.dist-info → kailash-0.4.1.dist-info}/METADATA +256 -20
- kailash-0.4.1.dist-info/RECORD +227 -0
- kailash/api/__init__.py +0 -17
- kailash/api/__main__.py +0 -6
- kailash/api/studio_secure.py +0 -893
- kailash/mcp/__main__.py +0 -13
- kailash/mcp/server_new.py +0 -336
- kailash/mcp/servers/__init__.py +0 -12
- kailash-0.3.2.dist-info/RECORD +0 -136
- {kailash-0.3.2.dist-info → kailash-0.4.1.dist-info}/WHEEL +0 -0
- {kailash-0.3.2.dist-info → kailash-0.4.1.dist-info}/entry_points.txt +0 -0
- {kailash-0.3.2.dist-info → kailash-0.4.1.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.3.2.dist-info → kailash-0.4.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,422 @@
|
|
1
|
+
"""
|
2
|
+
SDK-based Authentication Manager for Kailash Middleware
|
3
|
+
|
4
|
+
This module provides authentication management using SDK security nodes
|
5
|
+
instead of manual JWT handling and custom implementations.
|
6
|
+
|
7
|
+
Moved from middleware/auth.py to resolve directory/file confusion.
|
8
|
+
"""
|
9
|
+
|
10
|
+
import logging
|
11
|
+
import secrets
|
12
|
+
from datetime import datetime, timedelta, timezone
|
13
|
+
from enum import Enum
|
14
|
+
from typing import Any, Dict, List, Optional, Tuple
|
15
|
+
|
16
|
+
import jwt
|
17
|
+
from fastapi import Depends, HTTPException, Request
|
18
|
+
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
19
|
+
|
20
|
+
from ...nodes.admin import PermissionCheckNode
|
21
|
+
from ...nodes.data import AsyncSQLDatabaseNode
|
22
|
+
from ...nodes.security import (
|
23
|
+
AuditLogNode,
|
24
|
+
CredentialManagerNode,
|
25
|
+
RotatingCredentialNode,
|
26
|
+
SecurityEventNode,
|
27
|
+
)
|
28
|
+
from ...nodes.transform import DataTransformer
|
29
|
+
|
30
|
+
logger = logging.getLogger(__name__)
|
31
|
+
|
32
|
+
|
33
|
+
class AuthLevel(Enum):
|
34
|
+
"""Authentication levels for different security requirements."""
|
35
|
+
|
36
|
+
PUBLIC = "public"
|
37
|
+
BASIC = "basic"
|
38
|
+
STANDARD = "standard"
|
39
|
+
ADMIN = "admin"
|
40
|
+
SUPER_ADMIN = "super_admin"
|
41
|
+
|
42
|
+
|
43
|
+
class MiddlewareAuthManager:
|
44
|
+
"""
|
45
|
+
Authentication manager using SDK security nodes.
|
46
|
+
|
47
|
+
Provides:
|
48
|
+
- JWT token management with CredentialManagerNode
|
49
|
+
- API key rotation with RotatingCredentialNode
|
50
|
+
- Permission checking with PermissionCheckNode
|
51
|
+
- Security event logging with SecurityEventNode
|
52
|
+
- Audit trail with AuditLogNode
|
53
|
+
|
54
|
+
This replaces manual JWT handling with SDK components for better
|
55
|
+
security, performance, and consistency.
|
56
|
+
"""
|
57
|
+
|
58
|
+
def __init__(
|
59
|
+
self,
|
60
|
+
secret_key: str = None,
|
61
|
+
token_expiry_hours: int = 24,
|
62
|
+
enable_api_keys: bool = True,
|
63
|
+
enable_audit: bool = True,
|
64
|
+
database_url: str = None,
|
65
|
+
):
|
66
|
+
"""
|
67
|
+
Initialize SDK Auth Manager.
|
68
|
+
|
69
|
+
Args:
|
70
|
+
secret_key: Secret key for JWT signing (will use CredentialManager)
|
71
|
+
token_expiry_hours: Token expiration time in hours
|
72
|
+
enable_api_keys: Enable API key authentication
|
73
|
+
enable_audit: Enable audit logging
|
74
|
+
database_url: Database URL for persistence
|
75
|
+
"""
|
76
|
+
self.token_expiry_hours = token_expiry_hours
|
77
|
+
self.enable_api_keys = enable_api_keys
|
78
|
+
self.enable_audit = enable_audit
|
79
|
+
|
80
|
+
# Initialize SDK security nodes
|
81
|
+
self._initialize_security_nodes(secret_key, database_url)
|
82
|
+
|
83
|
+
# FastAPI security scheme
|
84
|
+
self.bearer_scheme = HTTPBearer(auto_error=False)
|
85
|
+
|
86
|
+
def _initialize_security_nodes(self, secret_key: str, database_url: str):
|
87
|
+
"""Initialize all SDK security nodes."""
|
88
|
+
|
89
|
+
# Store the secret key in memory for JWT operations
|
90
|
+
self.secret_key = secret_key
|
91
|
+
|
92
|
+
# Credential manager for fetching other credentials (not for JWT secret)
|
93
|
+
# In production, JWT secret would come from environment or vault
|
94
|
+
self.credential_manager = CredentialManagerNode(
|
95
|
+
credential_name="api_credentials",
|
96
|
+
credential_type="api_key",
|
97
|
+
name="jwt_credential_manager",
|
98
|
+
)
|
99
|
+
|
100
|
+
# Rotating credentials for API keys
|
101
|
+
if self.enable_api_keys:
|
102
|
+
self.api_key_manager = RotatingCredentialNode(
|
103
|
+
name="api_key_rotator"
|
104
|
+
# Note: RotatingCredentialNode doesn't require credential_name or rotation_interval_days in __init__
|
105
|
+
# These are passed during execution
|
106
|
+
)
|
107
|
+
|
108
|
+
# Permission checker
|
109
|
+
self.permission_checker = PermissionCheckNode(
|
110
|
+
name="middleware_permission_checker"
|
111
|
+
)
|
112
|
+
|
113
|
+
# Security event logger
|
114
|
+
self.security_logger = SecurityEventNode(name="middleware_security_events")
|
115
|
+
|
116
|
+
# Audit logger
|
117
|
+
if self.enable_audit:
|
118
|
+
self.audit_logger = AuditLogNode(name="middleware_audit")
|
119
|
+
|
120
|
+
# Data transformer for token operations
|
121
|
+
self.token_transformer = DataTransformer(name="token_transformer")
|
122
|
+
|
123
|
+
# Database node for user storage
|
124
|
+
if database_url:
|
125
|
+
self.db_node = AsyncSQLDatabaseNode(
|
126
|
+
name="auth_database", connection_string=database_url
|
127
|
+
)
|
128
|
+
|
129
|
+
async def create_access_token(
|
130
|
+
self,
|
131
|
+
user_id: str,
|
132
|
+
permissions: List[str] = None,
|
133
|
+
metadata: Dict[str, Any] = None,
|
134
|
+
) -> str:
|
135
|
+
"""
|
136
|
+
Create JWT access token using SDK nodes.
|
137
|
+
|
138
|
+
Args:
|
139
|
+
user_id: User identifier
|
140
|
+
permissions: List of permissions
|
141
|
+
metadata: Additional metadata
|
142
|
+
|
143
|
+
Returns:
|
144
|
+
JWT token string
|
145
|
+
"""
|
146
|
+
# Create token payload
|
147
|
+
payload = {
|
148
|
+
"user_id": user_id,
|
149
|
+
"permissions": permissions or [],
|
150
|
+
"metadata": metadata or {},
|
151
|
+
"exp": datetime.now(timezone.utc)
|
152
|
+
+ timedelta(hours=self.token_expiry_hours),
|
153
|
+
"iat": datetime.now(timezone.utc),
|
154
|
+
}
|
155
|
+
|
156
|
+
# Create JWT token
|
157
|
+
# In production, this would use a more sophisticated approach
|
158
|
+
# For now, we'll use the JWT library directly
|
159
|
+
try:
|
160
|
+
token = jwt.encode(payload, self.secret_key, algorithm="HS256")
|
161
|
+
token_result = {"token": token}
|
162
|
+
except Exception as e:
|
163
|
+
raise HTTPException(
|
164
|
+
status_code=500, detail=f"Failed to create token: {str(e)}"
|
165
|
+
)
|
166
|
+
|
167
|
+
# Log token creation
|
168
|
+
if self.enable_audit:
|
169
|
+
self.audit_logger.execute(
|
170
|
+
user_id=user_id,
|
171
|
+
action="create_token",
|
172
|
+
resource_type="jwt_token",
|
173
|
+
resource_id=user_id,
|
174
|
+
details={"permissions": permissions},
|
175
|
+
)
|
176
|
+
|
177
|
+
return token_result.get("token")
|
178
|
+
|
179
|
+
async def verify_token(self, token: str) -> Dict[str, Any]:
|
180
|
+
"""
|
181
|
+
Verify and decode JWT token using SDK nodes.
|
182
|
+
|
183
|
+
Args:
|
184
|
+
token: JWT token string
|
185
|
+
|
186
|
+
Returns:
|
187
|
+
Decoded token payload
|
188
|
+
|
189
|
+
Raises:
|
190
|
+
HTTPException: If token is invalid
|
191
|
+
"""
|
192
|
+
try:
|
193
|
+
# Verify JWT token
|
194
|
+
payload = jwt.decode(token, self.secret_key, algorithms=["HS256"])
|
195
|
+
|
196
|
+
# Check expiration
|
197
|
+
if payload.get("exp", 0) < datetime.now(timezone.utc).timestamp():
|
198
|
+
raise HTTPException(status_code=401, detail="Token has expired")
|
199
|
+
|
200
|
+
return payload
|
201
|
+
|
202
|
+
except Exception as e:
|
203
|
+
# Log security event
|
204
|
+
self.security_logger.execute(
|
205
|
+
event_type="token_verification_failed",
|
206
|
+
severity="warning",
|
207
|
+
details={"error": str(e)},
|
208
|
+
)
|
209
|
+
raise HTTPException(status_code=401, detail="Invalid authentication token")
|
210
|
+
|
211
|
+
async def create_api_key(
|
212
|
+
self, user_id: str, key_name: str, permissions: List[str] = None
|
213
|
+
) -> str:
|
214
|
+
"""
|
215
|
+
Create API key using RotatingCredentialNode.
|
216
|
+
|
217
|
+
Args:
|
218
|
+
user_id: User identifier
|
219
|
+
key_name: Name for the API key
|
220
|
+
permissions: List of permissions
|
221
|
+
|
222
|
+
Returns:
|
223
|
+
API key string
|
224
|
+
"""
|
225
|
+
if not self.enable_api_keys:
|
226
|
+
raise HTTPException(status_code=400, detail="API keys are disabled")
|
227
|
+
|
228
|
+
# Generate a secure API key
|
229
|
+
api_key = f"sk_{secrets.token_urlsafe(32)}"
|
230
|
+
|
231
|
+
# Store API key metadata using credential manager
|
232
|
+
result = self.credential_manager.run(
|
233
|
+
operation="store_credential",
|
234
|
+
credential_name=api_key,
|
235
|
+
credential_data={
|
236
|
+
"user_id": user_id,
|
237
|
+
"key_name": key_name,
|
238
|
+
"permissions": permissions or [],
|
239
|
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
240
|
+
"api_key": api_key,
|
241
|
+
},
|
242
|
+
)
|
243
|
+
|
244
|
+
if not result.get("success", False):
|
245
|
+
raise HTTPException(status_code=500, detail="Failed to create API key")
|
246
|
+
|
247
|
+
# Audit log
|
248
|
+
if self.enable_audit:
|
249
|
+
self.audit_logger.execute(
|
250
|
+
user_id=user_id,
|
251
|
+
action="create_api_key",
|
252
|
+
resource_type="api_key",
|
253
|
+
resource_id=key_name,
|
254
|
+
details={"permissions": permissions},
|
255
|
+
)
|
256
|
+
|
257
|
+
return api_key
|
258
|
+
|
259
|
+
async def verify_api_key(self, api_key: str) -> Dict[str, Any]:
|
260
|
+
"""
|
261
|
+
Verify API key using SDK nodes.
|
262
|
+
|
263
|
+
Args:
|
264
|
+
api_key: API key string
|
265
|
+
|
266
|
+
Returns:
|
267
|
+
API key metadata including user_id and permissions
|
268
|
+
|
269
|
+
Raises:
|
270
|
+
HTTPException: If API key is invalid
|
271
|
+
"""
|
272
|
+
if not self.enable_api_keys:
|
273
|
+
raise HTTPException(status_code=400, detail="API keys are disabled")
|
274
|
+
|
275
|
+
try:
|
276
|
+
# Verify using credential manager since rotating credential node doesn't have verify
|
277
|
+
result = self.credential_manager.run(
|
278
|
+
operation="get_credential", credential_name=api_key
|
279
|
+
)
|
280
|
+
|
281
|
+
if not result.get("success", False):
|
282
|
+
raise HTTPException(status_code=401, detail="Invalid API key")
|
283
|
+
|
284
|
+
credential_data = result.get("credential", {})
|
285
|
+
return credential_data.get("metadata", {})
|
286
|
+
|
287
|
+
except HTTPException:
|
288
|
+
raise
|
289
|
+
except Exception as e:
|
290
|
+
# Log security event
|
291
|
+
self.security_logger.execute(
|
292
|
+
event_type="api_key_verification_failed",
|
293
|
+
severity="warning",
|
294
|
+
details={"error": str(e)},
|
295
|
+
)
|
296
|
+
raise HTTPException(status_code=401, detail="Invalid API key")
|
297
|
+
|
298
|
+
async def check_permission(
|
299
|
+
self, user_id: str, permission: str, resource: Dict[str, Any] = None
|
300
|
+
) -> bool:
|
301
|
+
"""
|
302
|
+
Check user permission using PermissionCheckNode.
|
303
|
+
|
304
|
+
Args:
|
305
|
+
user_id: User identifier
|
306
|
+
permission: Permission to check
|
307
|
+
resource: Optional resource context
|
308
|
+
|
309
|
+
Returns:
|
310
|
+
True if permission is granted
|
311
|
+
"""
|
312
|
+
result = self.permission_checker.run(
|
313
|
+
user_context={"user_id": user_id},
|
314
|
+
permission=permission,
|
315
|
+
resource=resource or {},
|
316
|
+
)
|
317
|
+
|
318
|
+
granted = result.get("authorized", False)
|
319
|
+
|
320
|
+
# Audit permission check
|
321
|
+
if self.enable_audit:
|
322
|
+
self.audit_logger.execute(
|
323
|
+
user_id=user_id,
|
324
|
+
action="check_permission",
|
325
|
+
resource_type="permission",
|
326
|
+
resource_id=permission,
|
327
|
+
details={"granted": granted, "resource": resource},
|
328
|
+
)
|
329
|
+
|
330
|
+
return granted
|
331
|
+
|
332
|
+
def get_current_user_dependency(self, required_permissions: List[str] = None):
|
333
|
+
"""
|
334
|
+
Create FastAPI dependency for user authentication.
|
335
|
+
|
336
|
+
Args:
|
337
|
+
required_permissions: List of required permissions
|
338
|
+
|
339
|
+
Returns:
|
340
|
+
FastAPI dependency function
|
341
|
+
"""
|
342
|
+
|
343
|
+
async def verify_user(
|
344
|
+
request: Request,
|
345
|
+
credentials: HTTPAuthorizationCredentials = Depends(self.bearer_scheme),
|
346
|
+
) -> Dict[str, Any]:
|
347
|
+
"""Verify user from request."""
|
348
|
+
|
349
|
+
# Try bearer token first
|
350
|
+
if credentials and credentials.credentials:
|
351
|
+
try:
|
352
|
+
payload = await self.verify_token(credentials.credentials)
|
353
|
+
user_id = payload.get("user_id")
|
354
|
+
|
355
|
+
# Check permissions if required
|
356
|
+
if required_permissions:
|
357
|
+
user_permissions = payload.get("permissions", [])
|
358
|
+
for perm in required_permissions:
|
359
|
+
if perm not in user_permissions:
|
360
|
+
# Check using permission node
|
361
|
+
if not await self.check_permission(user_id, perm):
|
362
|
+
raise HTTPException(
|
363
|
+
status_code=403,
|
364
|
+
detail=f"Missing required permission: {perm}",
|
365
|
+
)
|
366
|
+
|
367
|
+
return {
|
368
|
+
"user_id": user_id,
|
369
|
+
"permissions": payload.get("permissions", []),
|
370
|
+
"metadata": payload.get("metadata", {}),
|
371
|
+
}
|
372
|
+
except HTTPException:
|
373
|
+
pass
|
374
|
+
|
375
|
+
# Try API key from header
|
376
|
+
api_key = request.headers.get("X-API-Key")
|
377
|
+
if api_key:
|
378
|
+
try:
|
379
|
+
metadata = await self.verify_api_key(api_key)
|
380
|
+
user_id = metadata.get("user_id")
|
381
|
+
|
382
|
+
# Check permissions
|
383
|
+
if required_permissions:
|
384
|
+
key_permissions = metadata.get("permissions", [])
|
385
|
+
for perm in required_permissions:
|
386
|
+
if perm not in key_permissions:
|
387
|
+
if not await self.check_permission(user_id, perm):
|
388
|
+
raise HTTPException(
|
389
|
+
status_code=403,
|
390
|
+
detail=f"Missing required permission: {perm}",
|
391
|
+
)
|
392
|
+
|
393
|
+
return {
|
394
|
+
"user_id": user_id,
|
395
|
+
"permissions": metadata.get("permissions", []),
|
396
|
+
"metadata": metadata,
|
397
|
+
}
|
398
|
+
except HTTPException:
|
399
|
+
pass
|
400
|
+
|
401
|
+
# No valid authentication
|
402
|
+
raise HTTPException(status_code=401, detail="Not authenticated")
|
403
|
+
|
404
|
+
return verify_user
|
405
|
+
|
406
|
+
|
407
|
+
# Convenience function for creating auth dependencies
|
408
|
+
def require_auth(permissions: List[str] = None):
|
409
|
+
"""
|
410
|
+
Create authentication dependency with required permissions.
|
411
|
+
|
412
|
+
Args:
|
413
|
+
permissions: List of required permissions
|
414
|
+
|
415
|
+
Returns:
|
416
|
+
FastAPI dependency
|
417
|
+
"""
|
418
|
+
# This would use a global auth manager instance
|
419
|
+
# In practice, this would be configured at app startup
|
420
|
+
raise NotImplementedError(
|
421
|
+
"Use auth_manager.get_current_user_dependency(permissions) instead"
|
422
|
+
)
|