Reputation: 15
I have a role with execute on schema, and a user that should be able to execute every procedure that he see (under that schema), but those procedures are using tables/views from separate database that that user should not be able to see.
Here is working solution but only if all components (table and procedure) are in same database, and with queries from this link I know that there are no any denied access for user/role:
Maybe there is some role setup that I should Use? Below there is basic example what I want achieve:
USE [master];
GO
CREATE DATABASE [temporary1];
CREATE DATABASE [temporary2];
CREATE LOGIN [hero1] WITH PASSWORD = 'batman', CHECK_POLICY = OFF;
---------------
USE [temporary1];
GO
CREATE USER [hero1] FROM LOGIN [hero1];
CREATE TABLE [dbo].[test_table] ([id] INT);
INSERT [dbo].[test_table] VALUES(1);
---------------
USE [temporary2];
GO
CREATE USER [hero1] FROM LOGIN [hero1];
---------------
CREATE PROCEDURE [dbo].[inter_database_secret]
AS
BEGIN
SELECT [id] FROM [temporary1].[dbo].[test_table];
END
---------------
GRANT EXECUTE ON [temporary2].[dbo].[inter_database_secret] TO [hero1]
---------------
EXECUTE AS USER = 'hero1';
GO
EXECUTE [temporary2].[dbo].[inter_database_secret]; --<---- Sad Error Here
REVERT;
---------------
USE [master];
GO
DROP DATABASE [temporary1];
DROP DATABASE [temporary2];
DROP LOGIN [hero1];
Upvotes: 1
Views: 924
Reputation: 89141
Almost there. Two small issues. First, you have to explicitly configure cross-database ownership chaining. It's off by default. Second is that you have to impersonate hero1's login, not the database user. hero1 the database principal (user) doesn't have access to the other database. hero1 the server principal (login) does. So
USE [master];
GO
CREATE DATABASE [temporary1];
CREATE DATABASE [temporary2];
CREATE LOGIN [hero1] WITH PASSWORD = 'batman', CHECK_POLICY = OFF;
ALTER DATABASE [temporary1] SET DB_CHAINING ON;
ALTER DATABASE [temporary2] SET DB_CHAINING ON;
go
USE [temporary1];
GO
CREATE USER [hero1] FROM LOGIN [hero1];
CREATE TABLE [dbo].[test_table] ([id] INT);
INSERT [dbo].[test_table] VALUES(1);
---------------
USE [temporary2];
GO
CREATE USER [hero1] FROM LOGIN [hero1];
go
CREATE PROCEDURE [dbo].[inter_database_secret]
AS
BEGIN
SELECT [id] FROM [temporary1].[dbo].[test_table];
END
go
GRANT EXECUTE ON [temporary2].[dbo].[inter_database_secret] TO [hero1]
go
use [temporary2]
go
EXECUTE AS login = 'hero1';
EXECUTE [dbo].[inter_database_secret]; --<---- Happy Result Here
REVERT;
go
USE [master];
GO
DROP DATABASE [temporary1];
DROP DATABASE [temporary2];
DROP LOGIN [hero1];
Upvotes: 1