tSQLt测试中的模拟和安全权限如何工作?

时间:2019-05-14 16:39:19

标签: sql-server testing sql-server-2016 tsqlt

我有一个tSQLt测试,我期望它会失败,但是可以成功运行。当我在过程外运行代码时,它按预期失败,但是使用Run执行测试时,不会发生错误。

我已经阅读了问题tSQLt Testing SQL Server security permissions,但是接受的答案不能解决我的问题。

我的测试如下:

    CREATE PROCEDURE TestSecurity.[test AFDK_Reader cannot read from AWS schema]
    AS 
    BEGIN
        --EXEC tSQLt.ExpectException
        EXECUTE AS USER = 'AFDK_Reader'

        select *
        from sys.user_token

        SELECT * FROM fn_my_permissions('AWS', 'SCHEMA')   
        ORDER BY subentity_name, permission_name ;   

        SELECT *
        FROM [AWS].[ADRESSEPUNKT_HISTORIK]
        REVERT
    END

该角色仅授予对AFDK模式的选择权限,这是SQL用户具有的唯一数据库角色成员身份。

AFDK_Reader没有读取AWS模式的权限。

有人可以告诉我如何进行调试吗?预先感谢。

1 个答案:

答案 0 :(得分:0)

EXECUTE AS... REVERT命令在存储过程中的行为与您期望的不同。这是SQL Server中存储过程安全性的常规功能。存储过程的一种常见用法是抽象权限。 MS文档页面Customizing Permissions with Impersonation in SQL Server说:

  

如果已存储,SQL Server不会检查调用方的权限   过程和表具有相同的所有者。

这实际上就是这里发生的事情。即使EXECUTE AS更改了安全上下文,也不会在存储过程中检查该安全上下文。

文档页面还显示:

  

但是,如果对象具有不同的所有权链接将不起作用   所有者,或者使用动态SQL。

获得预期行为的一种方法是从动态SQL语句内部运行SELECT语句,这意味着将针对表权限对活动的安全上下文进行测试:

CREATE PROCEDURE TestSecurity.[test AFDK_Reader cannot read from AWS schema]
AS 
BEGIN
    EXEC tSQLt.ExpectException
    EXECUTE AS USER = 'AFDK_Reader'

    EXEC ('SELECT * FROM [AWS].[ADRESSEPUNKT_HISTORIK]')
    REVERT
END

另一种(更好的)解决方案可能是使用内置的权限功能来通过元数据测试权限设置。这是仍然使用EXECUTE AS... REVERTsys.fn_my_permission的一种方法:

CREATE PROCEDURE TestSecurity.[test AFDK_Reader cannot read from AWS schema]
AS 
BEGIN
    EXECUTE AS USER = 'AFDK_Reader'
    DECLARE @permissionCount int = (SELECT COUNT(*) FROM sys.fn_my_permissions('[AWS].[ADRESSEPUNKT_HISTORIK]', 'OBJECT') WHERE permission_name = 'SELECT' AND subentity_name = '')
    REVERT
    EXEC tSQLt.AssertEquals 0, @permissionCount
END