[UPDATE 8/24/2010]: I added a companion post covering the theory behind this demo.
There is an excellent article on this topic in Books Online: Extending Database Impersonation by Using Execute As. I just wrote a small demo to illustrate the techniques described in that article. It can be used as a companion to that article, if you're looking for a more hands-on approach to learning about this subject. The demo is quite long and I have plenty of comments describing what is going on, but I'll include a short description as well: We have two database owners, Alice and Bob. Charles is a third principal that has access to some objects in Bob's database. We're looking at methods that allow (and restrict) how Alice can impersonate Charles inside her database and how she can then attempt to access the objects from Bob's database. The demo shows how the TRUSTWORTHY bit can be used and then it shows an alternative method of using a certificate as an authenticator. For the latter method, I also showed how Bob can allow Alice to sign a procedure without granting her access to the private key of the certificate used for signing. So here's the demo:
-- A demo for cross database access-- -- create our principals: alice, bob, charles--
-- create our principals: alice, bob, charles--
create login alice with password = 'SimplePwd01'create login bob with password = 'SimplePwd01'create login charles with password = 'SimplePwd01'
-- create two databases owned by alice and bob--
db_bob
alter
bob
--###################--#Setting up db_bob#--###################
use
-- execute the following as bob, this database's dbo--
'bob'
-- add charles to bob's database--
charles
-- create a table and a procedure accessing it,-- both owned by charles--
)
create
sys.user_token
end alter
-- verify the selection procedure--
'charles'
exec
proc_select_t
-- revert impersonation of charles--
revert
-- revert impersonation of bob--
--#####################--#Setting up db_alice#--#####################
db_alice
-- execute the following as alice, this database's dbo--
'alice'
-- add charles to alice's database--
-- note that alice cannot impersonate charles at server level-- the following call will produce an ERROR!--
-- however, being the dbo, she can impersonate charles at database level--
select
-- create a procedure for cross database access--
go
-- call the procedure, to impersonate charles and access bob's database--
-- revert the impersonation of alice--revert
--####################################--#Setting up db_alice as trustworthy#--#################################### -- let's mark alice's database as trustworthy--
--####################################--#Setting up db_alice as trustworthy#--####################################
-- let's mark alice's database as trustworthy--
on
--###################################--#Checking proc_crossdb in db_alice#--###################################
-- now let's see if this changes anything--
---- we now see alice as an authenticator,-- but bob doesn't trust alice to authenticate,-- so it still doesn't work
--#######################################################--#Setting up alice as trusted to authenticate in db_bob#--#######################################################
-- let's make bob trust alice to authenticate--
execute
alice
grant
-- let's see how things work now--
---- the token authenticated by alice is now accepted
--##########--#Comments#--##########
-- unfortunately, this method would also allow alice-- to rewrite the proc_crossdb procedure and call proc_drop_t instead---- what do we do if we don't trust alice, but we'd like to enable the select scenario?---- signing allows better control because it requires trusting code not principals
--##################################################--#Cleaning up db_bob and setting it up for signing#--##################################################
-- first, let's remove the trustworthy setting on alice's database-- and bob's trust in alice as an authenticator--
off use
-- remove alice, which will drop any permissions as well--
-- now we'll use signing to enable cross database access-- we'll create a certificate and a principal mapped to it-- that will be used as authenticator--
'Sign procedures in Alice''s database'
cert_sign_alice
u_cert_sign_alice
-- we create and sign the proc_crossdb procedure in bob's database,-- because we don't want to give the private key of the certificate to alice--
exec db_bob.dbo.proc_select_tendgo
add
'SimplePwd01'
-- retrieve the signature from the catalogs--
---- the value returned will change because the certificate will be generated randomly-- we need to copy the returned value-- for my execution, I got back:-- 0x17B803D0550C450AD4D815CB2CEB730E941E2F8BD41B6848B2546D0657E7F85FEDA69FF9048F358AECCBE0B7E9B4AC3F7420513AB539E6B87C8E638FB9AF2F557A3CB389D4ECA72DE1C34523AEDF48E2AB290AA94EC496CBAF527D3D0B95B7395DD7A77ED06A0894102C653DFC6425A317DD383B4F79C8AF8A7A5A62E5AA1899 -- backup the public key of the certificate to a file alice can access-- remember that the private key is needed for signing and the public key-- is only used for verification, hence alice won't be able to arbitrarily sign code--
-- backup the public key of the certificate to a file alice can access-- remember that the private key is needed for signing and the public key-- is only used for verification, hence alice won't be able to arbitrarily sign code--
---- if you rerun this script, you'll get an error if you already created the file-- you can either change the name of the file or drop the old file
---- we're done, now alice just has to take the signature and the certificate-- and apply the signature to the exact same procedure - she cannot change the code-- or the signature won't work-- bob can provide all these (procedure, certificate, and signature) to alice --#################################--#Setting db_alice to use signing#--#################################
--#################################--#Setting db_alice to use signing#--#################################
'cert_sign_alice.cer'
0x17B803D0550C450AD4D815CB2CEB730E941E2F8BD41B6848B2546D0657E7F85FEDA69FF9048F358AECCBE0B7E9B4AC3F7420513AB539E6B87C8E638FB9AF2F557A3CB389D4ECA72DE1C34523AEDF48E2AB290AA94EC496CBAF527D3D0B95B7395DD7A77ED06A0894102C653DFC6425A317DD383B4F79C8AF8A7A5A62E5AA1899
-- note that the certificate will appear as authenticator,-- which will enable the context to be trusted in bob's database,-- allowing the call to go through--
proc_crossdb
-- Let's see what happens if alice attempts to do something different in the procedure,-- such as attempting to drop the table--
end
-- won't work because impersonated context is not authenticated--
-- let's try to add the signature--
---- it won't work because signature is not valid-- alice's attempt has failed - she can only use the signature-- with the code provided by bob
--#########--#Cleanup#--#########
master
drop
---- EOD