wiki/d-guides/microsoft-entra-registration-checklist.md
2026-05-17 00:06:21 +02:00

118 lines
6.4 KiB
Markdown

# Checkliste: Microsoft Entra ID — PORTA (OAuth)
Operative Liste: **was in der App-Registrierung** im Ziel-Tenant (z. B. **poweron.swiss**) **konfiguriert** werden muss und **welche Gateway-Variablen/Code-Stellen** dazu passen.
Hintergrund Konzept Auth- vs. Data-App: [`z-archive/concepts/OAuth-Auth-vs-Data-Connection-Konzept.md`](../z-archive/concepts/OAuth-Auth-vs-Data-Connection-Konzept.md).
**Hinweis:** App-Registrierungen lassen sich nicht „in einen anderen Tenant verschieben“. Neu im Ziel-Tenant anlegen (oder bewusst Multi-Tenant), Secrets neu erzeugen, Nutzer müssen sich ggf. neu anmelden / Microsoft-Verbindungen neu verbinden.
---
## 1) Entra Admin Center — App registration
[Azure Portal](https://portal.azure.com) → **Microsoft Entra ID****App registrations****New registration**.
- **Name:** z. B. PowerOn PORTA.
- **Supported account types:**
- Nur eigener Tenant (**Single tenant**), oder
- **Multitenant** — dann passt typisch `Service_MSFT_TENANT_ID = common` zum Authority `login.microsoftonline.com/common`.
- Redirects werden unter **Authentication** ergänzt (nächster Abschnitt).
---
## 2) Authentication — Redirect URIs (Web)
**App registration****Authentication****Platform** „Web“ → **Redirect URIs**.
Pro öffentlich erreichbare Gateway-URL **drei** URIs (exakt, inkl. Schema):
| URI | Env-Variable / Zweck |
|-----|----------------------|
| `{origin}/api/msft/auth/login/callback` | `Service_MSFT_AUTH_REDIRECT_URI` (Login) |
| `{origin}/api/msft/auth/connect/callback` | `Service_MSFT_DATA_REDIRECT_URI` (User-Daten-Connection) |
| `{origin}/api/msft/adminconsent/callback` | Admin-Consent-Flow (abgeleitet aus `Service_MSFT_DATA_REDIRECT_URI`, siehe `_admin_consent_redirect_uri()` in `routeSecurityMsft.py`) |
> Fehlt die Admin-Consent-URI, scheitert der Flow mit `AADSTS50011: The redirect URI ... does not match` — der User sieht "Leider können wir Sie nicht anmelden".
**In diesem Repo typische Origins** (jeweils alle drei URIs):
- Lokal: `http://localhost:8000`
- INT: `https://gateway-int.poweron.swiss`
- PROD: `https://gateway-prod.poweron.swiss`
- Forgejo/ALT-Prod (falls genutzt): `https://api.poweron.swiss`
Implizite Flow / SPA: für dieses Gateway-Backend-Redirect-Muster **nicht** nötig (Confidential Client mit Secret).
Backend-Routing: `gateway/modules/routes/routeSecurityMsft.py` (Prefix `/api/msft`).
---
## 3) Certificates & secrets
**Certificates & secrets****New client secret**.
Wert in `Service_MSFT_AUTH_CLIENT_SECRET` und `Service_MSFT_DATA_CLIENT_SECRET` eintragen (bei **einer** App-Registrierung für beide Flows: **dieselben** Secrets — in den Envs oft identisch).
Verschlüsselung siehe [`encrypt-env-secrets.md`](encrypt-env-secrets.md).
---
## 4) API permissions (Microsoft Graph — Delegated)
**API permissions****Add a permission****Microsoft Graph****Delegated permissions**.
Single Source of Truth für die Scope-Liste: `gateway/modules/auth/oauthProviderConfig.py``msftAuthScopes`, `msftDataScopes`
| Zweck | Graph permissions (delegated) |
|-------|-------------------------------|
| Login (`msftAuthScopes`) | `User.Read` |
| Datenverbindung (`msftDataScopes`) | `User.Read`, `Mail.ReadWrite`, `Mail.Send`, `Files.ReadWrite.All`, `Sites.ReadWrite.All`, `Team.ReadBasic.All`, `OnlineMeetings.Read`, `Chat.ReadWrite`, `ChatMessage.Send`, `Calendars.Read`, `Contacts.Read` |
Viele dieser Permissions erfordern **Administratoreinwilligung** im Tenant: **Grant admin consent for {tenant}**.
Zusätzlicher Flow im Gateway: Admin-Consent-URL unter **`/api/msft/adminconsent`** mit Callback **`…/api/msft/adminconsent/callback`** (Redirect wird aus `Service_MSFT_DATA_REDIRECT_URI` abgeleitet — siehe `routeSecurityMsft.py`). Die Callback-URI muss zwingend unter den Redirect URIs in Abschnitt 2 eingetragen sein.
**Multi-Tenant-Apps (TENANT_ID=`common`):** Admin Consent gilt **pro Tenant**. Ein Admin-Consent durch einen valueon.ch-Admin hat keine Wirkung für pamocreate.com-User. Jeder neue Tenant, der die App nutzt, braucht eine eigene Admin-Zustimmung — entweder durch den Tenant-Admin via `/api/msft/adminconsent` (im PowerOn-Wizard: "Admin-Zustimmung erteilen") oder durch direkten Aufruf von `https://login.microsoftonline.com/{tenant}/v2.0/adminconsent?client_id=...`. Solange das fehlt, bekommen User aus diesem Tenant beim Login den "Anforderung gesendet"-Screen.
---
## 5) Gateway — Env-Dateien anpassen
| Variable | Bedeutung |
|----------|-----------|
| `Service_MSFT_AUTH_CLIENT_ID` | Application (client) ID für Login-Flow |
| `Service_MSFT_AUTH_CLIENT_SECRET` | Client secret (verschlüsselt) |
| `Service_MSFT_AUTH_REDIRECT_URI` | Muss **1:1** mit Entra Login-Redirect übereinstimmen |
| `Service_MSFT_DATA_CLIENT_ID` | Application (client) ID für Connect; darf = Auth sein |
| `Service_MSFT_DATA_CLIENT_SECRET` | Client secret (verschlüsselt) |
| `Service_MSFT_DATA_REDIRECT_URI` | Muss **1:1** mit Entra Connect-Redirect übereinstimmen |
| `Service_MSFT_TENANT_ID` | `common` (Multi-Tenant-Anmeldung) **oder** Verzeichnis-ID (GUID) des Tenants **poweron.swiss** für Single-Tenant-Authority |
**Dateien (Stand Repo):** `gateway/env-gateway-dev.env`, `env-gateway-int.env`, `env-gateway-prod.env`, `env-gateway-prod-forgejo.env`, ggf. `gateway/.env`.
Wenn neues **Frontend** oder neuer **API-Host**:
- `APP_API_URL` — öffentliche Basis des Gateways.
- `APP_ALLOWED_ORIGINS` — CORS für das UI.
---
## 6) Gateway — Python / Sicherheit (Referenz)
| Datei | Inhalt |
|-------|--------|
| `gateway/modules/auth/oauthProviderConfig.py` | `msftAuthScopes`, `msftDataScopes`, `msftDataScopesForRefresh` |
| `gateway/modules/routes/routeSecurityMsft.py` | Login, Connect, Admin-Consent; liest alle `Service_MSFT_*` |
| `gateway/modules/auth/tokenManager.py` | Refresh für Microsoft Data (`Service_MSFT_DATA_*`, `Service_MSFT_TENANT_ID`) |
| `gateway/modules/auth/csrf.py` | CSRF-Ausnahmen für `/api/msft/auth/*` und `/api/msft/adminconsent*` — bei **neuen** OAuth-Pfaden ggf. erweitern (selten) |
Keine Code-Änderung nötig, solange **gleiche Routen** und **gleiche Scope-Menge** wie in `oauthProviderConfig.py` verwendet werden.
---
## 7) Smoke-Tests
- [ ] Login mit Microsoft: Rückkehr ohne AADSTS50011 (Redirect mismatch)
- [ ] **Verbindungen** → Microsoft connect/reconnect
- [ ] Nach Tenant-Wechsel: Admin Consent im neuen Tenant ausgeführt
- [ ] Je nach Feature: Mail, OneDrive/SharePoint, Teams/Chat, Kalender, Kontakte kurz testen