Graph und Exchange On-Premises

In der Cloud wird die Graph-API früher oder später alle Daten erreichbar machen. Aber wer Exchange Hybrid nutzt, kann über die Cloud sogar Informationen in lokalen Postfächern erreichen.

Achtung: Die Funktion über Microsoft Graph mit Hybrid Mode auf lokale Exchange Ressourcen zuzugreifen, wird im März 2023 abgeschaltet!. Es wechselt direkt vom Status "Preview" (Seit 2018) in "Depreciated"

End of Live

Am 4. März 2022 habe ich im Microsoft 365 Message Center meines Microsoft 365 Tenants und per Mail die folgende Meldung bekommen:

  • MC338988 REST API for On-Premises Mailboxes Preview Ending

Damit verschwindet die auf der Ignite 2016 noch vorgestellte und seit 2018 als "Preview" dokumentiert Funktion eines Zugriffs auf On-Premises-Postfächer über die Microsoft Graph-API der Cloud und Exchange Hybrid Mode wieder in der Versenkung. Allerdings vermute ich, dass nicht allzu viele Entwickler diesen Weg bislang genutzt haben.

Allerdings wäre zu prüfen, ob Microsoft eigene Dienste, wie z.B. Microsoft Teams, dann z.B. noch den Exchange On-Premises Kalender unterstützen.

Ich kann leider nicht sagen, ob damit auch die "REST"-API auf dem Exchange On-Premises-Server zur gleichen Zeit verschwindet.

Für Entwickler bedeutet dies:
- Exchange Online: Microsoft Graph
- Exchange OnPremise: EWS

Microsoft Ignite 2016 Use Microsoft Graph to reach users on hybrid Exchange 2016
https://www.youtube.com/watch?v=YQVxy537wJ8

Funktionsweise

Der Charme dieser Lösung ist, dass sich eine Software oder Applikation nur einmal gegen Graph authentifizieren muss um dann abhängig von den Berechtigungen aber unabhängig vom physikalischen Standort der Daten auf Inhalte zugreifen zu können. Dennoch können Sie sehr granular mit Application Permissions und ggfls. Conditional Access steuern, wer Daten erhält.

Der Prozess durchläuft folgende Stationen:

  1. Client oder App geht auf https://graph.microsoft.com
    Diese URL ist quasi immer gleich. Ohne Anmeldedaten aber mit dem "Bearer"-Header bekommt der Client eine Umleitung zum evoSTS
  2. Anmeldung am EvoSTS
    Der Client oder Prozess identifiziert sich mit ClientID und Anmeldedaten um dann ein passendes Ticket zu bekommen.
  3. Client fordert Daten von Graph an
    Dazu übermittelt er die URL mit den Filterkriterien und im Header wird das Token gesendet
  4. Graph sammelt die Daten ein und liefert aus
    Je nach dem, wo sich die geforderte Daten befinden greift Graph auch auf ihren Exchange On-Premises Server zu und liefert die Daten aus. Die Rechte dazu hat er durch das Hybrid Setup schon bekommen.

Die Voraussetzungen für den Betrieb dürften heute bei den meisten Firmen mit Exchange im Hybrid-Mode vorhanden sind

  • Office 365 Tenant
    Ohne einen Tenant gibt es kein Graph. Es ist nicht ausreichen ein Microsoft Konto (vormals LiveID o.ä.) zu nutzen. Es muss ein richtiges Office 365 Business oder Enterprise-Konto sein
  • Benutzer mit ADSync in die Cloud synchronisiert
    Graph schaut im AzureAD des Tenant nach, ob der Benutzer ein Postfach hat und wo es liegt. Wenn Benutzer die API nutzen solle, müssen Sie sich natürlich auch an Graph authentifizieren, d.h. die Identität muss in der Cloud vorhanden und eine Anmeldung muss möglich sein.
  • Office 365 Lizenz
    Auch wenn der Benutzer sein Postfach "On-Premises" hat und Sie vielleicht lokal sauber Exchange CALs gekauft haben, braucht er eine Office 365 Lizenz. Allerdings gehen die Aussagen darüber auseinander, welche Lizenz genau benötigt wird.
  • Exchange 2016 CU3 oder höher mit explizit ausgeführtem "/PrepareAD"
    Dies gilt sowohl für Backend Server mit dem Postfach als auch die Frontend Server für den Clientzugriff
  • Exchange On-Prem per DNS (Autodiscover und Frontend-Server) auflösbar
    Die Cloud kann keine "ServiceConnectionPoints" per LDAP abfragen und geht daher zu "autodiscover.<maildomain>
  • Exchange On-Prem Autodiscover und REST erreichbar
    Siehe auch nächstes Kapitel
  • Exchange "Full Hybrid" Konfiguration mit HCW eingerichtet
    MinHybrid oder Modern Hybrid geht angeblich nicht

Rest auf Exchange 2016 CU3

Seit Exchange 2016 gib es auch eine REST-API für Exchange On-Premises. Unter dem virtuellen Verzeichnis "/API" ihres Exchange Frontend Servers können Sie recht einfach auf Postfachinhalte zugreifen.

Das Verzeichnis gibt es sowohl auf dem Frontend und dem Backend. Als Anwender greifen Sie immer auf den Exchange Frontend zu, der dann die Anfragen an den passenden Backend Server weiterleitet, auf dem ihr Postfach liegt. Damit ist auch verständlich, dass ihr Postfach auf einem Exchange 2016 CU3 Server oder neuer liegen muss und Graph von extern immer auf einem Exchange 2016 CU3 oder neuer Server landen muss.

Achtung: Die direkte Nutzung der API ist nicht supportet.
Microsoft nutzt diesen Zugang, wenn man im Hybrid-Mode gegen graph.microsoft.com geht und OnPremise Informationen abruft. Eigentlich sollte "Basic Auth" nicht gehen sondern nur OAUTH-Tokens und die kann man in einer reinen On-Prem Umgebung nicht generieren. Also besser nicht darauf eigenen Code aufsetzen.
OnPrem -> Bleiben Sie bei EWS
Cloud/Hybrid -> Nutzen Sie Microsoft Graph

Diese Funktion hat nicht mit dem Commandlets "Get-RestVirtualDirectory", "New-RestVirtualDirectory" oder "Remove-RestVirtualDirectory" zu tun. Diese Commandlets gibt es ebenfalls aber habe ich noch nie verwendet.

Outlook REST API v2.0 Deprecation Notice (30. Nov 2022)
https://developer.microsoft.com/en-us/office/blogs/outlook-rest-api-v2-0-deprecation-notice/

AutoDiscover V2

Damit Graph ihr Postfach findet, muss natürlich Autodiscover V2 funktionieren. Die Funktion habe ich in einem Vortrag der Ignite 2016 gefunden.

Use Microsoft Graph to reach users on hybrid Exchange 2016
https://channel9.msdn.com/Events/Ignite/2016/BRK3045
Ab Minute 26:23
Sprecher Venkat Ayyadevara (@VRAyyadevara)

Der Flow in Kürze:

  1. Der On-Premises Benutzer oder das Programm greift auf die GraphAPI zu
  2. Graph fragt das AzureAD nach dem Benutzer.
  3. Die Antwort sagt Graph, dass der Client nicht in Exchange Online ist
  4. Graph fragt nach "https://autodiscover.<domain>/autodiscover/autodiscover.json
  5. Der On-Premises Exchange Server liefert die passende URL zurück
  6. Graph greift auf die angegebene URL zurück
  7. Der On-Premises Server liefert die Daten an die Cloud API
  8. Graph liefert die Daten an den Client aus

Sie sehen aber auch hier noch deutlich, das alle Zugriffe über die Cloud erfolgen. Das ist gut für Apps in der Cloud und Mitarbeiter zu Hause aber ungünstig, wenn Sie Graph mit großen Datenmengen mit ihrem eigenen RZ gegen den lokalen Exchange Server nutzen.s

 Auch das können Sie einfach per Browser oder PowerShell testen.

Invoke-RestMethod "https://autodiscover.msxfaq.net/autodiscover/autodiscover.json?Email=user1@msxfaq.net&Protocol=REST"

Protocol Url
-------- ---
REST     https://outlook.office.com/api

Die ermittelte URL können Sie dann direkt ansprechen. Hier ein Beispiel. Versuchen Sie es doch einfach mal selbst.

# Anmeldedaten einsammeln
$cred=get-credential

#die ersten 10 Mail des eigenen Postfachs abrufen
$mails=Invoke-RestMethod "https://webmail.msxfaq.net/api/v2.0/me/messages" -Credential $cred

# Das Ergebnis sollte 10 Datensätze enhalten
$mails.value.count
10

#Ausgabe der ersten Mail
$mails.value[0]

Es ist wirklich erst mal so einfach. Genau diese Schnittstelle nutzt aber auch Graph beim Zugriff aus der Cloud. Sie müssen also auch das virtuelle Verzeichnis "/API" zumindest für Office 365 erreichbar machen.

Partner App auf Exchange

Bei der Funktionsbeschreibung habe ich in Punkt 4 geschrieben, dass Graph bei Bedarf auch auf ihren On-Premises Exchange Server zugreift. Das darf er natürlich nicht anonym machen sondern muss sich entsprechend ausweisen. Aus dem Grund wurde durch den Hybrid Konfiguration Wizard auch eine "Partner App" auf ihrer lokalen Umgebung eingerichtet. Neben Graph gibt es noch andere Partner Apps wie z.B. SfB-Online oder Exchange Online um z.B. Frei/Belegt-Zeiten abzurufen.

Die Existenz der Partnerapp können Sie in der lokalen Exchange PowerShell einfach prüfen:

[PS] C:\>Get-PartnerApplication "Microsoft Graph" | fl

Enabled                             : True
ApplicationIdentifier               : 00000003-0000-0000-c000-000000000000
CertificateStrings                  : {}
AuthMetadataUrl                     :
Realm                               :
UseAuthServer                       : True
AcceptSecurityIdentifierInformation : True
LinkedAccount                       :
DeploymentId                        :
IssuerIdentifier                    :
AccountType                         : OrganizationalAccount
AppOnlyPermissions                  :
ActAsPermissions                    : {Mail.Read, Mail.Write, Mail.Send, Calendars.Read, Calendars.ReadWrite,
                                      Calendars.Read.Shared, Calendars.ReadWrite.Shared, Contacts.Read,
                                      Contacts.ReadWrite, Contacts.Read.Shared, Contacts.ReadWrite.Shared,
                                      Mail.ReadWrite, Calendars.Write, Contacts.Write, Sites.Read.All,
                                      Sites.ReadWrite.All...}
AdminDisplayName                    :
ExchangeVersion                     : 0.20 (15.0.0.0)
Name                                : Microsoft Graph
DistinguishedName                   : CN=Microsoft Graph,CN=Partner Applications,CN=Auth
                                      Configuration,CN=MsxfaqEX01,CN=Microsoft
                                      Exchange,CN=Services,CN=Configuration,DC=msxfaq,DC=net
Identity                            : Microsoft Graph
Guid                                : 0b630e77-b476-41e7-9e54-0898e0536cc7
ObjectCategory                      : msxfaq.net/Configuration/Schema/ms-Exch-Auth-Partner-Application
ObjectClass                         : {top, msExchAuthPartnerApplication}
WhenChanged                         : 10/28/2017 9:09:16 PM
WhenCreated                         : 10/8/2016 8:42:54 PM
WhenChangedUTC                      : 10/28/2017 8:09:16 PM
WhenCreatedUTC                      : 10/8/2016 7:42:54 PM
OrganizationId                      :
Id                                  : Microsoft Graph
OriginatingServer                   : dc01.msxfaq.net
IsValid                             : True
ObjectState                         : Unchanged

EvoSTS Vertrauen

Allein mit einem passenden Token anzukommen reicht ihrem Exchange On-Premises Server natürlich noch nicht aus. Stellen Sie daher sicher, dass der ausstellende Server (evoSTS) auch als gültiger Server eingetragen ist. Die Einstellung kommt ihnen vielleicht von Hybrid Modern Authentication (HMA) schon bekannt. Auch diese Einstellung nimmt der HCW für sie vor. Eine Kontrolle schadet aber nicht.

[PS] C:\>Get-AuthServer EvoSTS | fl

RunspaceId                     : 75b11c34-3b55-4a0d-8c0b-7b6df28fdc90
IssuerIdentifier               : https://sts.windows.net/22991c1b-aa70-4d9c-85be-637908be565f/
CertificateStrings             : {MIIC8TCCAdmgAwIBAgIQfEWlTVc1uINEc9RBi6qHMjANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDExhsb2dpb
                                 i5taWNyb3NvZnRvbmxpbmUudXMwHhcNMTgxMDE0MDAwMDAwWhcNMjAxMDE0MDAwMDAwWjAjMSEwHwYDVQQDExh
                                 sb2dpbi5taWNyb3NvZnRvbmxpbmUudXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDEdJxkw+jwW
...
                                 xUld8C/3IY8ac72HKMR5AloTRlXxwXM8XUwLcrUCVp0c61VNY6U2J0TXYdSvJHwSQ98wSbiSryT2SUk}
RsaKeyModulusExponents         : 
CurrentEncryptedAppSecret      :
PreviousEncryptedAppSecret     :
TokenIssuingEndpoint           : https://login.windows.net/common/oauth2/token
AuthorizationEndpoint          : https://login.windows.net/common/oauth2/authorize
ApplicationIdentifier          :
AuthMetadataUrl                : https://login.windows.net/msxfaq365.onmicrosoft.com/federationmetadata/2007-06/federationmetadata.xml
Realm                          : 22991c1b-aa70-4d9c-85be-637908be565f
Type                           : AzureAD
Enabled                        : True
IsDefaultAuthorizationEndpoint : False
AdminDisplayName               :
ExchangeVersion                : 0.20 (15.0.0.0)
Name                           : EvoSts
DistinguishedName              : CN=EvoSts,CN=Auth Servers,CN=Auth Configuration,CN=MsxfaqEX01,CN=Microsoft
                                 Exchange,CN=Services,CN=Configuration,DC=msxfaq,DC=net
Identity                       : EvoSts
Guid                           : 21248c13-2f6d-4038-bd75-2779f91cb783
ObjectCategory                 : msxfaq.net/Configuration/Schema/ms-Exch-Auth-Auth-Server
ObjectClass                    : {top, msExchAuthAuthServer}
WhenChanged                    : 6/24/2019 1:49:41 PM
WhenCreated                    : 6/24/2019 1:49:26 PM
WhenChangedUTC                 : 6/24/2019 11:49:41 AM
WhenCreatedUTC                 : 6/24/2019 11:49:26 AM
OrganizationId                 :
Id                             : EvoSts
OriginatingServer              : dc01.msxfaq.net
IsValid                        : True
ObjectState                    : Unchanged

msolServicePrincipal in der Cloud

Auch in der Cloud muss eine Konfiguration durch den HCW angelegt worden sein. Die Applikation "Exchange" hat immer die AppID "00000002-0000-0ff1-ce00-000000000000" und damit Graph ein passendes Ticket von seinem evoSTS für den Zugriff auf ihren On-Premises Server erhalten kann, müssen alle URLs hinterlegt sein, die ihre lokale Umgebung nutzt. Auch das macht de HCW.

Trotzdem lohnt sich ein Blick mit der Microsoft Online Powershell:

[PS] C:\>get-msolServicePrincipal | ?{$_.AppPrincipalId -like '00000002-0000-0ff1-ce00-000000000000'}

ExtensionData         : System.Runtime.Serialization.ExtensionDataObject
AccountEnabled        : True
Addresses             : {Microsoft.Online.Administration.RedirectUri, 
                         Microsoft.Online.Administration.RedirectUri,
                         Microsoft.Online.Administration.RedirectUri}
AppPrincipalId        : 00000002-0000-0ff1-ce00-000000000000
DisplayName           : Office 365 Exchange Online
ObjectId              : 1861876d-1595-4721-9243-ef219fec7b64
ServicePrincipalNames : {https://mobile.msxfaq.net, https://ews.msxfaq.net,
                        00000002-0000-0ff1-ce00-000000000000/ews.msxfaq.net,
                        00000002-0000-0ff1-ce00-000000000000/autodiscover.msxfaq.net}
TrustedForDelegation  : True

Hier muss auch die On-Premises URL aller Server auftauchen, für die evoSTS Zertifikate ausstellen kann.

Graph Explorer

Der einfachste Weg diese neue Möglichkeit zu testen ist der Graph Explorer von Microsoft. Alles was sie benötigen ist ein Browser und Zugriff auf das Internet. Surfen Sie die URL https://developer.microsoft.com/en-us/graph/graph-explorer an. Zum Start ist ein "DemoUser" angemeldet aber über den Anmeldebutton können Sie sich auch problemlos als Office 365 Benutzer anmelden. Natürlich müssen Sie als Benutzer bestätigen, dass Graph Explorer in ihrem Namen einige Rechte ausüben darf. Die Liste ist umfangreich, weil Sie mit dem Graph Explorer natürlich auch alles APIs testen können

Wenn Sie dann auf "My Mal" klicken und Graph Explorer auf "https://graph.microsoft.com/v1.0/me/messages" zugreift, sollten sie ihre Mail sehen. Aber auch bei mir klappt nicht alles aufs erste mal und dieser Fehler ist etwas irreführend:

er hat nur indirekt etwas mit Berechtigungen zu tun und sagte bei mir immer, dass die Cloud nicht auf "/API" zugreifen konnte. Prüfen Sie sicherheitshalber noch einmal ihre externe Firewall und Reverse-Proxy-Systeme z.B.: mit folgenden Zeile aus dem Internet!

Es bringt nichts, den Test aus dem Haus-LAN von intern zu machen. Nutzen sie einen Computer im Internet ohne VPN o.ä. um möglichst realistisch auch den Zugriff von Graph zu entsprechen.

$cred=get-credential
$mails=Invoke-RestMethod "https://<ihr-ews-FQDN>/api/v2.0/me/messages" -Credential $cred
$mails.value.count

Es kann aber auch eine fehlende Lizenz sein. Wobei dann vielleicht ein andere Fehler kommt.

{
    "error": {
        "code": "AuthenticationError",
        "message": "Error authenticating with resource",
        "innerError": {
            "request-id": "xxx-xxx-xxx-xxx-xxx",
            "date": "2019-12-13T16:04:34"
        }
    }
}

Oder

{
    "error": {
        "code": "AuthenticationError",
        "message": "REST API is not yet supported for this mailbox",
        "innerError": {
            "request-id": "9d84aa13-90bd-4268-aa95-800648abe2c5",
            "date": "2019-12-13T16:04:34"
        }
    }
}

Wenn aber alles passt, dann sollten Sie die ersten 10 Mail sehen:

Der erste Abruf hat hier mit 2678ms natürlich etwas länger gedauert. Schließlich musste Graph erst den Weg zu meinem Exchange On-Premises Server finden und dann auch noch ein Authentication Ticket besorgen. das kann schon etwas dauern. Danach habe ich aber Antworten im Bereich 150-300ms bekommen.

Sample mit PowerShell

Der Zugriff per Graph Explorer ist natürlich nur eine Test- und Demo-Plattform. Interessant wird es erst, wenn Sie auch mit eigenen Skripten oder Code auf die API zugreifen. Wie bei Graph üblich gibt es hier wieder zwei verschiedene Zugriffe

  • Application Permission
    d.h. Sie geben einem Code oder Programm das Recht, auf die API zuzugreifen und sich als "App" zu legitimieren. Das würde dann etwa dem EWS und Impersonation entsprechen.
  • Programm durch den Benutzer gestartet
    Der zweite Fall bedeutet, dass der Anwender den Code mit seinem Anmeldedaten versieht und so den Zugriff erhält.

Der Zugriff per Application Permission habe ich auf Office 365 Service Communications API schon mit PowerShell Beispielen belegt. Ich möchte mich hier also darauf beschränken, wenn der Code durch den Anwender ausgeführt wird. Auch dabei muss sich der Code dennoch legitimieren. Allein eine gültige Kombination aus UPN und Kennwort reicht in den modernen Zeiten nicht mehr aus.

Ein Beispielcode liefere ich bei Gelegenheit nach

Microsoft Ignite 2016 Use Microsoft Graph to reach users on hybrid Exchange 2016
https://www.youtube.com/watch?v=YQVxy537wJ8

Weitere Links