When a user executes a stored procedure, does permission for each object (table, view or function) called inside the stored procedure is checked?
Answer is No. SQL Server uses a concept called Ownership Chaining to decide whether permission for an referenced object would be checked or not. Permission is checked whenever ownership chaining breaks. Let’s understand it with an example.
Here we take three users: UserA, UserB and UserC
UserA owns a table tblUserA
UserB owns a table tblUserB
UserA grants SELECT permission on table tblUserA to UserB.
UserB create a stored procedure usp_UserB in which both tables are used.
UserB grant EXECUTE permission on stored procedure to UserC.
Now take different execution scenario and status:
SP statements | UserB execute | UserC execute | ||
Permission check | Statement result | Permission check | Statement result | |
Execute usp_UserB | No | Success | Yes | Success |
SELECT * FROM tblUserB | No | Success | No | Success |
SELECT * FROM tblUserA | Yes | Success | Yes | Failed |
Stored procedure execution status | Successfully completed | Failed | ||
From the above result we can conclude that permission is checked at every statement where owner of called object changes. If all referenced objects are owned by owner of stored procedure or view then this ownership scenario is called unbroken ownership chaining. But if owner of any referenced object changes then its called broken ownership chaining.
The script to verify the above explanation is as below:
CREATE LOGIN UserA WITH PASSWORD = 'usera', CHECK_POLICY=OFF
CREATE LOGIN UserB WITH PASSWORD = 'userb', CHECK_POLICY=OFF
CREATE LOGIN UserC WITH PASSWORD = 'userc', CHECK_POLICY=OFF
GOUSE TestGOCREATE USER UserA
CREATE USER UserB
CREATE USER UserC
GOsp_addrolemember 'db_ddladmin', N'UserA'
GOsp_addrolemember 'db_ddladmin', 'UserB'
GOsp_addrolemember 'db_ddladmin', 'UserC'
GOCREATE SCHEMA SchemaA AUTHORIZATION UserA
GOCREATE SCHEMA SchemaB AUTHORIZATION UserB
GOCREATE SCHEMA SchemaC AUTHORIZATION UserC
GOEXECUTE AS USER = 'UserA'
GOCREATE TABLE SchemaA.tblUserA (col1 INT)
GOGRANT SELECT ON SchemaA.tblUserA TO UserB
GOREVERT
GOEXECUTE AS USER = 'UserB'
GOCREATE TABLE SchemaB.tblUserB (col1 INT)
GOCREATE PROC SchemaB.usp_UserB
ASSELECT * FROM SchemaB.tblUserB
SELECT * FROM SchemaA.tblUserA
GOGRANT EXECUTE ON SchemaB.usp_UserB TO UserC
GOEXEC SchemaB.usp_UserB -- completes successfully
GOREVERT
GOEXECUTE AS LOGIN = 'UserC'
GOEXEC SchemaB.usp_UserB -- Failing with error: The SELECT
-- permission was denied on the -- object 'tblUserA', schema 'SchemaA'.If for testing you have executed the above script in your database then to undo all changes execute the below script:
REVERT
GOREVERT
GOdrop table SchemaA.tblUserA
drop table SchemaB.tblUserB
DROP PROC SchemaB.usp_UserB
DROP SCHEMA SchemaA
DROP SCHEMA SchemaB
DROP SCHEMA SchemaC
GOdrop user UserA
drop USER UserB
drop USER UserC
GOdrop LOGIN UserAdrop LOGIN UserBdrop LOGIN UserC
No comments:
Post a Comment