2008-09-28 10 views
7

Ich implementiere einen sicheren WCF-Dienst. Die Authentifizierung erfolgt mit Benutzernamen/Passwort oder Windows-Anmeldedaten. Der Dienst wird in einem Windows-Dienstprozess gehostet. Jetzt versuche ich herauszufinden, die beste Möglichkeit, Autorisierung für jeden Service-Betrieb zu implementieren.WCF Service-Autorisierungsmuster

Betrachten wir zum Beispiel die folgende Methode:

public EntityInfo GetEntityInfo(string entityId); 

Wie Sie vielleicht wissen, in WCF, gibt es eine Operation Objekt, von dem Sie die Anmeldeinformationen abrufen können vom Anrufer/Client übergeben. Jetzt wäre die Authentifizierung bereits beendet, wenn die erste Zeile in der Methode aufgerufen wird. Wie implementieren wir jedoch die Autorisierung, wenn die Entscheidung von den Eingabedaten selbst abhängt? Im obigen Fall sagen Benutzer "admin" (deren Berechtigungen usw. in einer Datenbank gespeichert sind), Entitätsinformationen zu erhalten, und andere Benutzer sollten nicht erlaubt sein ... Wo setzen wir die Berechtigungsprüfungen?

Sagen wir es in der ersten Zeile des Verfahrens wie so setzen:

CheckAccessPermission(PermissionType.GetEntity, user, entityId) //user is pulled from the current OperationContext 

Nun gibt es ein paar Fragen:

  1. wir Sie die EntityID (zB Check validieren Null-/Leerwert usw.) VOR der Berechtigungsprüfung oder INSIDE der Berechtigungsprüfung? Mit anderen Worten, wenn Berechtigungsprüfungen in jeder Methode enthalten sein sollten, ist das ein gutes Muster? Was sollte zuerst geschehen - Argumentvalidierung oder Autorisierung?

  2. Wie testen wir einen WCF-Dienst, wenn die Berechtigungsprüfungen überall so sind und wir keinen OperationContext im Komponententest haben? (Angenommen, ich versuche, diese Dienstklassenimplementierung direkt ohne das WCF-Setup zu testen).

Irgendwelche Ideen Leute?

Antwort

3

Für Frage 1, absolut zuerst Autorisierung. Kein Code (innerhalb Ihrer Kontrolle) sollte vor der Autorisierung ausgeführt werden, um die strengste Sicherheit aufrechtzuerhalten. Pauls Beispiel oben ist ausgezeichnet.

Für Frage 2 könnten Sie damit umgehen, indem Sie Ihre konkrete Service-Implementierung ableiten. Machen Sie die echte Business-Logik-Implementierung zu einer abstrakten Klasse mit einer abstrakten "CheckPermissions" -Methode, wie Sie oben erwähnt haben. Erstellen Sie dann zwei Unterklassen, eine für die WCF-Verwendung und eine (sehr isoliert in einer nicht implementierten DLL), die den Wert true zurückgibt (oder was auch immer Sie in Ihrem Unit-Test tun möchten).

Beispiel (Hinweis, diese sollten nicht in der gleichen Datei oder sogar DLL sein, obwohl!):

public abstract class MyServiceImpl 
{ 
    public void MyMethod(string entityId) 
    { 
     CheckPermissions(entityId); 
     //move along... 
    } 
    protected abstract bool CheckPermissions(string entityId); 
} 

public class MyServiceUnitTest 
{ 
    private bool CheckPermissions(string entityId) 
    { 
     return true; 
    } 
} 

public class MyServiceMyAuth 
{ 
    private bool CheckPermissions(string entityId) 
    { 
     //do some custom authentication 
     return true; 
    } 
} 

dann Ihre WCF-Bereitstellung verwendet die Klasse „MyServiceMyAuth“, und Sie tun, um Ihre Unit-Tests gegen die andere.

6

Für Frage 1 ist es am besten, die Autorisierung zuerst durchzuführen. Auf diese Weise werden Validierungsfehlernachrichten nicht an nicht autorisierte Benutzer zurückgegeben.

BTW, anstatt eine selbstgewählte Authentifizierungsmethode zu verwenden (von der ich annehme, dass Ihre CheckAccessPermission ist), können Sie möglicherweise an die WCF-Standardunterstützung für ASP.NET-Rollenanbieter anschließen. Sobald dies erledigt ist, führen Sie die Autorisierung über OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole() durch. Die PrimaryIdentity ist ein IPrincipal.

+0

Danke Paul. Das Problem mit der ersten Autorisierung ist: Wie autorisieren wir einen Benutzer, wenn wir die Berechtigungen basierend auf den Eingabeargumenten überprüfen müssen? Müssen wir diese Argumente nicht zuerst validieren, bevor wir sie zur Autorisierung verwenden? – Krishna

+0

Die Autorisierung sollte nur von der Identität des Benutzers abhängen. Wenn es von Eingabeargumenten abhängt, kann der Aufrufer die Werte senden, die er benötigt, um die gewünschte Autorisierung zu erhalten, sodass Ihre Berechtigungsprüfung bedeutungslos wird. –

+6

Nein. Ich möchte auf ein Objekt mit der ID 'abc1' zugreifen. Ich bin 'Benutzer1'. Die Autorisierung entscheidet, ob 'Benutzer 1' auf das Objekt 'abc1' zugreifen kann. Das erste, was zu tun ist, ist, den Parameter zu validieren, der den Objekt-ID-String enthält! – Krishna

6

Über Frage # 2, würde ich dies mit Dependency Injection tun und Ihre Service-Implementierung in etwa so ein:

class MyService : IMyService 
{ 
    public MyService() : this(new UserAuthorization()) { } 
    public MyService(IAuthorization auth) { _auth = auth; } 

    private IAuthorization _auth; 

    public EntityInfo GetEntityInfo(string entityId) 
    { 
      _auth.CheckAccessPermission(PermissionType.GetEntity, 
        user, entityId); 

      //Get the entity info 
    } 
} 

Beachten Sie, dass IAuthorization ist eine Schnittstelle, die Sie definieren würde.

Da Sie den Diensttyp direkt testen werden (dh ohne ihn innerhalb des WCF-Hosting-Framework auszuführen), richten Sie einfach Ihren Dienst ein, um einen Dummy-Authentifizierungstyp zu verwenden, der alle Anrufe zulässt. Ein noch besserer Test besteht jedoch darin, die IA-Zulassung zu verspotten und zu testen, dass sie wann und mit den erwarteten Parametern aufgerufen wird. Auf diese Weise können Sie testen, ob Ihre Aufrufe der Autorisierungsmethoden zusammen mit der Methode selbst gültig sind.

Wenn Sie die Autorisierung in ihren eigenen Typ unterteilen, können Sie auch einfacher testen, ob sie in der richtigen Weise korrekt ist. In meiner (wenn auch begrenzten) Erfahrung gibt die Verwendung von DI "Mustern" Ihnen eine weit bessere Trennung von Bedenken und Testbarkeit in Ihren Typen und führt zu einer saubereren Schnittstelle (dies steht natürlich zur Debatte).

Meine bevorzugte Spott Framework ist RhinoMocks, die frei ist und hat sehr schöne fließende Schnittstelle, aber es gibt viele andere da draußen. Wenn Sie mehr über DI hier wissen möchten sind einige gute Primer und .Net-Frameworks: