openvpn-endpoint-server/server/app/web/gateways.py

251 lines
8.0 KiB
Python

"""Gateway web routes."""
from fastapi import APIRouter, Request, Depends, Form, Response
from fastapi.responses import HTMLResponse, RedirectResponse
from sqlalchemy.orm import Session
from ..database import get_db
from ..models.user import User, UserRole
from ..models.gateway import Gateway, RouterType, ProvisioningMethod
from ..models.endpoint import ApplicationTemplate
from ..models.tenant import Tenant
from ..models.access import UserGatewayAccess
from .deps import get_current_user_web, require_admin_web, flash, get_flashed_messages
router = APIRouter()
def get_accessible_gateways(db: Session, user: User):
"""Get gateways accessible by user."""
if user.role == UserRole.SUPER_ADMIN:
return db.query(Gateway).all()
elif user.role == UserRole.ADMIN:
return db.query(Gateway).filter(Gateway.tenant_id == user.tenant_id).all()
else:
return db.query(Gateway).join(
UserGatewayAccess,
UserGatewayAccess.gateway_id == Gateway.id
).filter(UserGatewayAccess.user_id == user.id).all()
@router.get("/gateways", response_class=HTMLResponse)
async def list_gateways(
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user_web)
):
"""List gateways page."""
return request.app.state.templates.TemplateResponse(
"gateways/list.html",
{
"request": request,
"current_user": current_user,
"flash_messages": get_flashed_messages(request)
}
)
@router.get("/gateways/new", response_class=HTMLResponse)
async def new_gateway_form(
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(require_admin_web)
):
"""New gateway form."""
tenants = db.query(Tenant).filter(Tenant.is_active == True).all()
return request.app.state.templates.TemplateResponse(
"gateways/form.html",
{
"request": request,
"current_user": current_user,
"gateway": None,
"tenants": tenants,
"flash_messages": get_flashed_messages(request)
}
)
@router.post("/gateways/new", response_class=HTMLResponse)
async def create_gateway(
request: Request,
name: str = Form(...),
router_type: str = Form(...),
firmware_version: str = Form(None),
serial_number: str = Form(None),
location: str = Form(None),
vpn_subnet: str = Form(None),
description: str = Form(None),
tenant_id: int = Form(None),
db: Session = Depends(get_db),
current_user: User = Depends(require_admin_web)
):
"""Create new gateway."""
# Determine tenant
if current_user.role == UserRole.SUPER_ADMIN and tenant_id:
gateway_tenant_id = tenant_id
else:
gateway_tenant_id = current_user.tenant_id
# Generate VPN cert CN
vpn_cert_cn = f"gateway-{name.lower().replace(' ', '-')}"
gateway = Gateway(
name=name,
router_type=RouterType(router_type),
firmware_version=firmware_version or None,
serial_number=serial_number or None,
location=location or None,
vpn_subnet=vpn_subnet or None,
description=description or None,
tenant_id=gateway_tenant_id,
vpn_cert_cn=vpn_cert_cn
)
db.add(gateway)
db.commit()
db.refresh(gateway)
flash(request, f"Gateway '{name}' erfolgreich erstellt", "success")
return RedirectResponse(url=f"/gateways/{gateway.id}", status_code=303)
@router.get("/gateways/{gateway_id}", response_class=HTMLResponse)
async def gateway_detail(
request: Request,
gateway_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user_web)
):
"""Gateway detail page."""
gateway = db.query(Gateway).filter(Gateway.id == gateway_id).first()
if not gateway:
flash(request, "Gateway nicht gefunden", "danger")
return RedirectResponse(url="/gateways", status_code=303)
# Check access
if current_user.role == UserRole.TECHNICIAN:
access = db.query(UserGatewayAccess).filter(
UserGatewayAccess.user_id == current_user.id,
UserGatewayAccess.gateway_id == gateway_id
).first()
if not access:
flash(request, "Kein Zugriff auf dieses Gateway", "danger")
return RedirectResponse(url="/gateways", status_code=303)
templates = db.query(ApplicationTemplate).all()
return request.app.state.templates.TemplateResponse(
"gateways/detail.html",
{
"request": request,
"current_user": current_user,
"gateway": gateway,
"templates": templates,
"flash_messages": get_flashed_messages(request)
}
)
@router.get("/gateways/{gateway_id}/edit", response_class=HTMLResponse)
async def edit_gateway_form(
request: Request,
gateway_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(require_admin_web)
):
"""Edit gateway form."""
gateway = db.query(Gateway).filter(Gateway.id == gateway_id).first()
if not gateway:
flash(request, "Gateway nicht gefunden", "danger")
return RedirectResponse(url="/gateways", status_code=303)
tenants = db.query(Tenant).filter(Tenant.is_active == True).all()
return request.app.state.templates.TemplateResponse(
"gateways/form.html",
{
"request": request,
"current_user": current_user,
"gateway": gateway,
"tenants": tenants,
"flash_messages": get_flashed_messages(request)
}
)
@router.post("/gateways/{gateway_id}/edit")
async def update_gateway(
request: Request,
gateway_id: int,
name: str = Form(...),
router_type: str = Form(...),
firmware_version: str = Form(None),
serial_number: str = Form(None),
location: str = Form(None),
vpn_subnet: str = Form(None),
description: str = Form(None),
db: Session = Depends(get_db),
current_user: User = Depends(require_admin_web)
):
"""Update gateway."""
gateway = db.query(Gateway).filter(Gateway.id == gateway_id).first()
if not gateway:
flash(request, "Gateway nicht gefunden", "danger")
return RedirectResponse(url="/gateways", status_code=303)
gateway.name = name
gateway.router_type = RouterType(router_type)
gateway.firmware_version = firmware_version or None
gateway.serial_number = serial_number or None
gateway.location = location or None
gateway.vpn_subnet = vpn_subnet or None
gateway.description = description or None
db.commit()
flash(request, "Gateway aktualisiert", "success")
return RedirectResponse(url=f"/gateways/{gateway_id}", status_code=303)
@router.post("/gateways/{gateway_id}/delete")
async def delete_gateway(
request: Request,
gateway_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(require_admin_web)
):
"""Delete gateway."""
gateway = db.query(Gateway).filter(Gateway.id == gateway_id).first()
if not gateway:
flash(request, "Gateway nicht gefunden", "danger")
return RedirectResponse(url="/gateways", status_code=303)
db.delete(gateway)
db.commit()
flash(request, f"Gateway '{gateway.name}' gelöscht", "warning")
return RedirectResponse(url="/gateways", status_code=303)
@router.get("/gateways/{gateway_id}/provision")
async def download_provisioning(
request: Request,
gateway_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(require_admin_web)
):
"""Redirect to VPN profiles for provisioning.
Provisioning is now done through VPN profiles.
Each profile contains its own certificate and VPN server configuration.
"""
gateway = db.query(Gateway).filter(Gateway.id == gateway_id).first()
if not gateway:
flash(request, "Gateway nicht gefunden", "danger")
return RedirectResponse(url="/gateways", status_code=303)
# Redirect to profiles page
flash(request, "Bitte erstellen Sie ein VPN-Profil für das Provisioning", "info")
return RedirectResponse(url=f"/gateways/{gateway_id}/profiles", status_code=303)