Showing posts with label triggers. Show all posts
Showing posts with label triggers. Show all posts

Monday, March 26, 2012

Permissions using CLR triggers

It seems that there is a difference between the way t-sql permissions and CLR permissions work. I don't know if this is a fault of SQL2005 or of my coding - perhaps someone can tell me.

E.g. Assume there are two tables called test1 and test2 with no permissions granted to anyone on them. Below is a simple trigger that inserts into test2 when test1 is updated

CREATE TRIGGER tr_test ON test1 FOR UPDATE AS
BEGIN
DECLARE @.v INT
SELECT @.v = MAX(ID) FROM test1
INSERT INTO test2 (audit) VALUES ('The max value is currently: ' + CONVERT(VARCHAR(10),@.v))
END
GO

Attempting to update a row from a non-DBO account will fail (because the user does not have update permissions). This is of course correct.

Now assume we have a stored proc that updates the row in test1. We can grant EXEC permission to the stored proc and, hey presto, everything works.

Now, the problem. If the above trigger were written like this instead:-

[Microsoft.SqlServer.Server.SqlTrigger (Name="tr_test", Target="test1", Event="FOR UPDATE")]
public static void Trigger1()
{
using (SqlConnection conn = new SqlConnection("Context Connection = true"))
{
conn.Open();

SqlCommand cmd = new SqlCommand("select max(id) from test1", conn);
SqlDataReader rdr = cmd.ExecuteReader();
rdr.Read();
int val = rdr.GetInt32(0);
rdr.Close();

string s = string.Format("The max value is currently: {0}", val);
cmd = new SqlCommand("insert into test2 (audit) values (@.p)", conn);
cmd.Parameters.AddWithValue("@.p", s);
cmd.ExecuteNonQuery();
}
}

This is functionally equivalent to our previous trigger. However, running our stored proc again fails this time because we don't have SELECT permissions on test1.

So ultimately my question is, how do I get this to work without having to grant permissions to the tables?

Thanks

swg

You should be using the 'inserted' and 'deleted' tables. What you are doing is requerying the table (therefore you need select rights).

So it should read something like: select max(id) from inserted

Cheers

Paul.

|||

The problem is that your CLR trigger breaks ownership chaining because it executes the sql code like dynamic sql. It has the same effect as using sp_executesql to make the query in your t-sql trigger, which would fail for the same reason.

Erland covers this in-depth here http://www.sommarskog.se/grantperm.html#ownershipchaining

There are two ways to work around this:

1. using the EXECUTE AS clause on your CLR trigger so that the trigger has access to the tables. Erland's article above is a good reference on how to do this and the potential pitfalls that should be avoided.

2. having your CLR trigger call a T-SQL stored proc to make the update, which shouldn't break the ownership chain. You can do this with SqlCommand.CommandType = CommandType.StoredProcedure

Steven

|||

Thanks for the responses guys.

Paul, yes I agree that would have been a better example. However, the same symptom occurs if you access the inserted/deleted trigger tables.

Steven, thanks very much. I'll give your options some consideration.

This would seem to me to be a deficiency in the CLR/SQL Server integration. Although I can see (now that you have pointed it out to me) why the CLR case is different, I would hope I'm not alone in thinking that when SQL2005 offers us CLR for use with triggers and stored procs, the developer should not expect that the CLR equivalent version to operate differently. Certainly I didn't expect this to be the case and the connection string "Context Connection = true" reinforced this. Obviously I cannot excercise your option 2 in a normal trigger because I will not have access to the inserted/deleted tables from a stored proc. However, the EXECUTE AS may offer some hope although it is still a kludge.

Many thanks

~swg

|||

Well just to put the cat among the pigeons, I've just done a small test app and, yes, sure enough everything worked fine. So I revoked the select permission on the table in my original app (the one that caused me to start this thread in the first place) and, yup, that's working fine too. So, God only knows what bug I had in there but it ain't there any more... or maybe I've written a new one in there to make the whole thing work now, who knows!

But certainly, going step-by-step and re-checking the permissions are there (or not there as appropriate) at each stage; it would seem the ownership chain is NOT broken when selecting from the inserted/deleted tables in a CLR trigger.

Cheers

~swg

Addedndum: To be clear, the ownership chain IS still broken if you follow my example (in the original post above) as explained in Steven's reply, because it does not use the inserted/deleted tables

|||

Your original example didn't use Inserted/Updated tables, CLR Triggers can access those fine as they are not real tables and don't have the same ownership concept.

However, your CLR trigger will still not be able to access your audit table test2 without doing one of the workarounds I mentioned above. This is not the case for a T-SQL trigger. Here is a full scenario based on your example demonstrating this:

public class triggers

{

public static void Trigger1()

{

using (SqlConnection conn = new SqlConnection("Context Connection = true"))

{

conn.Open();

SqlCommand cmd = new SqlCommand("select count(*) from inserted", conn);

Int32 val = (Int32)cmd.ExecuteScalar();

SqlContext.Pipe.Send("Inserted: " + val.ToString());

cmd = new SqlCommand("insert into test2 values (@.p)", conn);

cmd.Parameters.AddWithValue("@.p", val);

cmd.ExecuteNonQuery();

}

}

}

create assembly SimpleTrigger from 'c:\assemblies\SimpleTrigger.dll'

go

create table test1(c1 int)

go

create table test2(c1 int)

go

create proc InsertTest @.input int

as

begin

insert into test1 values(@.input)

end

go

create trigger Trigger1 on test1 for insert as external name SimpleTrigger.triggers.Trigger1

go

create user user1 without login

go

grant execute on InsertTest to user1

go

execute as user='user1'

go

--CLR Trigger fails to update test2 because it does not have permission

exec InsertTest 1

go

revert

go

drop trigger Trigger1

go

create trigger Trigger1 on test1 for insert

as

begin

insert into test2 select count(*) from inserted

end

go

execute as user='user1'

go

--T-SQL trigger is able to update test2

exec InsertTest 1

go

revert

go

drop user user1

drop proc InsertTest

drop table test1

drop table test2

drop assembly SimpleTrigger

|||

Sure thing, Steven

Absolutely agree. I hope you didn't take my last reply as a slur or contradiction of your answer. Most certainly wasn't intended that way. As I said in an earlier reply to Paul, my original post was a bad example; it should have contained inserted/deleted tables. That was why I couldn't understand why the CLR triggers wouldn't work. They would be next to useless if you couldn't access these tables.

My "real" situation was that the CLR trigger could not access the inserted table and granting select permission to the underlying table fixed the problem. There must have been something else at play somewhere though (and I'd like to know what) because I have now revoked select permission from this underlying table and my trigger continues to function correctly.

So, apologies for the confusion. I do appreciate your replies and it has helped me a lot in understanding ownership chains, and the differences between T-SQL and CLR triggers.

Thanks again

~swg

|||

No offense taken - I just wanted to make sure it was completely clear both to you and to those playing along at home. What's happening here isn't exactly obvious and I'm don't think it's clearly stated in BOL either.

Steven

Wednesday, March 21, 2012

Permissions on a SP

I have created and tested two triggers directly on the local server
and both work as they should. I initially had a problem with
xp_smtp_sendmail that was returning a 500.1
Internal server permissions error, I corrected this with applying the
correct permissions.
Both triggers work when activated from a direct logon but fail without
any error message when activated from the internet. Do I need to create
the necessary permissions on more stored procedures, or can I recreate a
SP from the master DB and copy it, if someone could point me in the right
direction it would be greatly appreciated.
JohnDon't send email from within a trigger. There is really no need to hold open
a transaction while you do this and you don't want to block other
transactions if the XP is slow in returning control to the trigger. Also, yo
u
want to avoid giving users the ability to run XPs in Master, even indirectly
,
if you can. The lack of execute permissions is what is causing this error
message.
Since Email is an inherently asynchronous medium it is easier and better to
schedule this with a SQL Agent based job running at suitable intervals.
Record whatever changes are required in a table and then use a job to pick
those up and send emails.
David Portas
SQL Server MVP
--|||Thanks David for the sound advice.
John
"David Portas" <REMOVE_BEFORE_REPLYING_dportas@.acm.org> wrote in message
news:10552FB0-890C-4036-80CD-CE40EE612444@.microsoft.com...
> Don't send email from within a trigger. There is really no need to hold
> open
> a transaction while you do this and you don't want to block other
> transactions if the XP is slow in returning control to the trigger. Also,
> you
> want to avoid giving users the ability to run XPs in Master, even
> indirectly,
> if you can. The lack of execute permissions is what is causing this error
> message.
> Since Email is an inherently asynchronous medium it is easier and better
> to
> schedule this with a SQL Agent based job running at suitable intervals.
> Record whatever changes are required in a table and then use a job to pick
> those up and send emails.
> --
> David Portas
> SQL Server MVP
> --

Friday, March 9, 2012

permissions

Hi All,
how I can setup a role, so that they can only create, drop stored procedure,
views and functions. and can't create triggers, tables or modify schema.
Tim
grant create procedure, create view, create function to <login>
----
Need SQL Server Examples check out my website at
http://www.geocities.com/sqlserverexamples
"t" <t@.t.t> wrote in message news:ehIWCmpaEHA.4048@.TK2MSFTNGP10.phx.gbl...
> Hi All,
> how I can setup a role, so that they can only create, drop stored
procedure,
> views and functions. and can't create triggers, tables or modify schema.
>
> Tim
>
>

permissions

Hi All,
how I can setup a role, so that they can only create, drop stored procedure,
views and functions. and can't create triggers, tables or modify schema.
Tim
Hi,
You can only assign CREATE PROC, CREATE FUNCTION, CREATE VIEW to a
USER/ROLE. The DROP
permissons for any of this objects is not grantable.
Thanks
Hari
MCDBA
"t" <t@.t.t> wrote in message news:eXYPwlpaEHA.384@.TK2MSFTNGP10.phx.gbl...
> Hi All,
> how I can setup a role, so that they can only create, drop stored
procedure,
> views and functions. and can't create triggers, tables or modify schema.
>
> Tim
>
>

permissions

Hi All,
how I can setup a role, so that they can only create, drop stored procedure,
views and functions. and can't create triggers, tables or modify schema.
Timgrant create procedure, create view, create function to <login>
----
----
--
Need SQL Server Examples check out my website at
http://www.geocities.com/sqlserverexamples
"t" <t@.t.t> wrote in message news:ehIWCmpaEHA.4048@.TK2MSFTNGP10.phx.gbl...
> Hi All,
> how I can setup a role, so that they can only create, drop stored
procedure,
> views and functions. and can't create triggers, tables or modify schema.
>
> Tim
>
>

permissions

Hi All,
how I can setup a role, so that they can only create, drop stored procedure,
views and functions. and can't create triggers, tables or modify schema.
Timgrant create procedure, create view, create function to <login>
----
----
--
Need SQL Server Examples check out my website at
http://www.geocities.com/sqlserverexamples
"t" <t@.t.t> wrote in message news:ehIWCmpaEHA.4048@.TK2MSFTNGP10.phx.gbl...
> Hi All,
> how I can setup a role, so that they can only create, drop stored
procedure,
> views and functions. and can't create triggers, tables or modify schema.
>
> Tim
>
>