Recibir "El permiso SELECT fue denegado en el objeto" aunque se le haya otorgado

11

Soy un programador, no un dba ... Sé lo suficiente como para ser peligroso.

Heredé una base de datos con un usuario heredado que es un db_owner para la base de datos. No podemos ajustar el permiso de este usuario para tablas, esquemas, etc. existentes, por razones comerciales, pero se están creando algunas tablas nuevas, y solo quiero que este usuario tenga acceso SELECCIONAR sobre ellas.

Se han establecido permisos para este usuario para estas tablas, de modo que todo está DENEGADO, excepto SELECT, que está establecido en GRANT.

Sin embargo, cuando este usuario (dbadmin) intenta realizar una SELECCIÓN en una de estas tablas (Auditoría de contabilidad), se produce este error:

The SELECT permission was denied on the object 'AccountingAudit', database 'billing', schema 'dbo'.

Ejecuté este SQL para probar y ver qué permisos están establecidos para esta tabla / usuario:

select object_name(major_id) as object,
 user_name(grantee_principal_id) as grantee,
 user_name(grantor_principal_id) as grantor,
 permission_name,
 state_desc
from sys.database_permissions

Y esto es lo que regreso:

AccountingAudit dbadmin dbo ALTER   DENY
AccountingAudit dbadmin dbo CONTROL DENY
AccountingAudit dbadmin dbo DELETE  DENY
AccountingAudit dbadmin dbo INSERT  DENY
AccountingAudit dbadmin dbo REFERENCES  DENY
AccountingAudit dbadmin dbo SELECT  GRANT
AccountingAudit dbadmin dbo TAKE OWNERSHIP  DENY
AccountingAudit dbadmin dbo UPDATE  DENY
AccountingAudit dbadmin dbo VIEW DEFINITION DENY
AccountingAudit dbadmin dbo VIEW CHANGE TRACKING    DENY

Parece que debería estar funcionando ¿verdad?

La llamada SELECT que estoy haciendo es una SELECT * FROM AccountingAudit muy básica, desde SSMS. No estoy haciendo ningún sp_executesql especial ni nada de eso.

He intentado explícitamente otorgar permiso:

GRANT SELECT ON [dbo].AccountingAudit TO dbadmin

Esto no tiene ningún efecto (¿por qué lo haría, la consulta anterior ya muestra que se ha concedido! ;-)

He buscado en stackoverflow.com y en otros lugares, y no puedo encontrar nada que aún no haya probado. Me pregunto si tiene algo que ver con cómo se configuran los esquemas. (En este punto, sé muy poco sobre esquemas).

¿Algunas ideas? ¡Gracias!

Mason G. Zhwiti
fuente

Respuestas:

10

No estoy seguro aquí, pero me voy a arriesgar. Creo que tu problema podría estar en tu DENY CONTROLhistorial. Vea aquí aproximadamente a la mitad de la página:

Negar el permiso CONTROL en una base de datos implícitamente niega el permiso CONNECT en la base de datos. Un director al que se le niega el permiso CONTROL en una base de datos no podrá conectarse a esa base de datos.

Me doy cuenta de que ese ejemplo es para una base de datos, pero tómalo un nivel más general. Un DENY CONTROLsobre una mesa negarán todos los privilegios en él, supongo. Haga lo posible REVOKE CONTROLpara deshacerse de eso y ver si eso soluciona su problema.

Si es así, tendrá que colocar al usuario en un rol de base de datos o negarle los privilegios explícitos contra la tabla.

Thomas Stringer
fuente
1
¡Gracias! Inicialmente, en mi experimento, descubrí que si no se negaba el CONTROL, podían SELECCIONAR. Pero al leer BOL había interpretado incorrectamente esto para significar que le estaba dando al usuario control total sobre la tabla. Ahora veo que mientras no les niegue CONTROL, aún puedo mantener los otros permisos (INSERTAR, BORRAR, etc.) en el nivel DENY y lograr los niveles de permiso que quiero. ¡Gracias!
Mason G. Zhwiti
Esta es una sutileza que voté, a pesar de no resolver mi problema, que creo que la mayoría pasaría por alto. Por separado, descubrí que si usa grupos de Active Directory, si ha cambiado la membresía del grupo, repadmin / syncall no necesariamente soluciona los problemas y descubrí que reiniciar el servidor solucionó el problema. Sin embargo, todavía estoy buscando menos acercamiento de mazo.
John Zabroski
0
  1. Use el sp_DBPermissionsprocedimiento almacenado de Ken Fisher para ver los permisos.

    1. Asegúrese de que DENY CONTROLno se aplica a la mesa, además de la habitual DENY SELECT, DENY INSERT, DENY UPDATE, DENY DELETEy DENY REFERENCES.
    2. Si la SELECTinstrucción contiene funciones con valores de tabla, asegúrese de que haya una EXECUTE AS OWNERen la función con valores de tabla o una GRANT EXECUTEen ella (¡y no DENY EXECUTE!). Si este es el caso, lea el mensaje de error con más cuidado, ya que probablemente no dirá que el permiso SELECT fue denegado en la tabla, sino algo sobre la denegación de EJECUTAR.
  2. Si el usuario es un usuario o grupo de AD, use el siguiente script para determinar los usuarios login_token:

EXECUTE AS LOGIN = 'EXAMPLEDOMAIN\JOHN.DOE';
SELECT * FROM sys.login_token;
REVERT;
  1. Mira el plan de ejecución real. Si el error está dentro de un procedimiento almacenado con SET NOCOUNT ON;, entonces el plan de ejecución real le dará una idea a la que podría no prestarle atención simplemente mirando la pestaña Mensajes en SSMS, ya que "Filas afectadas" pueden estar fuera de su control.

    1. Busque desencadenantes o tablas temporales.
  2. Puede compilar la declaración como un procedimiento almacenado y "Ver dependencias de objetos" de SSMS, así como los trucos descritos por Svetlana Golovko en diferentes formas para encontrar dependencias de objetos de SQL Server

  3. Use el evento de seguridad de SQL Server Profiler "Evento de acceso a objetos de esquema de auditoría" y las columnas "TextData" y "Success" para rastrear en qué objetos SQL Server está evaluando los permisos. - He visto situaciones en las que se emiten dos filas para este evento, y un valor dice Éxito = 1 y el otro dice Éxito = 0. En este escenario, la única solución que he encontrado que funciona es reiniciar el servidor. Incluso la ejecución repadmin /syncallno solucionó el problema, tampoco lo hizo iniciar y detener la aplicación (y, por lo tanto, el grupo de conexiones).

  4. Determine los permisos efectivos para el inicio de sesión:

-- '<domain>\<username>' is a domain user in the group you wish to test
EXECUTE AS LOGIN = '<domain>\<username>';
SELECT * FROM fn_my_permissions('Database.Schema.Table', 'OBJECT');
REVERT;
  1. Si el usuario está vinculado a un usuario o grupo de AD, considere ejecutar repadmin /syncallpara forzar que los cambios realizados en el directorio activo se sincronicen entre sus controladores de dominio. - Si alguien conoce una buena manera de comparar los valores actuales de dos controladores de dominio, hágamelo saber.

  2. Antes de considerar un reinicio completo de todo el sistema, intente eliminar todas las conexiones activas para ese usuario. La razón es que el usuario obtiene su token de Windows del DC que incluye sus grupos. El token no se actualizará hasta que el usuario obtenga un nuevo token, generalmente cerrando la sesión y volviendo a iniciarla.

  3. Hard reiniciar el sistema. Esto ha funcionado para mí. Todavía no estoy 100% seguro de por qué todavía. ¡SOLO HAGA ESTO SI PUEDE SOBREVIVIR EL TIEMPO ABAJO! ¡TENGA CUIDADO DE HACER ESTO MIENTRAS TIENE GRANDES OPERACIONES EXCEPCIONALES!

John Zabroski
fuente