Add backend team enforcement via requireTeam() middleware

Introduce server-side team-scoped data access enforcement:

- Add TEAM_TO_IVANTI/IVANTI_TO_TEAM mapping to helpers/teams.js
- Add requireTeam() middleware to middleware/auth.js
  - Admin bypass (req.teamScope = null)
  - 403 for users with no team assignment
  - Populates req.teamScope with short and ivanti name arrays
- Ivanti findings: replace client ?teams= param with req.teamScope filtering
  on GET /, /counts, /counts/history, /fp-workflow-counts, POST /sync
  - Override and note endpoints verify finding is in team scope
- Compliance: add requireTeam() router-level, validate ?team= param against scope
  on GET /items and GET /summary
- CARD: validate teamName param on GET /teams/:teamName/assets
- Todo queue: verify findings belong to user's teams on POST /batch
- Clarify IVANTI_BU_FILTER comment (sync-level vs query-time filtering)
- Update 14 test files to include requireTeam in auth middleware mocks
This commit is contained in:
Jordan Ramos
2026-06-24 11:36:25 -06:00
parent ab66d7d813
commit a003091b6a
20 changed files with 239 additions and 81 deletions

View File

@@ -4,7 +4,7 @@
const express = require('express');
const pool = require('../db');
const { requireAuth, requireGroup } = require('../middleware/auth');
const { requireAuth, requireGroup, requireTeam } = require('../middleware/auth');
const logAudit = require('../helpers/auditLog');
const {
isConfigured,
@@ -112,7 +112,7 @@ function createCardApiRouter() {
* @response 400 - { error: string } — missing disposition
* @response 503 - { error: string, missingVars: string[] } — CARD not configured
*/
router.get('/teams/:teamName/assets', requireAuth(), requireGroup('Admin', 'Standard_User'), async (req, res) => {
router.get('/teams/:teamName/assets', requireAuth(), requireGroup('Admin', 'Standard_User'), requireTeam(), async (req, res) => {
if (!isConfigured) {
return res.status(503).json({ error: 'CARD API is not configured.', missingVars });
}
@@ -120,6 +120,16 @@ function createCardApiRouter() {
const { teamName } = req.params;
const { disposition, page, page_size } = req.query;
// Validate requested team is in user's scope
if (req.teamScope && !req.teamScope.short.includes(teamName)) {
return res.status(403).json({
error: 'Access denied. You do not have access to the requested team.',
code: 'TEAM_ACCESS_DENIED',
requested: teamName,
allowed: req.teamScope.short
});
}
if (!disposition) {
return res.status(400).json({ error: 'disposition query parameter is required.' });
}