SharePoint-Veröffentlichung, Reverse-Proxy und Fiddler

… oder wie Fiddler mir geholfen hat eine fehlerhafte Reverse-Proxy Konfiguration bei der Veröffentlichung eines internen SharePoint-Portals zu umgehen.

Die Story

Einer unserer Kunden betreibt eine lokale Installation von SharePoint für sein Intranet. Im Laufe des Projekts wurde klar, dass auch von extern von Mitarbeitern auf den SharePoint zugegriffen werden sollte. Nun war SharePoint aber bereits mit portal.acme.local intern veröffentlicht. Für den externen Zugriff sollte aber eine Adresse wie portal.acme-extranet.de verwendet werden.

Für die IT-Abteilung des Kunden war es kein Problem, eine Web-Anwendung von extern unter einem anderen Namen zu veröffentlichen. Dazu stellt die IT einen Reverse Proxy zur Verfügung, der die eingehenden Anfragen an das interne Portal weiterleitet.

Das Problem

Nun hat die IT also den Reverse Proxy eingerichtet und alle Anfragen von https://portal.acme-extranet.de werden an http://portal.acme.local umgeleitet. Nun ist auf der Empfängerseite ein SharePoint, der die Anfrage für bare Münze nimmt. Als Folge werden interne Links und URLs in dem von SharePoint generierten HTML auch auf http://portal.acme.local gemünzt. In der Antwort für den Client sind die Links dann aber falsch, weil unter dieser Adresse die sind Ressourcen von extern ja nicht zu erreichen, da es sich dabei ja um eine interne Adresse handelt.

Glücklicherweise ist nur an wenigen Stellen in den URLs auch der Hostname inklusive Protokoll enthalten. Viele Links sind relativ zum Host, so dass diese funktionieren, egal wie die Seiten aufgerufen werden. Aber es gibt dennoch einige Stellen, an denen der Hostname aus der Anfrage eingefügt werden. Gerade im JavaScript findet sich der Hostname mehrfach wieder. Somit funktionieren diese Funktionen in diesem Fall nicht.

Das Problem an dieser Stelle ist, dass der Reverse-Proxy die Anfrage intern an http://portal.acme.local umleitet und nicht den original Host-Headernamen https://portal.acme-extranet.de im HTTP-Request beibehält (nur damit funktioniert dann das AAM im SharePoint auch richtig).

Die Lösung

Solange die die Konfiguration des Reverse-Proxy nicht angepasst wird kann man von extern nicht vollständig auf SharePoint zugreifen … oder … ich verwende Fiddler.

Wenn ich zunächst in meinem Browser http://portal.acme.local aufrufe, dann bekomme ich eine Fehlermeldung, dass der Name nicht aufgelöst werden kann.

Nun habe ich also mal meinen Fiddler gestartet und der Traffic meines Browsers geht durch Fiddler. Und nun kommt Magic … ich kann im Fiddler mit Fiddler-Script in die Verarbeitung eingreifen, indem ich Custom-Rules definiere. So gibt es ein OnBeforeRequest-Event in dem ich in die Verarbeitung eines Requests in Fiddler eingreifen kann. Hier habe ich nun folgenden Eingriff vorgenommen:

if (oSession.HostnameIs("portal.acme.local")) {    
    oSession.hostname="portal.acme-extranet.de"; 
    oSession.fullUrl = "https" + oSession.fullUrl.Substring(oSession.fullUrl.IndexOf(':'));  
}

Damit erreiche ich, dass aller Traffic, den mein Browser an http://portal.acme.local sendet an https://portal.acme-extranet.de umgelenkt wird. Somit ist mir egal wie die URLs in der HTML-Antwort von SharePoint aussehen und ich somit auch auf Seite und Funktionen zugreifen kann, die mir vorher verwehrt waren, weil sie nur die “interne” URL angezeigt haben.

Das Ziel

Als Ergebnis kann ich nun auch mit ShareGate auf das Portal zugreifen und dort Daten migrieren, was vorher nicht möglich war, weil insbesondere in den Antworten der Webservices immer die komplette URL angegeben ist, und alle Antworten auf einen Webservice-Aufruf immer gegen die interne Adresse laufen.

AutoResponder mit Fiddler

Vor einigen Tagen sollte ich einen Proof-Of-Concept erstellen, ob man ein System XYZ z.B. in BizTalk anbinden könnte. Das System XYZ bietet dazu eine Schnittstelle an, welche über HTTP mit JSON Nachrichten angesprochen werden kann und auch mit JSON wieder antwortet.

Also mal eben eine kleine BizTalk-Lösung bauen, um zu testen ob man diese JSON Nachrichten richtig erstellen und die Antworten auch richtig verarbeiten kann. Als erstes wird in Azure eine BizTalk 2013 R2 Entwicklungsumgebung erstellt. Das geht recht schnell, innerhalb von knapp 15 Minuten ist die Umgebung verfügbar – cool.

So, also nächstes musste also die Lösung erstellt werden. Aber die Frage ist: wie kann ich testen, ob nun aus BizTalk die Services richtig angesprochen werden und auch die Antwort dann von BizTalk richtig verarbeitet wird? Das System XYZ läuft beim Kunden On-Premise, da habe ich also von Azure aus keinen Zugang. Und mal eben XYZ installiert ist ja auch nicht so einfach, da brauche ich einen SQL-Server, Tomcat … und das ganze Konfigurieren – und alles nur für einen Proof-Of-Concept? Nein Danke!

Und mal wieder ist Fiddler der Retter!

Ich habe also meine Lösung mit BizTalk gebaut und dann auch komplett im BizTalk deployed. Nur leider steht mir ja das System XYZ nicht zur Verfügung, welches in eigentlich ansprechen wollte. Also mal eben Fiddler auf dem Server installiert und dann mit Fiddler das System simuliert. Anstatt dem System XYZ hat Fiddler auf die Aufrufe, welche für XYZ bestimmt waren, abgefangen und beantwortet. Für BizTalk erfolgte das komplett transparent – sweet!

Und wie geht das?

Ganz einfach! Fiddler hat eine Funktion „AutoResponder“. Damit kann Fiddler automatisch auf eingehende Nachrichten reagieren und antworten. Hier haben ich also für die HTTP Aufrufe entsprechende Regeln eingerichtet, die zum einen überprüfen ob die URL http://system-xyz:9090/abc/ aufgerufen wurde und ob im Body des Requests clazz=foo steht. Wenn ja, dann wird der Inhalt der Datei foo_response.json zurückgefliefert. Mit einer zweiten Regeln prüfe ich dann analog ob im Body clazz=bar steht und antworte mit bar_response.json.

fiddler_01

Alle anderen Anfragen werden ganz normal weitergegeben. Für BizTalk ist es also vollkommen transparent, ob nun das System XYZ oder ein anderes tatsächlich auf die Anfragen reagiert. Es muss ja noch nicht einmal der Server-Name existieren, da der Request ja direkt von Fiddler abgefangen wird.

Cool! Somit kann ich testen, ob meine Anwendung richtig mit dem System XYZ sprechen würde, auch wenn ich das System nicht habe – ich muss „nur“ wissen wie die Requests und die Responses ausseen würden.