diff --git a/AZURE_AD_CONSENT_LINKS.md b/AZURE_AD_CONSENT_LINKS.md new file mode 100644 index 00000000..45cf6511 --- /dev/null +++ b/AZURE_AD_CONSENT_LINKS.md @@ -0,0 +1,121 @@ +# Azure AD Consent Links + +## Konfiguration +- **Client ID**: `c7e7112d-61dc-4f3a-8cd3-08cc4cd7504c` +- **Tenant ID**: `common` (Multi-Tenant) +- **Redirect URI (Prod)**: `https://gateway-prod.poweron-center.net/api/msft/auth/callback` +- **Redirect URI (Int)**: `https://gateway-int.poweron-center.net/api/msft/auth/callback` + +## Berechtigungen (Scopes) +- `Mail.ReadWrite` - E-Mails lesen und schreiben +- `Mail.Send` - E-Mails senden +- `Mail.ReadWrite.Shared` - Zugriff auf geteilte Postfächer +- `User.Read` - Benutzerprofil lesen +- `Sites.ReadWrite.All` - Alle SharePoint-Standorte lesen und schreiben +- `Files.ReadWrite.All` - Alle Dateien lesen und schreiben + +## Admin Consent Link (für Tenant-Administrator) + +**WICHTIG:** Der Admin Consent Endpoint gibt `admin_consent` und `tenant` zurück, nicht `code` und `state`. +Der bestehende `/auth/callback` Handler erwartet `code` und `state` für den normalen OAuth-Flow. + +**Option 1: Admin Consent über Azure Portal (für eigenen Tenant)** +1. Gehe zu Azure Portal → Azure Active Directory → App registrations +2. Wähle die App `c7e7112d-61dc-4f3a-8cd3-08cc4cd7504c` +3. Gehe zu "API permissions" +4. Klicke auf "Grant admin consent for [Tenant Name]" + +**Option 1b: App für andere Tenants verfügbar machen** + +Um die App für andere Tenants sichtbar zu machen, müssen folgende Schritte durchgeführt werden: + +1. **Multi-Tenant Konfiguration prüfen:** + - Azure Portal → Azure Active Directory → App registrations + - Wähle die App `c7e7112d-61dc-4f3a-8cd3-08cc4cd7504c` + - Gehe zu "Authentication" + - Stelle sicher, dass "Supported account types" auf **"Accounts in any organizational directory and personal Microsoft accounts"** oder **"Accounts in any organizational directory"** gesetzt ist + +2. **App für andere Tenants verfügbar machen:** + + **Methode A: Direkter Admin Consent Link (empfohlen)** + - Andere Tenant-Administratoren können den Admin Consent Link verwenden: + ``` + https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=c7e7112d-61dc-4f3a-8cd3-08cc4cd7504c&redirect_uri=https://gateway-prod.poweron-center.net/api/msft/adminconsent/callback + ``` + - Ersetze `{TENANT_ID}` durch die Tenant-ID des Ziel-Tenants (oder verwende `common` für Multi-Tenant) + + **Methode B: Manuell über Azure Portal (für andere Tenants)** + - Tenant-Administrator des anderen Tenants: + 1. Gehe zu Azure Portal → Azure Active Directory → Enterprise applications + 2. Klicke auf "+ New application" + 3. Wähle "Browse Azure AD Gallery" (optional) oder "Create your own application" + 4. Wenn nicht in Gallery: Wähle "Non-gallery application" + 5. Gib die Client ID ein: `c7e7112d-61dc-4f3a-8cd3-08cc4cd7504c` + 6. Oder verwende direkt diesen Link: + ``` + https://portal.azure.com/#blade/Microsoft_AAD_IAM/ManagedAppMenuBlade/Overview/objectId/{CLIENT_ID} + ``` + (Ersetze `{CLIENT_ID}` mit `c7e7112d-61dc-4f3a-8cd3-08cc4cd7504c`) + 7. Gehe zu "Permissions" → "Grant admin consent" + + **Methode C: App in Azure AD Gallery veröffentlichen (optional)** + - Für größere Sichtbarkeit kann die App in der Azure AD App Gallery veröffentlicht werden + - Azure Portal → App registrations → App → "Branding & properties" + - Kontaktiere Microsoft für Gallery-Veröffentlichung + +3. **Wichtig für Multi-Tenant Apps:** + - Die Redirect URIs müssen öffentlich erreichbar sein + - Die App muss die richtigen Berechtigungen deklarieren + - Tenant-Administratoren müssen explizit zustimmen (Admin Consent) + +**Option 2: Admin Consent Link (mit Callback-Handler)** +### Production +``` +https://login.microsoftonline.com/common/adminconsent?client_id=c7e7112d-61dc-4f3a-8cd3-08cc4cd7504c&redirect_uri=https://gateway-prod.poweron-center.net/api/msft/adminconsent/callback +``` + +### Integration +``` +https://login.microsoftonline.com/common/adminconsent?client_id=c7e7112d-61dc-4f3a-8cd3-08cc4cd7504c&redirect_uri=https://gateway-int.poweron-center.net/api/msft/adminconsent/callback +``` + +**Hinweis:** Der `/adminconsent/callback` Endpoint ist implementiert und verarbeitet die `admin_consent` und `tenant` Parameter. Nach erfolgreichem Admin Consent wird eine Bestätigungsseite angezeigt. + +## User Consent Link (für einzelne Benutzer) + +### Production +``` +https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=c7e7112d-61dc-4f3a-8cd3-08cc4cd7504c&response_type=code&redirect_uri=https://gateway-prod.poweron-center.net/api/msft/auth/callback&response_mode=query&scope=Mail.ReadWrite Mail.Send Mail.ReadWrite.Shared User.Read Sites.ReadWrite.All Files.ReadWrite.All offline_access openid profile&state=login +``` + +### Integration +``` +https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=c7e7112d-61dc-4f3a-8cd3-08cc4cd7504c&response_type=code&redirect_uri=https://gateway-int.poweron-center.net/api/msft/auth/callback&response_mode=query&scope=Mail.ReadWrite Mail.Send Mail.ReadWrite.Shared User.Read Sites.ReadWrite.All Files.ReadWrite.All offline_access openid profile&state=login +``` + +## Hinweise + +1. **Admin Consent**: Muss von einem Tenant-Administrator durchgeführt werden, um die App für alle Benutzer im Tenant zu genehmigen +2. **User Consent**: Jeder Benutzer kann individuell zustimmen (wenn Admin Consent nicht durchgeführt wurde) +3. **Multi-Tenant**: Da `common` als Tenant verwendet wird, funktioniert die App für alle Azure AD Tenants +4. **Redirect URI**: Muss exakt in der Azure AD App-Registrierung konfiguriert sein + +## Azure Portal Konfiguration + +Stelle sicher, dass in der Azure AD App-Registrierung (`c7e7112d-61dc-4f3a-8cd3-08cc4cd7504c`) folgendes konfiguriert ist: + +1. **Redirect URIs**: + - `https://gateway-prod.poweron-center.net/api/msft/auth/callback` + - `https://gateway-int.poweron-center.net/api/msft/auth/callback` + +2. **API Permissions** (Delegated): + - ✅ Mail.ReadWrite + - ✅ Mail.Send + - ✅ Mail.ReadWrite.Shared + - ✅ User.Read + - ✅ Sites.ReadWrite.All + - ✅ Files.ReadWrite.All + +3. **Supported account types**: + - "Accounts in any organizational directory and personal Microsoft accounts" (Multi-tenant) + diff --git a/modules/routes/routeSecurityMsft.py b/modules/routes/routeSecurityMsft.py index b72f4fa3..be7f6476 100644 --- a/modules/routes/routeSecurityMsft.py +++ b/modules/routes/routeSecurityMsft.py @@ -132,6 +132,80 @@ async def login( detail=f"Failed to initiate Microsoft login: {str(e)}" ) +@router.get("/adminconsent/callback") +async def adminconsent_callback( + admin_consent: Optional[str] = Query(None), + tenant: Optional[str] = Query(None), + error: Optional[str] = Query(None), + error_description: Optional[str] = Query(None), + request: Request = None +) -> HTMLResponse: + """Handle Microsoft Admin Consent callback""" + try: + if error: + logger.error(f"Admin consent error: {error} - {error_description}") + return HTMLResponse( + content=f""" + + Admin Consent Failed + +

Admin Consent Failed

+

Error: {error}

+

Description: {error_description or 'No description provided'}

+

Please contact your administrator.

+ + + """, + status_code=400 + ) + + if admin_consent == "True" and tenant: + logger.info(f"Admin consent granted for tenant: {tenant}") + return HTMLResponse( + content=f""" + + Admin Consent Successful + +

Admin Consent Successful

+

The application has been granted admin consent for tenant: {tenant}

+

All users in this tenant can now use the application without individual consent.

+

You can close this window.

+ + + + """ + ) + else: + logger.warning(f"Admin consent callback received unexpected parameters: admin_consent={admin_consent}, tenant={tenant}") + return HTMLResponse( + content=f""" + + Admin Consent Status + +

Admin Consent Status

+

Admin Consent: {admin_consent or 'Not provided'}

+

Tenant: {tenant or 'Not provided'}

+ + + """ + ) + except Exception as e: + logger.error(f"Error in admin consent callback: {str(e)}", exc_info=True) + return HTMLResponse( + content=f""" + + Admin Consent Error + +

Error Processing Admin Consent

+

{str(e)}

+ + + """, + status_code=500 + ) + @router.get("/auth/callback") async def auth_callback(code: str, state: str, request: Request, response: Response) -> HTMLResponse: """Handle Microsoft OAuth callback"""