Domanda

Sto implementando un servizio WCF sicuro. L'autenticazione viene eseguita utilizzando nome utente / password o credenziali di Windows. Il servizio è ospitato in un processo di servizio di Windows. Ora sto cercando di scoprire il modo migliore per implementare autorizzazione per ogni operazione di servizio.

Ad esempio, considera il seguente metodo:

public EntityInfo GetEntityInfo(string entityId);

Come forse saprai, in WCF esiste un oggetto OperationContext da cui è possibile recuperare le credenziali di sicurezza passate dal chiamante / client. Ora, autenticazione sarebbe già terminata quando viene chiamata la prima riga del metodo. Tuttavia, come implementiamo l'autorizzazione se la decisione dipende dai dati di input stessi? Ad esempio, nel caso precedente, dire agli utenti "admin" (le cui autorizzazioni, ecc. Sono archiviate in un database), possono ottenere informazioni sull'entità e altri utenti non dovrebbero essere autorizzati ... dove effettuiamo i controlli di autorizzazione?

Supponiamo che lo inseriamo nella prima riga del metodo in questo modo:

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

Ora ci sono un paio di domande:

  1. Convalidiamo entityId (ad esempio controllo valore nullo / vuoto ecc.) PRIMA del controllo dell'autorizzazione o ALL'INTERNO del controllo dell'autorizzazione? In altre parole, se i controlli di autorizzazione dovrebbero essere inclusi in ogni metodo, è un buon modello? Cosa dovrebbe accadere per primo - convalida o autorizzazione dell'argomento?

  2. In che modo testiamo un'unità di un servizio WCF quando i controlli di autorizzazione sono ovunque in questo modo e non abbiamo un OperationContext nel test unità !? (Supponendo che sto provando a testare l'implementazione di questa classe di servizio direttamente senza alcuna configurazione WCF).

Qualche idea ragazzi?

È stato utile?

Soluzione

Per la domanda 1, prima fai assolutamente l'autorizzazione. Nessun codice (sotto il tuo controllo) deve essere eseguito prima dell'autorizzazione per mantenere la massima sicurezza. L'esempio di Paolo sopra è eccellente.

Per la domanda 2, è possibile gestirlo eseguendo la sottoclasse dell'implementazione del servizio concreto. Trasforma la vera implementazione della logica di business in una classe astratta con un abstract "CheckPermissions" metodo come menzionato sopra. Quindi crea 2 sottoclassi, una per l'uso di WCF e una (molto isolata in una DLL non distribuita) che restituisce true (o qualsiasi cosa tu voglia che faccia nel test dell'unità).

Esempio (nota, questi non dovrebbero essere nello stesso file o persino DLL!):

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;
    }
}

Quindi la tua distribuzione WCF usa la classe " MyServiceMyAuth " ;, e fai i test delle tue unità contro l'altro.

Altri suggerimenti

Per la domanda 1, è meglio eseguire prima l'autorizzazione. In questo modo, non perdi i messaggi di errore di convalida agli utenti non autorizzati.

A proposito, invece di utilizzare un metodo di autenticazione cresciuto in casa (che presumo sia il tuo CheckAccessPermission), potresti essere in grado di collegarti al supporto immediato di WCF per i provider di ruoli ASP.NET. Al termine, si esegue l'autorizzazione tramite OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole (). PrimaryIdentity è un IPrincipal.

A proposito della domanda n. 2, lo farei utilizzando Dependency Injection e imposterò l'implementazione del servizio in questo modo:

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
    }
}

Nota che IAuthorization è un'interfaccia che definiresti.

Poiché testerai direttamente il tipo di servizio (ovvero, senza eseguirlo all'interno del framework di hosting WCF), devi semplicemente configurare il tuo servizio per utilizzare un tipo di IAuthorization fittizio che consente tutte le chiamate. Tuttavia, un test ancora MIGLIORE è quello di deridere l'autorizzazione IA e testare che viene chiamato quando e con i parametri previsti. Ciò consente di verificare che le chiamate ai metodi di autorizzazione siano valide, insieme al metodo stesso.

La separazione dell'autorizzazione nel proprio tipo consente inoltre di verificare più facilmente che sia corretta isolatamente. Nella mia (seppur limitata) esperienza, usare DI "schemi" darti una separazione nettamente migliore delle preoccupazioni e della verificabilità nei tuoi tipi, oltre a portare a un'interfaccia più pulita (questo è ovviamente aperto al dibattito).

Il mio framework di derisione preferito è RhinoMocks che è gratuito e ha un'interfaccia fluida molto bella ma ce ne sono molti altri là fuori. Se vuoi saperne di più su DI ecco alcuni buoni primer e framework .Net:

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top