Azure SQL how to create database user by procedure? - tsql

I would like to register new user from client app, by calling webapi, where dapper will execute procedure to create new db user and store credentials in table (without password). After registration, I will change connection string with user credentials to log in.
Is it possible to dynamically create db users by executing stored procedure on Azure sql db?
I've made such query:
CREATE PROCEDURE [dbo].[AddDbUser]
#Login nvarchar(50),
#Password nvarchar(50),
#Mail nvarchar(70),
#Phone nvarchar(9),
#SQL nvarchar(1000)
AS
BEGIN
SET #SQL = 'USE [testdb] '
+ 'CREATE LOGIN '+quotename(#Login)+' WITH PASSWORD =
'+quotename(#Password,'''')+'; '
+ 'CREATE USER '+#Login +'; '
+ 'EXEC [sys].[sp_addrolemember] ''db_datareader'', '+#Login+'; '
+ 'EXEC [sys].[sp_addrolemember] ''db_datawriter'', '+#Login+'; '
+ 'GRANT EXECUTE ON SCHEMA :: [dbo] TO '+#Login+'; '
+ 'INSERT INTO [dbo].[Users] (Login, Mail, Phone) '
+ 'VALUES ('+quotename(#Login,'''')+', '+quotename(#Mail,'''')+',
'+quotename(#Phone,'''')+');'
EXEC (#SQL)
END
GO
exec [dbo].[AddDbUser] 'dawidtest', 'password', 'mail#mail.pl', '123123123', null results in message: "User must be in the master database.", but when I add USE [master] instead of USE [testdb] I get message: "USE statement is not supported to switch between databases. Use a new connection to connect to a different database.".
Anybody could provide me some tips how to solve my problem or maybe there is some other more elegant solution?
Thank you in advance!

According to the Microsoft you will have to do in two steps since the USE statement is not supported:
One thing to note is that SQL Azure does not allow the USE Transact-SQL statement, which means that you cannot create a single script to execute both the CREATE LOGIN and CREATE USER statements, since those statements need to be executed on different databases.
So follow the advice given in the message you are getting. Create two sql statements and execute them using different connections.
One that connects to the master db and creates the login and the other one that connects to the specific db and creates the user.

Related

Change to other database in sql developer

I would like to change the database connection of a SQL worksheet in Sql Developer. For example I'm now working in database connection !OMY_OWNER_C_1 and want to change the database connection to !OMY_OWNER_C_2.
The way I do that now is by clicking on the 'Choose DB connection' button on the top right, and select !OMY_OWNER_C_2, but I want to achieve the same by running some sql.
Can anyone tell me how to that that? (or whether it is possible?)
I already tried some with 'ALTER SESSION SET current_schema = !OMY_OWNER_C_2;', but that does not do the trick.
In other stack overflow threads a simular question is there, and the use of 'ALTER SESSION SET current_schema = !OMY_OWNER_C_2' is suggested, but for me that does not do the trick. I do something wrong or it just can't, or there is something else why it does not work.
In Sql Server I just use 'USE database !OMY_OWNER_C_2', but Oracle/Sql developer works different.
I made two printscreens which makes some above used names more clear hopefully: http://prntscr.com/9mo3us and http://prntscr.com/9mo7hh.
ALTER SESSION SET CURRENT_SCHEMA = SchemaNameTwo should do the job.
But don't rely on SQL Developers GUI. The field showing the current schema name doesn't display SchemaNameTwo when you fire the alter session command.
Instead: To validate that the schema has changed: use this select:
SELECT sys_context( 'userenv', 'current_schema' ) FROM dual;
My example:
ALTER SESSION SET CURRENT_SCHEMA = minimaks;
SELECT sys_context( 'userenv', 'current_schema' ) FROM dual;
ALTER SESSION SET CURRENT_SCHEMA = minimakskontrol;
SELECT sys_context( 'userenv', 'current_schema' ) FROM dual;
Gives this result:
Session altered.
SYS_CONTEXT('USERENV','CURRENT_SCHEMA')
\-------------------------------------------------------------------------------
MINIMAKS
Session altered.
SYS_CONTEXT('USERENV','CURRENT_SCHEMA')
\--------------------------------------------------------------------------------
MINIMAKSKONTROL

Delete from table in all databases containing table

I want to create a T-SQL query which are deleting all rows in the table Logins in ALL databases containing this exact table, so it can be run without any errors.
I want to reuse the code to other stuff as well, e.g. finding all active users from all databases containing the table Users. Therefore, I think, the best solution would be a pure T-SQL solution. This way the query can even become an automated job run by SQL Server Agent
Is it possible? And how?
Build some dynamic SQL:
declare #sql varchar(max) = ''
select #sql = #sql +
'use [' + name + '] ' +
'if exists (select * from sys.tables where name = ''Logins'') ' +
'delete from Logins '
from sys.databases where name not in ('master','model','msdb','tempdb')
print #sql
--exec (#sql)
Uncomment the exec line to actually run the code rather than just see what would be executed.

FuelPHP - How do I execute custom, multi-line MySQL statement?

How do I execute an SQL statement that is performing multiple actions?
When I try to execute the following code, I get an error Fuel\Core\Database_Exception [ 1064 ]: You have an error in your SQL syntax;
PHP with MySQL embeded
$sql = "
SET #sql = CONCAT(
'CREATE TEMPORARY TABLE IF NOT EXISTS temp_compiled_properties AS
(SELECT
id,
', #sql, '
FROM properties
WHERE properties.property_id = ?
GROUP BY properties.property_id)');
PREPARE stmt FROM #sql;
EXECUTE stmt USING #property_id;
DEALLOCATE PREPARE stmt;";
DB::query($sql)->execute();
At the moment you can't.
You can work around it by fetching the current database connection, and use the native PHP calls directly
$db = \DB::instance()->connection();
$result = $db->exec($sql); // for PDO
Afaik the native MySQL drivers don't support multiple statements at all.

Use Stored Procedure to "EXECUTE AS USER" and Apply to Calling Context (Session)

I'm using SQL Server 2008 R2 on a Windows 7 box. I have created a stored procedure to run the SQL command EXECUTE AS USER:
CREATE PROCEDURE dbo.ImpersonateUser
AS
BEGIN
EXECUTE AS USER = 'UserName';
END
Then, I'm trying to see if I am impersonating the user...
PRINT CURRENT_USER;
EXEC ImpersonateUser;
PRINT CURRENT_USER
...and the result is...
dbo
dbo
...when I want it to be...
dbo
UserName
This doesn't work, of course, because the EXECUTE AS USER statement is only valid inside the stored procedure ImpersonateUser. My question is this: Is it possible for the stored procedure ImpersonateUser to affect the calling context (session)? I want to encapsulate (and hide) other logic in the stored procedure.
It is not possible. Any EXECUTE AS change is automatically reverted at the end of a procedure.
Other things that dont live past the scope of the procedure are changes using the SET command and #TempObjects.
However, what you could do is encapsulate the logic that needs to be executed under the different security context in a procedure and then call that from within the procedure that changes the context. Something like:
CREATE PROCEDURE dbo.CallWithImpersonateUser
#ProcedureName
AS
BEGIN
EXECUTE AS USER = 'UserName';
EXEC #ProcedureName;
END;
Answer by Sebastian is correct, but still you have to grant impersonate for calling user.
Syntax can be found here
GRANT IMPERSONATE ON LOGIN::[login_to_be_impersonated] to [login1];
GO

Does EXECUTE AS protect against SQL Injection?

I have a situation where I need to do this
CREATE PROCEDURE search_sp #condition varchar(8000) AS
SELECT * FROM tbl WHERE #condition
If I add a user to the database that only has the 'db_datareader' role and then use execute as to switch context to that user for the purposes of running the select statement, would this then protect me from SQL injection?
e.g.
DECLARE #cookie varbinary(100);
EXECUTE AS USER = 'restricted__user' WITH COOKIE INTO #cookie;
DECLARE #SQL AS NVARCHAR(MAX)
SET #SQL= 'SELECT * FROM tbl WHERE ' + #condition
EXEC sp_executesql #SQL
REVERT WITH COOKIE = #cookie;
No, it won't. This will limit the queries that could be run if injected if the "EXECUTE AS USER" is even evaluated. It won't stop something like foo' or 1 = 1; /*... which can be a case where "EXECUTE AS USER" is never reached. Properly handling the input is required.
What happens when I pass "1=1" as condition?
Now you send back all rows in 'tbl'. If table is, say, users, I now have all user names and all passwords (hopefully they're hashed and salted...).