Question

J'implémente un service WCF sécurisé. L'authentification est effectuée à l'aide du nom d'utilisateur / mot de passe ou des informations d'identification Windows. Le service est hébergé dans un processus de service Windows. Maintenant, j'essaie de trouver le meilleur moyen d'implémenter l'autorisation pour chaque opération de service.

Par exemple, considérons la méthode suivante:

public EntityInfo GetEntityInfo(string entityId);

Comme vous le savez peut-être, dans WCF, il existe un objet OperationContext à partir duquel vous pouvez récupérer les informations d'identification de sécurité transmises par l'appelant / client. Maintenant, l’authentification aurait déjà été terminée au moment de l’appel de la première ligne de la méthode. Cependant, comment mettre en œuvre l'autorisation si la décision dépend des données d'entrée elles-mêmes? Par exemple, dans le cas ci-dessus, par exemple, les utilisateurs 'admin' (dont les autorisations sont stockées dans une base de données) sont autorisés à obtenir des informations sur l'entité et les autres utilisateurs ne doivent pas être autorisés ... où placer les contrôles d'autorisation?

Disons que nous le mettons dans la première ligne de la méthode comme suit:

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

Maintenant, il y a quelques questions:

  1. Valide-t-on le entityId (par exemple, contrôle null / valeur vide, etc.) AVANT le contrôle d'autorisation ou DANS le contrôle d'autorisation? En d'autres termes, si les contrôles d'autorisation doivent être inclus dans chaque méthode, est-ce un bon modèle? Que devrait-il se passer en premier - validation ou autorisation des arguments?

  2. Comment testons-nous un service WCF lorsque les contrôles d'autorisation sont omniprésents et que nous n'avons pas d'OperationContext dans le test unitaire!? (En supposant que j'essaie de tester directement cette implémentation de classe de service sans aucune configuration de WCF).

Des idées les gars?

Était-ce utile?

La solution

Pour la question 1, faites absolument l’autorisation en premier. Aucun code (sous votre contrôle) ne doit être exécuté avant l'autorisation de maintenir la sécurité la plus étroite possible. L'exemple de Paul ci-dessus est excellent.

Pour la question 2, vous pouvez gérer cela en sous-classant votre implémentation de service concrète. Faites de la véritable implémentation de la logique métier une classe abstraite avec un résumé "CheckPermissions". méthode que vous mentionnez ci-dessus. Créez ensuite 2 sous-classes, une pour l'utilisation de WCF et une autre (très isolée dans une DLL non déployée) qui renvoie la valeur true (ou ce que vous souhaitez que ce soit dans vos tests unitaires).

Exemple (à noter, ceux-ci ne doivent pas figurer dans le même fichier ni dans la même 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;
    }
}

Ensuite, votre déploiement WCF utilise la classe "MyServiceMyAuth", et vous testez votre unité par rapport à l'autre.

Autres conseils

Pour la question 1, il est préférable d'exécuter l'autorisation au préalable. Ainsi, vous ne transmettez pas les messages d'erreur de validation aux utilisateurs non autorisés.

BTW, au lieu d’utiliser une méthode d’authentification maison (ce que je suppose, c’est ce que votre CheckAccessPermission est), vous pourrez peut-être vous connecter à la prise en charge immédiate de WCF pour les fournisseurs de rôles ASP.NET. Une fois cela effectué, vous effectuez une autorisation via OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole (). PrimaryIdentity est un IPrincipal.

À propos de la question n ° 2, je le ferais à l’aide de l’injection de dépendance et configurerais la mise en œuvre de votre service, comme suit:

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

Notez que IAuthorization est une interface que vous définiriez.

Etant donné que vous allez tester directement le type de service (c'est-à-dire sans l'exécuter dans la structure d'hébergement WCF), vous configurez simplement votre service de manière à utiliser un type IAuthorization factice qui autorise tous les appels. Cependant, un test encore MEILLEUR consiste à simuler l’autorisation IA et à vérifier qu’elle est appelée quand et avec les paramètres que vous attendez. Cela vous permet de vérifier que vos appels aux méthodes d'autorisation sont valides, ainsi que la méthode elle-même.

La séparation de l'autorisation dans son propre type vous permet également de vérifier plus facilement son exactitude. Dans mon expérience (certes limitée), l’utilisation de "motifs" de DI vous permet de séparer nettement mieux les problèmes et les problèmes de testabilité de vos types, tout en vous permettant de créer une interface plus propre (ce point est évidemment sujet à débat).

Mon cadre moqueur préféré est le RhinoMocks , qui est gratuit et possède une très bonne interface mais il y en a beaucoup d'autres là-bas. Si vous souhaitez en savoir plus sur DI, voici quelques bonnes amorces et cadres .Net:

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top