basyx commited on
Commit
cfbca5c
·
verified ·
1 Parent(s): 270ac5f

Mark verified Studio identity for privileged routes

Browse files
Files changed (1) hide show
  1. app/security/middleware.py +2 -88
app/security/middleware.py CHANGED
@@ -76,6 +76,7 @@ class APIKeyAuthenticationMiddleware(BaseHTTPMiddleware):
76
  logger.warning("rejected Studio identity envelope: %s", str(exc))
77
  raise UnauthorizedError from exc
78
  principal = await self.api_keys.tenants.resolve_studio_subject(identity.subject)
 
79
  try:
80
  # The shared key authenticates transport only; persisted
81
  # membership capabilities constrain its effective scopes.
@@ -215,91 +216,4 @@ class APIKeyAuthenticationMiddleware(BaseHTTPMiddleware):
215
  context,
216
  "social_schedule",
217
  limit=self.settings.social_schedule_requests_per_minute,
218
- window_seconds=60,
219
- )
220
- elif path.endswith("/reschedule"):
221
- await self.rate_limiter.acquire_category(
222
- context,
223
- "social_schedule",
224
- limit=self.settings.social_schedule_requests_per_minute,
225
- window_seconds=60,
226
- )
227
- elif path.endswith("/bulk"):
228
- await self.rate_limiter.acquire_category(
229
- context,
230
- "social_bulk",
231
- limit=max(1, self.settings.social_schedule_requests_per_minute // 4),
232
- window_seconds=60,
233
- )
234
-
235
- @staticmethod
236
- def _bearer_token(header: str | None) -> str:
237
- if not header:
238
- raise UnauthorizedError
239
- parts = header.strip().split()
240
- if len(parts) != 2 or parts[0].casefold() != "bearer" or not parts[1]:
241
- raise UnauthorizedError
242
- return parts[1]
243
-
244
- @staticmethod
245
- def _content_length(value: str | None) -> int:
246
- try:
247
- return max(0, int(value or 0))
248
- except ValueError:
249
- return 0
250
-
251
- @staticmethod
252
- def _error(
253
- status_code: int,
254
- error: str,
255
- message: str,
256
- request: Request,
257
- headers: dict[str, str] | None = None,
258
- ) -> JSONResponse:
259
- response_headers = dict(headers or {})
260
- request_id = getattr(request.state, "request_id", None)
261
- if request_id:
262
- response_headers["X-Request-ID"] = request_id
263
- return JSONResponse(
264
- {"error": error, "message": message},
265
- status_code=status_code,
266
- headers=response_headers,
267
- )
268
-
269
- def _client_ip(self, request: Request) -> str | None:
270
- if self.settings.auth_trust_proxy_headers:
271
- forwarded = request.headers.get("x-forwarded-for")
272
- if forwarded:
273
- return forwarded.split(",", 1)[0].strip()[:64]
274
- return request.client.host[:64] if request.client else None
275
-
276
- async def _audit_request(
277
- self,
278
- request: Request,
279
- context: AuthContext,
280
- response_code: int,
281
- elapsed_ms: int,
282
- bytes_uploaded: int,
283
- bytes_downloaded: int,
284
- ) -> None:
285
- data = {
286
- "request_id": getattr(request.state, "request_id", "-"),
287
- "api_key_id": context.api_key_id,
288
- "key_name": context.key_name,
289
- "ip_address": self._client_ip(request),
290
- "user_agent": request.headers.get("user-agent", "")[:512] or None,
291
- "endpoint": request.url.path,
292
- "http_method": request.method,
293
- "response_code": response_code,
294
- "processing_time_ms": elapsed_ms,
295
- "bytes_uploaded": bytes_uploaded,
296
- "bytes_downloaded": bytes_downloaded,
297
- }
298
- try:
299
- await self.audit.record(**data)
300
- except Exception:
301
- logger.exception(
302
- "authentication audit persistence failed",
303
- extra={"api_key_id": context.api_key_id},
304
- )
305
- logger.info("authenticated request", extra=data)
 
76
  logger.warning("rejected Studio identity envelope: %s", str(exc))
77
  raise UnauthorizedError from exc
78
  principal = await self.api_keys.tenants.resolve_studio_subject(identity.subject)
79
+ request.state.studio_identity_verified = True
80
  try:
81
  # The shared key authenticates transport only; persisted
82
  # membership capabilities constrain its effective scopes.
 
216
  context,
217
  "social_schedule",
218
  limit=self.settings.social_schedule_requests_per_minute,
219
+