Control de acceso basado en roles y permisos

45

Estoy tratando de entender la compensación inherente entre roles y permisos cuando se trata de control de acceso (autorización).

Comencemos con un hecho: en nuestro sistema, un Permiso será una unidad de acceso específica (" Editar recurso X ", " Acceder a la página del tablero ", etc.). Un Rol será una colección de 1+ Permisos. Un usuario puede tener 1+ Roles. Todas estas relaciones (usuarios, roles, permisos) se almacenan en una base de datos y se pueden cambiar sobre la marcha y según sea necesario.

Mis preocupaciones:

(1) ¿Qué tiene de malo "comprobar los roles para el control de acceso? ¿Qué beneficios se obtienen al verificar los permisos? En otras palabras, ¿cuál es la diferencia entre estos dos fragmentos a continuación:

if(SecurityUtils.hasRole(user)) {
    // Grant them access to a feature
}

// vs.
if(SecurityUtils.hasPermission(user)) {
    // Grant them access to a feature
}

Y:

(2) En este escenario, ¿qué valor útil proporcionan los roles? ¿No podríamos simplemente asignar 1+ Permisos a los Usuarios directamente? ¿Qué valor concreto de abstracción ofrecen los Roles (alguien puede dar ejemplos específicos)?

smeeb
fuente
2
Un par de puntos: (1) un solo usuario puede tener múltiples roles, (2) es posible que desee buscar en ACL (Listas de control de acceso), por ejemplo. es posible que desee otorgar "Acceso a la página del panel" a solo un subconjunto de páginas del panel (si hay varias).
Matthieu M.

Respuestas:

63

(1) ¿Qué tiene de malo "comprobar los roles para el control de acceso? ¿Qué beneficios se obtienen al verificar los permisos?

En el momento de la comprobación, el código de llamada solo necesita saber "¿el usuario X tiene permiso para realizar la acción Y?" .
El código de llamada no le importa y no debe tener en cuenta las relaciones entre roles y permisos.

La capa de autorización verificará si el usuario tiene este permiso, generalmente verificando si el rol del usuario tiene este permiso. Esto le permite cambiar la lógica de autorización sin actualizar el código de llamada.

Si verifica directamente el rol en el sitio de la llamada, está formando implícitamente relaciones de permiso de rol and e inyectando lógica de autorización en el código de llamada, violando la separación de preocupaciones.

Si luego decide que ese rol foono debe tener permiso baz, debería cambiar cada código que verifica si el usuario es un foo.

(2) En este escenario, ¿qué valor útil proporcionan los roles? ¿No podríamos simplemente asignar 1+ Permisos a los Usuarios directamente? ¿Qué valor concreto de abstracción ofrecen los Roles (alguien puede dar ejemplos específicos)?

Los roles representan conceptualmente una colección con nombre de permisos.

Supongamos que está agregando una nueva función que permite al usuario editar ciertas configuraciones. Esta función debería estar disponible solo para administradores.

Si está almacenando permisos por usuario, tendría que encontrar todos los usuarios en su base de datos que de alguna manera sabe que son administradores (si no está almacenando información de roles para los usuarios, ¿cómo podría saber qué usuarios son administradores?) Y agregar este permiso a su lista de permisos.

Si usa roles, solo tiene que agregar el permiso al Administratorrol, que es más fácil de realizar, más eficiente en cuanto al espacio y menos propenso a errores.

Rotem
fuente
Uh La capa de autenticación verificará que el usuario es el que dice ser; la capa que verifica qué funciones / datos puede acceder dicho usuario es la capa de autorización
SJuan76
44
Esta debería ser una lectura obligatoria para todos los programadores. Excelente.
Kosta Kontos
2
Simple, conciso y al grano: supera un capítulo entero de un libro en alguna parte. Gracias.
Dan Nissenbaum
2
Comente para mayor claridad (y corríjame si me equivoco): authorization layerProbablemente no significa nada más que simplemente tener la definición de la función (es decir, user->hasPermission(SOME_PERMISSION)verificar internamente los roles del usuario primero y luego verificar si alguno de los roles incluye / excluye el dado permiso. Por ejemplo, the calling codepodría estar verificando si una determinada página es visible para el usuario y llamaría user->hasPermission(VIEW_GIVEN_PAGE), y authorization layerconsiste en la definición de la hasPermissionfunción que verifica los roles como se indicó anteriormente.
Dan Nissenbaum
1
@DanNissenbaum Sí, parece que lo hiciste bien, puede ser tan simple como verificar si el rol del usuario tiene esta autorización. También podría ser más que eso. Por ejemplo, tal vez tenga la opción de suspender temporalmente a un usuario y, en ese caso, hasPermissionpodría verificar usersRole.HasPermission(VIEW_GIVEN_PAGE) && !user.Suspended. El punto es que todo se hace en un lugar y no en el código de consumo (llamada).
Rotem
18

En respuesta a su primera pregunta, el mayor problema con la comprobación de que un usuario tiene un rol en lugar de un permiso específico, es que los permisos pueden tener múltiples roles. Como ejemplo de esto, un desarrollador podría tener acceso para ver el portal del desarrollador en la intranet de la compañía, que probablemente también sea un permiso de su gerente. Si un usuario intenta acceder al portal del desarrollador, tendrá una verificación similar a:

if(SecurityUtils.hasRole(developer)) {
    // Grant them access to a feature
} else if(SecurityUtils.hasRole(manager)) {
    // Grant them access to a feature
} else if...

(Una switchdeclaración en su idioma de elección sería mejor, pero aún no particularmente ordenada)

Cuanto más común o más extendido sea un permiso, más roles de usuario necesitará verificar para asegurarse de que alguien pueda acceder a un sistema determinado. Esto también llevaría al problema de que cada vez que modifique los permisos para un rol, necesitaría modificar la verificación para reflejar esto. En un sistema grande, esto se volvería muy difícil de manejar muy rápidamente.

Si simplemente verifica que el usuario tiene el permiso que le permite acceder al portal del desarrollador, por ejemplo, no importa qué rol tenga, se le otorgará acceso.

Para responder a su segunda pregunta, la razón por la que tiene roles es porque actúan como fáciles de modificar y distribuir "paquetes" de permisos. Si tiene un sistema que tiene cientos de roles y miles de permisos, agregar un nuevo usuario (por ejemplo, un nuevo gerente de Recursos Humanos) requeriría que lo revise y les otorgue todos los permisos que tienen otros gerentes de Recursos Humanos. Esto no solo sería tedioso, sino que es propenso a errores si se hace manualmente. Compare esto con simplemente agregar el rol de "gerente de recursos humanos" al perfil de un usuario, lo que le otorgará el mismo acceso que cualquier otro usuario con ese rol.

Podría argumentar que podría simplemente clonar un usuario existente (si su sistema lo admite), pero si bien esto le otorga al usuario los permisos correctos para ese momento, puede ser posible que intente agregar o eliminar un permiso para todos los usuarios en el futuro. difícil. Un escenario de ejemplo para esto es si quizás en el pasado el personal de recursos humanos también estaba a cargo de la nómina, pero más tarde la compañía se vuelve lo suficientemente grande como para contratar personal específicamente para manejar la nómina. Esto significa que RR.HH. ya no necesita acceder al sistema de nómina, por lo que se puede eliminar el permiso. Si tiene 10 miembros diferentes de RR. HH., Deberá hacerlo manualmente y asegurarse de eliminar el permiso correcto que introduce la posibilidad de error del usuario. El otro problema con esto es que simplemente no escala; A medida que gana más y más usuarios en un rol determinado, la modificación de un rol es mucho más difícil. Compare esto con el uso de roles, donde solo necesitaría modificar el rol general en cuestión para eliminar el permiso, lo que sería reflejado por cada usuario que tenga ese rol.

Matt Champion
fuente
buen ejemplo, gracias!
franco