Initial release of the oVirt/RHV Engine API simulator.

Stateful FastAPI lab with contract packs, Compose/Helm, Docker Hub release
targets, and Pulumi coverage across all Engine series (GET/POST/PUT/DELETE/HEAD).
This commit is contained in:
2026-07-18 04:49:28 +03:00
commit cbd0adca91
218 changed files with 246804 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
"""oVirt Engine SSO OAuth2 endpoints."""
from __future__ import annotations
from fastapi import APIRouter, Form, Request
from fastapi.responses import JSONResponse
from app.ovirt.auth import issue_oauth_token
from app.ovirt.deps import get_db
from app.ovirt.errors import OVirtError
from app.ovirt.settings import OPT_DEFAULT_API_SCOPE, option_value
router = APIRouter(tags=["sso"])
@router.post("/ovirt-engine/sso/oauth/token")
async def oauth_token(
request: Request,
grant_type: str = Form(default=""),
username: str = Form(default=""),
password: str = Form(default=""),
scope: str = Form(default=""),
) -> JSONResponse:
if grant_type and grant_type != "password":
raise OVirtError("BadRequest", f"Unsupported grant_type: {grant_type}", status_code=400)
if not username:
try:
body = await request.json()
except Exception:
body = {}
username = str(body.get("username") or "")
password = str(body.get("password") or "")
scope = str(body.get("scope") or scope or "")
grant_type = str(body.get("grant_type") or grant_type or "password")
if not username or not password:
raise OVirtError("Unauthorized", "username and password required", status_code=401)
db = get_db(request)
async with db.pool.acquire() as conn:
if not scope:
scope = await option_value(conn, OPT_DEFAULT_API_SCOPE)
token = await issue_oauth_token(
conn, username=username, password=password, scope=scope
)
return JSONResponse(token)
@router.get("/ovirt-engine/sso/oauth/token-info")
async def token_info(request: Request) -> JSONResponse:
from app.ovirt.auth import resolve_request_auth
db = get_db(request)
async with db.pool.acquire() as conn:
ctx = await resolve_request_auth(conn, dict(request.headers))
row = await conn.fetchrow(
"SELECT scope, revoked, expires_at FROM ov_tokens WHERE id=$1", ctx.token_id
)
active = bool(row) and not row["revoked"]
return JSONResponse(
{
"active": active,
"user_id": str(ctx.user_id),
"user_name": f"{ctx.user_name}@{ctx.domain}",
"exp": int(ctx.expires_at.timestamp()),
"scope": (row["scope"] if row else ctx.scope),
}
)
@router.post("/ovirt-engine/sso/oauth/revoke")
async def revoke_token(request: Request) -> JSONResponse:
from app.ovirt.auth import extract_auth
db = get_db(request)
kind = extract_auth(dict(request.headers))
token = None
if kind and kind[0] in {"bearer", "session"}:
token = kind[1]
else:
form = await request.form()
token = str(form.get("token") or "")
result = "missing"
if token:
async with db.pool.acquire() as conn:
updated = await conn.fetchval(
"""UPDATE ov_tokens SET revoked=true WHERE id=$1
RETURNING id""",
token,
)
result = "ok" if updated else "not_found"
return JSONResponse({"result": result})