SQL Server: schema access through stored procedure - sql-server

I have two schemas, schema_ui and schema_logic.
schema_logic is for privileged users and I will define my tables in this schema. schema_ui is for restricted users with limited functionality, so they cannot access the tables in schema_logic.
I create a sp_ReadTable1 in schema_ui and this stored procedure reads from Table1 in schema_logic. user1 has restricted permission and can only access, schema_ui. Now user1 has access to sp_ReadTable1 but can he actually execute it, as the stored procedure reads from table1?
So, something like C# public method, which returns private members...

Related

Setting System Wide Variables in Snowflake

I'm interested in finding a method where a system wide variable can be written onto the Snowflake Account, and used in a view so that users can see the underlying DDL, but not know the value used in a particular function.
At the moment this is done by making these a "Secure" View, but that limits almost everyone from seeing the underlying DDL (which would be helpful to our users and admins).
I'm wondering if there is a way to set a System Wide Variable, and use that in the DDL.
Example:
SET SYSTEM VARIABLE variable_name = 'some_value';
CREATE VIEW catalog.schema.tablename AS
SELECT TRANSLATE(COLUMN_NAME, '0123456789', variable_name) AS NEW_COLUMN_NAME
FROM <FULL SOURCE TABLE NAME>
WHERE <WHATEVER CONDITIONS APPLY>;
I have found setting variables on a session, and I know I can see / change Account Parameters. But can I create something like Account Variables?
Function has two privileges on it - OWNERSHIP and USAGE. If you don't give either of these function privileges to the viewer of the view, but you give the viewer SELECT privileges on the view, they will be able to see the DDL of the view, but won't be able to see the details of the UDF. Then you can store values in your UDF that you don't want other people seeing. I'll post code for this in just a second.
--Something like this to test it out from scratch. You must have accountadmin for this to work:
--use role accountadmin:
--create a database called demo_db;
--create a role called owner_demo_db and grant it usage, monitor, and create schema; also give it usage on a warehouse;
--create a user called demo_db_user. give them ownership on demo_db;
--create a role called reader_demo_db;
--assign the "reader" and the "owner" role to demo_db_user;
--as the owner_demo_db role, create the following:
use role owner_demo_db;
--The role owner_demo_db will own this function
create function pi_udf()
returns float
as '3.141592654::FLOAT'
;
--The role owner_demo_db will own this view
create view MyView as
select 'some_value' AS someval
, pi_udf() pi_val;
--Because owner_demo_db owns the view, they can grant select to the reader role to the view
grant select on view demo_db.demo_schema.MyView to reader_demo_db;
--Show functions and views and you'll be able to see both.
show functions;
show views;
--Show functions and views as reader_demo_db, and you'll only be able to see DDL for the view b/c you don't have a privilege on the function
use role reader_demo_db;
show functions;
show views;

is it possible to create global UDF on snowflake data warehouse

I want to create a function once and have it be available everywhere on the account.
I don't want to have to specify fully-qualified name in all usages.
And I don't want to create it in every database, and possibly on every schema.
Ideally, it is accessible across the account without specifying database / schema.
For example, suppose I want a case-insensitive contains function available everywhere.
CREATE OR REPLACE FUNCTION udf_icontains(val varchar, search_pattern varchar)
RETURNS BOOLEAN
AS
$$
contains(lower(val), lower(search_pattern))
$$;
It seems I must create it on every database and every schema in order to reference without FQN.
You can create it in a single database and schema, grant public access, and then reference it in queries using its fully-qualified name (db.schema.udf...) from everywhere.
Just create a public database with a name like global or account (we call ours utils) with a public schema called udfs.
You already have a udf_ prefix in the name of your UDF; global.udfs.icontains is not much longer to type than udf_icontains.
CREATE DATABASE IF NOT EXISTS global;
CREATE SCHEMA IF NOT EXISTS global.udfs
GRANT USAGE ON DATABASE global TO ROLE public;
GRANT USAGE ON SCHEMA global.udfs TO ROLE public;
GRANT USAGE ON FUTURE FUNCTIONS IN SCHEMA global.udfs TO ROLE public;
GRANT USAGE ON ALL FUNCTIONS IN SCHEMA global.udfs TO ROLE public;

T-Sql Equivalent of Authorization and Grand for a function in Oracle

We have a function that is written in t-sql and we converted it for oracle. But I cannot find equivalent of Authorization keyword for oracle.
GO
ALTER AUTHORIZATION ON [DOCSADM].[Cbinary] TO SCHEMA OWNER
GO
GRANT EXECUTE ON [DOCSADM].[Cbinary] TO [public] AS [DOCSADM]
GO
DOCSAdm is a user and CBinary is myfunction name. How to convert these sql code for oracle?
The ALTER AUTHORIZATION transfers ownership of an object to another user.
As Oracle handles Users and Schemas a bit differently than SQL Server, there is no equivalent. In general, an object like your function Cbinary is owned by the schema it is located in.
Moving an object to another user/schema in Oracle is done in the way that you use the CREATE-Script like you would use it normally, but just add the new schema-name in front of the object-name, like this:
create function newschema.cbinary return varchar2 as
begin
-- your code here
end cbinary;

DB2 Stored Procedure Returning SQLCODE=-440, SQLSTATE=42884

I am currently using RazorSQL to test queries with IBM DB2. Right now, I am stuck on an issue with creating procedures
I have the following procedure. I create this procedure as an admin user called db2inst1:
CREATE OR REPLACE PROCEDURE CANCEL_ACTIVITY (IN application_handle INTEGER)
LANGUAGE SQL
BEGIN
DECLARE UOW_ID INTEGER;
DECLARE ACTIVITY_ID INTEGER;
FOR v AS cur1 CURSOR FOR
SELECT UOW_ID, ACTIVITY_ID FROM TABLE(SYSPROC.MON_GET_ACTIVITY(application_handle, -1))
DO
CALL WLM_CANCEL_ACTIVITY(application_handle, v.uow_id, v.activity_id);
END FOR ;
END
Now, I log onto my regular user called applicationtest which is NOT an admin. If I run the following:
CALL CANCEL_ACTIVITY(12345)
I get the following error:
DB2 SQL Error: SQLCODE=-440, SQLSTATE=42884, SQLERRMC=CANCEL_ACTIVITY;PROCEDURE, DRIVER=4.16.53
According to IBM, it's caused by:
NO AUTHORIZED routine-type BY THE NAME routine-name HAVING COMPATIBLE ARGUMENTS WAS FOUND
Looking at this question, I ran this debug code to check if the users are the same, and it does not appear to be the same, because the results are:
| ROUTINESCHEMA
1 | db2inst1
2 | DB2INST1
Logically, ROUTINESCHEMA should have my regular user applicationtest in it, right?
I even ran the following:
GRANT EXECUTE ON PROCEDURE CANCEL_ACTIVITY TO PUBLIC;
To see if it would help, but still, same error.
I also tried to create the procedure using applicationtest, but as expected, I don't have the privileges required to do so.
EDIT:
I just specified DB2INST1.CANCEL_PROCEDURE(12345), and now I am getting the following error:
2016-11-18 11:27:34.983 -0800 [ERROR|01c56|] :: Java::ComIbmDb2JccAm::SqlSyntaxErrorException : DB2 SQL Error: SQLCODE=-551, SQLSTATE=42501, SQLERRMC=APPLICATIONTEST;EXECUTE;DB2INST1.CANCEL_ACTIVITY, DRIVER=4.16.53
I guess that user applicationtest doesn’t have permission to execute that procedure?
I have two questions:
Is it possible to not have to call DB2INST1 before calling the procedure? So I can just call it like this CALL CANCEL_PROCEDURE(..) instead of CALL DB2INST1.CANCEL_ACTIVITY. I feel like this would remove a lot of the ambiguity..
How do I grant applicationtest the necessary privilege to call the procedure?
You have two issues here:
The schema of the stored procedure is the implicit schema of the user that created the procedure. In this case the schema name is 'db2inst1'. When you connect with the other user, 'applicationtest' the implicit schema is the same name of the user. Then you have the following possibilities:
Set the schema to db2inst1: https://www.ibm.com/support/knowledgecenter/es/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0001016.html
Call the stored procedure with schema.name: db2inst1.cancel_activity
Set the path, including db2inst1 on it: https://www.ibm.com/support/knowledgecenter/es/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0001014.html
Between, the previous three options, I personally recommend the second one schema.name.
The other problem is the execution permission. When you create a procedure, you have to grant execution to other users / groups. In this case, db2inst1 user created the procedure, but just this user (or someone with DBADM authority) can execute it.
Because you are connecting with the other user you have to grant the execution (https://www.ibm.com/support/knowledgecenter/es/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0007699.html):
db2 grant execution on procedure db2inst1.cancel_activity to user applicationtest

Dynamic Row Level Security In a SQL Server Database Using Extended Properties

We have a requirement to provide customer access to a staging database so that they can extract their data into their own servers, but every table contains all customers data. All of the tables have a 'CustomerID' column. Customers should only see rows where the customerID is the same as theirs.
I am not looking for suggestions to create separate databases or views for each customer as both suggestions are high maintenance and low efficiency.
My solution has to work with:
100GB database
400 Tables
Updates every 30 minutes from the core transaction database
Quarterly schema changes (Application is in continuous Development).
Can anyone give me a definitive answer as to why the following method is not secure or will not work?:
I've set up a database user for each customer, with their customerID as an extended property.
I've created a view of every table that dynamically selects * from the table where the customerID column is the same as the extended property CustomerID of the logged in user. The code looks like this and appears to work well:
CREATE VIEW [CustomerAccessDatabase].[vw_Sales]
AS SELECT * FROM [CustomerAccessDatabase].[Sales]
WHERE [Sales].[CustomerID]=
(SELECT CONVERT(INT,p.value) AS [Value]
FROM sys.extended_properties
JOIN sys.sysusers ON extended_properties.major_id=sysusers.[uid]
AND extended_properties.name = 'CustomerID'
AND sysusers.[SID]=(SELECT suser_sid())
);
GO
To provide access to the views I've created a generic database role 'Customer_Access_Role'. This role has access granted to all of the table views, but access to the database tables themselves is denied.
To prevent users from changing their own customerID I've denied access to the extended properties like so:
USE [master];
GO
DENY EXEC ON sys.sp_addextendedproperty to [public];
GO
DENY EXEC ON sys.sp_dropextendedproperty to [public];
GO
DENY EXEC ON sys.sp_updateextendedproperty to [public];
GO
The end result is that I only need one database, and one set of permissions.
To add a new customer all I would need to do is create a new user with their customerID as an extended attribute and add them to the Customer_Access_Role. Thats it!
I am going to reiterate what everyone is stating already and sum it up.
You are making your job harder than it has to be.
Create a View, that is just their data and then give them Security access to that View.
Alternatively, extract all their data out of the "Core" database and into their own and give them the necessary access to that data.

Resources