Reputation: 25
I'm trying to create a view in MSSQL2008 that provides some specific details from system tables, as the users of this view don't have access to the system tables themselves. Is there a way to give provide permission for them to see that data via the view but not access it directly from the table? Like giving the view a specific user to execute under regardless of who is calling the view (providing that user has permission to select from the view).
I've found permissions to select from the view, select from the table, but not the in-between that I'm looking for.
Upvotes: 0
Views: 874
Reputation: 95561
As I mentioned (in my deleted comment), provided that the 2 objects, in this case the TABLE
and VIEW
, have the same owner then a USER
using the object can make use of ownership chaining. So if the USER
has access to SELECT
from the VIEW
but not the TABLE
, when they query the VIEW
they will be given implicit permission to be able to query the table, as they are owned by the same user.
This chaining can continue on afterwards. For example, a PROCEDURE
that references a VIEW
, that references 3 TABLE
s and then INSERT
s into a 4th. The USER
might only have access to use the PROCEDURE
, but if all the objects are owned by the same USER
, then the permissions will be implicitly given to both SELECT
and INSERT
within the context of the PROCEDURE
.
This is explained in more detail in the documentation.
As a simple example, see the below, where the user SomeUser
successfully manages to SELECT
from the VIEW
, despite the explicit DENY
on the underlying table. In this case, on my instance, both objects are owned by the dbo
user:
--Create table
CREATE TABLE dbo.SomeTable (SomeID int IDENTITY,
SomeDate datetime DEFAULT GETDATE());
GO
--Some Rows
INSERT INTO dbo.SomeTable
DEFAULT VALUES;
GO 25
--Create view
CREATE VIEW dbo.SomeView AS
SELECT SomeDate
FROM dbo.SomeTable;
GO
--See Owners
SELECT o.[name] AS ObjectName, dp.[name] AS OwningUser
FROM sys.objects o
JOIN sys.schemas s ON s.schema_id = o.schema_id
JOIN sys.database_principals dp ON o.principal_id = dp.principal_id
OR (o.principal_id IS NULL AND s.principal_id = dp.principal_id)
WHERE o.[name] IN (N'SomeTable','SomeView');
GO
--Create User
CREATE USER SomeUser WITHOUT LOGIN;
GO
--Grant SELECT on View, DENY on Table
GRANT SELECT ON dbo.SomeView TO SomeUser;
DENY SELECT ON dbo.SomeTable TO SomeUser;
GO
--Switch User Context
EXECUTE AS USER = 'SomeUser';
GO
--Run Select
SELECT *
FROM dbo.SomeView;
GO
--Revert context
REVERT
GO
--Clean up
DROP USER SomeUser;
DROP VIEW dbo.SomeView;
DROP TABLE dbo.SomeTable;
Upvotes: 2