REST API, OAuth 2.0 und Service Hooks

Visual Studio Online Extensibility
Kommentare

Teams arbeiten heutzutage mit unterschiedlichsten Technologien und Plattformen. Diese Diversität führt auch dazu, dass ALM-Plattformen einfach erweiterbar sein müssen, um die Integration anderer Werkzeuge zu ermöglichen. Genau das ist das Ziel der neuen Visual-Studio-Online-Integration-Plattform.

Die drei wesentlichen Bestandteile für die Integration weiterer Werkzeuge sind hierbei das REST API, OAuth 2.0 und Service Hooks. Das REST API kann als zukünftige Basisschnittstelle für Visual Studio Online und Team Foundation Server angesehen werden und ermöglicht eine relativ einfache Kommunikation mit Visual Studio Online oder auch mit dem zukünftigen TFS 2015. Unter Visual Studio Online Integrations finden sich schon jetzt eine ganze Reihe von Integrationen wie zum Beispiel UserVoice, Trello, HipChat, Jenkins und viele mehr. Eine aktuelle Auflistung findet sich hier. Als erweitertes Beispiel haben wir auf Basis des REST API eine Windows-App als Showcase entwickelt. Der Code für diesen Showcase ist auf GitHub verfügbar und zeigt den Umgang mit dem REST API.

Die Grundlagen des REST API werden wir aber am Beispiel einer einfachen Konsolenanwendung erklären.

REST API

Für was steht eigentlich REST API? Der Begriff REST steht für REpresentational State Transfer und API für Application Programming Interface. Demzufolge ist ein REST API eine Art Beschreibung für eine Schnittstelle einer Webanwendung. Ein sog. RESTful Service zeichnet sich unter anderem durch folgende Merkmale aus:

  • Er referenziert alle Datenobjekte durch einen eindeutigen URL.
  • Er verwendet die Standardmethoden des HTTP-Protokolls (GET, PUT, POST und DELETE).
  • Er kann angefragte Objekte unter anderem als JSON-serialisiert zurückgeben.

Diese drei Eigenschaften machen das REST API von Visual Studio Online relativ leicht benutzbar und ermöglichen einen verständlichen Aufbau. Die URLs folgen dabei diesem Pattern:

https://{account}.VisualStudio.com/DefaultCollection/_apis[/{area}]/{resource}?api-version=1.0

Der Platzhalter {account} steht für den tatsächlichen Visual-Studio-Account, in unserem Fall https://almsports.visualstudio.com. Mit {area} werden dann die tatsächlichen Bereiche von Visual Studio Online referenziert, und {resource} beschreibt das Datenobjekt, das abgefragt werden soll.

Teamprojekte

Um z. B. Informationen aus einem Projekt abzurufen, muss folgender Aufruf abgesetzt werden:

https://almsports.visualstudio.com/DefaultCollection/_apis/projects/f2c5...

Dabei wird die Projekt-ID als Datenobjekt übergeben und als Rückgabewert folgendes JSON-Objekt erwartet (Listing 1).

{
"id": "f2c5c767-36ba-485a-b478-f6de0f8f84b3",
"name": "gitStart", 
"url": "https://almsports.visualstudio.com/DefaultCollection/_apis/projects/f2c5...",
"description": "Git",
"state": "wellFormed",
"_links": {
  "self": {
    "href": "https://almsports.visualstudio.com/DefaultCollection/_apis/projects/f2c5..."
  },
  "collection": {
    "href": "https://almsports.visualstudio.com/_apis/projectCollections/31360acb-beb..."
  },
  "web": {
    "href": "https://almsports.visualstudio.com/DefaultCollection/gitStart"
  }
},
"defaultTeam": {
  "id": "0c655975-4f18-4a4a-bb28-527cf4e44489",
  "name": "gitStart Team",
  "url": "https://almsports.visualstudio.com/DefaultCollection/_apis/projects/f2c5..."
  }
}

Der Aufbau der Rückgabeobjekte erfolgt nahezu immer nach dem gleichen Schema. Das JSON-Objekt enthält die Basisdaten eines Teamprojekts aus dem VSO-Account almsports und hält im Property name den Wert gitStart. Wie jedes Objekt ist es über eine id eindeutig identifizierbar und beinhaltet in der Property url den kompletten Aufruf für die Ressource. Innerhalb des Datensatzes des Teamprojekts wird ein weiteres Objekt mitgeliefert, welches durch das Property defaultTeam beschrieben wird. Es enthält ebenso eine eindeutige id, einen name und einen url.

In einer .NET-Konsolenapplikation kann man relativ einfach die Daten eines Visual-Studio-Online-Accounts abrufen und ausgeben. Dafür genügen wenige Zeilen Code.

Als Erstes wird ein HttpClient mithilfe eines using-Statements erzeugt, um HTTP-Requests absetzen und HTTP-Responses empfangen zu können. Da das REST API von Visual Studio Online bekanntermaßen JSON-Objekte zurückliefert, muss der Accept-Header des Aufrufs mit application/json gesetzt werden (Listing 2).

using (HttpClient client = new HttpClient())
{
  // set default RequestHeader
  client.DefaultRequestHeaders.Accept.Add(new 
    System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
  // Set alternate credentials
  client.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Basic", Convert.ToBase64String( 
      System.Text.ASCIIEncoding.ASCII.GetBytes( 
        string.Format("{0}:{1}", _altUsername, _altPassword))));
  // do something
}

Die Authentifizierung im Listing 2 findet mit den alternativen Credentials eines VSO-Benutzers statt, dabei wird der Authentication-Header auf „Basic“ gesetzt. Aber Achtung: Diese Art der Authentifizierung ist definitiv nicht für den produktiven Einsatz gedacht, da bei jedem HTTP-Aufruf Username und Passwort übertragen werden müssen. Eine bessere Art der Authentifizierung, nämlich OAuth 2.0 für VSO, stellen wir im weiteren Verlauf des Artikels vor. Ein Sample zu den vorgestellten Codebeispielen steht auf GitHub zur Verfügung.

Work Items abrufen

Ein relativ großer Bereich der REST API in Visual Studio Online ist das Work-Item-Tracking. Mithilfe des REST-Interface kann auf nahezu alle Bereiche des Work-Item-Tracking zugegriffen werden. Work Items können erstellt oder editiert, Attachements und Historie ausgelesen und Tags vergeben werden (Abb. 1).

Abb. 1: Übersicht der unterstützten Work-Item-Bereiche des REST API

Work-Item-Informationen können über zwei verschiedene Wege abgerufen werden: Entweder man verwendet eine vordefinierte Abfrage (Query) aus einem Teamprojekt, oder man erstellt sich eine eigene Abfrage mithilfe der Work Item Query Language (WIQL). Egal welche Methode letztendlich gewählt wird, beide Abfragetypen liefern erst nur eine Liste von Work-Item-IDs zurück (Listing 3).

string baseUrl = String.Format(constBaseUrl, projectName + "/");
// create Json Object with work item query
JObject wiql = JObject.FromObject(new
{
  query = string.Format("SELECT [System.Id], [System.WorkItemType], [System.Title], [System.AssignedTo], [System.State], [System.Tags] " +
    "FROM WorkItemLinks " +
    "Where Source.[System.WorkItemType] IN GROUP 'Microsoft.RequirementCategory' " +
    "AND Target.[System.WorkItemType] IN GROUP 'Microsoft.RequirementCategory' " +
    "AND Target.[System.State] IN ('New','Approved','Committed') " +
    "AND [System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward' " +
    "ORDER BY [Microsoft.VSTS.Common.BacklogPriority] ASC, " +
    "[System.Id] ASC MODE (Recursive, ReturnMatchingChildren)")
});
// first we only get all work item ids
var responseBody = await Common.PushAsync(client, wiql, 
  String.Format(baseUrl + "/wit/wiql?{0}", constApiVersion));

Um detaillierte Work-Item-Informationen zu erhalten, muss eine zweite Abfrage abgesetzt werden (Listing 4). In dieser Query werden die zurückgegeben Work-Item-IDs zusammen mit den gewünschten Datenfeldern angegeben. Dabei muss darauf geachtet werden, dass kein Projektname im URL angegeben wird, sonst wird die angefragte Ressource vom Service nicht gefunden und man bekommt eine „404 not found“-Fehlermeldung zurück.

// this time base URL is without projectname!!!
baseUrl = String.Format(constBaseUrl, "");
// set fields - which data we want to get
string fields = string.Format("fields=System.Id,System.Title,System.WorkItemType,Microsoft.VSTS.Scheduling.RemainingWork");
// create uri for requesting work item data
string uriString = String.Format(baseUrl + "wit/workitems?ids={0}", workItemStrings), fields);

Das JSON der Rückgabe sollte dann wie in Abbildung 2 aussehen und kann z. B. im JSON Visualizer, einem Visualizer des Debugging-Watch-Window von Visual Studio 2013, überprüft werden.

Abb. 2: JSON Response der Work Item Query

Das REST API steht natürlich nicht nur für das Work-Item-Tracking sondern auch für viele verschiedene Bereiche zur Verfügung, wie z. B. Build, TFS Version Control, Git, Test Case Management und Team Rooms. Einen aktuellen Überblick zum API findet man hier.

Richtig authentifizieren und autorisieren – OAuth 2.0

Die Visual Studio Online REST APIs unterstützen die Verwendung von OAuth 2.0 zur Autorisierung als Standardmechanismus. Das OAuth-2.0-Protokoll ist eine Erweiterung des seit 2006 bestehenden OAuth-1.0-Protokolls und soll Authentifizierungsabläufe für Cliententwickler vereinfachen. Der große Vorteil von OAuth ist, dass die aufrufende Applikation keine Credentials des Benutzers vorhält und diese beim Aufruf der VSO APIs mitübertragen muss. OAuth 2.0 ist auch kein Standard, der alleine von Visual Studio Online eingesetzt wird. Es gibt zahlreiche Unternehmen, die ebenfalls auf dieses Protokoll setzen (z. B. Dropbox, Foursquare, GitHub und Google).

Der zugrunde liegende Mechanismus von OAuth 2.0 unterliegt folgendem Ablauf: Als Erstes muss sich eine Applikation am aufzurufenden Service registrieren. In diesem Registrationsverfahren werden üblicherweise allgemeine Daten wie App-Name, Webseite, Logo etc. abgefragt. Wesentlicher Bestandteil ist auch die Angabe einesr sog. Redirect-URL, zu dem der Benutzer beim Aufruf des Service umgeleitet wird, um unerwünschte Serviceaufrufe, die nicht von der Applikation kommen, zu vermeiden. Nach der erfolgreichen Registrierung erhält man dann eine Client-ID und ein Client Secret. Die Client-ID enthält öffentliche Informationen und wird dann in der App verwendet, um den Service aufzurufen. Das Client Secret hingegen muss absolut vertraulich behandelt werden, damit eine sichere Authentifizierung erfolgen kann.

OAuth 2.0 für Visual Studio Online

Abbildung 3 zeigt den Mechanismus für Visual Studio Online. Als Erstes wird von der App eine Anfrage an Visual Studio Online zur Autorisierung eines neuen Benutzers gesendet. Nach erfolgreicher Anmeldung bei Visual Studio Online muss der User die App für die Abfrage von Daten aus VSO berechtigen. Mithilfe eines von VSO übersendeten Authorization-Codes kann von VSO ein Access Token und ein Refresh Token angefragt werden. Diese Token können dann von der Anwendung verwendet werden, um Daten über das Visual Studio Online REST Interface abzufragen.

Abb. 3: OAuth-Mechanismus von Visual Studio Online

Registrierung einer Anwendung bei Visual Studio Online

Wie bereits erwähnt, muss eine Anwendung erst für Visual Studio Online registriert werden, damit der eigentliche Authentifizierungsmechanismus durchgeführt werden kann. Dafür ist eine Webseite notwendig, die als Redirect verwendet werden kann. Zur Registrierung werden einige Informationen der Anwendung sowie der URL der Webseite im Registrierungsformular von Visual Studio Online eingegeben und bestätigt – dies erfolgt hier.

Abb. 4: Registrierungsformular für eine Anmeldung bei VSO

Wichtig an dieser Stelle ist, dass der richtige Bereich angegeben wird, auf den die Anwendung Zugriff haben soll. Diese sog. Authentication Scopes können bisher nicht nachträglich geändert werden, demzufolge sollte man sich vor dem Abschluss der Registrierung ausreichend sicher sein (Abb. 4).

Hinweis: Wenn ein Authentication Scope falsch gesetzt oder eine App noch während der Previewphase registriert wurde, kann eine App auch ein weiteres Mal registriert werden, um die Scopes zu ändern.

Authentifizierung durch OAuth 2.0

Nach einer erfolgreichen Registrierung der Anwendung erhält man wie bereits erwähnt eine App-ID und ein App Secret. Durch den folgenden URL ist man nun in der Lage, sich aus der App heraus zu authentifizieren:

https://app.vssps.visualstudio.com/oauth2/authorize?
client_id={AppID}&response_type=Assertion&state=User1&scope=vso.work%20vso.code_write&redirect_uri=https://almsportsoauth.azurewebsites.net/oauth/callback

In unserer Beispielanwendung wird zum Aufruf des URL der in Listing 5 gezeigte Code ausgeführt.

public ActionResult RequestToken(string code, string status)
{
  return new RedirectResult(GenerateAuthorizeUrl());
}
public String GenerateAuthorizeUrl()
{
  return String.Format("{0}?client_id={1}&response_type=Assertion&state={2}&scope={3}&redirect_uri={4}",
  ConfigurationManager.AppSettings["AuthUrl"],
  ConfigurationManager.AppSettings["AppId"],
  "state",
  ConfigurationManager.AppSettings["Scope"],
  ConfigurationManager.AppSettings["CallbackUrl"]);
}

Durch den Aufruf der Seite wird dem Benutzer der Screen gezeigt, der in Abbildung 5 zu sehen ist.

Abb. 5: Berechtigungen überprüfen für App-Zugriff

Durch diese Seite wird die Zustimmung des Benutzers für den Zugriff der App auf den VSO-Account bestätigt. Nach der Zustimmung schickt Visual Studio Online einen Authorization-Code zurück an die Anwendung, die den Code aufbereitet und für die Anfrage für das Access Token verwendet:

https://app.vssps.visualstudio.com/oauth2/token?
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={AppSecret}&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={authorization code}&redirect_uri={callbackUrl}

Die Methode PerformTokenRequest(string, out Token) verwendet dafür einen Post-Data-Wert, der ungefähr dem obigen String entspricht. Der eigentliche Aufruf in der App sieht dann wie in Listing 6 aus.

HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(ConfigurationManager.AppSettings["TokenUrl"]);
webRequest.Method = "POST";
webRequest.ContentLength = postData.Length;
webRequest.ContentType = "application/x-www-form-urlencoded";
 
using (StreamWriter swRequestWriter = new StreamWriter(webRequest.GetRequestStream()))
{
  swRequestWriter.Write(postData);
}
try
{
  HttpWebResponse hwrWebResponse = (HttpWebResponse)webRequest.GetResponse();
 
  // to be done
}

Ist der Aufruf erfolgreich, verbirgt sich im HttpWebResponse-Objekt das Access Token, zusammen mit einem Gültigkeitszeitstempel, der Token-Typbezeichnung und einem Refresh Token. Das Refresh Token muss nach Ablauf des Zeitstempels verwendet werden, denn dann ist das Access Token nicht mehr gültig.

Daten abfragen

Bei jeder Datenabfrage über das REST API muss nun das erhaltene Token im Header mitgeschickt werden. Die Abfrage der Build-Statusinformationen würde demnach wie in Listing 7 aussehen.

using (HttpClient client = new HttpClient())
{
  client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
 
  client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", "bearer " + token.accessToken);
 
  using (HttpResponseMessage response = 
    client.GetAsync("https://almsports.visualstudio.com/DefaultCollection/_apis/build/builds").Result)
  {
    response.EnsureSuccessStatusCode();
    responseBody = await response.Content.ReadAsStringAsync();
 
    // Response.Write(responseBody);
  }
}

Verglichen mit dem ersten kleinen Beispiel zum REST API in diesem Artikel fällt sofort auf, dass nun im Authentication-Header nicht mehr Basic, sondern Authorization als Schema angegeben ist, und als Parameter nicht mehr Username/Passwort sondern das Token über bearer {Access Token}.

Integration von Diensten via Service Hooks

Service Hooks ermöglichen die Benachrichtigung von externen Diensten bei spezifischen Ereignissen innerhalb eines Projekts. Dies ermöglicht es, einen Workflow zwischen VSO und externen Diensten zu etablieren (Abb. 6).

Abb. 6: Eventmodell der Service Hooks

Der Service Hook Publisher definiert Events. Diese können via Subscription durch einen Service Hook Consumer konsumiert werden, der wiederum eine Action ausführt.

Mittlerweile gibt es etwas mehr als ein Dutzend Dienste, die sich über Service Hooks integrieren lassen. Unter ihnen sind Anbieter wie Jenkins, HipChat, Slack, UserVoice, Trello etc. Wir wollen als Beispiel die Integration mit Trello, einem Kollaborationswerkzeug, zeigen. Hierbei wird der Service Hook so konfiguriert, dass für alle neu angelegten Work Items in einem VSO-Projekt eine neue Karte in Trello erzeugt wird. Auch kann man sich über Build-Zustände oder über Änderungen in der Versionskontrolle informieren lassen.

Integration von Trello

Positiv ist aufgefallen, dass die Integration externer Services ziemlich einfach und immer sehr ähnlich ist. Trello lässt sich in wenigen Minuten in Visual Studio Online integrieren. Der Ausgangspunkt der Integration ist die Service-Hooks-Seite im administrativen Bereich eines Teamprojekts (Abb. 7).

Abb. 7: Erzeugen eines Service Hooks über die Adminoberfläche

Über den Link Create the first subscription for this project und danach über das Pluszeichen in der Menüleiste gelangt man zu einem Installationsassistenten, der bei der Anlage des Service Hooks behilflich ist. Als Erstes wählt man aus einer Liste den gewünschten Dienst aus und konfiguriert dann einen sog. Trigger. Trigger ist das Event, das innerhalb eines Teamprojekts eine Action auslösen soll. Die für Trello unterstützten VSO-Events zeigt Abbildung 8.

Abb. 8: Liste der integrierbaren Dienste und Anwendungen

Für diesen Test haben wir das Work item created-Event und im nächsten Abschnitt die Aktion Create a card ausgewählt, die in Trello durch dieses Ereignis ausgeführt werden soll.

Um die Konfiguration zu vervollständigen und um eine sichere Kommunikation mit Trello zu ermöglichen, muss ein „Trello“-Token angegeben werden. Das Token wird von Trello bereitgestellt, nachdem die Anwendung für den Zugriff auf einen Visual-Studio-Online-Account berechtigt wurde. Diese Art der Authentifizierung haben wir unter dem Thema OAuth 2.0 näher beschrieben. Außerdem muss noch in den Settings hinterlegt werden, in welchem Board und in welcher Liste eine neue Karte erstellt werden soll und ob diese ggf. ein bestimmtes Label bekommt.

Nach der Integration von Trello in das Teamprojekt können Änderungen an den bestehenden Work Items vorgenommen werden. Die Änderungen werden dann unmittelbar angezeigt (Abb. 9).

Abb. 9: Trello Cards aus Visual Studio Online

Die aktuelle Version der Service Hooks unterstützt leider noch keinen vereinfachten Mechanismus zur Synchronisation zurück aus einer externen Anwendung zum Teamprojekt in Visual Studio Online. Die Anwendung kann aber diesen Weg direkt über das REST API triggern und durchführen. Ein gutes Beispiel dafür ist die Integration von UserVoice mit Visual Studio Online.

Fazit

Die Integration mit Visual Studio Online und Team Foundation Server wurde bisher primär mit dem .NET SDK und dem Java SDK durchgeführt. Mit dem REST API, OAuth-2.0-Support und Service Hooks ist die Plattform aber offener denn je und ermöglicht Integrationen auf einfache Weise. Diese Offenheit ist für die Visual-Studio-ALM-Plattform ein wichtiger und essenzieller Bestandteil der Produktstrategie, die sich auch in anderen Bereichen, wie zum Beispiel dem neuen Cross-Plattform-Build-Agent zeigt.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -