How to check Procedure Ownership? - snowflake-cloud-data-platform

On Snowflake that is easy to check other objects ownership by running (e.g.): "SHOW TABLES" - column OWNER will be there.
If, however, we try "SHOW PROCEDURES", ownership is not shown.
Do we have a workaround for that?

Using INFORMATION_SCHEMA.PROCEDURES:
This Information Schema view displays a row for each stored procedure defined in the specified (or current) database.
PROCEDURE_OWNER Name of the role that owns the stored procedure
SELECT *
FROM INFORMATION_SCHEMA.PROCEDURES
WHERE PROCEDURE_NAME ILIKE '<procedure_name_here>';

Related

Snowflake having Grants persist , when table re-creates every day during ETL

I have to 'Grant References' to a table in snowflake that gets 'create(d) or replace(d)' every morning as part of a daily ETL. So I have to run this every day to grant the right privilege to a certain role.
grant references on table example_table to role example_role;
I know the is a 'grant select on future', but this does not appear to exist for 'references'.
Anybody know the syntax or have an idea on how to get this grant to persist?
I cannot find anything in the snowflake docs.
CREATE OR REPLACE TABLE x (i int) COPY GRANTS
CREATE OR REPLACE VIEW x COPY GRANTS
AS
select 1 as i
Keyword is COPY GRANTS , it should work with all ddl command having create or replace syntax, of course if object does not exists it does not copy anything.
I have solved this type of issues by adding the grants as part of the ETL pipeline. For better maintenance, I created a table in snowflake which has two columns, table name and the grant required on that table. I wrote a stored procedure that looks at these tables and execute the grants. The stored procedure is part of the last step in the ETL pipeline
Snowflake's implementation of materialized views provides a number of unique characteristics which can be helpful because materialized views can improve the performance of queries that use the same subquery results repeatedly.
OR follow the syntax of these commands which may help.
"grant create materialized view on schema mydb.myschema to role myrole;"
OR
"grant operate on warehouse report_wh to role analyst with grant option"

Using application role to set default schema - commands unexpectedly uses dbo

I'm attempting to use an application role with a specific default schema to facilitate using SQL commands without schema designations, i.e. unqualified names. I need to create and work with 4+ complete sets of tables+views+etc. (each 50-100 objects) that all should work exclusively within their own schema.
To test it, I've created an application role with a suitable default schema. I then use 'sp_setapprole' to attach this role, and 'sp_unsetapprole' to revert to my previous role. This seems to be working, as SCHEMA_NAME() returns the expected schema name (and 'dbo' before 'set' and after 'unset').
While in my approle, I attempt to drop and create a table, and then insert a record into the created table. The drop/creation works fine, but the insert fails, as it attempts to insert the record into a table with a similar name in the 'dbo' schema (which it hasn't been given permission to do).
Why is it, that my (purposedly) unqualified table reference suddenly reverts to 'dbo' even though my approle dictated default schema is another ?
It also fails when I do a 'select', which again defaults to 'dbo'.
I have granted all possible permissions for my approle to the designated schema, and only SELECT to dbo.
Any help is appreciated.
Cheers
Lars
This is tricky because the object resolution is based on the default schema active when the batch is parsed. So a batch like this:
DECLARE #cookie varbinary(8000);
exec sp_setapprole a_role,'P#ssword', #fCreateCookie = true, #cookie = #cookie output
--go
select * from t
Will reference dbo.t, even if a_role has a different default schema. If you break it into two batches, then t will resolve to a.t.
Either that or you're using static SQL in a stored procedure, which is resolved relative to the procedure's schema, rather than any user's default_schema.
Apart from that, I don't think Application Roles are the right approach. You can accomplish this more simply by using impersonation than using Application Roles. EG grant the application users the right to impersonate a user who has rights only in a specific schema. Something like:
create role app_users
create user a_user without login with default_schema=a
grant select, insert, update, delete, execute on schema::a to a_user
grant impersonate on user::a_user to app_users
go
execute as user='a_user'
select * from t --resolves to a.t
select * from dbo.t --fails
revert

execute('tsql_string') inside stored procedure - what permissions/user is used for execute()?

I have a stored procedure where I'd like to save the execution of an update statement for further down in the procedure, which I'm doing by putting the sql into a varchar variable.
My problem is that the EXECUTE() seems to use the original caller's permissions and then gives an error, as the caller does not (and should not) have UPDATE permissions for table1.
Why doesn't it use the permissions of the stored procedure's owner?
And more importantly: how can I make it use those permissions?
The stored procedure looks basically like this: (except #tsql_string is set dynamically)
create procedure dbo.woopwoop() as
BEGIN
DECLARE #tsql_string varchar(max)
SET #tsql_string = 'UPDATE table1 set c1 = 1'
EXECUTE(#tsql_string)
END
I'm on SQL Server 2008, and the owner (me) of the stored procedure is a Windows Authentication user with domain\user.
Anyone?
That's what the EXECUTE AS clause exists for - to allow you to control this:
By specifying the context in which the module is executed, you can control which user account the Database Engine uses to validate permissions on objects that are referenced by the module.
CALLER
Specifies the statements inside the module are executed in the context of the caller of the module. The user executing the module must have appropriate permissions not only on the module itself, but also on any database objects that are referenced by the module.
CALLER is the default for all modules except queues
You would be wanting to specify that the stored procedure executes as OWNER (or possibly SELF, read the above page and decide which makes most sense for you) instead.
create procedure dbo.woopwoop()
with execute as owner
as
....
From MSDN (This example grants EXECUTE permission on the stored procedure HumanResources.uspUpdateEmployeeHireInfo to an application role named Recruiting11):
USE AdventureWorks2012;
GRANT EXECUTE ON OBJECT::HumanResources.uspUpdateEmployeeHireInfo
TO Recruiting11;
GO
Source
Of course you should have permission to grant the permission.

Stored Procedure and Permissions - Is EXECUTE enough?

I have a SQL Server 2008 database where all access to the underlying tables is done through stored procedures. Some stored procedures simply SELECT records from the tables while others UPDATE, INSERT, and DELETE.
If a stored procedure UPDATES a table does the user executing the stored procedure also need UPDATE permissions to the affected tables or is the fact that they have EXECUTE permissions to the stored procedure enough?
Basically I am wondering if giving the user EXECUTE permissions to the stored procedures is enough or do I need to give them SELECT, UPDATE, DELETE, and INSERT permissions to the tables in order for the stored procedures to work. Thank you.
[EDIT] In most of my stored procedures it does indeed appear that EXECUTE is enough. However, I did find that in stored procedures where "Execute sp_Executesql" was used that EXECUTE was not enough. The tables involved needed to have permissions for the actions being performed within "sp_Executesql".
Permissions on tables are not checked (including DENY) if tables and proc have the same owner. They can be in different schemas too as long as the schemas have the same owner.
See Ownership chaining on MSDN
Edit, from a comment from a deleted answer.
The context is always the current login unless EXECUTE AS as been used: only referenced object DML permissions are not checked. Try OBJECT_ID(referencedtable) in a stored proc where no rights are assigned to referencedtable. It gives NULL. If executed by the owner of the stored proc then it would give a value because owener has rights on referencedtable
Execute permissions on the stored procedure is sufficient.
CREATE TABLE dbo.Temp(n int)
GO
DENY INSERT ON dbo.Temp TO <your role>
GO
CREATE PROCEDURE dbo.SPTemp(#Int int)
AS
INSERT dbo.Temp
SELECT #Int
GO
GRANT EXEC ON dbo.SPTemp TO <your role>
GO
Then the (non-db_owner) user will have the following rights:
EXEC dbo.SPTemp 10
GO
INSERT dbo.Temp --INSERT permission was denied on the object 'Temp'
SELECT 10
However, if there is dynamic SQL inside dbo.SPTemp that attempts to insert into dbo.Temp then that will fail. In this case direct permission on the table will need to be granted.
Maybe you can use
"with execute as owner"
when you create the stored procedure, such as below:
create procedure XXX
with execute as owner
as
begin
...
end
go
Then you only need to grant the user the EXECUTE permission for the stored procedure XXX.
Execute permission on a stored procedure that does an insert, update, or delete is sufficient. You do not need to grant those permissions at the table level. In fact, I would discourage that approach. Using a stored procedure gives you more control over how the change occurs. For instance, you may wish to do some checking prior to allowing the update. Using a stored procedure can also help prevent major accidents--like deleting all the rows in the table because someone forgot the WHERE clause!
THANK YOU SO MUCH! I had a similar problem. This lead me to the answer.
I was attempting to trunctate a table in a stored procedure that called other stored procedures that were nested in IF statements.
My error was
The server principal "domain\my_id" is not able to access the database "2nd_DB" under the current security context.
I had given the calling stored procedure rights to do the truncate (EXECUTE AS SELF), which then caused a problem because SELF didn't have rights to the 2nd DB. Our solution was to move the truncate to another SP, include the EXECUTE AS SELF. We now call the truncate SP, execute our data processing, make logic determination, and call the appropriate 3rd SP.

Multi-Schema Privileges for a Table Trigger in an Oracle Database

I'm trying to write a table trigger which queries another table that is outside the schema where the trigger will reside. Is this possible? It seems like I have no problem querying tables in my schema but I get:
Error: ORA-00942: table or view does not exist
when trying trying to query tables outside my schema.
EDIT
My apologies for not providing as much information as possible the first time around. I was under the impression this question was more simple.
I'm trying create a trigger on a table that changes some fields on a newly inserted row based on the existence of some data that may or may not be in a table that is in another schema.
The user account that I'm using to create the trigger does have the permissions to run the queries independently. In fact, I've had my trigger print the query I'm trying to run and was able to run it on it's own successfully.
I should also note that I'm building the query dynamically by using the EXECUTE IMMEDIATE statement. Here's an example:
CREATE OR REPLACE TRIGGER MAIN_SCHEMA.EVENTS
BEFORE INSERT
ON MAIN_SCHEMA.EVENTS REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
DECLARE
rtn_count NUMBER := 0;
table_name VARCHAR2(17) := :NEW.SOME_FIELD;
key_field VARCHAR2(20) := :NEW.ANOTHER_FIELD;
BEGIN
CASE
WHEN (key_field = 'condition_a') THEN
EXECUTE IMMEDIATE 'select count(*) from OTHER_SCHEMA_A.'||table_name||' where KEY_FIELD='''||key_field||'''' INTO rtn_count;
WHEN (key_field = 'condition_b') THEN
EXECUTE IMMEDIATE 'select count(*) from OTHER_SCHEMA_B.'||table_name||' where KEY_FIELD='''||key_field||'''' INTO rtn_count;
WHEN (key_field = 'condition_c') THEN
EXECUTE IMMEDIATE 'select count(*) from OTHER_SCHEMA_C.'||table_name||' where KEY_FIELD='''||key_field||'''' INTO rtn_count;
END CASE;
IF (rtn_count > 0) THEN
-- change some fields that are to be inserted
END IF;
END;
The trigger seams to fail on the EXECUTE IMMEDIATE with the previously mentioned error.
EDIT
I have done some more research and I can offer more clarification.
The user account I'm using to create this trigger is not MAIN_SCHEMA or any one of the OTHER_SCHEMA_Xs. The account I'm using (ME) is given privileges to the involved tables via the schema users themselves. For example (USER_TAB_PRIVS):
GRANTOR GRANTEE TABLE_SCHEMA TABLE_NAME PRIVILEGE GRANTABLE HIERARCHY
MAIN_SCHEMA ME MAIN_SCHEMA EVENTS DELETE NO NO
MAIN_SCHEMA ME MAIN_SCHEMA EVENTS INSERT NO NO
MAIN_SCHEMA ME MAIN_SCHEMA EVENTS SELECT NO NO
MAIN_SCHEMA ME MAIN_SCHEMA EVENTS UPDATE NO NO
OTHER_SCHEMA_X ME OTHER_SCHEMA_X TARGET_TBL SELECT NO NO
And I have the following system privileges (USER_SYS_PRIVS):
USERNAME PRIVILEGE ADMIN_OPTION
ME ALTER ANY TRIGGER NO
ME CREATE ANY TRIGGER NO
ME UNLIMITED TABLESPACE NO
And this is what I found in the Oracle documentation:
To create a trigger in another user's
schema, or to reference a table in
another schema from a trigger in your
schema, you must have the CREATE ANY
TRIGGER system privilege. With this
privilege, the trigger can be created
in any schema and can be associated
with any user's table. In addition,
the user creating the trigger must
also have EXECUTE privilege on the
referenced procedures, functions, or
packages.
Here: Oracle Doc
So it looks to me like this should work, but I'm not sure about the "EXECUTE privilege" it's referring to in the doc.
What you are experiencing is a feature of Oracle's security model. The entire point of using schemas is to control access to the data. The tables in my schema are mine, you cannot even see them until I grant you privileges on them.
The syntax is quite simple: the owner schema issues
grant select, insert on my_table to you
/
Alternatively an account with the GRANT ANY privilege (such as a DBA) can pass privileges on any user's objects.
grant select, insert on apc.my_table to you
/
The grantee can be either a user or a role. However, note that we can only build program units - stored procedures, views, triggers - using privileges which have been granted directly through to our user.
So, if you get the other schema owner to grant you the necessary privileges you will be able to build your trigger.
edit
When referencing an object in another schema we need to qualify the object with the schema name ....
insert into apc.whatever_table values ...
or else we need to create a synonym for it
create synonym whatever for apc.whatever_table;
I feel someone should add the obvious - the other schema's table must be qualified with the schema name or a private/public synonym is needed. I wonder if the original problem was merely a name resolution issue. If not, APC's answer is a good explanation of the Oracle security model.
You should execute this for every table and schema involved:
grant select on OTHER_SCHEMA_%.table_name to MAIN_SCHEMA;

Resources