Daten per OData Interface sicher konsumieren–Teil 4

Im letzten Teil dieses Themas möchte ich zeigen, wie Schnittstellen abgesichert werden können. Das OData Interface aus Teil 1 soll nicht mehr anonym, sondern nur für authentifizierte Benutzer erreichbar sein.

In Teil 1 wurde ein ASP.NET Projekt erstellt, welches Daten mit dem Entity Framework aus einem SQL Azure ausliest und über eine WebAPI als OData Interface bereitstellt. Nun geht es darum, wie diese Schnittstelle geändert werden kann, damit eine sichere Benutzung nur für authentifizierte Anwender erreicht wird.

Wie absichern?
Zunächst einmal muss überlegt werden, was das Ziel ist. In meinem Beispiel möchte ich die Event-Daten über Excel abfragen lassen (siehe Teil 2). Jetzt ist es so, dass das OData Interface jeden (anonymen) Request bedient. Wenn die Daten jedoch nur von bestimmten Personen abgefragt werden sollen, benötigen wir eine Authentifizierung. Hier soll also eine Abfrage nach Benutzername und Kennwort eingebaut werden.
Natürlich gibt es viele Wege, das Service abzusichern. Ich verwende hier einen sehr einfachen Weg: Authentifizierung mit Username und Kennwort über “Basic

Authentication”.

Code weiterverwenden
Der Aufwand zur Absicherung soll möglichst gering sein. Freundlicherweise gibt es hierfür ein fertiges HttpModule auf GitHub: Lucid.Web.Portal / Lucid.Web.Portal / HttpModules / BasicAuthHttpModule.cs

Dieses 100 Zeilen Modul kann einfach in eigene Webprojekte integriert werden. Es verwendet einen Usernamen und ein Passwort aus den AppSettings und kann für eigene Module zwischengeschalten werden.

Der erste Schritt ist also das Modul in eine eigene Class, etwa BasicAuthHttpModule.cs, zu kopieren und den Namespace anzupassen.

Projekt anpassen
In der CheckPassword-Funktion finden hier zwei Keys aus den AppSettings Verwendung:
// TODO: Here is where you would validate the username and password.
private static bool CheckPassword(string username, string password)
{
var defaultUser = ConfigurationManager.AppSettings["defaultuser"];
var defaultPassword = ConfigurationManager.AppSettings["defaultpassword"];
return username == defaultUser && password == defaultPassword;
}
Diese beiden Keys defaultuser und defaultpassword müssen also in unsere web.config hinzugefügt werden.
(Huch, jetzt habe ich den Usernamen und das Kennwort verraten….)

Und natürlich muss unsere eigene Authentifizierungsmethode in den <system.webServer><modules> angegeben werden, schließlich wollen wir sie verwenden. Die gelb markierten Teile müssen also angepasst werden.
Fast fertig
Jetzt fehlt nur noch eines: Im OData Controller muss die [Authorize] Direktive hinzugefügt werden, damit dieser Controller die (eigene) Http-Autorisierung verwendet.

Die restlichen Controller (pardon, Seiten) bleiben anonym erreichbar. Sollen auch sie geschützt werden, kann diese genauso einfach mit der [Authorize] Anweisung erfolgen.
Ausprobieren
Das wars. Die Anwendung wird (lokal) gestartet. Nun navigieren wir zur URL des Controllers (https://localhost:61653/odata/RatingAverages). Voila, die Authentifizierung schlägt zu:

Wenn die Authentifizierung erfolgreich war, folgt der Datafeed. Cool, oder?
Ohne Autorisierung kein Zugriff
Die Schnittstelle kann nun nur mehr von authentifizierten Benutzern verwendet werden. Nicht autorisierte Benutzer (wir haben nur einen Benutzer…) erhalten eine “request denied” Meldung.

Bemerkungen
In realen Umgebungen würde man Benutzer wohl in einer Datenbank ablegen oder andere Verfahren anstelle von BasicAuthentication einsetzen. Basic Authentication verwendet etwa nur base64 encoding für das verschlüsselte Passwort und dieses kann im Browser gecacht werden. Außerdem sollte immer HTTPS verwendet werden (Azure WebApps haben das ja per default im Programm…). Dennoch, diese Methode ist einfach und rasch umgesetzt.
Eine zusätzliche Überlegung stellt auch die weitere Nutzung der Daten dar: Excel und PowerBI etwa (siehe Teil 2) können mit BasicAuthentication umgehen und Username und Kennwort für die DataConnection speichern.
In einer SharePoint App (siehe Teil 3) kann die Authorization nicht über den Webproxy transportiert werden – SharePoint blockiert diesen Zugriff, besser gesagt, transportiert den Header mit der Authorization nicht über den Proxy. Somit fällt Basic Authentication (und jede andere Authentifizierung über den HTTP Header) für eine SharePoint App aus. Hier wäre eventuell BCS eine Alternative.
Wie immer in der IT: Es hängt davon ab, um welche Daten es sich handelt und wie sicher diese transportiert und geschützt werden müssen. Die vorgestellte Absicherung ist ein einfacher Weg, Daten über eine WebAPI nur bestimmten Benutzern zur Verfügung zu stellen.
Ich hoffe, ich habe mit dieser kleinen Artikel-Serie ein paar Ideen geliefert, wie Schnittstellen mit einer Datenbank und OData gebaut und verwendet werden können.
Happy Interface-Developing!