hotfix msft/google login tokens end to end separated from connection
This commit is contained in:
parent
d0b0b1c853
commit
d5679f6e07
1 changed files with 351 additions and 0 deletions
351
concepts/OAuth-Auth-vs-Data-Connection-Konzept.md
Normal file
351
concepts/OAuth-Auth-vs-Data-Connection-Konzept.md
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
# OAuth: Login (Auth-only) vs. UserConnection (Data) — Zielzustand & Umsetzungsplan
|
||||
|
||||
## Übersicht
|
||||
|
||||
Dieses Dokument beschreibt den **ausschließlichen Zielzustand** der Google- und Microsoft-Integration im **PowerOn Gateway** (`poweron/gateway`). Es gibt **keine Übergangsphase** und **keine Rückwärtskompatibilität**.
|
||||
|
||||
Der folgende Abschnitt **„Ist (Codebasis)“** belegt den Ausgangspunkt mit konkreten Stellen im Repo. Alles danach ist **Soll**: feste URLs, feste Scope-Listen, feste Env-Keys, feste Verhaltensregeln.
|
||||
|
||||
| Ebene | OAuth-Client | Token in DB |
|
||||
|--------|----------------|-------------|
|
||||
| **Identity (Login)** | Auth-App | `connectionId = null`, `tokenPurpose = authSession`, `tokenAccess` = Gateway-JWT |
|
||||
| **Data (UserConnection)** | Data-App | `connectionId` gesetzt, `tokenPurpose = dataConnection`, `tokenAccess` / `tokenRefresh` = Microsoft/Google |
|
||||
|
||||
---
|
||||
|
||||
## Ist (Codebasis) — Referenz für den Umbau
|
||||
|
||||
### Router & URLs (heute)
|
||||
|
||||
- **Prefix Google:** `APIRouter(prefix="/api/google", …)` in `gateway/modules/routes/routeSecurityGoogle.py`.
|
||||
- **Prefix MSFT:** `APIRouter(prefix="/api/msft", …)` in `gateway/modules/routes/routeSecurityMsft.py`.
|
||||
- **Heute sichtbare Endpunkte:**
|
||||
- `GET /api/google/login` — startet OAuth mit **einem** globalen `SCOPES`-Array (enthält Gmail + Drive + Userinfo + `openid`).
|
||||
- `GET /api/google/auth/callback` — gemeinsamer Callback für Login (`state.type == "login"`) und Connect (`state.type == "connect"`).
|
||||
- `GET /api/msft/login` — startet OAuth mit **einem** globalen `SCOPES` (alle Business-Scopes).
|
||||
- `GET /api/msft/auth/callback` — gemeinsamer Callback Login/Connect.
|
||||
- `GET /api/msft/adminconsent` + `GET /api/msft/adminconsent/callback`.
|
||||
- `GET /api/google/config` — Debug-Konfiguration.
|
||||
|
||||
### Google — eine Scope-Liste für alles (`routeSecurityGoogle.py`, ca. Zeilen 88–94)
|
||||
|
||||
Heute:
|
||||
|
||||
```text
|
||||
https://www.googleapis.com/auth/gmail.readonly
|
||||
https://www.googleapis.com/auth/drive.readonly
|
||||
https://www.googleapis.com/auth/userinfo.profile
|
||||
https://www.googleapis.com/auth/userinfo.email
|
||||
openid
|
||||
```
|
||||
|
||||
Zusätzlich setzt der Login `access_type=offline`, `include_granted_scopes=true` (Zeilen ~166–169) — auch für den reinen Login-Pfad.
|
||||
|
||||
### Microsoft — eine Scope-Liste für alles (`routeSecurityMsft.py`, Zeilen 56–67)
|
||||
|
||||
Heute (delegiert, an MSAL übergeben; MSAL ergänzt u. a. `openid`, `profile`, `offline_access`):
|
||||
|
||||
```text
|
||||
User.Read
|
||||
Mail.ReadWrite
|
||||
Mail.Send
|
||||
Files.ReadWrite.All
|
||||
Sites.ReadWrite.All
|
||||
Team.ReadBasic.All
|
||||
OnlineMeetings.Read
|
||||
Chat.ReadWrite
|
||||
ChatMessage.Send
|
||||
```
|
||||
|
||||
Kommentar im Code: Admin Consent unter `GET /api/msft/adminconsent`.
|
||||
|
||||
### Microsoft Login speichert zwei Access-Token-Rows (`routeSecurityMsft.py`, ca. 340–389)
|
||||
|
||||
1. `Token` mit `tokenAccess = token_response["access_token"]` (Graph) → `saveAccessToken`.
|
||||
2. `Token` mit `tokenAccess = jwt_token` (Gateway-JWT) → `saveAccessToken` erneut.
|
||||
|
||||
Der Login-Pfad soll im Ziel **nur** Schritt 2 persistieren (ein Row, `authSession`).
|
||||
|
||||
### Google Login-Callback postet Provider-Token ans Frontend (`routeSecurityGoogle.py`, ca. 387–391)
|
||||
|
||||
Im HTML wird `postMessage` mit `access_token: token_response["access_token"]` (Google Access Token) mitgeschickt. **Ziel:** Im Login-Flow kein Google Access Token an `window.opener` senden — nur noch `token_data` für das Gateway-JWT (oder nur Cookies, je nach UI-Vertrag).
|
||||
|
||||
### Connections → OAuth-Start (`routeDataConnections.py`, Zeilen 450–465)
|
||||
|
||||
`connect_service` baut:
|
||||
|
||||
- MSFT: `auth_url = f"/api/msft/login?state={json.dumps(state_data)}"` mit `type: "connect"`, `connectionId`, `userId`.
|
||||
- Google: `auth_url = f"/api/google/login?state=…"` gleiches Muster.
|
||||
|
||||
**Ziel:** Diese Strings werden durch die neuen **Connect-URLs** ersetzt (siehe unten). Die fachliche Validierung „Connection gehört `currentUser`“ bleibt: Zeilen 436–440.
|
||||
|
||||
### Token-Refresh Microsoft (`gateway/modules/auth/tokenManager.py`, Zeilen 47–53)
|
||||
|
||||
`refreshMicrosoftToken` sendet beim Refresh einen **fest eingeschränkten** `scope`:
|
||||
|
||||
```text
|
||||
Mail.ReadWrite Mail.Send Mail.ReadWrite.Shared User.Read
|
||||
```
|
||||
|
||||
Das deckt **nicht** die in `routeSecurityMsft.py` verwendeten Scopes ab (`Files.ReadWrite.All`, `Sites.ReadWrite.All`, Teams, …). **Ziel:** Refresh-`scope` ist **zeichenidentisch** zur Data-Scope-Liste aus dem Connect (eine Konstante `MSFT_DATA_SCOPES` im Code, für Authorize + Token + Refresh).
|
||||
|
||||
### JWT-Validierung (`gateway/modules/auth/authentication.py`, Zeilen 150–196)
|
||||
|
||||
- Datenbankprüfung (`findActiveTokenById`) gilt **nur** für `AuthAuthority.LOCAL`.
|
||||
- JWTs mit `authenticationAuthority` `google` / `msft` werden **ohne** diese DB-Zeilenprüfung akzeptiert, sofern Signatur und Claims passen.
|
||||
|
||||
**Ziel:** Für `google` und `msft` dieselbe Regel wie LOCAL: aktive Row mit `id = jti`, `tokenPurpose = authSession`, `authority` passend. (Kein „optional“.)
|
||||
|
||||
### CSRF (`gateway/modules/auth/csrf.py`, Zeilen 24–31)
|
||||
|
||||
`exempt_paths` enthält u. a.:
|
||||
|
||||
- `/api/msft/login`, `/api/google/login`
|
||||
- `/api/msft/callback`, `/api/google/callback` — diese Pfade entsprechen **nicht** den realen Callback-Routen (`/api/msft/auth/callback`, `/api/google/auth/callback`).
|
||||
|
||||
**Ziel:** `exempt_paths` auf die **neuen** OAuth-GET-Start-URLs setzen (siehe unten). Tote Einträge entfernen. (Hinweis: CSRF greift nur für `POST`/`PUT`/`DELETE`/`PATCH`; die Einträge sind trotzdem mit den echten Pfaden zu synchronisieren.)
|
||||
|
||||
### Konfiguration (`gateway/env_dev.env`, `env_int.env`, `env_prod.env`, `.env`)
|
||||
|
||||
Heute u. a.:
|
||||
|
||||
- `Service_GOOGLE_CLIENT_ID`, `Service_GOOGLE_CLIENT_SECRET`, `Service_GOOGLE_REDIRECT_URI` → zeigen auf **eine** App und Callback `…/api/google/auth/callback`.
|
||||
- `Service_MSFT_CLIENT_ID`, `Service_MSFT_CLIENT_SECRET`, `Service_MSFT_REDIRECT_URI` → `…/api/msft/auth/callback`.
|
||||
|
||||
**Ziel:** Diese Keys werden **ersetzt** (siehe Abschnitt Konfiguration).
|
||||
|
||||
### App-Einbindung (`gateway/app.py`, ca. Zeilen 539–543)
|
||||
|
||||
`msftRouter` und `googleRouter` werden eingebunden; der Umbau bleibt in denselben Modulen oder splittet intern — **keine** parallelen Legacy-Router.
|
||||
|
||||
---
|
||||
|
||||
## Soll: Öffentliche HTTP-API (nur diese Routen)
|
||||
|
||||
Die heutigen Routen **`GET /api/google/login`**, **`GET /api/msft/login`** und der **gemeinsame** Callback **`GET /api/google/auth/callback`** / **`GET /api/msft/auth/callback`** werden **entfernt**. Stattdessen:
|
||||
|
||||
| Aktion | Google | Microsoft |
|
||||
|--------|--------|-----------|
|
||||
| Login start | `GET /api/google/auth/login` | `GET /api/msft/auth/login` |
|
||||
| Login callback | `GET /api/google/auth/login/callback` | `GET /api/msft/auth/login/callback` |
|
||||
| Connect start | `GET /api/google/auth/connect` | `GET /api/msft/auth/connect` |
|
||||
| Connect callback | `GET /api/google/auth/connect/callback` | `GET /api/msft/auth/connect/callback` |
|
||||
| Admin Consent | — | `GET /api/msft/adminconsent` |
|
||||
| Admin Consent Callback | — | `GET /api/msft/adminconsent/callback` |
|
||||
|
||||
**Connect-Start:** Query-Parameter und Pflichten — **konkret:**
|
||||
|
||||
- `connectionId` (UUID der `UserConnection`) ist **Pflicht**.
|
||||
- Der Handler ruft `getCurrentUser` (oder gleichwertige Session) auf, lädt die Connection über `getInterface(currentUser).getUserConnections` bzw. verifiziert Besitz wie in `routeDataConnections.connect_service` (heute Zeilen 436–440). Stimmt `connectionId` nicht mit `currentUser` überein → `404` / `403`.
|
||||
- **Kein** separater OAuth-State mit `userId`/`connectionId` als alleinige Sicherheit: Session + serverseitige Ownership-Prüfung sind maßgeblich.
|
||||
|
||||
**Redirects in Google Cloud / Azure (pro Umgebung):**
|
||||
|
||||
- Auth-App: genau die beiden URIs `…/auth/login/callback`.
|
||||
- Data-App: genau die beiden URIs `…/auth/connect/callback`.
|
||||
- MSFT Admin Consent Redirect: wie heute aus dem Data-Redirect URI abgeleitet, aber mit dem **Data-**`REDIRECT_URI` als Basis:
|
||||
|
||||
Heute: `REDIRECT_URI.replace("/auth/callback", "/adminconsent/callback")`.
|
||||
|
||||
**Ziel:** `Service_MSFT_DATA_REDIRECT_URI.replace("/auth/connect/callback", "/adminconsent/callback")` (oder gleiche relative Ersetzung auf dem neuen Connect-Callback-Pfad).
|
||||
|
||||
Debug **`GET /api/google/config`:** entweder entfernen oder auf **Auth-** und **Data-**Client getrennt dokumentieren (ohne Secrets); nicht zwingend für Produktion.
|
||||
|
||||
---
|
||||
|
||||
## Soll: Scope-Listen (fest im Code)
|
||||
|
||||
### Google — Auth (`GOOGLE_AUTH_SCOPES`)
|
||||
|
||||
Nur OIDC + Profil, **keine** Gmail-/Drive-API-Scopes:
|
||||
|
||||
```text
|
||||
openid
|
||||
https://www.googleapis.com/auth/userinfo.email
|
||||
https://www.googleapis.com/auth/userinfo.profile
|
||||
```
|
||||
|
||||
- **`access_type`:** `online` (kein Refresh-Token-Zwang für Login).
|
||||
- **`include_granted_scopes`:** **`false`** oder Parameter weglassen.
|
||||
|
||||
### Google — Data (`GOOGLE_DATA_SCOPES`)
|
||||
|
||||
Übernahme der **heutigen** Daten-Scopes aus `routeSecurityGoogle.py`, ohne die Userinfo-Scopes zu duplizieren, wenn sie für den Data-Flow nicht nötig sind; **Minimum** zur Kompatibilität mit `connectorGoogle.py` (Drive + Gmail):
|
||||
|
||||
```text
|
||||
openid
|
||||
https://www.googleapis.com/auth/userinfo.email
|
||||
https://www.googleapis.com/auth/userinfo.profile
|
||||
https://www.googleapis.com/auth/gmail.readonly
|
||||
https://www.googleapis.com/auth/drive.readonly
|
||||
```
|
||||
|
||||
- **`access_type`:** `offline`.
|
||||
- **`include_granted_scopes`:** `true` **nur** hier (Data-App / Connect), nicht im Auth-Login.
|
||||
|
||||
### Microsoft — Auth (`MSFT_AUTH_SCOPES`)
|
||||
|
||||
Nur Profil für `GET https://graph.microsoft.com/v1.0/me` nach Code-Tausch:
|
||||
|
||||
```text
|
||||
User.Read
|
||||
```
|
||||
|
||||
MSAL erhält **ausschließlich** diese Liste für `get_authorization_request_url` / `acquire_token_by_authorization_code` im **Login**-Pfad. Die von MSAL ergänzten Standard-Claims (`openid`, `profile`, `offline_access`, …) bleiben unverändert Provider-seitig.
|
||||
|
||||
### Microsoft — Data (`MSFT_DATA_SCOPES`)
|
||||
|
||||
**Unverändert** gegenüber der heutigen Liste in `routeSecurityMsft.py` (Zeilen 56–67):
|
||||
|
||||
```text
|
||||
User.Read
|
||||
Mail.ReadWrite
|
||||
Mail.Send
|
||||
Files.ReadWrite.All
|
||||
Sites.ReadWrite.All
|
||||
Team.ReadBasic.All
|
||||
OnlineMeetings.Read
|
||||
Chat.ReadWrite
|
||||
ChatMessage.Send
|
||||
```
|
||||
|
||||
**Regel:** `MSFT_DATA_SCOPES` ist **eine** Konstante; sie wird für Authorize, für `acquire_token_by_authorization_code` Connect und für den **Refresh** (`tokenManager.refreshMicrosoftToken`, Feld `scope` im POST an `…/oauth2/v2.0/token`) als **eine** Space-getrennte Zeichenkette verwendet (Reihenfolge wie oben, konsistent halten).
|
||||
|
||||
---
|
||||
|
||||
## Soll: Konfiguration (`gateway/env_*.env` / `APP_CONFIG`)
|
||||
|
||||
Die bisherigen Einträge werden **entfernt** und **ersetzt** durch:
|
||||
|
||||
**Google**
|
||||
|
||||
- `Service_GOOGLE_AUTH_CLIENT_ID`
|
||||
- `Service_GOOGLE_AUTH_CLIENT_SECRET`
|
||||
- `Service_GOOGLE_AUTH_REDIRECT_URI` → muss `…/api/google/auth/login/callback` enden.
|
||||
- `Service_GOOGLE_DATA_CLIENT_ID`
|
||||
- `Service_GOOGLE_DATA_CLIENT_SECRET`
|
||||
- `Service_GOOGLE_DATA_REDIRECT_URI` → muss `…/api/google/auth/connect/callback` enden.
|
||||
|
||||
**Microsoft**
|
||||
|
||||
- `Service_MSFT_AUTH_CLIENT_ID`
|
||||
- `Service_MSFT_AUTH_CLIENT_SECRET`
|
||||
- `Service_MSFT_AUTH_REDIRECT_URI` → `…/api/msft/auth/login/callback`
|
||||
- `Service_MSFT_DATA_CLIENT_ID`
|
||||
- `Service_MSFT_DATA_CLIENT_SECRET`
|
||||
- `Service_MSFT_DATA_REDIRECT_URI` → `…/api/msft/auth/connect/callback`
|
||||
- `Service_MSFT_TENANT_ID` (unverändert, z. B. `common`)
|
||||
|
||||
**Zu aktualisierende Dateien:** `gateway/env_dev.env`, `gateway/env_int.env`, `gateway/env_prod.env`, `gateway/.env`, sowie jede zentrale Konfiguration, die `APP_CONFIG` befüllt.
|
||||
|
||||
**`TokenManager`** lädt für Refresh **ausschließlich** Data-Client-Zugangsdaten: `Service_MSFT_DATA_CLIENT_ID`, `Service_MSFT_DATA_CLIENT_SECRET`, `Service_MSFT_TENANT_ID` (heute nutzt die Klasse `Service_MSFT_CLIENT_ID` / `SECRET` — das wird ersetzt).
|
||||
|
||||
---
|
||||
|
||||
## Soll: Datenmodell & DB
|
||||
|
||||
### `Token` (`gateway/modules/datamodels/datamodelSecurity.py`)
|
||||
|
||||
Pflichtfeld:
|
||||
|
||||
```text
|
||||
tokenPurpose: Literal["authSession", "dataConnection"]
|
||||
```
|
||||
|
||||
| `tokenPurpose` | `connectionId` | `tokenAccess` | `tokenRefresh` |
|
||||
|----------------|----------------|---------------|----------------|
|
||||
| `authSession` | `null` | Gateway-JWT | leer oder nicht genutzt |
|
||||
| `dataConnection` | gesetzt | Provider Access | Provider Refresh (Data-Flow) |
|
||||
|
||||
Kein weiteres optionales Metadatenfeld im ersten Schritt.
|
||||
|
||||
### Migration
|
||||
|
||||
- Spalte `tokenPurpose` **NOT NULL** mit Check-Constraint oder App-Validierung.
|
||||
- Cutover: bestehende Datenbankzeilen ohne klare Zuordnung werden **bereinigt**; Nutzer führen Login und Connect **einmal neu** aus.
|
||||
|
||||
### `UserConnection.grantedScopes`
|
||||
|
||||
Nach Connect-Callback:
|
||||
|
||||
- **Google:** aus `token_response["scope"]` (bzw. aus der Antwort des Token-Endpunkts) als Liste splitten.
|
||||
- **Microsoft:** aus dem erfolgreichen MSAL-Resultat-Feld für Scope, falls vorhanden; wenn der Provider nur eine Teilmenge zurückgibt, persistieren was zurückkommt — **nicht** blind `MSFT_DATA_SCOPES` in die DB schreiben, wenn die Antwort etwas anderes meldet.
|
||||
|
||||
---
|
||||
|
||||
## Soll: Verhalten pro Flow
|
||||
|
||||
### Login
|
||||
|
||||
1. `GET …/auth/login` → Redirect Google/Microsoft **Auth-App**, Scopes = `GOOGLE_AUTH_SCOPES` bzw. `MSFT_AUTH_SCOPES`.
|
||||
2. Callback `…/auth/login/callback` → Code tauschen, Userinfo (`oauth2/v2/userinfo` bzw. Graph `/me`), User anlegen/lesen, JWT erzeugen.
|
||||
3. Genau **ein** `saveAccessToken`: `tokenPurpose=authSession`, `connectionId=null`, `tokenAccess=jwt`, `id=jti` wie heute bei Google/MSFT-JWT-Row.
|
||||
4. Cookies setzen wie heute (`setAccessTokenCookie`, `setRefreshTokenCookie`).
|
||||
5. **Microsoft:** kein `saveAccessToken` mit Rohtoken aus Graph.
|
||||
6. **Google:** `postMessage` **ohne** `access_token` mit Google-Bearer-Token.
|
||||
|
||||
### Connect
|
||||
|
||||
1. Client ruft weiter `POST /api/connections/{connectionId}/connect` auf (bestehende Vertragsstelle).
|
||||
2. Response `authUrl` ist **relativ** z. B. `/api/google/auth/connect?connectionId={id}` bzw. `/api/msft/auth/connect?connectionId={id}`.
|
||||
3. Browser folgt `GET …/auth/connect` mit gültiger Session → Server prüft Ownership → Redirect **Data-App**, Scopes = `GOOGLE_DATA_SCOPES` / `MSFT_DATA_SCOPES`.
|
||||
4. Callback `…/auth/connect/callback` → `saveConnectionToken` mit `tokenPurpose=dataConnection`, gleiche `connectionId`; `UserConnection` aktualisieren inkl. `grantedScopes`.
|
||||
|
||||
### Admin Consent (MSFT)
|
||||
|
||||
- `GET /api/msft/adminconsent` verwendet **`Service_MSFT_DATA_CLIENT_ID`** und `redirect_uri` abgeleitet von **`Service_MSFT_DATA_REDIRECT_URI`**.
|
||||
|
||||
---
|
||||
|
||||
## Soll: Codeänderungen (Dateien)
|
||||
|
||||
| Datei | Konkrete Aufgabe |
|
||||
|-------|------------------|
|
||||
| `gateway/modules/routes/routeSecurityGoogle.py` | Router neu strukturieren: vier Zielrouten; zwei Client-Paare aus Config; Konstanten `GOOGLE_AUTH_SCOPES` / `GOOGLE_DATA_SCOPES`; Login ohne `include_granted_scopes`; Connect mit `offline` + `include_granted_scopes`; `/login` und `/auth/callback` löschen. |
|
||||
| `gateway/modules/routes/routeSecurityMsft.py` | Wie oben; `MSFT_AUTH_SCOPES` / `MSFT_DATA_SCOPES`; Login nur eine `saveAccessToken`-Row; Connect unverändert fachlich, aber nur Data-Client; Admin Consent auf Data-Client; `/login` und `/auth/callback` löschen. |
|
||||
| `gateway/modules/routes/routeDataConnections.py` | `auth_url` auf `/api/msft/auth/connect?connectionId=…` und `/api/google/auth/connect?connectionId=…` (kein JSON-`state` mehr nötig für Security — Session + DB-Check). |
|
||||
| `gateway/modules/interfaces/interfaceDbApp.py` | `saveAccessToken` / `saveConnectionToken` validieren `tokenPurpose` und `connectionId` wie in der Tabelle oben; Verstoß → `ValueError`. |
|
||||
| `gateway/modules/auth/tokenManager.py` | `msft_client_id` / `secret` aus `Service_MSFT_DATA_*`; Refresh-`scope` = space-joined `MSFT_DATA_SCOPES`; Refresh nur sinnvoll aufrufen wenn `oldToken.tokenPurpose == dataConnection` (oder implizit nur solche Tokens in DB). |
|
||||
| `gateway/modules/serviceCenter/core/serviceSecurity/mainServiceSecurity.py` | `getFreshToken`: wenn geladener Token nicht `dataConnection` → `None` zurück + Log. |
|
||||
| `gateway/modules/auth/authentication.py` | Erweiterung: für `authenticationAuthority` `google` und `msft` dieselbe aktive-Row-Prüfung wie LOCAL auf `findActiveTokenById` mit passender `authority` und `tokenPurpose=authSession`. |
|
||||
| `gateway/modules/auth/csrf.py` | `exempt_paths`: `/api/google/auth/login`, `/api/msft/auth/login` (und keine toten `/api/*/callback` ohne `/auth/`). |
|
||||
| `gateway/env_*.env`, `.env` | Keys wie im Abschnitt Konfiguration. |
|
||||
| Frontend (PowerOn UI) | Alle Links von `/api/google/login` → `/api/google/auth/login`, von `/api/msft/login` → `/api/msft/auth/login`; `connect` nutzt neue `authUrl`. |
|
||||
|
||||
---
|
||||
|
||||
## Umsetzungsschritte (ein Schnitt, Reihenfolge)
|
||||
|
||||
1. Vier OAuth-Apps in Google Cloud / Zwei in Azure (Auth + Data) anlegen; Redirect-URIs exakt wie oben.
|
||||
2. DB-Migration `tokenPurpose` NOT NULL; Datenbereinigung / erzwungener Re-Login und Re-Connect.
|
||||
3. Konstanten und Handler in `routeSecurityGoogle.py` / `routeSecurityMsft.py` implementieren; alte Routen entfernen.
|
||||
4. `routeDataConnections.py` `authUrl` anpassen.
|
||||
5. `interfaceDbApp` + `authentication.py` + `tokenManager` + `mainServiceSecurity.py` anpassen.
|
||||
6. `csrf.py` + alle `env_*.env` aktualisieren.
|
||||
7. Frontend-URLs ersetzen.
|
||||
8. Tests: Login-Tokeninfo ohne Gmail/Drive; Connect mit Daten-Scopes; Refresh MSFT mit vollständigem Scope-String; API-Aufruf mit altem `/api/*/login` muss **404** liefern.
|
||||
|
||||
---
|
||||
|
||||
## Tests (Akzeptanzkriterien)
|
||||
|
||||
- [ ] `GET /api/google/login` und `GET /api/msft/login` existieren **nicht** (404).
|
||||
- [ ] Nach Login liefert Google `tokeninfo` (falls mit kurzlebigenm Token geprüft) **keine** `gmail`/`drive` Scope-Strings.
|
||||
- [ ] Nach MSFT-Login enthält das Access Token **keine** Ressourcen-Zustimmung für Mail/Files jenseits von `User.Read` (Scope-String prüfen).
|
||||
- [ ] Nach Connect: `getConnectionToken` → `dataConnection`; Browse über `ConnectorResolver` funktioniert.
|
||||
- [ ] `refreshMicrosoftToken` sendet `scope` = vollständiger `MSFT_DATA_SCOPES`-String.
|
||||
- [ ] `postMessage` beim Google-Login enthält **keinen** Google `access_token`.
|
||||
|
||||
---
|
||||
|
||||
## Changelog (Dokument)
|
||||
|
||||
| Datum | Änderung |
|
||||
|-------|----------|
|
||||
| 2026-03-20 | Erstversion |
|
||||
| 2026-03-20 | Nur Zielzustand, ohne Übergang |
|
||||
| 2026-03-20 | Ist-Analyse am Code; fest definierte Scopes, URLs, Env-Keys; vage Formulierungen entfernt |
|
||||
|
||||
---
|
||||
|
||||
*Ende Dokument*
|
||||
Loading…
Reference in a new issue