服务器主体“sa”无法访问当前安全上下文下的数据库“model”

时间:2013-04-25 10:19:12

标签: sql-server execute-as

我创建了一个存储过程,它执行一系列需要特殊权限的操作,例如:创建数据库,还原数据库等。我使用

创建此存储过程
execute as self

...以便它作为SA运行。这是因为我想给一个没有任何权限的SQL用户只能运行我定义的这些命令。

但是当我运行这个存储过程时,我得到了

The server principal "sa" is not able to access the database "model" under the current security context.

为什么SA无法访问模型数据库?我实际上在SA下运行了存储过程中的代码,运行正常。

2 个答案:

答案 0 :(得分:9)

继续阅读Extending Database Impersonation by Using EXECUTE AS

  

使用EXECUTE AS USER语句模拟主体时,   或者在数据库范围的模块中使用EXECUTE AS子句,   默认情况下,模拟范围仅限于数据库。这个   表示对数据库范围之外的对象的引用   将返回错误。

您需要使用module signingHere就是一个例子。

答案 1 :(得分:0)

对于其他来这里寻找此信息的人来说,这里有一个示例代码,可以准确地演示OP(和我)想要的内容(基于上面Remus的优秀信息):

    -- how to sign a stored procedure so it can access other Databases on same server
    -- adapted from this very helpful article 
    -- http://rusanu.com/2006/03/01/signing-an-activated-procedure/

    USE [master]
    GO
    CREATE DATABASE TempDB1
    CREATE DATABASE OtherDB2
    GO
    USE TempDB1
    GO
    -- create a user for TempDB1
    CREATE USER [foo] WITHOUT LOGIN
    GO

    CREATE PROCEDURE TempDB1_SP 
    AS 
    BEGIN 
        CREATE TABLE OtherDB2.dbo.TestTable (ID int NULL)
        IF @@ERROR=0 PRINT 'Successfully created table.' 
    END
    GO

    GRANT EXECUTE ON dbo.TempDB1_SP TO [foo]
    GO

    EXECUTE AS User='foo'
        PRINT 'Try to run an SP that accesses another database:'
        EXECUTE dbo.TempDB1_SP
        GO
    REVERT

    -- Output: Msg 916, Level 14, State 1, Procedure TempDB1_SP, Line 5
    --   [Batch Start Line 14]
    -- The server principal "..." is not able to access the database 
    --    "OtherDB2" under the current security context.

    PRINT ''
    PRINT 'Fix: Try again with signed SP...'

    -- Create cert with private key to sign the SP with. 
    -- Password not important, will drop private key

    USE TempDB1
    GO
    -- create a self-signed cert
    CREATE CERTIFICATE [DB_Cert] 
        ENCRYPTION BY PASSWORD = 'Password1' 
        WITH SUBJECT = 'Signing for cross-DB SPs';
    -- Sign the procedure with the certificate’s private key
    ADD SIGNATURE TO OBJECT::[TempDB1_SP] 
        BY CERTIFICATE [DB_Cert] 
        WITH PASSWORD = 'Password1'
    -- Drop the private key. This way it cannot be used again to sign other procedures.
    ALTER CERTIFICATE [DB_Cert] REMOVE PRIVATE KEY
    -- Copy the public key part of the cert to [master] database 
    -- backup to a file and create cert from file in [master]
    BACKUP CERTIFICATE [DB_Cert] TO FILE = 'C:\Users\Public\DBCert.cer'

    USE [OtherDB2] -- or use [master] = all DBs on server accessible
    GO
    CREATE CERTIFICATE [DB_Cert] FROM FILE = 'C:\Users\Public\DBCert.cer';
    -- the 'certificate user' carries the permissions that are automatically granted 
    -- when the signed SP accesses other Databases
    CREATE USER [DB_CertUser] FROM CERTIFICATE [DB_Cert]
    GRANT CREATE TABLE TO [DB_CertUser] -- or whatever other permissions are needed
    GO

    USE TempDB1
    EXECUTE dbo.TempDB1_SP
    GO
    -- output: 'Successfully created table.'
    -- clean up: everything except the cert file, have to delete that yourself sorry
    USE [master]
    GO
    DROP DATABASE TempDB1
    DROP DATABASE OtherDB2
    GO