views:

1336

answers:

4

Hello I have a table on which I have denied SELECT privs to a user.
This table has a trigger which references the INSERTED table, basically doing an

AFTER UPDATE SET <table>.[UPDATED] = getdate() 
  WHERE ROWID IN SELECT ROWID FROM INSERTED

It is giving me an error though, saying "SELECT PERMISSIONS DENIED", I am guessing because of the SELECT FROM INSERTED.

How can I keep the SELECT deny, but allow the trigger to SELECT from the INSERTED pseudotable?

Thanks in advance!

A: 

join to the inserted table instead something like:

update t1
set updated = getdate()
from table1 t1
join inserted i
on i.rowid = t1.rowid

This will probaly also perfom better than a subselect anyway.

HLGEM
Hmm... no go. Just for fun I tried commenting out the trigger body, so it shouldn't be SELECTing anything, but i still get the error. I really don't know why though, because all i am doing is UPDATE site.CONTENT SET NAME = 'Contact Us', CONTENT = 'Hi there! You can contact us at 212.555.1212.<br /><br />Wicked Cheers!<br />' WHERE ROWID = 2And there is only the one trigger on the table. So i don't see where it is doing a SELECT. Even SQL Profiler doesn't show any SELECT statements happening in the transaction. GRRR... well, thanks anyway, guess i'll have to cxome back to this.
eidylon
(oops, didn't realize it doesn't use the formatting rules when posting comments)
eidylon
+1  A: 

Why did you deny select? What about just not granting select to them? There is a subtle difference between denying select and just not granting it to them. Also, if you denied select to any of the system level roles, then that would also probably be part of the problem.

--EDIT--

In the comments you asked whether or not SQL Server has context info. 2005 does and you can see how to use it here.

Session Variable – Context_Info: Session is a powerful tool in any of the programming language. SQL-Server is not a full fledge programming language but it do supports session variable for current session or connection. It stores value of session in 128 byte of binary information.

Nick DeVore
Well, what we have is a database which has a SITEID on several of the tables, and is using that to sort of recreate the Virtual DB functionality of ORACLE... so multiple websites run off this db, and they filter their results from these tables by SITEID. What I had wanted to do was to deny SELECT on the table, and force the website login to use a set of table-valued functions to access these tables, which take in SITEID as a parameter. This way the site would never inadvertently do a SELECT without the SITEID getting back the records for ALL the sites.
eidylon
Perhaps a stored procedure is what you're really after then. Or, maybe views filtered by site id would be best? Denying select is not going to help you with this problem though.
Nick DeVore
Well, the denying select was really just to forcibly make sure that none of the web code called the tables directly inadvertently. The functions really are best i think, since you cannot directly select from the table results of a sproc. Using a table-valued function allows using the function name directly in a select statement. But even with a sproc or TVF, it would be possible to still select from the main tables by accident. Does Sql provide a way to do parameterized views? Or did you mean just a separate view for each site?
eidylon
A separate view for each site.
Nick DeVore
yah, that's really not ideal, because then there would be a separate copy of each one for each site, and it's 5 tables, so 4 sites would clutter the db with 20 different views.thanks for the ideas though. Sql Server doesn't actually have the idea of CONTEXT variables like what powers Oracle's VDBs, does it?
eidylon
A: 

I suspect your problem is that your UPDATE statement itself requires the SELECT permission.

I created a test database as follows:

DROP DATABASE triggerPermissionTest
CREATE DATABASE triggerPermissionTest
GO
USE triggerPermissionTest
GO
CREATE USER foo FROM LOGIN tester
GO
CREATE TABLE triggerTable (id int)
GO
DENY SELECT ON triggerTable to foo
GRANT UPDATE ON triggerTable to foo
GO
CREATE TRIGGER execAsTrigger ON triggerTable
AFTER UPDATE AS SELECT * FROM triggerTable
GO
INSERT INTO triggerTable VALUES (1)
GO

and tried the following Update statements with the 'tester' login:

UPDATE triggerTable SET id = 2
GO
UPDATE triggerTable SET id = id *2
GO

The first one executes fine and the trigger executes (providing the results of select * from triggerTable to the user without select permissions, demonstrating that it managed to do a select).

The second one gives me an error stating that I don't have select permission on triggerTable (because it needs to select from triggerTable in order to get the value of id to do the update).

This leads me to conclude that the trigger is incidental to the problem, and the UPDATE statement is the cause of the permission issue.

+2  A: 

Consider adding an EXECUTE AS clause so the trigger runs with the schema owner's permissions.

CREATE TRIGGER [dbo].[TR_Product_Update] ON [Product]
   WITH EXECUTE AS OWNER
   AFTER UPDATE
AS
SELECT ProductId
FROM INSERTED
Anthony Faull