Teams eingehend WebHooks

Eine sehr interessante und einfache API zur Interaktion mit Teams sind die Webhooks. Auf dieser Seite stelle ich die Funktionsweise anhand von Beispielen vor.

Aufgabenstellung

Die Arbeit in Teams mit dem normalen Client ist nichts besonderes. Auch weitere Dienste als Webseite über eine URL einzubinden oder einen der Microsoft Connectoren zu nutzen, die z.B. einen RSS-Feed regelmäßig abfragen, geht noch einfach von der Hand. Aber es gibt Anforderungen, bei denen etwas mehr Interaktion und schnellere Reaktion wünschenswert ist. Es gibt dazu natürlich auch die Funktion eines Teams Bot, der von einem Anwender kontaktiert werden kann mehr oder weniger interaktiv mit dem Anwender kommuniziert. eine Bot-Entwicklung ist aber etwas umfangreicher und es gibt sehr oft die Anforderung, etwas dazwischen nutzen zu können, z.B.

  • Ich möchte eine Nachricht in einem Kanal posten
    Das kann z.B. ein Monitoring-System sein, welches einen Status dort meldet. Auch ein Helpdesk-System könnte dort ein neues Ticket bereitstellen und ein Anwender kann dieses dann "annehmen". Eine gewisse Interaktion zur Reaktion wäre interessant
  • Benachrichtigung bei Aktionen im Kanal
    Auch in der Gegenrichtung kann es interessant sein, Meldungen in einem Kanal automatisch zu erfassen. Das unterscheidet sich von einem Bot, der aktiv angesprochen wird. Über WebHooks kann ein Prozess quasi informiert werden, wenn in einem Channel was passiert ist. Denkbar sind Aktionen zu Compliance, Archivierung, Reporting aber auch die Funktion als Trigger

Die Optionen sind Vielfältig und anders als bei Graph oder anderen "high level APIs", die man am besten mit entsprechenden Libraries nutzt, sind Webhooks einfache HTTP-Aufrufe. Die sind so einfach, dass Sie sogar von Kleinstrechner wie einem  Arduino oder ESP8266 oder aus Sprachen wie PHP, Perl, JavaScript etc. angesprochen werden können, für die es keine Libraries gibt.

Incoming Webhook einrichten

Zuerst beschäftige ich mich mit den eingehenden WebHooks. Dazu gibt es schon einige Hinweise im Internet und der Weg ist sehr einfach. Sie müssen sich zuerst in einem Team-Kanal einen WebHook erstellen. Dazu gehe ich in das Team unter Apps.

Dort suche ich dann auf "Weitere Apps" nach den WebHooks und schon nach den ersten Buchstaben sollten sie den Eintrag sehen:

Ansonsten können Sie auch direkt den Link https://teams.microsoft.com/l/app/203a1e2c-26cc-47ca-83ae-be98f960b6b2 ansurfen. Im nächsten Dialog müssen Sie das Team auswählen, in dem der Webhook installiert wird.

Nach dem Klick auf "Öffnen" wählen Sie dann den Kanal aus:

Damit sind wir aber noch nicht fertig. Sie können dann noch ein Bild für die Nachrichten hinterlegen

Erst mit den Klick auf "Erstellen bekommen Sie dann eine sehr lange URL, die nicht mal in das Fenster passt aber hier kopiert werden kann.

Hier ein Beispiel:

https://fcarius.webhook.office.com/webhookb2/e5de0191-xxx-xxxx-xxxx-xxxxxxx@3c6855ff-xxxx-xxxx-xxxx-xxxxxx/IncomingWebhook/xxxxxxxxx/xx-xxx-xxxx-xxx-xx

Aufbau
https://<tenantname>.webhook.office.com/webhookb2/<guid des Office Group>@<TenantID>/IncomingWebhook/<zeichenfolge>/<guid>

Zwei Dinge finde ich da interessant:

  • Hostname <tenantname>.webhook.office.com
    Der Hostname für den Service ist nicht teams.com oder teams.microsoft.com. Früher war es sogar noch "outlook.office.com" und hat damit direkt auf die Office Group in Exchange verwiesen. Das ist aber auch logisch, denn Nachrichten in Kanälen liegen ja in Office Groups und das ist ein Ablageort in Exchange. Der Name sollte Sie aber nicht verwirren, denn es ist immer noch Exchange, wie ein NSLOOKUP schnell zeigt:
C:\>nslookup msxfaq.webhook.office.com

Nicht autorisierende Antwort:
Name: AMS-efz.ms-acdc.office.com
Addresses: 2603:1026:206:4::2
2603:1026:204:1::2
2603:1026:c03:3030::2
2603:1026:207:163::2
40.101.12.18
40.101.83.194
52.97.201.82
52.97.250.226
Aliases: msxfaq.webhook.office.com
outlook.office365.com
outlook.ha.office365.com
outlook.ms-acdc.office.com
							
  • Keine Authentifizierung
    Die Angabe der URL reicht komplett aus. Unsicher ist das aber nicht, denn auch die langen Zeichenketten können ja wie Anmeldeinformationen gewertet werden und sind sicher, solange niemand den HTTPS-Kanal aufbricht. Wer die URL kennt kann natürlich Daten so in den Kanal senden.

So eine Veränderung bleibt natürlich nicht unbemerkt. Im Unterhaltung-Kanal landet eine entsprechende Meldung

Und auch auf dem Team-Level erscheint die neue "App"

Incoming Webhook verwalten

Bereits eingerichtete Webhooks können Sie über die Konfiguration der Connectoren auf dem Kanal sehen.

Hier lassen Sie sich dann die bereits konfigurierten Connectoren anzeigen und bestehende Webhooks erneut anzeigen und löschen.

Sicherheit von Webhooks

Sie werden sicher gesehen haben, dass es bei Webhooks nur die URL gibt aber keine Einschränkung nach Source-IP oder eine Möglichkeit zur Anmeldung mit Credentials o.ä. Das ist so korrekt und erwartet und dennoch nicht unsicherer sondern eher sicherer.

Wer die komplette URL des eingehende Webhooks kennt, kann eine Nachricht an diesen Kanal senden

Das gilt aber genauso für SMTP-Mails an ein Postfach. Dort gibt es natürlich Spamfilter, die es beim Webhook nicht gibt aber ich kann einen Webhook einfach löschen und neu anlegen, um eine neue URL zu bekommen. Der Schlüssel zur Sicherheit liegt in der Kontrolle, wer Zugriff auf die URL hat. Denn auch wenn es eine Möglichkeit zur Anmeldung gäbe, müssten sie dann die Anmeldedaten bei dem Prozess hinterlegen, welche den Webhook nutzt. Wenn ich die URL abgreifen kann, dann klappt das mit den Anmeldedaten genauso einfach.

Wer dem einliefernden Service nicht traut oder doch eine eigene Authentifizierung umsetzen will, kann das natürlich selbst nachrüsten. Ein Webhook ist ein Webservice, der auf einen HTTP-POST reagiert und natürlic könnten Sie eine Web Application Firewall, einen Azure AD App Proxy oder auch eine selbst geschrieben Azure Funktion oder PHP-Seite bei einem Webhoster ihrer Wahl nutzen. Sie verraten dann dem Absender nicht die originale Webhook-URL sondern nur den von ihnen bereitstellten Zugang mit ihrer individuellen Anforderung an Authentifizierung, welche den Request annimmt und seinerseits dann an den Webhook sendet.

Das ist zwar etwas "Security by Obscurity", aber wenn Sie sich den Webhook anschauen, dann sind da ganz viele Zeichen drin, die deutlich sicherer sind als die Codierung eines von Menschen eingegeben Benutzernamen und Kennworts je sein können.

Ich konnte noch nicht ermitteln. ob Teams ein "Throttling" auf Webhooks anwendet, damit ein tatsächlich gelungener Abgriff der URL den Schaden beschränkt.

Nachricht als Adaptive Card erstellen

Ehe wir nun eine Message an den Kanal senden können, müssen wir natürlich noch die Nachricht selbst erstellen. Microsoft hat sich hier eine Lösung einfallen lassen, die plattformübergreifend werden soll. "Adaptive Cards" ist der Schlüsselbegriff, über die Microsoft Benachrichtigungen nicht nur schön formatieren, sondern auch mit Interaktion versehen will und die nicht nur ein Teams, sondern auch in Outlook, Auf Webseiten und anderen Plattformen immer passende angezeigt werden sollen.

Fehlerbehandlung

Ich verzichte mal auf all die Fehler, die nicht direkt mit Teams etwas zu tun haben, z.B. fehlende Namensauflösung, Probleme beim HTTPProxy oder Firewall, PowerShell Code Signing u.a. Wenn Sie grundsätzlich schon mal einen HTTP-Post zu outlook.office365.com absetzen können, dann kann es fast nur noch an der URL oder dem Payload liegen. Wenn ihre eigene Message nicht auf Anhieb funktioniert, dann gibt es mehrere Ansatzpunkte:

Fehler Lösung
Invalid webhook URL

Klassischer Cut-Copy-Paste-Fehler. Die URL ist nicht korrekt. Prüfen Sie noch mal die komplette URL, nicht dass Sie abgeschnitten wurde.

Summary or Text is required.

Sie haben entgegen meiner Beschreibung vergessen, zwischen den Properties "Version" und "Body" eine "Summary

Bad payload received by generic incoming webhook.

JSON ist einfach aber Menschen überlesen doch mal das ein oder andere Sonderzeichen. Wenn ich meine Message in der Variable "$Body" habe, dann kann ich einfach folgende Funktion nutzen, um die Gültigkeit des JSON-Strings zu prüfen.

$body | convertfrom-json -asHashtable

Name                           Value
----                           -----
actions                        {System.Collections.Hashtable}
body                           {System.Collections.Hashtable, System.Collections.Hashtable}
version                        1.0
type                           AdaptiveCard
summary                        Update der MSXFAQ
                               http://adaptivecards.io/schemas/adaptive-card.json

Sollt hier schon ein Fehler vorliegen, dann haben Sie irgendwo ein Zeichen vergessen, z.B. ein Komma am Ende der Zeilen etc.

IoT und WebHooks

Aufgrund der sehr einfachen Funktion dieser Webhooks ganz ohne Username, Kennwort o.ä. bietet es sich gerade zu an, diese Funktion auch in Geräten zu verwenden, die andere APIs nicht nutzen können. Sie könnten den Code in PHP-Seiten ihrer Webseite einbinden und z.B. einen "Form Post" eines Kontaktformulars so in einen Teams Channel senden. Interessant ist aber auch, dass noch kleinere Systeme entsprechende Meldungen generieren können. Theoretisch könnten Sie auch einen MQTT zu Teams-Gateway bauen, bei dem ein Prozess einen "Subscribe" auf bestimmte MQTT-Kanäle macht und die Werte dann in Teams sendet.

Das sind natürlich alles Beispiele, die ihre Daten am besten in ein Monitoring-System einspielen und nicht direkt zu Teams. Aber auch Monitoring-Systeme könnten solche Meldungen dann zu Teams weiter leiten.

Aktuell habe ich noch keinen konkreten Fall, um mit meinen Arduinos, ESP8266, ESP32 u.a. mal einen Webhook von Teams zu füttern. Aber mit den entsprechenden HTTP-Libraries ist das sehr einfach umzusetzen.

Push only, kein Polling

Sowohl ausgehende Webhooks als auch eingehende Webhooks sind getriggerte Aktionen. Ein eingehender Webhook kann einfach eine Meldung in einen Kanal ablegen. Ein ausgehender Webhooks kann auf eine neue Meldung quasi nur in Echtzeit reagieren und genau eine Antwort darauf liefern. Beide Schnittstellen erlauben aber weder einen Zugriff als frühere Chats und Nachrichten noch ein Polling durch einen Client. Es fehlt also die Funktion, wie diese in EWS vorhanden ist, damit ein Service nach einer Unterbrechung z.B. frühere Nachrichten aufarbeiten kann. Dies ist nicht das Ziel von Webhooks. Für solche Anforderungen sind anderen APIs, insbesondere die Graph API erforderlich. Diesen APIs fehlt dann natürlich die "Echtzeit-Komponente".

Weitere Links