Seleccionar permiso dentro del procedimiento almacenado?

8

He otorgado a un usuario permiso de ejecución para un procedimiento almacenado que utiliza SQL dinámico. Pero cuando intenta ejecutarlo, obtiene el error:

El permiso SELECT fue denegado en el objeto '[nombre de la tabla]', base de datos '[nombre de la base de datos]', esquema 'dbo'.

¿Se le debe otorgar permiso al usuario para las tablas que utiliza el procedimiento almacenado? Eso realmente no tendría ningún sentido para mí.

xdumaine
fuente

Respuestas:

5

De acuerdo con el comentario anterior y según mi sospecha, parece que está intentando ejecutar SQL dinámico dentro de su procedimiento almacenado.

Lo que debe recordar es que cuando hace esto no se ejecuta dentro del contexto del procedimiento almacenado, sino que se ejecuta dentro de una nueva sesión. Debido a esto, el hecho de que la declaración se llame dentro de un procedimiento almacenado es un punto discutible, y deberá otorgar permiso explícito sobre los objetos que está utilizando su SQL dinámico.

Si no desea hacer esto, refactorizaría su procedimiento almacenado para no usar SQL dinámico.

El siguiente enlace de Microsoft debería ayudarlo con su problema:

PRB: contexto de seguridad de sentencias SQL dinámicas dentro de un procedimiento almacenado (archivo Wayback Machine)

Este comportamiento se produce porque una consulta de ejecución dinámica (sp_executesql o EXECUTE) se ejecuta en un contexto separado del procedimiento almacenado principal; se ejecuta en el contexto de seguridad del usuario que ejecuta el procedimiento almacenado y no en el contexto de seguridad del propietario del procedimiento almacenado.

Esto también se discute en el artículo (más reciente) de Microsoft Docs:

Escribir SQL dinámico seguro en SQL Server

La ejecución de sentencias SQL creadas dinámicamente en su código de procedimiento rompe la cadena de propiedad, haciendo que SQL Server verifique los permisos de la persona que llama contra los objetos a los que accede el SQL dinámico.

DBA mundial
fuente
2

Parece que hay diferentes propietarios del procedimiento, así como el objeto subyacente que el SELECT está consultando. Todo esto tiene que ver con las cadenas de propiedad . Vea el siguiente ejemplo para una breve explicación y demostración de lo que estoy hablando:

use YourTestDatabase;
go

create login TestLogin1
with 
    password = 'password',
    check_policy = off;
go

create user TestUser1
for login TestLogin1;
go

create table Table1
(
    id int identity(1, 1) not null,
    SomeString varchar(30) not null
        default replicate('a', 30)
);
go

insert into Table1
values(default);
go 10

create proc Proc1
as
    select *
    from Table1;
go


grant execute
on Proc1
to TestUser1;
go

-- this works because permissions aren't checked
--  on Table1.  That is why TestUser1 can get the
--  result set without SELECT permissions on Table1
execute as user = 'TestUser1';
go

exec Proc1;
go

revert;
go

-- let's change the owner of Proc1 so that the 
--  ownership chain is broken and permissions are
--  checked on Table1
alter authorization
on Proc1
to TestUser1;
go

-- this no longer works because permissions are now
--  checked on Table1, which TestUser1 does not have
--  SELECT permissions on
execute as user = 'TestUser1';
go

exec Proc1;
go

revert;
go

Si desea averiguar la propiedad de sus objetos, puede ejecutar la consulta a continuación (obviamente, cambiando la cláusula WHERE para incluir sus nombres de objeto específicos):

select
    o.name,
    o.type_desc,
    case
        when o.principal_id is null
            then sp.name
        else dp.name
    end as principal_name
from sys.objects o
inner join sys.schemas s
on o.schema_id = s.schema_id
left join sys.database_principals dp
on o.principal_id = dp.principal_id
left join sys.database_principals sp
on s.principal_id = sp.principal_id
where o.name in
(
    'Table1',
    'Proc1'
);
Thomas Stringer
fuente