EWS und OAUTH

Der Zugriff auf Exchange Server per EWS ist mittlerweile allgegenwärtig. Auch wenn Outlook viel über MAPI/HTTP überträgt, ist EWS weiterhin z.B. für OOF-Einstellungen, Mailtipps. etc. in Verwendung. Von Skype for Business und vielen Drittprodukten wollen wir gar nicht sprechen. Mit Office 365 möchte Microsoft am besten alle Dienste per OAUTH authentifizieren. Das ist mit EWS möglich aber erfordert etwas Wissen beim Programmierer. Beachte dazu auch Authentifizierung im Wandel der Zeit.

Beachten Sie, dass EWS in Exchange Online nicht aktiv weiter entwickelt wird und stattdessen die Graph API genutzt werden sollte. Beispiele finden Sie u.a. auf Graph Mail.Send und MGGraph Mail

Was kann Exchange

Microsoft beschreibt auf https://docs.microsoft.com/de-de/exchange/client-developer/exchange-web-services/authentication-and-ews-in-exchange direkt, welche Anmeldeverfahren EWS prinzipiell könnte:

  • OAuth 2.0 (Exchange Online only)
  • NTLM (Enthält auch Kerberos) (Exchange OnPremises only)
  • Basic (no longer recommended)

OAOAUTH 2.0 wird hier nur für Exchange Online gelistet, wenngleich ich sicher bin, dass auch Exchange OnPremises dies bald kann oder vielleicht schon inoffiziell kann.

Verwechseln Sie EWS nicht mit der Graph API. . Hier gibt es nur OAUTH

"Klassische" Anmeldung

Ehe wir auf OAUTH gehen, schaue ich mir einfach mal eine normale EWS-Anmeldung. Ich habe dazu mein Test-Skript Test-EWS genutzt, um über Fiddler eine Anmeldung an meinem Office 365 Konto durchzuführen und die Anzahl der Mails zu lesen. Da ich zu dem Zeitpunkt "Hybrid" war, sehen Sie eine Autodiscover-Anfragen nach OnPremises mit Umleitung zur Cloud und dann den Zugriff aufs Postfach. Hier einfach mal der Überblick.

Ich habe hier extra noch den "Authorization"-Header mit addiert, dass Sie schnell sehen können, welche Zugriffe anonym erfolgen und welche wie authentifiziert werden. In aller Kürze ist das:

Paket Beschreibung
14-21

Der Client geht zuerst anonym auf "https://<maildomain>" und fängt sich einen 404 ein um dann auf "https://autodiscover.<maildomain>" weiter zu gehen. Hier bekommt er einen 401 mit der Info, dass er sich anmelden muss. In dem Beispiel bietet der Webserver gleich mehrere Verfahren an.

Im Hinblick auf später sollten Sie im Request erkennen, dass es da kein "Authentication: Bearer" gibt. Das wird später noch mal interessant. Der Client wählt hier NTLM aus und fängt sich noch einen zweiten 401 ein, da er damit erst die Details der Verschlüsselung rausfindet, eher dann im letzten  Paket die Antwort bekommt, die ihn in die Cloud verweist.

29-32

Die "TargetAddress" verweist auf "netatwork.mail.onmicrosoft.com" und so kommt nun auch eine neue Autodiscover-Anfragen an den Start. Hier sehen Sie aber schon dass der Client sich per "Basic" authentifiziert. Die Domäne "netatwork.de" ist zu dem Zeitpunkt zwar per ADFS-Federation verbunden aber da mein EWS-Client das nicht kann, fordert Exchange Online die Anmeldedaten quasi im Klartext (Base64 ist keine Verschlüsselung) über HTTPS-Verschlüsselung an. Die Cloud hat nun die Anmeldedaten, um damit sich dann zu meinem ADFS-Server zu begeben und ein Ticket zu bekommen. Der Exchange Frontend Server ist also Reverse Proxy mit Pre-Authentication.

Der Exchange Server macht dies am Feld "User-Agent" fest. Ältere EWS.Clients (z.B."ExchangeServicesClient/15.00.0913.015") kommen mit OAUTH und der Umleitung auf einen ADFS nicht zureht. Neuere Versionen aber schon.

M365 Platform Call Jun 14 2022 - Greg Taylor - Basic Auth Deprecation in Exchange Online
https://pnp.github.io/blog/microsoft-365-platform-community-call/2022-06-14/files/M365%20Platform%20Call%20-%20June%2014%202022.pptx

22-43

Dann versucht der Client noch einige andere Dinge per Autodiscover, auf die ich nicht weiter eingehe. Schon im Antwortpaket 32 bekommt mein Client eine große XML mit allen Zugangspunkten.

45-47

Diese Pakete zeigen dann zuerst wieder den anonymen Zugriff, der von Exchange abgelehnt wird. Der Client kennt ja den Server noch nicht und muss erst mal anfragen, welche Anmeldeverfahren zur Verfügung stehen. Der Exchange Server wertet wieder den "User-Agent" aus und in meinem Beispiel gibt es keine ADFS-Umleitung sondern nur Basic

Damit ist klar, dass in dem Beispiel mein Client die Anmeldedaten direkt zum Exchange Server sendet.

Nun haben Sie auf "Authentication and EWS in Exchange " (https://docs.microsoft.com/de-de/exchange/client-developer/exchange-web-services/authentication-and-ews-in-exchange) aber auch gelesen, dass Basic-Auth den Status "no longer recommended" hat. Nun wollen wir natürlich nicht den EWS-Client noch "ADFS-Tauglich" machen, wenn das ADFS-Ticket am Ende dann doch nur für die Anforderung eines OAUTH-Tokens genutzt wird. dann geht das direkt besser

EWS und ADFS

Die Anmeldung per "BASIC" an Exchange Online kann ja noch verstanden werden, wenn das Postfach eine Cloud-Identität kennt oder das lokale Kennwort mit Password Hash Sync (PHS) in die Cloud repliziert wurde oder von der Cloud per Pass-Through Authentifizierung (PTA) verifiziert werden kann. Wenn eine Firma aber die Authentication per ADFS-Federation (ADFS Basics ff.) abbildet, dann werden normale Browser und andere "taugliche Clients" zum ADFS-Service umgeleitet. Es ist Aufgabe des Service zu erkennen, ob der Client eine Umleitung unterstützt.

Microsoft pflegt dazu wohl eine "User-Agent:"-Liste mit kompatible Clients oder entsprechend inkompatiblen Clients, die dann keine Bearer-Umleitung angeboten bekommen. Der EWS-Client gehört hier nicht dazu, denn er meldet sich als "ExchangeServicesClient/15.00.0913.015", wobei die Versionsnummer nicht relevant sein wird.

Für Office 365 dürfte hier nur wichtig sein, dass der Clients sich nicht als "Browser" oder ein anderes taugliche Device zu erkennen gibt.

EWS und ADFS funktionieren aber sehr wohl zusammen, wie mir Leser berichtet haben. Sie nutzen z.B. Clients aus dem Internet, die per WAP-Proxy und ADFS eine Preauthentiation durchführen, ehe Sie dann zum Exchange 2016 Server im Backend verbunden werden.

OAUTH statt Basic

Nun ist die Übertragung von Kennworten an einen Service zwar zeit Jahrzehnten bekannt und einfach aber bürdet dem Zielsystem die Arbeit auf, die Anmeldedaten zu verifizieren und dann auch noch die Berechtigungen zu ermitteln. Diesen Code müssen alle Anbieter quasi für jedes Produkt erneut schreiben oder weiter entwickeln. Hier kommt dann OAUTH ins Spiel, indem sich der Client nicht mit klassischen Credentials sondern mit einem Token anmeldet. Das Token wurde von einer vertrauenswürdigen Stelle ausgestellt und ist digital signiert.

Der Service muss nun nur noch "lernen", welcher Client auch dieses Verfahren unterstützt und beim ersten anonymen Zugriff dann den Client auf den OAUTH-Server umleiten. Der Client "verrät" seine Funktion, indem er bei dem ersten Request ein "BEARER" als Authentication mitliefert. Ob ihr Exchange Server damit etwas anfangen kann, bekommen Sie durch einen einfachen Webreqeuest in der Powershell raus.

Invoke-WebRequest `
   -Uri https://outlook.office365.com/exchange.asmx `
   -Headers @{ Authorization = "Bearer"} `
   -UseBasicParsing

Der WebServer liefert zwar einen "Invoke-WebRequest : Der Remoteserver hat einen Fehler zurückgegeben: (401) Nicht autorisiert." zurück, aber das ist ja auch korrekt. Im Header der Antwort steht aber, was uns interessiert:

Wenn ich das Feld "WWW-Authenticate" mal genauer auseinandernehme, dann steht da nun:

Bearer client_id="00000002-0000-0ff1-ce00-000000000000", 
trusted_issuers="00000001-0000-0000-c000-000000000000@*", 
token_types="app_asserted_user_v1 service_asserted_app_v1", 
authorization_uri="https://login.windows.net/common/oauth2/authorize",
Basic Realm="",
Negotiate

Der Server auf der anderen Seite bietet mir als erstes nun auch Bearer an und verweist mich zur URL https://login.windows.net/common/oauth2/authorize.

Natürlich habe ich auch mal meinen Exchange OnPremises Server mit der gleichen Anfrage beaufschlagt. Und auch hier kam ein Bearer in der Antwort zurück:

Hier der Header als Text

WWW-Authenticate: Bearer client_id="00000002-0000-0ff1-ce00-000000000000", 
   trusted_issuers="00000001-0000-0000-c000-000000000000@de21c301-a4ae-4292-aa09-6db710a590a6,
00000003-0000-0ff1-ce00-000000000000@0fb5b3a9-4993-4eae-80e1-82a164b25ab7,
00000004-0000-0ff1-ce00-000000000000@netatwork.de",
token_types="app_asserted_user_v1 service_asserted_app_v1"

Sie sehen aber schon, dass hier z.B. die Authorization-URL fehlt. Damit kann ich OnPremises ohne weitere Einrichtung nicht weiter kommen. Aber ich kann es durchaus konfigurieren.

EWS mit OAUTH

Nun haben wir aber auch gesehen, dass EWS eben gar kein BEARER im ersten Request mit sendet. Mit Fiddler sehen Sie aber sehr wohl, dass z.B. Outlook seine EWS-Abfragen per Bearer-Token authentifiziert:

EWS unterstützt in der Cloud also sehr wohl Bearer. Also stellt sich die Frage, ob dies neben Outlook auch über einen EWS-Zugriff möglich ist. Es gibt ja durchaus Vorteile, wenn sich der getrennte Authentifizierungsserver um die Verifizierung und Rechteermittlung kümmert und Sie auf ihrer Seite den Zugriff auch auf Programme beschränken können

Die Umsetzung von OAUTH ist aber erst mal gar nicht so einfach, da die EWS.DLL von Microsoft ja erst mal dazu gebracht werden müsste, ein OAUTH-Token anzufordern. Das kann sie so aber nicht. Das müssen wie selbst vorher machen und dann die Authentication für EWS entsprechend setzen. Ehe Sie aber ein OAUTH-Token bekommen müssen Sie noch weitere Tätigkeiten durchführen, die erst einmal kompliziert aussehen.

Mit Basic-Auth reicht es wenn ihr Skript sich einfach mit einem Benutzernamen und Kennwort authentifiziert und die Daten bekommt. Das Backend muss sich dann aber um die Anmeldung kümmern und auch prüfen, welche Berechtigungen sie haben Da ist mit OAUTH anders, da hier das Token nicht nur ihre Identität bestätigt, sondern auch ihre Berechtigungen enthält und für einen Ziel-Service ausgestellt wird. Der OAUTH-Service muss dazu aber nicht nur ihren Benutzer kennen und die Anmeldung überprüfen können , sondern auch ihre Applikation kennen, um dann für das Ziel die passenden Berechtigungen zusammen zu stellen und ihnen als Token zu übergeben geben.

Daher müssen Sie ihre Applikation, d.h. auch ihr PowerShell-Skript mit einer ClientID (GUID) und einem Secret oder Zertifikat eindeutig gegenüber dem OAUTH Server bekannt machen, damit dieser den Request überhaupt erst annimmt.

DoS Attacken

Wenn EWS nur noch OAUTH-Token annimmt, dann verlagert sich das Potential von DoS-Attacken auf den OAUTH-Server. Der Exchange Service selbst kann sich erst einmal darauf beschränken, dass er HTTP-Anfragen generell nur noch Anonym annimmt und sich nicht mehr mit BASI, Negotiate o.ä. Feldern im Header herumschlagen und die übersandten Anmeldedaten zum Backend gegen einen Domain Controllre o.ä. überprüfen muss.. Ganz anonyme Anfragen ohne ein Bearer-Token kann er einfach mit einem "401 Unauthorized" und dem Hinweis auf die OAUTH-Server beantworten. Sobald ein Request mit einem "Bearer"-Header kommt, muss der Webserver einfach lokal das Token mal schnell durch eine BASE64-Decoder-Funktion senden und aus der JSON-Ausgabe die digitale Signatur prüfen. Das geht rasend schnell und ist unabhängig von anderen Systemen. Wenn hier dann alles OK ist, dann wertet er den Benutzer und dessen Rechte aus dem Token aus und führt die Anfrage aus.

Das macht es dann schon recht einfach, auch Exchange Webserver quasi ohne weitere Preauthentication aus dem Internet erreichbar zu machen, da die klassischen Password Attacken ins Leere laufen. Eine DoS/DDoS-Attacke mit dem Ziel den Server zu beschäftigen ist sehr viel aufwändiger und zielt wohl eher auf die Bandbreite.

Weitere Links