SQLServerCentral Article

Execute As

,

"Execute As" is a nice solution for testing user permissions or controlling security within stored procedures while still allowing execute permission to the users that need the item. In this article I am going to use an example involving data encryption. I will create an application user, and will only allow the user to decrypt the encrypted data through a stored procedure. The user will be able to select from the table, but will not be able to decrypt the data using a select statement.

Let's start by creating an application user and an encryption user. The application user will have execute and select permissions. The encryption user will only have permission to encrypt and dencrypt the data, but no execute and select permissions.

The following script will create a database called MyTesting. It will then create two users, EncryptionUser and ApplicationUser. Next it will create the master key, certificate and symmetric key in the MyTesting database. It will create the table EncryptionTest and two stored procedures that simply select from the table while decrypting the encrypted column. The first stored procedure getEncryption will not use "Execute As" while the second stored procedure getEncryptionWithExecute will use "Execute As". Last it will populate the table.

USE [master]
GO
--Create a database called TestDB
IF EXISTS (SELECT name FROM sys.databases WHERE name = N'TestDB')
BEGIN
 ALTER DATABASE [TestDB] SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE
 DROP DATABASE [TestDB]
END 
GO
CREATE DATABASE [TestDB]
--Create two sql users
IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE name = N'EncryptionUser')
CREATE LOGIN [EncryptionUser] WITH PASSWORD=N'123456abc', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF;
GO
IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE name = N'ApplicationUser')
CREATE LOGIN [ApplicationUser] WITH PASSWORD=N'123456xyz', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF;
GO
USE [TestDB]
GO
--Create Users
CREATE USER [EncryptionUser] FOR LOGIN [EncryptionUser]
GO
CREATE USER [ApplicationUser] FOR LOGIN [ApplicationUser]
GO 
--Create Keys and certificates for encryption
CREATE MASTER KEY Encryption By Password = '7B35E6CF-16F4-4A9A-A8AB-7B150BE531EA';
GO
CREATE CERTIFICATE CertTest
WITH SUBJECT = 'Test Cert' ;
GO
CREATE SYMMETRIC KEY SymKeyTest
 WITH ALGORITHM = AES_256 
 ENCRYPTION BY CERTIFICATE CertTest ;
GO
--Grant Permissions
GRANT CONTROL ON CERTIFICATE::CertTest TO EncryptionUser;
GO
GRANT VIEW DEFINITION ON SYMMETRIC KEY::SymKeyTest TO EncryptionUser;
GO
GRANT EXECUTE ON SCHEMA::[dbo] TO [ApplicationUser]
GO
GRANT SELECT ON SCHEMA::[dbo] TO [ApplicationUser]
GO
--Create Table
CREATE TABLE [dbo].[EncryptionTest](
 [EncryptionTestId] [int] IDENTITY(1,1) NOT NULL,
 [EncryptionNumber] [varbinary](100) NOT NULL,
 [PlainTextNumber] [int] NOT NULL)
GO 
--Create Test procedures
CREATE PROCEDURE dbo.getEncryption
 @EncryptionTestId INT 
AS 
BEGIN 
 SELECT EncryptionTestId
 ,PlainTextNumber
 ,CONVERT(VARCHAR(10),DecryptByKeyAutoCert(cert_id('CertTest'),NULL,EncryptionNumber)) DecryptedNumber
 FROM dbo.EncryptionTest
 WHERE EncryptionTestId = @EncryptionTestId
END 
GO 
CREATE PROCEDURE dbo.getEncryptionWithExecute
 @EncryptionTestId INT 
WITH EXECUTE AS 'EncryptionUser'
AS 
BEGIN 
 SELECT EncryptionTestId
 ,PlainTextNumber
 ,CONVERT(VARCHAR(10),DecryptByKeyAutoCert(cert_id('CertTest'),NULL,EncryptionNumber)) DecryptedNumber
 FROM dbo.EncryptionTest
 WHERE EncryptionTestId = @EncryptionTestId
END
GO
--Populate table
OPEN SYMMETRIC KEY SymKeyTest
DECRYPTION BY CERTIFICATE CertTest ;
DECLARE @Encrypt VARCHAR(10) ;
DECLARE @i INT = 10
WHILE @i > 0 
 BEGIN 
 SELECT @Encrypt = ROUND(((99999) * RAND()),0)
 INSERT INTO dbo.EncryptionTest
 (EncryptionNumber
 ,PlainTextNumber
 )
 VALUES (ENCRYPTBYKEY(KEY_GUID('SymKeyTest'),@Encrypt)
 ,@Encrypt
 )
 SET @i = @i - 1
 END 
CLOSE SYMMETRIC KEY SymKeyTest ;
GO

Now we can run a test for each user to see how they act when selecting from the table or running the stored procedures. Here we will use the Execute As Login to test running everything as the EncryptionUser.

EXECUTE AS LOGIN = 'EncryptionUser'
EXEC dbo.getEncryption
EXEC dbo.getEncryptionWithExecute
SELECT * FROM dbo.EncryptionTest
REVERT

Since this user has no select or execute permissions all three statements will fail. Here are the results.

Msg 229, Level 14, State 5, Procedure getEncryption, Line 1

The EXECUTE permission was denied on the object 'getEncryption', database 'MyTesting', schema 'dbo'.

Msg 229, Level 14, State 5, Procedure getEncryptionWithEXECUTE, Line 1

The EXECUTE permission was denied on the object 'getEncryptionWithEXECUTE', database 'MyTesting', schema 'dbo'.

Msg 229, Level 14, State 5, Line 5

The SELECT permission was denied on the object 'EncryptionTest', database 'MyTesting', schema 'dbo'.

Now let's try the running the code with the Execute As Login for the ApplicationUser.

EXECUTE AS LOGIN = 'ApplicationUser'
SELECT EncryptionTestId
 ,PlainTextNumber
 ,CONVERT(VARCHAR(10),DecryptByKeyAutoCert(cert_id('CertTest'),NULL,EncryptionNumber)) DecryptedNumber
FROM dbo.EncryptionTest
REVERT

The Application user has permissions to run the select query, but it does not have permissions to decrypt the encrypted column. This is why the results return a null value for the column.

Now when you execute the stored procedure getEncryption (this is the procedure without EXECUTE AS 'EncryptionUser') as the ApplicationUser, it runs without error, but it is unable to decrypt the encrypted number.

EXECUTE AS LOGIN = 'ApplicationUser'
 EXEC dbo.getEncryption @EncryptionTestId = 3 
REVERT

Results

When ApplicationUser runs the stored procedure getEncryptionWithExecute (this is the procedure with EXECUTE AS 'EncryptionUser'), it is able to decrypt the encrypted number.

EXECUTE AS LOGIN = 'ApplicationUser'
 EXEC dbo.getEncryptionWithExecute @EncryptionTestId = 3
REVERT

Results

By using the "execute as" I am better able to control which users have access to the encrypted data, and how they have access to this data. "Execute As" also gives me the ability to test running a stored procedure or select statement as a different user, without having to login as that user.

Rate

4.56 (41)

You rated this post out of 5. Change rating

Share

Share

Rate

4.56 (41)

You rated this post out of 5. Change rating