Skip to content

Request & Data Flows ​

How data moves from the browser, through the portal and API, into the infrastructure and back.

Frontend to backend to infrastructure ​

Flow 1: Loading a protected page ​

  1. The browser requests /dashboard. middleware.ts decrypts the NextAuth cookie with NEXTAUTH_SECRET.
  2. No cookie: redirect to /login?callbackUrl=/dashboard. No application role: redirect to /no-role. Role does not match the path (for example a student opening /admin): redirect to /dashboard.
  3. The page renders and its hooks call BFF routes under /api/*.

Source: cyberrange/portal/src/middleware.ts, cyberrange/portal/src/lib/routeRoles.ts.

Flow 2: Calling the API through the BFF ​

  1. A hook calls, for example, GET /api/pods/5/status.
  2. The route handler calls proxyToApi(), which reads the server-side session. No session: 401.
  3. It forwards to http://10.115.77.1:5000/pods/5/status with Authorization: Bearer <access token>, forwarding only allow-listed query parameters.
  4. FastAPI introspects the token (cached up to 60 seconds), checks the role and ownership, and answers.
  5. If FastAPI is unreachable, the proxy logs the error and returns a degraded answer (an empty list for GET /pods, otherwise 503).

Source: cyberrange/portal/src/lib/apiProxy.ts, cyberrange/src/provisioning/auth.py.

Flow 3: Starting a lab ​

POST /api/pods/provision → POST /pods/provision (202) → background perform_provisioning(). The portal polls GET /pods/{id}/status until the status is ACTIVE. The build creates the lab's egress ACL with its network, and a lab only becomes ACTIVE once its Wazuh agents are connected (when Wazuh scoring is configured; the provisioning page lists the exceptions) and, for Scenario 1, its flags are planted; otherwise it ends in FAILED_ROLLBACK_COMPLETE. Full sequence: Provisioning & Teardown.

Flow 4: Terminal session ​

Browser WebSocket wss://<host>/api/ssh-websocket?token=...&pod_id=...&pod_type=kali → nginx → bridge.py → Keycloak introspection → GET /pods/{id}/status (ownership) → lxc exec ... tmux attach -t lab. Browser resizes are also pushed into the container's tmux client, and a dropped connection is retried automatically with backoff. Full sequence: Terminal Access.

Flow 5: Automatic and manual scoring ​

  • Automatic: score_poller.py every 3 seconds calls scoring.verify_milestone() for each unpassed milestone of each active lab.
  • Manual Check: POST /pods/{id}/verify/{scenario}/{milestone} from the Tasks panel.
  • Both run scoring_checks.sh in the container via lxc exec, optionally look up Wazuh detection evidence, and insert a row in milestone_verification tagged with its source (auto or manual). For scenarios with diagnostics switched on, a failed check's reason code is stored in scoring_diagnostics for instructors (GET /instructor/students/{id}/diagnostics).
  • The Tasks panel polls GET /pods/{id}/milestones every 3 seconds (TerminalView.tsx).

Details: Lifecycle & Scoring.

Flow 6: Scenario 2 browser scoring ​

  1. The student opens DVWA through the portal (/lab/dvwa/...), which requires a portal session.
  2. The proxy forwards the request to the lab's DVWA proxy port and inspects the response.
  3. When detectBrowserMilestone() recognizes a successful attack (for example a UNION SELECT that returns 32-character hashes), the portal calls POST /internal/browser-score with X-Browser-Score-Secret.
  4. The API checks the secret in constant time, checks that the lab is active, owned by that student and on Scenario 2, and records a PASS with detection_data such as browser:sqli-m3 and source='browser'.
  5. When an attempt looks like a near miss (for example the security level is not Low, or a UNION returns no hashes), the proxy posts only an allow-listed reason code to POST /internal/browser-diagnostic with the same secret. It is stored only if Scenario 2 diagnostics are switched on and the milestone has not already passed on that lab.

Source: cyberrange/portal/src/lib/dvwaScoreSignals.ts, cyberrange/src/provisioning/pods_router.py.

Flow 7: SIEM alerts ​

  • Student (Scenario 3): GET /pods/{id}/alerts returns up to 50 recent alerts for that lab's agents, with only six allow-listed fields (timestamp, agent id and name, rule id, description, level).
  • Instructor, live: GET /instructor/pods/{id}/alerts.
  • Instructor, ended labs: GET /instructor/students/{id}/labs lists lab sessions; GET .../labs/{pod}/alerts?started_at=... reads the manager's daily archive files for that time window.
  • Frozen with a report: GET /instructor/reviews/{id}/alert-snapshot.

Source: cyberrange/src/provisioning/alerts_endpoint.py, alerts_reader.py, lab_history.py.

Flow 8: Review submission and resolution ​

  1. Student POST /reviews/submit creates a review_cases row with status PENDING; a background task freezes the lab's alerts in review_alert_snapshots.
  2. The student can attach up to 5 screenshots (POST /reviews/{id}/images).
  3. An instructor opens the case and resolves it: APPROVED, REJECTED or RETRY, with a score from 0 to 100 and feedback.
  4. A RETRY case can be resubmitted by its owner, which returns it to PENDING and takes a fresh snapshot.

Source: cyberrange/src/provisioning/pods_router.py.

Data written where ​

DataWritten byStored in
Lab rows and statuspods_router.py, provision.py, reaper.pySQLite pods
Milestone resultsscoring.py (every check), browser-score, flag capture, instructor approval; each row tagged with its source (schema v15)SQLite milestone_verification
Failure reason codes (instructor-only)scoring_diagnostics.py, browser-diagnostic callbackSQLite scoring_diagnostics (one row per student, lab, scenario and milestone; purged after 14 days by default)
Research exclusionsAdmin → Users (users_router.py)SQLite research_exclusions
First-login orientationonboarding_router.pySQLite user_onboarding
Audit eventsdb.log_event() from provisioning, scoring, admin actionsSQLite audit_log
Lab time windowslab_history.pySQLite lab_sessions
Reviews and snapshotspods_router.py, lab_history.pySQLite review_cases, review_alert_snapshots
Evidence screenshotsevidence_images.pyFiles in EVIDENCE_IMAGE_DIR, metadata in review_evidence_images
Accounts, passwords, rolesKeycloak (Admin page via users_router.py)Keycloak's database
Shell history, triage filesThe student, inside the labLab container filesystem (deleted with the lab)
Security alertsWazuh manager/var/ossec/logs/alerts/ in the wazuh-manager container
Test-session bookingsBooking Apps ScriptA Google Sheet, outside the platform

Cyber Range capstone documentation (Capstone 2 · Group 2 · A4102). Documents main at commit 6971373.