SharePoint Online – REST/OData Endpunkt via Konsolenanwendung ansprechen

In diesem Blogbeitrag möchte ich beschreiben, wie die Authentifizierung gegen einen SharePoint Online Server von einer Konsolenanwendung aus durchgeführt wird. Ziel dieses Blogbeitrages ist es, am Ende erfolgreich eine Anfrage gegen den REST/OData Endpunkt durchzuführen. Das folgende Sequenz Diagramm zeigt einen Überblick über die geplanten Schritte.

SAML Anfrage senden​

Um das Binary Security Token zu erhalten muss eine SOAP Anfrage via HTTP POST gegen folgenden Endpunkt ausgeführt werden: https://login.microsoftonline.com/extSTS.srf . Das SOAP XML benötigt drei Parameter:

  • Benutzername
  • Passwort
  • Tenant

Wie in der nachfolgenden GetSoapXml Methode zu sehen, werden die drei Parameter über die String.Format Methode eingebunden.

private static string GetSoapXml(string username, string password, string tenant)
{
​     return string.Format(@"
<s:Envelope xmlns:s='http://www.w3.org/2003/05/soap-envelope' xmlns:a='http://www.w3.org/2005/08/addressing' xmlns:u='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'>
  <s:Header>
    <a:Action s:mustUnderstand='1'>http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
    <a:To s:mustUnderstand='1'>https://login.microsoftonline.com/extSTS.srf</a:To>
    <o:Security s:mustUnderstand='1' xmlns:o='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'>
      <o:UsernameToken>
        <o:Username>{0}</o:Username>
        <o:Password>{1}</o:Password>
      </o:UsernameToken>
    </o:Security>
  </s:Header>
  <s:Body>
    <t:RequestSecurityToken xmlns:t='http://schemas.xmlsoap.org/ws/2005/02/trust'>
      <wsp:AppliesTo xmlns:wsp='http://schemas.xmlsoap.org/ws/2004/09/policy'>
        <a:EndpointReference>
          <a:Address>{2}</a:Address>
        </a:EndpointReference>
      </wsp:AppliesTo>
      <t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>
      <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
      <t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
    </t:RequestSecurityToken>
  </s:Body>
</s:Envelope>", username, password, tenant);
}​

Um die SOAP Anfrage abzusenden verwende ich die WebClient Klasse. Diese ermöglicht es, einfach HTTP POST Anfragen gegen einen Server zu senden.​

SAML Antwort mit Binary Security Token

Nachdem die Anfrage abgesendet wurde, sollte ein SOAP XML nach folgendem Schema empfangen werden:

In dem BinarySecurityToken Tag ist unser Binary Security Token enthalten. Um das SOAP XML zu verarbeiten, verwende ich die XDocument Klasse. Über diese Klasse lassen sich einfach Knoten selektieren. Nachfolgend nun die Methode, welche die Anfrage absendet und anschießend den „BinarySecurityToken” Knoten selektiert:

private static string GetBinarySecurityToken(string username, string password, stringtenant)
 {
     using (var webClient = new WebClient())
     {
         var soapXml = GetSoapXml(username, password, tenant);
         var soapResponse = webClient.UploadString("https://login.microsoftonline.com/extSTS.srf", soapXml);
 
         var document = XDocument.Parse(soapResponse);
         var binarySecurityTokenElement = document.Descendants().FirstOrDefault(d =&amp;amp;amp;amp;gt; d.Name.LocalName == "BinarySecurityToken");
         if (binarySecurityTokenElement == null)
         {
             return null;
         }
         return binarySecurityTokenElement.Value;
     }
 }

Binary Security Token an SharePoint Online senden

​​Das erhaltene Binary Security Token kann anschließend verwendet werden, um sich am SharePoint Online Server zu authentifizieren. Hierzu wird folgender Endpunkt benötigt: https://tenant.sharepoint.com/_forms/default.aspx?wa=wsignin1.0

Die Anfrage muss wieder mit dem HTTP POST Verb verschickt werden. Zusätzlich muss als Content Type der application/x-www-form-urlencoded Header mit versendet werden. Um die Anfrage zu versenden habe ich mich diesmal für die WebRequest Klasse entschieden, da diese eine Eigenschaft AllowAutoRedirect enthält, welche wir auf false setzten müssen. Die Methode, um die Anfrage zu versenden, sieht wie folgt aus:​

private static WebResponse GetWebResponse(string url, string method, string data, stringcontentType)
   {
       var webRequest = WebRequest.Create(url) as HttpWebRequest;
       webRequest.Method = method;
       if (!string.IsNullOrEmpty(contentType))
       {
           webRequest.ContentType = contentType;
       }
 
       webRequest.AllowAutoRedirect = false;
 
       if (!string.IsNullOrEmpty(data))
       {
           var bytes = Encoding.ASCII.GetBytes(data);
           webRequest.ContentLength = bytes.Length;
           var requestStream = webRequest.GetRequestStream();
           requestStream.Write(bytes, 0, bytes.Length);
           requestStream.Close();
       }
 
       return webRequest.GetResponse();

Der Aufruf der Methode GetBinarySecurityToken und der GetWebResponse Methode könnte dann wie folgt aussehen:

var binarySecurityToken = GetBinarySecurityToken("*protected email*""mypassword","http://tenant.sharepoint.com");
var webResponse = GetWebResponse("https://tenant.sharepoint.com/_forms/default.aspx?wa=wsignin1.0""POST", binarySecurityToken, "application/x-www-form-urlencoded");

Authentifizierung-Cookies empfangen

Der SharePoint Online Server sendet als Cookie die zwei benötigten Cookies mit:

  • FedAuth
  • RtFa

Das folgende Bild zeigt eine Beispiel Antwort, welche mit Fiddler aufgezeichnet wurde:

Um diese beiden Informationen zu speichern, habe ich eine Klasse AccessToken erstellt.

private class AccessToken
{
    public string RtFa { get; set; }
 
    public string FedAuth { get; set; }
}​

Um das RtFa und FedAuth Cookie auszulesen habe ich eine Methode erstellt, welche die Cookies ausliest und eine neue Instanz der Klasse AccessToken zurück gibt.

private static AccessToken GetAccessToken(string binarySecurityToken)
        {
            var webResponse = GetWebResponse("https://tenant.sharepoint.com/_forms/default.aspx?wa=wsignin1.0""POST", binarySecurityToken, "application/x-www-form-urlencoded");
 
            if (webResponse.Headers.AllKeys.Contains("Set-Cookie"))
            {
                var values = webResponse.Headers.GetValues("Set-Cookie");
                var rtFaCookieValue = values.FirstOrDefault(v => v.StartsWith("rtFa"));
                var rtFa = string.Empty;
                var fetAuth = string.Empty;
                if (!string.IsNullOrEmpty(rtFaCookieValue))
                ​{
                ​​    rtFa = rtFaCookieValue.Split(';').FirstOrDefault();
                ​}
                ​​var fedAuthCookieValue = values.FirstOrDefault(v => v.StartsWith("FedAuth"));
                if (!string.IsNullOrEmpty(fedAuthCookieValue))
                ​{
                ​    fetAuth = fedAuthCookieValue.Split(';').FirstOrDefault();
                ​}
 
                return new AccessToken
                    ​{
                        FedAuth = fetAuth,
                        RtFa = rtFa
                    ​};
            }
 
            return null;
        }​

REST/OData Anfrage senden

Mit den empfangen RtFa und FedAuth Cookies können wir jetzt Anfragen gegen den REST/OData Endpunkt absenden. Diese beiden Cookies müssen wir bei jeder Anfrage anhängen, damit wir uns gegenüber dem SharePoint Online Server authentifizieren können. Hierzu habe ich die Methode ExecuteGet vorbereitet, welche als Argument einen Endpunkt URL und eine Sammlung von Cookies entgegennimmt.

private static string ExecuteGet(string url, IEnumerable<string> cookies)
        {
            using (var webClient = new WebClient())
            {
                if (cookies != null)
                {
                    webClient.Headers[System.Net.HttpRequestHeader.Cookie] = string.Join(";", cookies);
                }
 
                return webClient.DownloadString(url);
            }
        }
    

Um zu demonstrieren, dass nun erfolgreich Abfragen gegen den REST/OData Endpunkt abgesendet werden können, habe ich mich für folgende Methode entschieden:https://tenant.sharepoint.com/_api/web/lists?$select=Title

Diese Anfrage gibt die Listen-Titel des Webs zurück. Mehr Informationen über die REST/OData Schnittstelle finden Sie hier.

Die Main Methode, welche alle Methoden in der korrekten Reihenfolge ausführt, könnte wie folgt aussehen:

private static void Main(string[] args)
       {
           var binarySecurityToken = GetBinarySecurityToken("*protected email*""password","http://tenant.sharepoint.com");
           var accessToken = GetAccessToken(binarySecurityToken);
           var listTitleXmlResponse = ExecuteGet("https://tenant.sharepoint.com/_api/web/lists?$select=Title"new string[]
               {
                   accessToken.FedAuth,
                   accessToken.RtFa
               });
       }

Die Variable listTitleXmlResponse sollte nach dem Ausführen der Operation die Listen-Titel auf Web Ebene enthalten.

Erfahren Sie mehr

Office 365 Groups als Evolution von SharePoint?
Blog
Blog

Office 365 Groups als Evolution von SharePoint?

Zusätzlich zu SharePoint erlauben die Office 365 Groups es mir als Anwender, schnell und einfach neue Gruppen anzulegen und selbständig Benutzer hinzuzufügen.

Das neuste Mitglied der Office 365 Familie: Delve
Blog
Blog

Das neuste Mitglied der Office 365 Familie: Delve

Microsoft legt nach: Mit Delve startet eine neue Form des Suchens und des Auffinden von Dokumenten und Informationen.

Nov
07
Webcast mit Microsoft: Das Intranet zu Ende gedacht
Webinar
Webinar

Webcast mit Microsoft: Das Intranet zu Ende gedacht

Am 07. November findet erneut eines unserer Webinare gemeinsam mit Mircosoft statt. Das Thema dieses Mal: Das Intranet zu Ende gedacht – Die Informationszentral...

Ich bin im Flow! – Eine Übersicht zu Microsoft Flow
Blog
Blog

Ich bin im Flow! – Eine Übersicht zu Microsoft Flow

Die Power Platform wird aktuell von Microsoft sehr stark gepusht. Zeit, sich mit dem Potenzial der einzelnen Komponenten zu beschäftigen. Heute: Flow.

Sprechen Sie LUIS? – Der intelligente Chat-Bot im Praxistest
Blog
Blog

Sprechen Sie LUIS? – Der intelligente Chat-Bot im Praxistest

Mit LUIS, der Sprach- und Texterkennungssoftware von Microsoft, und dem Bot Framework von Azure haben wir eine Lösung für den IT-Support entwickelt.

novaCapta auf der Fachtagung für Interne Revision
Event
Event

novaCapta auf der Fachtagung für Interne Revision

Das Expertenteam der novaCapta präsentiert am 15. und 16. November ihre innovative Audit Management Lösung auf dem DIIR-Kongress in Dresden. Besuchen Sie unsere...

Auf Goldkurs in der Cloud
News
News

Auf Goldkurs in der Cloud

Die novaCapta hat ihren Partnerstatus bei Microsoft zusätzlich vergoldet: Auch in der Sparte Cloud Productivity haben wir jetzt den Goldstatus.

Valo ist neuer Partner der novaCapta für Intranets
News
News

Valo ist neuer Partner der novaCapta für Intranets

Durch die Partnerschaft mit Valo, dem Ready-2-Go Intranet-Baukasten aus Finnland baut die novaCapta ihr Angebot bei der Umsetzung von schnellen und funktionalen...

Mit der HoloLens ein Stück Berlin nach Köln holen
News
News

Mit der HoloLens ein Stück Berlin nach Köln holen

Im Rahmen eines zweitägigen Hackathons haben sich einige Mitarbeiter der novaCapta der Microsoft HoloLens und dem Thema Mixed Reality gewidmet. Dabei haben wir...

Azure Functions: Der Webservice ohne Webserver
Blog
Blog

Azure Functions: Der Webservice ohne Webserver

Azure Functions als Authentifizierungs-Helfer für clientseitige Lösungen mit 3rd Party APIs

Paket Dependency Manager für .NET
Blog
Blog

Paket Dependency Manager für .NET

Paket ist ein Dependency Manager für .NET, welcher es sich zum Ziel gesetzt hat einige Probleme von NuGet zu beheben.

PowerApps – Neuigkeiten, Übersicht, Tipps & Tricks
Blog
Blog

PowerApps – Neuigkeiten, Übersicht, Tipps & Tricks

Neues aus der Welt von PowerApps