mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-29 09:14:33 +00:00
feat(auth): Add session event logging for login attempts
- Added session callback mechanism in secubox_core.auth - Login events (success/failure) now emit to registered callback - secubox-auth module records sessions in JSON file - Fixed login.html endpoint URLs and JSON parsing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
676630ca71
commit
fb5c33eadc
|
|
@ -22,6 +22,22 @@ log = get_logger("auth")
|
|||
# auto_error=False allows us to handle missing token gracefully
|
||||
_bearer = HTTPBearer(auto_error=False)
|
||||
|
||||
# Session event callback (set by auth module to record sessions)
|
||||
_session_callback = None
|
||||
|
||||
def set_session_callback(callback):
|
||||
"""Set callback function for session events: callback(event, username, details)"""
|
||||
global _session_callback
|
||||
_session_callback = callback
|
||||
|
||||
def _emit_session_event(event: str, username: str, details: dict = None):
|
||||
"""Emit session event to callback if set."""
|
||||
if _session_callback:
|
||||
try:
|
||||
_session_callback(event, username, details or {})
|
||||
except Exception as e:
|
||||
log.warning("Session callback error: %s", e)
|
||||
|
||||
# ── JWT helpers ────────────────────────────────────────────────────
|
||||
|
||||
def _secret() -> str:
|
||||
|
|
@ -111,10 +127,12 @@ async def login(req: LoginRequest):
|
|||
"""Endpoint de login — retourne un JWT."""
|
||||
if not _check_password(req.username, req.password):
|
||||
log.warning("Échec login: %s", req.username)
|
||||
_emit_session_event("login_failed", req.username, {"reason": "invalid_credentials"})
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Identifiants incorrects",
|
||||
)
|
||||
token = create_token(req.username)
|
||||
log.info("Login OK: %s", req.username)
|
||||
_emit_session_event("login_success", req.username, {"expires_in": 86400})
|
||||
return TokenResponse(access_token=token)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""SecuBox Auth API - OAuth2 + Vouchers + Sessions with Enhanced Monitoring"""
|
||||
from fastapi import FastAPI, APIRouter, Depends, HTTPException, BackgroundTasks
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from secubox_core.auth import router as auth_router, require_jwt, create_token
|
||||
from secubox_core.auth import router as auth_router, require_jwt, create_token, set_session_callback
|
||||
from secubox_core.config import get_config
|
||||
import json
|
||||
import secrets
|
||||
|
|
@ -194,11 +194,29 @@ async def _periodic_cleanup():
|
|||
await asyncio.sleep(300) # Every 5 minutes
|
||||
|
||||
|
||||
def _handle_session_event(event: str, username: str, details: dict):
|
||||
"""Handle session events from secubox_core.auth login."""
|
||||
_record_event(event, {"username": username, **details})
|
||||
# Also create session record for successful logins
|
||||
if event == "login_success":
|
||||
sessions = _load(SESSIONS_FILE, [])
|
||||
sessions.append({
|
||||
"id": secrets.token_hex(8),
|
||||
"username": username,
|
||||
"created": datetime.now().isoformat(),
|
||||
"expires": int(time.time()) + details.get("expires_in", 86400),
|
||||
"type": "jwt"
|
||||
})
|
||||
_save(SESSIONS_FILE, sessions)
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup():
|
||||
"""Start background cleanup."""
|
||||
"""Start background cleanup and register session callback."""
|
||||
global _cleanup_task
|
||||
_cleanup_task = asyncio.create_task(_periodic_cleanup())
|
||||
# Register callback for login events
|
||||
set_session_callback(_handle_session_event)
|
||||
|
||||
|
||||
@app.on_event("shutdown")
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@
|
|||
submitBtn.textContent = 'Authenticating...';
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/v1/hub/auth/login', {
|
||||
const res = await fetch('/api/v1/auth/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ username, password })
|
||||
|
|
@ -268,25 +268,26 @@
|
|||
// Load auth mode and version info (public endpoint)
|
||||
async function loadPublicInfo() {
|
||||
try {
|
||||
const res = await fetch('/api/v1/hub/public/info');
|
||||
const res = await fetch('/api/v1/hub/health');
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
|
||||
// Update auth mode
|
||||
const authModeEl = document.getElementById('auth-mode');
|
||||
const authModeText = document.getElementById('auth-mode-text');
|
||||
if (data.auth_mode) {
|
||||
authModeText.textContent = data.auth_mode;
|
||||
authModeEl.className = 'auth-mode ' + (data.auth_mode.toLowerCase() === 'zkp' ? 'zkp' : 'standard');
|
||||
}
|
||||
|
||||
// Update version
|
||||
if (data.version) {
|
||||
document.getElementById('version-badge').textContent = 'SecuBox v' + data.version;
|
||||
const text = await res.text();
|
||||
// Only parse if it looks like JSON
|
||||
if (text.startsWith('{')) {
|
||||
const data = JSON.parse(text);
|
||||
// Update version from health endpoint
|
||||
if (data.version) {
|
||||
document.getElementById('version-badge').textContent = 'SecuBox v' + data.version;
|
||||
}
|
||||
// Check for ZKP auth mode
|
||||
const authModeEl = document.getElementById('auth-mode');
|
||||
const authModeText = document.getElementById('auth-mode-text');
|
||||
authModeText.textContent = data.auth_mode || 'ZKP';
|
||||
authModeEl.className = 'auth-mode zkp';
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Silently fail - use defaults
|
||||
console.log('[Login] Info fetch skipped:', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user