Can we create Database Scoped credential inside T-SQL procedure on Azure - sql-server

Can we create database scoped credential for shared access signature inside a T-SQL procedure on Azure SQL ?
We are trying to bulk insert data from csv file stored on Azure blob
Below are the steps
Create SAS credentials using JAVA
Java will call stored procedure to create/alter external data source and pass SAS credential to this procedure as a parameter
Above procedure will internally call another procedure to do BULK INSERT
We are facing challenges in creation of database scoped credential via T-SQL procedure , can someone confirm if this approach is actually possible
It would be great help if we can get some sample code for the same .
I've seen the syntax to create database scoped credential on Microsoft site , it works when we run scripts as standalone statements but we are unable to compile the code using a procedure
We tried below code
CREATE procedure prc_create_external_data_source #SAS VARCHAR(100)
AS
BEGIN
SET nocount ON
DECLARE #command varchar(MAX);
PRINT 'Shared Access Key Received Key: '+#SAS;
SET #command =
'CREATE DATABASE SCOPED CREDENTIAL MyAzureBlobStorageCredential
WITH IDENTITY = ''SHARED ACCESS SIGNATURE'',
SECRET = '+#SAS
EXECUTE (#command);
PRINT 'Database Scoped Credential Created';
END
We get below Error message after executing this procedure
EXECUTE prc_create_external_data_source '1245632512344'
Error Number : 102 Error Message : Incorrect syntax near '1245632512344'. Line Number : 3 Procedure Name : (SQL State: S0001 - Error Code: 0)
Thanks

Your secret probably needs to be surrounded by quotes. Also this all needs to be on one line or concatenated with +
If you printed the string it might be obvious. Try this:
SET #command =
'CREATE DATABASE SCOPED CREDENTIAL MyAzureBlobStorageCredential ' +
'WITH IDENTITY = ''SHARED ACCESS SIGNATURE''' +
',SECRET = '''+ #SAS + ''''

Related

Sql Server: How to create a db-snapshot from within stored procedure for non-privileged user?

I'm trying to create a stored procedure that creates a dB-snapshot for a non privileged user.
The idea is to provide to a normal user a way to create a dB snapshot in order to run queries against it and delete the snapshot when it is done with it.
I thought it would be possible to use the 'with execute as owner" in the procedure declaration. However, I always get the following error:
CREATE DATABASE permission denied in database 'master'.
Here is my code:
-- The user that create the sp has sysadmin right
CREATE OR ALTER PROCEDURE [dbo].[makeSnapshot] WITH EXECUTE AS OWNER
AS
-- just an extract of the code (should test if exist...)
DECLARE #exec NVARCHAR(2000)
set #exec = 'CREATE DATABASE test_dbss1900 ON ( NAME = test, FILENAME =
''C:\\Program Files\\Microsoft SQL Server\\MSSQL14.SQLSERVER2017\\MSSQL\\Data\\test_1900.ss'' ) AS SNAPSHOT OF test';
EXEC (#exec)
GO
-- try to execute it (with any user)
EXEC dbo.[makeSnapshot]
Has anyone an idea how I can come up with a stored proc that will allow a normal user to create a db snapshot?
Thank for any help!
José
I actually found a solution by looking at - http://www.sommarskog.se/grantperm.html#serverlevel (chapter 5.3)
The way was to use certificates

modifiy connection manager information from SSIS Catalog from sql

Is there a way, to update the connection manager information from the ssis catalog after deploying with an sql code ?
I'd like to deploy the project without sensitive data first :
exec catalog.deploy_project ..
then add username and password to the SSIS Catalog Project via SQL...
Is there a way, to update the connection manager information from the
ssis catalog after deploying with an sql code ?
It is possible since all changed in SSISDB catalog are via stored procedure.
This is a SQL script generated by SSMS during connection string change:
DECLARE #var SQL_VARIANT
= N'Data Source=ServerName;Initial Catalog=dbName;
Provider=SQLNCLI11.1;Integrated Security=SSPI;Auto Translate=False;';
EXEC [SSISDB].[catalog].[set_object_parameter_value] #object_type = 20,
#parameter_name = N'_ConnectionStringParam',
#object_name = N'ProjectName',
#folder_name = N'FolderName',
#project_name = N'ProjectName',
#value_type = V,
#parameter_value = #var;
References:
catalog.set_object_parameter_value (SSISDB Database)
How can I automate setting SSIS Project Parameters in SSIS 2012?
Since you're asking how to change the username and password once a package is deployed, I assume you're already familiar with the SSIS Catalog, if not the documentation outlines this further. To set the username and passwords via T-SQL use environment variables, with the variable holding the password marked as sensitive. The SSISDB.CATALOG.SET_ENVIRONMENT_VARIABLE_VALUE stored procedure is used to update the values of environment variables, including those marked as sensitive, and can be used as follows.
Start off by creating an environment. To do this, right-click SSISDB and create a new folder. Then in this folder, right-click and create a new environment.
After this right-click the environment and select Properties then go to the Variables pane. Create a string variable for both the username and password, with the variable storing the password set as Sensitive.
Next, right click the package or project depending on the scope that the connection manager was defined in, and press Configure and go to the References page. On this add the newly created environment with the Add button.
Still in the properties window of the project/package, go to the Parameters page and then Connection Managers tab. Find the connection manager that will use the environment variables, right-click the ellipsis on both the username and password properties, change the radio button to "Use Environment Variable", and choose the corresponding variables.
Before executing the package, run the SSISDB.CATALOG.SET_ENVIRONMENT_VARIABLE_VALUE stored procedure to update the environment variables. An example of this follows.
If this package is executed using T-SQL from a SQL Agent job or another method, linked the environment reference to it as done below.
Example:
DECLARE #usernameVar SQL_VARIANT = N'UsernameValue'
EXEC SSISDB.[CATALOG].SET_ENVIRONMENT_VARIABLE_VALUE #variable_name=N'Username',
#environment_name=N'Environment Name', #folder_name=N'Environment folder', #value=#usernameVar
DECLARE #passwordVar SQL_VARIANT = N'PasswordValue'
EXEC SSISDB.[CATALOG].SET_ENVIRONMENT_VARIABLE_VALUE #variable_name=N'Password',
#environment_name=N'Environment Name', #folder_name=N'Environment folder', #value=#passwordVar
--make sure environment mapped with #reference_id
DECLARE #execution_id bigint
EXEC SSISDB.[CATALOG].CREATE_EXECUTION #package_name=N'Package.dtsx', #execution_id=#execution_id OUTPUT,
#folder_name=N'Project Folder', #project_name=N'PackageProject', #use32bitruntime=False, #reference_id=99
DECLARE #var0 smallint = 1
EXEC SSISDB.[CATALOG].SET_EXECUTION_PARAMETER_VALUE #execution_id, #object_type=50,
#parameter_name=N'LOGGING_LEVEL', #parameter_value=#var0
--execute package
EXEC SSISDB.[CATALOG].START_EXECUTION #execution_id

The specified schema name "sys" either does not exist or you do not have permission to use it

I needed Msforeach_table stored procedure which depends upon sys.MSforeach_worker (System) stored procedure.
I am following this source code to create stored procedure MSforeach_worker
The syntax here is for dbo and not for sys so I have changed it to sys.MSforeach_worker from dbo.MSforeach_worker
When I try to create in my Databases, i get this error
The specified schema name "sys" either does not exist or you do not
have permission to use it
And when I try to create it in master db, I get
CREATE PROCEDURE permission denied in database 'master'
I am confused where should I run this script to create System stored procedure in my SQL server.
I have googled but could not find solution to my problem.
First, don't use undocumented system stored procedures. These are not supported.
Second, if these undocumented procs don't already exist, you must be using Azure SQL Database. Azure SQL Database has a significantly different architecture with regards to separation of master and user databases. Rather than trying to port the procs, I suggest you create your own proc with the functionality you need. Below is an example.
CREATE PROC dbo.usp_ForEachTable
#SQL nvarchar(MAX)
AS
DECLARE
#SQLBatch nvarchar(MAX)
, #TableName nvarchar(261);
DECLARE tables CURSOR LOCAL FAST_FORWARD FOR
SELECT QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' + QUOTENAME(name)
FROM sys.tables
WHERE is_ms_shipped = 0;
OPEN tables;
WHILE 1 = 1
BEGIN
FETCH NEXT FROM tables INTO #TableName;
IF ##FETCH_STATUS = -1 BREAK;
SET #SQLBatch = REPLACE(#SQL, N'?', #TableName);
EXEC sp_executesql #SQLBatch;
END;
CLOSE tables;
DEALLOCATE tables;
GO

"service broker" The server principal "sa" is not able to access the database under the current security context

I'm working with SQL Server 2012 Express.
I'm using Service Broker to run a stored procedure asynchronously.
The activation procedure has to access another database to execute another stored procedure. This is the code:
CREATE PROCEDURE [dbo].[GetNewCodes]
#gintNewCodes bigint,
#presNewCodes tinyint,
#levelNewCodes bigint,
#quantityNewCodes smallint
AS
-- Get new codes from INCIC database.
DECLARE #return_value int,
#xmlGenerated xml,
#xmlString NVARCHAR(MAX)
SET NOCOUNT ON;
-- Set that this stored procedure is running
update dbo.RunningSPs with (serializable) set conf_value = 1
where sp_name = N'GetNewCodes'
if ##rowcount = 0
begin
insert dbo.RunningSPs(sp_name, conf_value) values (N'GetNewCodes', 1)
end
EXEC #return_value = [INCIC].[dbo].[ReadCodeBuffer]
#gint = #gintNewCodes,
#pres = #presNewCodes,
#level = #levelNewCodes,
#quantity = #quantityNewCodes,
#xmlGenerated = #xmlGenerated OUTPUT
SET #xmlString = cast(#xmlGenerated as nvarchar(max))
-- Process these new codes on TRZ.
EXEC dbo.ProcessCodes #XmlString = #xmlString
-- Update that we are not running this procedure any more.
update dbo.RunningSPs with (serializable) set conf_value = 0
where sp_name = N'GetNewCodes'
if ##rowcount = 0
begin
insert dbo.RunningSPs(sp_name, conf_value) values (N'GetNewCodes', 0)
end
The problem is here: [INCIC].[dbo].[ReadCodeBuffer], and the error message is:
Error: 50000
Unrecoverable error in procedure GetNewCodes: 916: The server principal "sa" is not able to access the database "INCIC" under the current security context.
I have followed this tutorial to implement Service, queue and activation stored procedure.
How can I fix this problem?
Read Call a procedure in another database from an activated procedure.
The problem is that activated procedures are run under an EXECUTE AS USER context and as such are subject to database impersonation restrictions (they are sandboxed within the database). Is all explained in Extending Database Impersonation by Using EXECUTE AS.
The solution is to sign your activated procedure and create an user derived from the signing certificate in the target database, and grant this derived user the required permissions. The first link shows a full example.
Remus Rusanu's answer is clearly definitive and correct. (Anyone dealing with Broker Services knows his expertise and invaluable blog.)
I just wanted to document my experience, since google will direct to this question when searching on "The server principal "sa" is not able to access the database..."
In my case, I was call another database from within an activated procedure, but invoking a sql statement directly, not a stored procedure.
Originally, the cross-database call worked fine without a signed certificate and the use of impersonation. Then, after a small syntax change, it started returning the above error message.
Here is what worked without the need for a signed certificate:
IF EXISTS (SELECT name FROM sys.databases WHERE name = N'MyOtherDb')
and here is what provoked the security exception:
IF DB_ID(N'MyOtherDb') IS NOT NULL

Bulk Insert problem

I have a stored procedure that makes bulk insert from some file:
CREATE PROCEDURE [dbo].[SP_BulkInsert] #FileName NVARCHAR(200) AS
BEGIN
DECLARE #bulkinsert NVARCHAR(1000)
SET #bulkinsert = N'BULK INSERT TblTemp FROM ''' + #FileName +
N''' WITH (FIELDTERMINATOR = '','', ROWTERMINATOR = ''\n'')'
EXEC sp_executesql #bulkinsert
RETURN ##ROWCOUNT
END
This stored procedure runs fine when I run it from SQL Server Management Studio, but when I try to run it with ExecuteNonQuery of ADO.NET I get the following error:
"The INSERT permission was denied on the object 'TblTemp', database
'TempDB', schema 'dbo'."
Important: all other stored procedures (that make SELECT/INSERT/DELETE/UPDATE) run fine from ADO.NET.
The user under which all the things are run is a member of the bulkadmin role, and also a member of a custom db_executer role (that has just EXECUTE permission).
The code runs fine for a lot of stored procedures, it's a first time that it fails..
This is the function
public static int BulkInsert(string fileName)
{
SqlParameter paramFileName = new SqlParameter("FileName", fileName);
SqlParameter paramRetValue = new SqlParameter();
paramRetValue.Direction = ParameterDirection.ReturnValue;
SqlParameter[] #parameters = { paramFileName, paramRetValue };
SqlHelper.ExecuteNonQuery(ConnectionSettings.ConnectionString,
CommandType.StoredProcedure, "SP_BulkInsert", parameters, true);
return (int)paramRetValue.Value;
}
I logging into the SSMS with the same username/password that are in the connection string on ADO.NET side..
The bottom question is, why in Management Studio the stored procedure succeed, while via ADO.NET it fails (with the above error message).
Running SQL via the sp_executesql uses different permissions than directly in the stored procedure. I would advise checking that the user which you are running the stored procedure as has (in this instance) INSERT permissions against the table "TblTemp".
To do this in Sql Server Management Studio...
expand the list of tables
right click on the appropriate one and select properties
on the "permissions" tab, click the "Add..." button.
Either type in the user or role, or "Browse..." for it.
with the user or role selected in the top table, tick "Grant" in the appropriate permissions in the "Explicit permissions for {username/role}"
click OK
The Management Studio must be running on the sa account which has all privileges, but the user that you are connecting through ADO.NET may not have the correct privileges set. You need to give the users writing permissions through the Management studio. Look in the users list.

Resources