security - que - Control de acceso en el diseño impulsado por el dominio
domain drive development (1)
Leí acerca de DDD y Control de acceso, y encontré alguna contradicción entre las dos opiniones siguientes:
- "las preocupaciones de seguridad deben manejarse fuera del dominio"
- "los requisitos de control de acceso son específicos del dominio"
Estoy buscando una mejor práctica sobre esto. Entonces, ¿dónde debería poner la lógica de control de acceso por diseño impulsado por dominio, y cómo debería implementarlo?
(Para ser más específico por DDD + CQRS + ES.)
Creo que debería estar cerca de la lógica comercial, por ejemplo, una historia de usuario podría ser algo como esto:
El usuario puede editar su perfil enviando un nombre de usuario, una lista de pasatiempos, cv, etc.
En base a la historia del usuario implementamos el modelo de dominio y los servicios, por ejemplo:
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)
Esto está bien, pero ¿dónde está el HIS profile
parte de la historia?
Obviamente, este es el control de acceso basado en atributos, porque deberíamos escribir una regla como esta:
deny all, but if subject.id = resource.owner.id then grant access
Pero, ¿dónde deberíamos hacer cumplir esta regla, y cómo deberíamos implementarla?
Entonces, ¿dónde debería poner la lógica de control de acceso?
De acuerdo con esto: https://softwareengineering.stackexchange.com/a/71883/65755 el punto de cumplimiento de la política debe estar justo antes de la llamada de UserService.editProfile()
.
Llegué a la misma conclusión: no puede estar en la interfaz de usuario porque con varias UI tendremos repetición del código. Debería ser antes de la creación de eventos de dominio, porque indicaron que ya hemos hecho algo en el sistema. De modo que podemos restringir el acceso a objetos de dominio o a servicios que usan esos objetos de dominio. Por CQRS no es necesario tener objetos de dominio por el modelo de lectura, solo servicios, por lo que tenemos que restringir el acceso a los servicios si queremos una solución general. Podríamos poner las decisiones de acceso al comienzo de cada operación de servicio, pero eso sería grant all, deny x
patrón de seguridad anti.
¿Cómo debería implementarlo?
Esto depende de qué modelo de control de acceso se ajuste al dominio, por lo que depende de la historia del usuario. Por una decisión de acceso generalmente enviamos una solicitud de acceso y esperamos un permiso a cambio. La solicitud de acceso generalmente tiene las siguientes partes: tema, recurso, operación, entorno. Entonces el sujeto requiere permiso para realizar una operación en el recurso en un entorno. Primero identificamos el tema, luego lo autenticamos, y luego viene la autorización, donde verificamos si la solicitud de acceso se ajusta a nuestra política de acceso. Cada modelo de control de acceso funciona de manera similar. De c. pueden carecer de algunos de estos pasos, pero eso no importa ...
Creé una breve lista de modelos de control de acceso. Puse las reglas, las políticas en anotaciones, pero normalmente deberíamos almacenarlas en una base de datos probablemente en formato XACML si queremos tener un sistema bien mantenible ...
Por control de acceso basado en la identidad (IBAC) tenemos una identidad: permiso de almacenamiento (lista de control de acceso, lista de capacidades, matriz de control de acceso). Entonces, por ejemplo, mediante una lista de control de acceso, almacenamos la lista de los usuarios o grupos que pueden tener permisos.
UserService @AccessControlList[inf3rno] editProfile(EditUserProfileCommand command)
Por control de acceso basado en celosía (LBAC), el sujeto tiene un nivel de autorización, el recurso tiene un nivel de aprobación requerido, y verificamos qué nivel es más alto ...
@posseses[level=5] inf3rno UserService @requires(level>=3) editProfile(EditUserProfileCommand command)
Mediante el control de acceso basado en roles (RBAC) definimos los roles de los sujetos y otorgamos permisos a los sujetos que actúan como el rol real.
@roles[admin] inf3rno UserService @requires(role=admin) editProfile(EditUserProfileCommand command)
Mediante el control de acceso basado en atributos (ABAC), definimos atributos de sujeto, recurso y entorno y escribimos nuestras políticas en función de ellos.
@attributes[roles=[admin]] inf3rno UserService @policy(subject.role=admin or resource.owner.id = subject.id) editProfile(EditUserProfileCommand command) @attribute(owner) Subject getOwner(EditUserProfileCommand command)
Mediante el control de acceso basado en políticas (PBAC), no asignamos nuestras políticas a ninguna otra cosa, son independientes.
@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
Mediante el control de acceso adaptativo al riesgo (RAdAC) basamos nuestra decisión en el perfil de riesgo relativo del sujeto y el nivel de riesgo de la operación. Esto no se puede describir con reglas, creo. No estoy seguro de la implementación, quizás esto es lo que usa por su sistema de puntos.
Mediante el control de acceso basado en autorización (ZBAC) no hacemos identificación y autenticación, sino que asignamos permisos a los factores de identificación. Por ejemplo, si alguien envía un token, entonces ella puede tener acceso a un servicio. Todo lo demás es similar a las soluciones anteriores. Por ejemplo con ABAC:
@attributes[roles=[editor]] token:2683fraicfv8a2zuisbkcaac ArticleService @policy(subject.role=editor) editArticle(EditArticleCommand command)
Entonces, todos los que conocen la ficha
2683fraicfv8a2zuisbkcaac
pueden usar el servicio.
y así...
Hay muchos otros modelos, y el mejor ajuste siempre depende de las necesidades de su cliente.
Entonces para resumir
- "security concerns should be handled outside the domain"
- "access control requirements are domain specific"
ambos pueden ser correctos, porque la seguridad no es parte del modelo de dominio, pero su implementación depende del modelo de dominio y la lógica de la aplicación.
editar después de 2 años 2016-09-05
Desde que contesté mi propia pregunta como novato de DDD, he leído Implementing Domain-Driven Design de Vaughn Vernon. Fue un libro interesante en el tema. Aquí hay una cita de esto:
Esto constituye un nuevo contexto delimitado: el contexto de identidad y acceso, y será utilizado por otros contextos delimitados a través de técnicas de integración DDD estándar. Para los contextos de consumo, el contexto de identidad y acceso es un subdominio genérico. El producto se llamará IdOvation.
De acuerdo con Vernon, probablemente la mejor solución para mover el control de acceso a un subdominio genérico.