Control de Acceso en el Diseño Impulsado por Dominio


Leí sobre DDD y Control de Acceso, y encontré cierta contradicción entre las siguientes dos opiniones:

  • "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 al respecto. Entonces, ¿dónde debo poner la lógica de control de acceso por diseño impulsado por dominio y cómo debo implementarla?

(Para ser más específico por DDD + CQRS + ES.)

Creo que debería ser en algún lugar cercano a la lógica de negocio, 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 aficiones, cv, etc...

En base a la historia de 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á la HIS profile parte de la historia?

Esto es obviamente un control de acceso basado en atributos, porque deberíamos escribir una regla algo como esto:

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

Pero, ¿dónde debemos hacer cumplir esta regla y cómo debemos implementarla?

Author: inf3rno, 2014-05-05

1 answers

Entonces, ¿dónde debo poner la lógica de control de acceso?

De acuerdo con esto: https://softwareengineering.stackexchange.com/a/71883/65755 el punto de aplicación de la política debe estar justo antes de la llamada del UserService.editProfile().

Llegué a la misma conclusión: no puede estar en la interfaz de usuario porque por múltiples UIs tendríamos repetición de código. Debe ser antes de la creación de eventos de dominio, porque indicaron que ya hemos hecho algo en el sistema. Así que podemos restringir el acceso a los objetos de dominio o a los servicios que utilizan esos objetos de dominio. Por CQRS no necesitamos 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 principio de cada operación de servicio, pero eso sería grant all, deny x security anti pattern.

¿Cómo debo implementarlo?

Esto depende de qué modelo de control de acceso se ajuste a el 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: asunto, recurso, operación, entorno. Por lo tanto, el sujeto requiere permiso para realizar una operación en el recurso en un entorno. Primero identificamos el sujeto, 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 el modelo de control de acceso funciona de manera similar. Ofc. pueden carecer de algunos de estos pasos, pero eso no importa...

He creado una breve lista de modelos de control de acceso. Pongo las reglas, 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 identidad (IBAC) tenemos un almacenamiento de permisos de identidad( lista de control de acceso, lista de capacidades, matriz de control de acceso). Así, por ejemplo, mediante una lista de control de acceso, almacenamos la lista de los usuarios o grupos cuyos permisos pueden tener.

    UserService
        @AccessControlList[inf3rno]
        editProfile(EditUserProfileCommand command)
    
  • Mediante el control de acceso basado en red (LBAC) el sujeto tiene un nivel de autorización, el recurso tiene un nivel de autorización requerido, y verificamos qué nivel es mayor...

    @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 cuyo acto real rol.

    @roles[admin]
    inf3rno
    
    UserService
        @requires(role=admin)
        editProfile(EditUserProfileCommand command)
    
  • Por control de acceso basado en atributos (ABAC) definimos atributos de sujeto, recurso y entorno y escribimos nuestras políticas basadas en 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 nada más, 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. Este creo que no se puede describir con reglas. No estoy seguro de la implementación, tal vez esto es lo que stackoverflow utiliza 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 factores de identificación. Por ejemplo, si alguien envía un token, entonces 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)
    

    Así que todo el mundo quién sabe que el token 2683fraicfv8a2zuisbkcaac puede usar el servicio.

Y así sucesivamente...

Hay muchos otros modelos, y el mejor ajuste siempre depende de las necesidades de su cliente.

Así que 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 de la lógica de la aplicación.

Editar después de 2 años 2016-09-05

Desde que respondí a mi propia pregunta como DDD novato, he leído Implementando Diseño basado en Dominios de Vaughn Vernon. Fue un libro interesante en el tema. He aquí una cita de ella:

Esto constituye un nuevo Contexto Acotado - la Identidad y el Acceso Contexto-y será utilizado por otros Contextos Acotados a través del estándar Técnicas de integración DDD. A los contextos consumidores la Identidad y El Contexto de Acceso es un subdominio Genérico. El producto será nombrado IdOvación.

Así que según para Vernon probablemente la mejor solución para mover el control de acceso a un subdominio genérico.

 28
Author: inf3rno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-12 07:31:17