web-dev-qa-db-fra.com

Contrôle d'accès dans la conception pilotée par domaine

J'ai lu sur DDD et le contrôle d'accès, et j'ai trouvé une contradiction entre les deux opinions suivantes:

  • "les problèmes de sécurité doivent être traités en dehors du domaine"
  • "les exigences de contrôle d'accès sont spécifiques au domaine"

Je recherche une meilleure pratique à ce sujet. Alors, où dois-je mettre la logique de contrôle d'accès par conception pilotée par domaine, et comment dois-je l'implémenter?

(Pour être plus précis par DDD + CQRS + ES.)

Je pense que cela devrait être quelque part près de la logique métier, par exemple une histoire d'utilisateur pourrait être quelque chose comme ceci:

L'utilisateur peut modifier son profil en envoyant un nom d'utilisateur, une liste de loisirs, cv, etc ...

Sur la base de la user story, nous implémentons le modèle de domaine et les services, par exemple:

UserService
    editProfile(EditUserProfileCommand command)
        User user = userRepository.getOneById(command.id)
        user.changeName(command.name)
        user.changeHobbies(command.hobbies)
        user.changeCV(command.cv)

UserRepository
    User getOneById(id)

User
    changeName(String name)
    changeHobbies(String[] hobbies)
    changeCV(String cv)

C'est bon, mais où est le HIS profile une partie de l'histoire?

Il s'agit évidemment d'un contrôle d'accès basé sur des attributs, car nous devrions écrire une règle comme ceci:

deny all, but if subject.id = resource.owner.id then grant access

Mais où devons-nous appliquer cette règle et comment la mettre en œuvre?

59
inf3rno

Alors, où dois-je mettre la logique de contrôle d'accès?

Selon ceci: https://softwareengineering.stackexchange.com/a/71883/65755 le point d'application de la politique devrait être juste avant l'appel de la UserService.editProfile().

Je suis arrivé à la même conclusion: il ne peut pas être dans l'interface utilisateur parce que par plusieurs interfaces utilisateur, nous aurions la répétition de code. Cela devrait être avant la création des événements de domaine, car ils indiquent que nous avons déjà fait quelque chose dans le système. Nous pouvons donc restreindre l'accès aux objets de domaine ou aux services qui utilisent ces objets de domaine. Par CQRS, nous n'avons pas nécessairement des objets de domaine par le modèle de lecture, juste des services, nous devons donc restreindre l'accès aux services si nous voulons une solution générale. Nous pourrions mettre les décisions d'accès au début de chaque opération de service, mais ce serait grant all, deny x anti motif de sécurité.

Comment dois-je l'implémenter?

Cela dépend du modèle de contrôle d'accès qui correspond au domaine, donc cela dépend de la user story. Par une décision d'accès, nous envoyons généralement une demande d'accès et attendons une autorisation en retour. La demande d'accès comprend généralement les parties suivantes: sujet, ressource, fonctionnement, environnement. Le sujet nécessite donc la permission d'effectuer une opération sur la ressource dans un environnement. Nous identifions d'abord le sujet, puis nous l'authentifions, et ensuite vient l'autorisation, où nous vérifions si la demande d'accès correspond à notre politique d'accès. Chaque modèle de contrôle d'accès fonctionne de manière similaire. Ofc. ils peuvent manquer de certaines de ces étapes, mais cela n'a pas d'importance ...

J'ai créé une courte liste de modèles de contrôle d'accès. J'ai mis les règles, les politiques en annotations, mais normalement nous devrions les stocker dans une base de données probablement au format XACML si nous voulons avoir un système bien maintenable ...

  • Par le contrôle d'accès basé sur l'identité (IBAC), nous avons un stockage de permission d'identité (liste de contrôle d'accès, liste de capacités, matrice de contrôle d'accès). Ainsi par exemple par une liste de contrôle d'accès, on stocke la liste des utilisateurs ou groupes dont on peut avoir les permissions.

    UserService
        @AccessControlList[inf3rno]
        editProfile(EditUserProfileCommand command)
    
  • Par contrôle d'accès basé sur réseau (LBAC), le sujet a un niveau d'autorisation, la ressource a un niveau d'autorisation requis, et nous vérifions quel niveau est supérieur ...

    @posseses[level=5]
    inf3rno
    
    UserService
        @requires(level>=3)
        editProfile(EditUserProfileCommand command)
    
  • Par le contrôle d'accès basé sur les rôles (RBAC), nous définissons les rôles des sujets et nous accordons des autorisations aux sujets dont le rôle est réel.

    @roles[admin]
    inf3rno
    
    UserService
        @requires(role=admin)
        editProfile(EditUserProfileCommand command)
    
  • Par le contrôle d'accès basé sur les attributs (ABAC), nous définissons les attributs du sujet, des ressources et de l'environnement et nous écrivons nos politiques en fonction d'eux.

    @attributes[roles=[admin]]
    inf3rno
    
    UserService
        @policy(subject.role=admin or resource.owner.id = subject.id)
        editProfile(EditUserProfileCommand command)
        @attribute(owner)
        Subject getOwner(EditUserProfileCommand command)
    
  • Par le contrôle d'accès basé sur les politiques (PBAC), nous n'affectons pas nos politiques à autre chose, elles sont autonomes.

    @attributes[roles=[admin]]
    inf3rno
    
    UserService
        editProfile(EditUserProfileCommand command)
        deleteProfile(DeleteUserProfileCommand command)
        @attribute(owner)
        Subject getOwner(EditUserProfileCommand command)
    
    @permission(UserService.editProfile, UserService.deleteProfile)
    @criteria(subject.role=admin or resource.owner.id = subject.id)
    WriteUserServicePolicy
    
  • Par le contrôle d'accès adaptatif au risque (RAdAC), nous basons notre décision sur le profil de risque relatif du sujet et le niveau de risque de l'opération. Je ne peux pas décrire cela avec des règles. Je ne suis pas sûr de l'implémentation, c'est peut-être ce que stackoverflow utilise par son système de points.

  • Par le contrôle d'accès basé sur les autorisations (ZBAC), nous ne faisons pas d'identification et d'authentification, nous attribuons plutôt des autorisations aux facteurs d'identification. Par exemple, si quelqu'un envoie un jeton, elle peut avoir accès à un service. Tout le reste est similaire aux solutions précédentes. Par exemple avec ABAC:

    @attributes[roles=[editor]]
    token:2683fraicfv8a2zuisbkcaac
    
    ArticleService
        @policy(subject.role=editor)
        editArticle(EditArticleCommand command)
    

    Donc, tous ceux qui connaissent le 2683fraicfv8a2zuisbkcaac le jeton peut utiliser le service.

etc...

Il existe de nombreux autres modèles et le meilleur ajustement dépend toujours des besoins de votre client.

Donc, pour résumer

- "security concerns should be handled outside the domain"
- "access control requirements are domain specific"

les deux peuvent avoir raison, car la sécurité ne fait pas partie du modèle de domaine, mais sa mise en œuvre dépend du modèle de domaine et de la logique d'application.

modifier après 2 ans 2016-09-05

Depuis que j'ai répondu à ma propre question en tant que débutant DDD, j'ai lu Implémentation de la conception pilotée par le domaine de Vaughn Vernon. C'était un livre intéressant sur le sujet. En voici une citation:

Cela constitue un nouveau contexte délimité - le contexte d'identité et d'accès - et sera utilisé par d'autres contextes délimités via des techniques d'intégration DDD standard. Pour les contextes consommateurs, le contexte d'identité et d'accès est un sous-domaine générique. Le produit sera nommé IdOvation.

Ainsi, selon Vernon, probablement la meilleure solution pour déplacer le contrôle d'accès vers un sous-domaine générique.

38
inf3rno