clearview/docs/plan-mailbox-scanning.md
Ivo Oskamp bccc39b185 Plan: add AlertHub-style sidebar layout to frontend refactor
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 10:20:59 +02:00

11 KiB

Plan — Mailbox Permission Scanning

Voorstel voor het uitbreiden van Clearview met mailbox-rechten scanning naast de bestaande SharePoint-scan. Status: voorstel, nog niet geïmplementeerd.

1. Scope & aanpak

In Exchange Online zijn dit de relevante permissie-categorieën:

Permissie Bron Waarop
Full Access / Read Get-MailboxPermission hele mailbox
Send As Get-RecipientPermission identiteit
Send on Behalf mailbox-property GrantSendOnBehalfTo identiteit
Folder delegaties (Calendar, Inbox) Get-MailboxFolderPermission per folder

Microsoft Graph dekt dit slechts gedeeltelijk (vooral folder-permissies). De volledige set vereist Exchange Online PowerShell met certificaat-auth (Connect-ExchangeOnline -CertificateThumbprint ... -AppId ... -Organization ...). Dat sluit goed aan op het bestaande cert-model van Clearview — dezelfde Azure-app kan zowel Sites.FullControl.All (SharePoint) als Exchange.ManageAsApp (Exchange) krijgen.

Voorgestelde aanpak: EXO PowerShell aanroepen vanuit Python via pwsh subprocess, JSON-output retour. Alternatief is pure Graph, maar dan mist Send As / Send on Behalf grotendeels.

Deviation-baseline voor mailboxen: anders dan SharePoint heeft een mailbox geen "root vs. child" hiërarchie waar een baseline uit volgt. Voorstel: rapporteer alle non-default permissies (filter standaard-entries als NT AUTHORITY\SELF, S-1-5-10, default folder-permissies "Default"/"Anonymous=None") als deviation. Dus géén delta-vergelijk, maar wel dezelfde dedup-logica per (principal, role).

2. Layout-wijzigingen frontend

Huidige website is volledig op SharePoint gemodelleerd (één scanflow, één resultaattabel) en bestaat uit één lange single-page met alle panels (Tenants, Start New Scan, Scan Jobs, Job Details) onder elkaar. Voorstel: opsplitsen in pagina's met een vaste linker zijbalk zoals AlertHub gebruikt.

a. Sidebar-layout (geïnspireerd op AlertHub)

Vaste zijbalk links (~200px, donkere achtergrond, logo bovenaan, account-blok onderaan):

┌────────────┬──────────────────────────────────┐
│ Clearview  │                                  │
│ ─────────  │  (page content)                  │
│ Dashboard  │                                  │
│ Scan Jobs  │                                  │
│ ─────────  │                                  │
│ SharePoint │                                  │
│   New Scan │                                  │
│ Mailboxes  │                                  │
│   New Scan │                                  │
│ ─────────  │                                  │
│ Tenants    │                                  │
│ Settings   │                                  │
│ ─────────  │                                  │
│ Manual     │                                  │
│ Changelog  │                                  │
│ ─────────  │                                  │
│ [account]  │                                  │
└────────────┴──────────────────────────────────┘

Items:

  • Dashboard — hero/KPI's (Tenants, Jobs, Active Jobs) — huidige hero sectie
  • Scan Jobs — gecombineerde lijst van alle jobs (filter op type/tenant) + Job Details als detail-view (klik op job → toont onder lijst óf als aparte route)
  • SharePoint → New Scan — formulier alleen voor SharePoint-scans (URLs / CSV)
  • Mailboxes → New Scan — formulier alleen voor mailbox-scans (UPNs / CSV)
  • Tenants — huidige tenants-panel
  • Settings — placeholder voor toekomstige instellingen (timeouts, env-overrides als die exposed worden)
  • Manual / Changelog — statische docs als die online beschikbaar moeten komen
  • Account-blok onderaan: huidige sessie / build-versie

Implementatie blijft vanilla HTML/JS/CSS (geen React-introductie — dat zou een grote scope-uitbreiding zijn). Concreet:

  • index.html houdt alle secties als <section data-route="...">, default verborgen
  • Hash-based routing in app.js (#/jobs, #/scan/sharepoint, #/scan/mailbox, #/tenants, …)
  • styles.css krijgt grid-layout met sidebar + content area
  • Geen page reloads; navigatie wisselt zichtbaarheid van secties en update active-state in de sidebar

Voordelen tegenover de huidige single-scroll:

  • Scan-typen visueel gescheiden — voorkomt verwarring tussen SharePoint- en Mailbox-formulieren
  • Schaalt naar meer scan-types (OneDrive, Teams) zonder dat de pagina nóg langer wordt
  • Visuele consistentie met AlertHub binnen jouw productenfamilie

b. Scan-formulier per type (gescheiden pagina's)

  • SharePoint-pagina: huidige URLs/CSV-formulier, ongewijzigd qua velden
  • Mailbox-pagina: invoerveld voor UPN/email (één per regel), géén "skip default sites"
  • CSV-import per pagina, met geschikte kolomdetectie (URL/Site URL versus UserPrincipalName/Email/Mailbox)

c. Jobs-pagina

  • Gecombineerde tabel met alle jobs ongeacht type
  • Nieuwe kolom Type (SharePoint / Mailbox)
  • Tenant-filter blijft, extra filter op type
  • Klik op een job opent de detail-view (sectie eronder of dedicated route #/jobs/{id})

d. Job Details (binnen Jobs-pagina)

  • Sectie heading wordt dynamisch: "Targets" blijft, maar URL-kolom wordt "Mailbox" voor mailbox-jobs
  • Permission Deviations tabel krijgt voor mailbox-jobs andere kolommen:
    • Mailbox · Folder (leeg voor mailbox-level) · Permission Type (FullAccess/SendAs/SendOnBehalf/Folder) · Principal · Access Rights
  • SharingLinks-blok wordt verborgen voor mailbox-jobs
  • Site-filter wordt mailbox-filter

e. Tenants-pagina

  • In de onboarding-instructies een extra stap erbij: API permission Office 365 Exchange Online → Exchange.ManageAsApp + role Exchange Administrator toekennen aan de service principal. Voor de geautomatiseerde flow betekent dit een extra Graph-call (rol-toekenning kan niet altijd, dus mogelijk handmatige stap).
  • Statuskolom Auth toont al cert/secret; voorstel: extra capability-badge per tenant (SP, EXO) zodat zichtbaar is welke scans mogelijk zijn.

3. Backend-optimalisatie / herstructurering

scanner.py is nu één bestand met SharePoint-specifieke logica én generieke helpers (auth, HTTP, dedup, role-name normalization). Voorstel:

src/clearview_app/scanners/
    __init__.py            # dispatcher: scan(target_type, ...)
    common.py              # AuthConfig, DeviationRecord, ScanResult, ProbeResult,
                           # MSAL token cache, _request_json, _iter_paged,
                           # _deduplicate_hierarchical, role-name normalization
    sharepoint.py          # huidige scan_site_for_deviations + probe_site + resolve_sharing_link_members
    mailbox.py             # nieuw: scan_mailbox_for_deviations + probe_mailbox
                           # roept pwsh aan met EXO-script en parseert JSON
    exo_scripts/
        get-permissions.ps1  # connect + get mailbox/recipient/folder permissions, output JSON
        probe.ps1            # lichtgewicht: Get-EXOMailbox -Identity x | select Identity

Voordelen:

  • scanner.py was richting 540 regels en mengt concerns; opsplitsen maakt testen makkelijker
  • worker.py krijgt één dispatcher-call: scan(target_type, target, auth, progress) ipv. directe import van SharePoint-specifieke functies
  • Toekomstige scan-types (OneDrive, Teams) passen in hetzelfde patroon

Worker.py moet leren: per target weten welke scanner aan te roepen op basis van scan_targets.target_type (of scan_jobs.scan_type).

4. Datamodel

Minimale, niet-brekende wijzigingen — toegepast via bestaand _ensure_schema_columns():

Tabel Nieuwe kolom Default
scan_jobs scan_type VARCHAR(32) 'sharepoint'
scan_targets (geen — site_url blijft, bevat UPN voor mailbox-jobs; of hernoem naar target met DB-view voor compat)
permission_deviations permission_type VARCHAR(32) NULL NULL (voor SP-rows)
permission_deviations object_type krijgt nieuwe waarden: Mailbox, MailboxFolder

Vraag: liever site_url houden als generieke "target identifier" (compacter, geen migratie), of nu hernoemen? Eerste optie is mijn voorstel.

5. API-endpoints

Bestaand blijft werken. Toevoegingen:

POST   /api/scan-jobs            payload krijgt optioneel "scan_type": "sharepoint"|"mailbox"
                                 en "mailboxes": [...] naast/ipv "site_urls"
POST   /api/scan-jobs/import-csv extra "scan_type" form-field
GET    /api/scan-jobs?scan_type=mailbox    filter

Nieuwe response-velden in ScanJobDetail: scan_type, en deviations krijgen permission_type.

6. Onboarding & runtime-vereisten

  • Container: PowerShell 7 (pwsh) en de ExchangeOnlineManagement PS-module installeren in de Docker image. Dit voegt ~150MB toe. Acceptabel?
  • Azure-app: extra permission Office 365 Exchange Online → Exchange.ManageAsApp + Entra-rol "Exchange Administrator" voor de service principal. In Mode A (automated) kan het permission-deel via Graph, het rol-deel meestal niet — handmatige bevestigingsstap nodig.
  • Probe: voor mailboxen één kleine call (Get-EXOMailbox -Identity <upn> -Properties Identity via een korter PS-script) om vroeg te falen op auth/rol.

7. Implementatiestappen (volgorde)

  1. Backend refactor: scanner-module opsplitsen, geen functionele wijziging (groen test)
  2. Datamodel: scan_type + permission_type toevoegen, default 'sharepoint'
  3. Frontend layout-refactor: sidebar + hash-routing introduceren, bestaande functionaliteit (alleen SharePoint) verdelen over pagina's. Nog géén mailbox-UI.
  4. Mailbox-scanner: PS-scripts + Python-wrapper + dispatcher; alleen via API testbaar
  5. API: scan-job creatie uitbreiden met scan_type/mailboxes
  6. Frontend: Mailboxes-pagina toevoegen + dynamische kolommen in Job Details
  7. Onboarding-tekst en build (Dockerfile voor pwsh)
  8. Documentatie: TECHNICAL.md + changelog-develop.md

Open vragen

  1. PowerShell-route akkoord, of liever Graph-only (incompleter, maar pure Python)?
  2. Eén scan-type per job (voorstel), of mengbare jobs (SharePoint + mailboxen door elkaar)?
  3. Baseline voor mailbox: alle non-default rechten als deviation rapporteren (voorstel), of moet er een "expected baseline" per mailbox/tenant configureerbaar worden?
  4. Image-grootte: is +150 MB voor pwsh + EXO-module aanvaardbaar?
  5. site_url kolom hergebruiken als generieke target-identifier, of nu hernoemen naar target?