Pratiques standard pour le contrôle d'accès (modèle de conception)

9

J'examine la conception de mon interface et j'ai du mal à décider quelle est la façon la plus "correcte" d'implémenter le contrôle d'accès basé sur les rôles, étant donné un useret un subjectauxquels userils aimeraient accéder.


Pour autant que je puisse voir, j'ai trois options de base (avec une quatrième étant une bâtardisation des trois premiers et une cinquième étant un ajustement du quatrième):

  1. Recherchez le subjectavec une liste d'autorisations que le usera -subject.allowAccess(user.getPermissionSet)
  2. Recherchez le useravec une liste d'autorisations que le subjectrequiert -user.hasPermissionTo(subject.getRequiredPermissions())
  3. Interrogez un tiers pour localiser les intersections des autorisations - accessController.doPermissionSetsIntersect(subject.permissionSet, user.getPermissionSet())
  4. Interrogez le subject/ usertout en déléguant la "décision" à une classe tierce
  5. Avoir la usertentative d'accéder à subjectet lancer une erreur si l'accès n'est pas autorisé

Je me penche vers l'option quatre - Avoir le subjectcontient un accessControllerchamp, où les appels à subject.userMayAccess(User user)déléguer l'opération à la:

class Subject {
    public function display(user) {
        if(!accessController.doPermissionSetsIntersect(this.permissionSet, user.getPermissionSet())) {
            display403(); //Or other.. eg, throw an error..
        }
    }
}

.. mais cela soulève d'autres questions:

  • devrait accessControllerêtre un champ vs une classe statique ..?
  • Faut-il subject savoir quelles autorisations sont nécessaires pour pouvoir le voir?
  • où le principe de moindre connaissance entre-t-il en jeu ici, en ce qui concerne l'appel subject.display()? Les appelants devraient-ils subject.display()savoir que le contrôle d'accès est en vigueur? (où se subject.display()trouve une "méthode modèle" finale)
  • avoir subject.display()gérer le contrôle d'accès, levant une exception où l'utilisateur n'a pas l'autorisation requise?

Quelle serait la «meilleure pratique» dans cette situation? Où la responsabilité d'effectuer les contrôles devrait-elle réellement se produire?

Comme il s'agit en quelque sorte d'un exercice académique qui progressera ensuite dans la mise en œuvre, des références aux modèles de conception seraient appréciées.

kwah
la source

Réponses:

7

La meilleure pratique consiste à utiliser ce que l'on appelle le modèle d'intercepteur pour intercepter les appels vers les zones protégées.

Ceci peut être réalisé en utilisant AOP ou des préoccupations transversales appliquées à vos points d'entrée d'accès.

Le sujet ne doit jamais savoir qui peut le voir. Cela complique inutilement le code sujet et il n'y a aucune raison qu'il soit nécessaire, sauf si vous fournissez par inadvertance un mécanisme d'accès direct à la même fonction.

De préférence, l'appelant et l'appelé ne devraient pas être informés de l'accès, à part gérer les refus. Cependant, le problème dépendra du système sur lequel vous implémentez et de la façon dont vous aurez accès aux informations d'identification / principal de sécurité pour l'appelant. Par exemple, dans les systèmes SOAP, ces informations sont ajoutées à l'en-tête d'un message SOAP, tandis que dans un système Windows, elles seraient disponibles via le mécanisme d'authentification Windows.

Si vous utilisez l'approche AOP ou modèle d'intercepteur, elle lèverait toutes les exceptions nécessaires et il appartiendrait au client (appelant) de gérer les exceptions levées.

De cette façon, vous gardez votre client, votre service et votre code d'authentification séparés sans mélange de connaissances ou de fonctionnalités.

sweetfa
la source
2

Je pense que votre option 3 est la plus proche, mais au lieu d'interroger le useret subjectsur leurs jeux d'autorisations, vous devez passer le useret subjectau contrôleur d'accès.

class Subject {
    public function display(user) {
        if(!accessController.checkAccess(this, user, AccessControl.Read)) {
            display403(); //Or other.. eg, throw an error..
        }
    }
}

Le contrôleur d'accès devrait être responsable à la fois de l'obtention des jeux d'autorisations et de la vérification si l'accès est suffisant. De cette façon, vous isolez à la fois la logique de stockage et la logique de vérification dans votre contrôleur d'accès, distinctes de l'utilisateur et du sujet.

L'autre élément qui manque peut-être à votre exemple est quelle opération est effectuée. Certains utilisateurs peuvent avoir le droit de lire certaines données , mais pas à mettre à jour, supprimer, exécuter, etc. Donc , vous pourriez avoir une checkAccessméthode sur le contrôleur d'accès à trois paramètres: user, subject, operation. Vous pouvez également fournir des informations supplémentaires de checkAccessretour pour renvoyer des informations sur les raisons pour lesquelles l'accès n'a pas été accordé.

Par exemple, déléguer tout cela au contrôleur d'accès ultérieurement vous permet de remplacer la façon dont vos autorisations sont représentées. Vous pouvez commencer par le contrôle d'accès basé sur les rôles et passer ultérieurement aux revendications. Vous pouvez stocker des autorisations dans une structure simple pour commencer, puis ajouter des groupes / rôles hiérarchiques et des opérations autorisées sur différents types de sujets. Ne pas mettre vos jeux d'autorisations dans l'interface permet d'activer cela.

Que vous utilisiez AOP ou un code standard pour le brancher est, à mon avis, moins important.

Rory
la source