Spaces:
Sleeping
Sleeping
Commit
ยท
dbbc4b1
1
Parent(s):
d1a53e8
dd
Browse files- backend/middleware/auth.py +30 -16
backend/middleware/auth.py
CHANGED
|
@@ -7,25 +7,25 @@ Local development bypasses authentication entirely.
|
|
| 7 |
|
| 8 |
import os
|
| 9 |
import logging
|
| 10 |
-
from typing import Optional, Dict, Any
|
| 11 |
from fastapi import Request, Response, HTTPException
|
| 12 |
-
from starlette.middleware.base import BaseHTTPMiddleware
|
| 13 |
from starlette.responses import RedirectResponse, JSONResponse
|
|
|
|
| 14 |
from utils.environment import should_enable_auth, get_oauth_config, is_huggingface_space
|
| 15 |
|
| 16 |
logger = logging.getLogger(__name__)
|
| 17 |
|
| 18 |
|
| 19 |
-
class ConditionalAuthMiddleware
|
| 20 |
"""
|
| 21 |
-
|
| 22 |
|
| 23 |
- In HF Spaces: Full OAuth authentication required
|
| 24 |
- In local development: Authentication bypassed
|
| 25 |
"""
|
| 26 |
|
| 27 |
-
def __init__(self, app, excluded_paths: Optional[list] = None):
|
| 28 |
-
|
| 29 |
|
| 30 |
# Paths that don't require authentication even in HF Spaces
|
| 31 |
self.excluded_paths = excluded_paths or [
|
|
@@ -56,24 +56,33 @@ class ConditionalAuthMiddleware(BaseHTTPMiddleware):
|
|
| 56 |
else:
|
| 57 |
logger.info("๐ Authentication middleware DISABLED (Local development)")
|
| 58 |
|
| 59 |
-
async def
|
| 60 |
"""
|
| 61 |
-
|
| 62 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
# If auth is disabled (local dev), bypass all authentication
|
| 64 |
if not self.auth_enabled:
|
| 65 |
logger.debug(f"๐ Auth disabled - allowing {request.url.path}")
|
| 66 |
-
|
|
|
|
| 67 |
|
| 68 |
# If auth is enabled but OAuth not properly configured, log warning and continue
|
| 69 |
if not self.oauth_config:
|
| 70 |
logger.warning("OAuth not configured properly, bypassing auth")
|
| 71 |
-
|
|
|
|
| 72 |
|
| 73 |
# Check if path is excluded from authentication
|
| 74 |
if self._is_excluded_path(request.url.path):
|
| 75 |
logger.debug(f"๐ช Excluded path - allowing {request.url.path}")
|
| 76 |
-
|
|
|
|
| 77 |
|
| 78 |
# Log the authentication check
|
| 79 |
logger.info(f"๐ Checking authentication for {request.url.path}")
|
|
@@ -88,7 +97,7 @@ class ConditionalAuthMiddleware(BaseHTTPMiddleware):
|
|
| 88 |
|
| 89 |
# For API calls, return JSON error with login instructions
|
| 90 |
if request.url.path.startswith("/api/"):
|
| 91 |
-
|
| 92 |
status_code=401,
|
| 93 |
content={
|
| 94 |
"error": "Authentication required to access OpenAI-powered features",
|
|
@@ -97,13 +106,18 @@ class ConditionalAuthMiddleware(BaseHTTPMiddleware):
|
|
| 97 |
"reason": "API access requires user authentication for security and usage tracking"
|
| 98 |
}
|
| 99 |
)
|
|
|
|
|
|
|
|
|
|
| 100 |
|
| 101 |
-
|
| 102 |
-
return
|
| 103 |
|
| 104 |
# Add user info to request state
|
| 105 |
-
|
| 106 |
-
|
|
|
|
|
|
|
| 107 |
|
| 108 |
def _is_excluded_path(self, path: str) -> bool:
|
| 109 |
"""Check if the request path should bypass authentication."""
|
|
|
|
| 7 |
|
| 8 |
import os
|
| 9 |
import logging
|
| 10 |
+
from typing import Optional, Dict, Any, Callable, Awaitable
|
| 11 |
from fastapi import Request, Response, HTTPException
|
|
|
|
| 12 |
from starlette.responses import RedirectResponse, JSONResponse
|
| 13 |
+
from starlette.types import ASGIApp, Receive, Scope, Send
|
| 14 |
from utils.environment import should_enable_auth, get_oauth_config, is_huggingface_space
|
| 15 |
|
| 16 |
logger = logging.getLogger(__name__)
|
| 17 |
|
| 18 |
|
| 19 |
+
class ConditionalAuthMiddleware:
|
| 20 |
"""
|
| 21 |
+
ASGI middleware that conditionally enables authentication based on deployment environment.
|
| 22 |
|
| 23 |
- In HF Spaces: Full OAuth authentication required
|
| 24 |
- In local development: Authentication bypassed
|
| 25 |
"""
|
| 26 |
|
| 27 |
+
def __init__(self, app: ASGIApp, excluded_paths: Optional[list] = None):
|
| 28 |
+
self.app = app
|
| 29 |
|
| 30 |
# Paths that don't require authentication even in HF Spaces
|
| 31 |
self.excluded_paths = excluded_paths or [
|
|
|
|
| 56 |
else:
|
| 57 |
logger.info("๐ Authentication middleware DISABLED (Local development)")
|
| 58 |
|
| 59 |
+
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
| 60 |
"""
|
| 61 |
+
ASGI callable that processes HTTP requests.
|
| 62 |
"""
|
| 63 |
+
if scope["type"] != "http":
|
| 64 |
+
await self.app(scope, receive, send)
|
| 65 |
+
return
|
| 66 |
+
|
| 67 |
+
request = Request(scope, receive)
|
| 68 |
+
|
| 69 |
# If auth is disabled (local dev), bypass all authentication
|
| 70 |
if not self.auth_enabled:
|
| 71 |
logger.debug(f"๐ Auth disabled - allowing {request.url.path}")
|
| 72 |
+
await self.app(scope, receive, send)
|
| 73 |
+
return
|
| 74 |
|
| 75 |
# If auth is enabled but OAuth not properly configured, log warning and continue
|
| 76 |
if not self.oauth_config:
|
| 77 |
logger.warning("OAuth not configured properly, bypassing auth")
|
| 78 |
+
await self.app(scope, receive, send)
|
| 79 |
+
return
|
| 80 |
|
| 81 |
# Check if path is excluded from authentication
|
| 82 |
if self._is_excluded_path(request.url.path):
|
| 83 |
logger.debug(f"๐ช Excluded path - allowing {request.url.path}")
|
| 84 |
+
await self.app(scope, receive, send)
|
| 85 |
+
return
|
| 86 |
|
| 87 |
# Log the authentication check
|
| 88 |
logger.info(f"๐ Checking authentication for {request.url.path}")
|
|
|
|
| 97 |
|
| 98 |
# For API calls, return JSON error with login instructions
|
| 99 |
if request.url.path.startswith("/api/"):
|
| 100 |
+
response = JSONResponse(
|
| 101 |
status_code=401,
|
| 102 |
content={
|
| 103 |
"error": "Authentication required to access OpenAI-powered features",
|
|
|
|
| 106 |
"reason": "API access requires user authentication for security and usage tracking"
|
| 107 |
}
|
| 108 |
)
|
| 109 |
+
else:
|
| 110 |
+
# For web requests, redirect to login page
|
| 111 |
+
response = RedirectResponse(url="/auth/login-page", status_code=302)
|
| 112 |
|
| 113 |
+
await response(scope, receive, send)
|
| 114 |
+
return
|
| 115 |
|
| 116 |
# Add user info to request state
|
| 117 |
+
scope["state"] = scope.get("state", {})
|
| 118 |
+
scope["state"]["user"] = user
|
| 119 |
+
|
| 120 |
+
await self.app(scope, receive, send)
|
| 121 |
|
| 122 |
def _is_excluded_path(self, path: str) -> bool:
|
| 123 |
"""Check if the request path should bypass authentication."""
|