Cross-database ownership NOT working
-
07-04-2021 - |
Question
I've read an article
http://www.sommarskog.se/grantperm.html#ownershipchaining
which has a very good information regarding ownership chaining in SQL Server.
So this is what i've done on my SQL Server 2008,
- Created 2 databases DatabaseA, DatabaseB with login sa
- Created a procedure 'TestProc' in DatabaseA which executes a procedure in DatabaseB
- Created a login 'testuser'
- Added this login as a user in DatabaseA and give rights to execute procedure 'TestProc'
As you can see my goal is to make 'testuser' execute a procedure in DatabaseB without adding this user in DatabaseB and without giving him direct execution rights on procedure in DatabaseB.
I did enable the Ownership Chaining on Server Level and on both Databases. I've restarted the SQL Server Service.
But still getting this error
Msg 916, Level 14, State 1, Procedure TestProc, Line 18 The server principal "testuser" is not able to access the database "DatabaseB" under the current security context.
Am I missing something here?
Solution
Ownership chaining works for objects inside a database. It does not allow you to enter the database itself. So you have to create a login in any database you read from, like:
use DatabaseB
exec sp_grantdbaccess 'testuser'
Ownership chaining does grant rights on the stored procedure. So the database login can be devoid of any permissions. It just has to exist.
Query that creates two test databases and calls a procedure in one:
use master
if exists (select * from sys.databases where name = 'TestDatabase1')
drop database TestDatabase1
if exists (select * from sys.databases where name = 'TestDatabase2')
drop database TestDatabase2
create database TestDatabase1
go
use TestDatabase1
exec sp_changedbowner 'sa'
go
create procedure dbo.sp1 as select 'hello world!'
go
create database TestDatabase2
go
use TestDatabase2
exec sp_changedbowner 'sa'
go
create procedure dbo.sp2 as exec TestDatabase1.dbo.sp1
go
use TestDatabase2
exec sp_grantdbaccess 'testuser'
grant execute on sp2 to testuser as dbo
use TestDatabase1
-- Either of the below lines would work
-- exec sp_grantdbaccess 'guest'
-- exec sp_grantdbaccess 'testuser'
use TestDatabase2
execute as login = 'testuser'
exec sp2
revert -- Revert back to original login
Query to display ownership for databases and procedures:
select d.name
, l.name
from sys.databases d
join sys.syslogins l
on d.owner_sid = l.sid
where d.name like '...your database...'
select p.name
, dp.name
from TestDatabase.sys.procedures p
join TestDatabase.sys.schemas s
on s.schema_id = p.schema_id
join TestDatabase.sys.database_principals dp
on s.principal_id = dp.principal_id
where p.name like '...your stored procedure...'