2015-10-17 37 views
1

正在運行SQL Server 2014 Express。登錄爲sa我嘗試執行下面的代碼。它給我以下錯誤:無法使用EXECUTE AS OWNER在存儲過程中創建登錄名?

Msg 15247, Level 16, State 1, Line 25 User does not have permission to perform this action.

爲什麼?!如果我在程序中選擇SYSTEM_USER,則確實是sa(合法所有者)。

USE [MyDatabase] 
GO 

CREATE PROCEDURE [dbo].[create_login] 
    @Login [nvarchar](256), 
    @Password [nvarchar](128) 
WITH EXECUTE AS OWNER 
AS 
BEGIN 
    SET NOCOUNT ON 

    DECLARE @Sql NVARCHAR(4000) 

    SET @sql = N'CREATE LOGIN ' + QUOTENAME(@Login) + N' WITH PASSWORD = ' 
     + QUOTENAME(@Password, N'''') + N',CHECK_EXPIRATION=OFF, CHECK_POLICY=ON;' 
    EXEC (@sql) 
END 
GO 

GRANT EXECUTE ON [dbo].[create_login] TO [my_simple_role] 
GO 

-- Let's go! 
EXEC [dbo].[create_login] N'NewUser', N'[email protected]' 
GO 

-- Error! :(

如果我運行報表存儲過程,它的工作原理。

我試圖做一個存儲過程,允許普通用戶添加服務器登錄。以上似乎並不奏效。請指教!

回答

1

登錄是服務器級別的對象,因此需要服務器級別權限。 EXECUTE AS <database-user>是一個數據庫範圍的安全上下文。

通過存儲過程授予普通用戶特權操作的一種方法是使用映射到具有必要權限的登錄名的證書對模塊進行簽名。在這種情況下,必要的步驟是:

  1. 創建主數據庫
  2. 證書爲證
  3. 授予證書登錄的權限創建登錄
  4. 出口從主
  5. 證書創建登錄
  6. 將證書導入應用程序數據庫
  7. 使用證書籤署存儲過程

下面是從Erland Sommarskog's web site收集的一個例子。請注意,每次更改證書時,您都需要使用證書退出程序。

--create database master key, if necessary 
IF NOT EXISTS(SELECT 1 FROM sys.symmetric_keys WHERE name = N'##MS_DatabaseMasterKey##') 
BEGIN 
    CREATE MASTER KEY ENCRYPTION BY PASSWORD='[email protected]'; 
END; 
GO 

CREATE CERTIFICATE SecurityAdministratorCertificate 
    WITH 
    SUBJECT = 'Allows non-privileged users to create and alter logins' 
    , START_DATE = '20020101' 
    , EXPIRY_DATE = '20300101'; 
GO 

CREATE LOGIN SecurityAdministratorCertificateLogin 
    FROM CERTIFICATE SecurityAdministratorCertificate; 
GO 
GRANT ALTER ANY LOGIN TO SecurityAdministratorCertificateLogin; 
GO 

--export cert from master 
DECLARE @CERTENC VARBINARY(MAX); 
DECLARE @CERTPVK VARBINARY(MAX); 
SELECT @CERTENC = CERTENCODED(CERT_ID(N'SecurityAdministratorCertificate')); 
SELECT @CERTPVK = CERTPRIVATEKEY(CERT_ID(N'SecurityAdministratorCertificate'), 
     'All you need is love'); 

DECLARE @sql nvarchar(MAX); 
SELECT @sql = N'CREATE CERTIFICATE SecurityAdministratorCertificate FROM BINARY = ' 
    + CONVERT(nvarchar(MAX), @CERTENC, 1) 
    + ' WITH PRIVATE KEY (BINARY = ' 
    + CONVERT(nvarchar(MAX), @CERTPVK, 1) 
    + ', DECRYPTION BY PASSWORD = ''All you need is love'');' 

--import cert into app databases 
USE MyDatabase; 

--create database master key, if necessary 
IF NOT EXISTS(SELECT 1 FROM sys.symmetric_keys WHERE name = N'##MS_DatabaseMasterKey##') 
BEGIN 
    CREATE MASTER KEY ENCRYPTION BY PASSWORD='[email protected]'; 
END; 

EXEC(@sql); 
GO 

CREATE PROCEDURE [dbo].[create_login] 
    @Login [nvarchar](256), 
    @Password [nvarchar](128) 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @Sql NVARCHAR(4000); 

    SET @sql = N'CREATE LOGIN ' + QUOTENAME(@Login) + N' WITH PASSWORD = ' 
     + QUOTENAME(@Password, N'''') + N',CHECK_EXPIRATION=OFF, CHECK_POLICY=ON;'; 

    EXEC (@sql); 

END 
GO 

--grant exec permissions to users 
GRANT EXECUTE ON [dbo].[create_login] TO [my_simple_role]; 
GO 

--sign proc with certificate 
ADD SIGNATURE TO dbo.create_login BY CERTIFICATE SecurityAdministratorCertificate; 
GO 

編輯:

上面的例子使用加密數據庫主密鑰而不是特定的證書的密碼證書的私鑰。在還原數據庫或將其附加到不同SQL實例(不還原master數據庫)的情況下,您需要在master數據庫中重新創建服務器級別的對象,包括應用程序所需的所有登錄名和存儲在主。要恢復證書,一種方法是在恢復/附加後將用戶數據庫中的證書複製到主數據庫,然後使用權限重新創建證書登錄名。在這種情況下DMK無法自動打開,因爲在新實例上加密數據庫主密鑰的服務主密鑰不同。需要原始密碼才能在將證書複製到主數據庫的腳本中手動打開DMK。用於在數據庫之間複製證書的證書密碼是臨時的,不需要保留。

這裏是和例子來重新創建一個恢復或附加後掌握證書和證書登錄:

USE MyDatabase; 
--open DMK with original password 
OPEN MASTER KEY DECRYPTION BY PASSWORD='[email protected]'; 
--export cert from user database 
USE MyDatabase; 
DECLARE @CERTENC VARBINARY(MAX); 
DECLARE @CERTPVK VARBINARY(MAX); 
SELECT @CERTENC = CERTENCODED(CERT_ID(N'SecurityAdministratorCertificate')); 
SELECT @CERTPVK = CERTPRIVATEKEY(CERT_ID(N'SecurityAdministratorCertificate'), 
     'temporary password here'); 

DECLARE @sql nvarchar(MAX); 
SELECT @sql = N'CREATE CERTIFICATE SecurityAdministratorCertificate FROM BINARY = ' 
    + CONVERT(nvarchar(MAX), @CERTENC, 1) 
    + ' WITH PRIVATE KEY (BINARY = ' 
    + CONVERT(nvarchar(MAX), @CERTPVK, 1) 
    + ', DECRYPTION BY PASSWORD = ''temporary password here'');' 
SELECT @sql 
CLOSE MASTER KEY; 

--import cert into master 
USE master; 

--create database master key in new instance master database, if necessary 
IF NOT EXISTS(SELECT 1 FROM sys.symmetric_keys WHERE name = N'##MS_DatabaseMasterKey##') 
BEGIN 
    CREATE MASTER KEY ENCRYPTION BY PASSWORD='[email protected]'; 
END; 

EXEC(@sql); 
GO 

--recreate login and assign permissions 
CREATE LOGIN SecurityAdministratorCertificateLogin 
    FROM CERTIFICATE SecurityAdministratorCertificate; 
GRANT ALTER ANY LOGIN TO SecurityAdministratorCertificateLogin; 
GO 
+0

出色答卷。謝謝!需要將這兩個密碼中的哪一個存儲在「安全的地方」以供將來使用?我可以在創建數據庫時創建兩個隨機的強臨時密碼,只是爲了讓上面的'create_login'存儲過程起作用嗎? – l33t

+0

@ l33t,用於導出/導入證書的密碼是臨時的,可以是隨機的。數據庫主密鑰密碼應保留以供數據庫恢復或附加到其他SQL實例時使用。 我會添加一些額外的信息給我的答案來更詳細地解釋。 –

相關問題