flyway against azure: user permission creating stored procedure - sql-server

We use FlyWay as a migration tool to manage our database version.
Recently we added two stored procedures in repeatable scripts, one of which uses user defined types (CREATE TYPE). The other calls the former.
The account I use in my deployment script is not the db_owner on master (the account you get from the Azure portal). Instead, I created a separate deployment account on the database in question, initially only as db_ddladmin, and now upgraded to db_owner so that it can GRANT EXEC on the user defined types.
However, the second procedure consistently fails when I try to run the migration using this account:
Migration R__21Proc_ConflictsForUI.sql failed
---------------------------------------------
SQL State : 08S01
Error Code : 0
Message : I/O Error: Connection reset
Location : ./db/Stored Procedures/R__21Proc_ConflictsForUI.sql
Line : 5
Statement : CREATE PROC Conflicts_For_UI #CustomerId INT, #TotalRows INT = 20
When I try to run the same migration using my portal db_owner account that is also on master, it works.
Why would Azure close the connection on the second procedure, but not the first?

By doing just GRANT EXEC you gave the permission on execution, but to be able to CREATE PROC that REFERENCES UDT, a user should have REFERENCES permission on UDT.
Alternatively you can grant CONTROL on UDT that will bring to user
REFERENCES
EXECUTE
VIEW DEFINITION
TAKE OWNERSHIP
on UDT

Related

How to create a login that ONLY has access to run stored procedures?

I have a C# Winform application that interacts with an SQL Server DB via stored procedures. In SSMS, how do I create a login that ONLY has permissions to run stored procedures? That login wouldn't be able to view/edit/create table definitions, etc. It would also only have access to a single specified DB.
The reason I want to create such a login is because I store the SQL Server credentials used by my Winform application in its App.config file. Since the app.config can easily be read, anyone with malicious intent can easily perform unwanted operations on the database if the given login had any other permissions than just stored procedures.
A neat trick in this scenario is to create a separate (custom) SQL Server role that can only execute stored procedures:
CREATE ROLE db_executor;
GRANT EXECUTE TO db_executor;
This role now has the permission to execute any stored procedure in the database in which it's been created - and in addition: that permission will also extend to any future stored procedures you might create later on in this database.
Now create a user in your database and give it only this database role - this user will only be able to execute stored procedures - any and all of them in your database.
If you user should be allowed to execute any and all stored procedures - this is a very convenient way to allow this (and you don't have to constantly update the permissions when new stored procedures are created).
You can use the following query in order to allow stored procedure execute permision to your user
USE [DB]
GRANT EXECUTE ON dbo.procname TO username;
However, in my humble opinion , you should secure the connection string in the app.config.
Maybe , this How to store login details securely in the application config file link can be helped to you.
The access to a specific database is done through creating a user on the database that you want him to operate on. You can find more infos about users here.
If the user is created you can Grant, With Grant and Deny actions for every single item on the database.
The user will then be granted/denied those rights by a grantor, which is the dbo by default.
You can use this to also deny him access to every item on your database that isn't your stored procedure, which is what you're looking for if I understand you correctly.
Try folloiwng approach (grant execute should be repeated for every SP). Note that MyStoredProcedure has to be in MyDatabase :)
-- create login to server
create login test_user with password = 'test';
-- create user mapped to a database
use MyDatabase
go
create user test_user for login test_user;
-- grant permission to execute SP
grant execute on MyStoredProcedure to test_user

Sql Server Agent job failing to execute stored procedure

I have a stored procedure that I can execute in SSMS with a non domain SQL Server user.
This stored procedure selects data from tables in one database (DB1) truncates and selects into a table in DB2.
The user has datareader,datawriter and dbowner for both databases.
Problem:
When I execute the stored procedure via SS Agent with execute as the user I get the following error
The server principal [user] is not able to access the database [DB1]
under the current security context.
Actions taken So far:
I have tried to resolve this so far by:
Turning on db chaining for both databases
Deleted the user from DB1 and added again
Checked using EXEC sp_change_users_login #Action=’Report’ to see if user orphaned. As this is a database that is a restore of a live one. However I added the user after the restore. The user was not listed as orphaned
A possible workaround if you don't want to have the owner be sa is to have the user be a member of msdb and grant the the SQLAgentOperatorRole in msdb. See if that works.
But to be honest, either use sa or a dedicated service account with enough permissions. It's better if the job runs under that context.

VS2013 Database Project using SQL CLR - unresolved reference to object [servername\username] (the Database Owner)

I am working on a Database project in VS2013 that contains a C# SQL CLR stored procedure.
The assembly owner is [servername\User123]
The database owner is also [servername\User123] (Being the database owner, this user obviously already exists on the server. I managed a successful publish of the database by commenting out the code in my SQL CLR procedure and publishing, the following occurs after I un-comment-out that code.)
If I try to build the project in VS, I get the error:
Error 1 SQL71501: Assembly: [DatabaseProject] has an unresolved reference to object [servername\User123].
...caused by:
CREATE ASSEMBLY [DatabaseProject] AUTHORIZATION [servername\User123]
FROM 0x4D5A90000300000004000000FFFF0000B8000etcetcetcetc
WITH PERMISSION_SET = EXTERNAL_ACCESS
GO
So, if in VS I add a create user script in the \Security folder:
CREATE USER [servername\User123] FOR LOGIN [servername\User123] WITH DEFAULT_SCHEMA = dbo
GO
GRANT CONNECT TO [servername\User123]
Then I can build the project.
However, if I then try to Publish the database, I get the error:
Creating [servername\User123]...
(47,1): SQL72014: .Net SqlClient Data Provider: Msg 15063, Level 16, State 1, Line 1 The login already has an account under a different user name.
(47,0): SQL72045: Script execution error. The executed script:
CREATE USER [servername\User123] FOR LOGIN [servername\User123];
An error occurred while the batch was being executed.
Is there a "right" way to do this?
This issue is due to a simple misunderstanding of how SQL Server handles the "owner" of the database as a database "principal". The concept of "database owner" shows up in two different ways:
As a database-level User having the name of dbo and a principal_id of 1. Now, what server-level Login maps to this particular User (i.e. "principal") is simply a matter of the value in the SID field in sys.database_principals:
SELECT sdp.*
FROM [sys].[database_principals] sdp
WHERE sdp.[principal_id] = 1;
This field will map to the SID field in sys.server_principals:
SELECT sdp.*, '---' AS [---], ssp.*
FROM [sys].[database_principals] sdp
INNER JOIN [sys].[server_principals] ssp
ON ssp.[sid] = sdp.[sid]
WHERE sdp.[principal_id] = 1;
Pay attention to the following fields in sys.database_principals:
type
type_desc
authentication_type
authentication_type_desc
Seeing as how your database is currently owned by a Windows Login, run the query immediately above (the 2nd query--the one with both tables). Next, change the database to be owned by sa. Next, open up a NEW query tab. Finally, run the same query in this new window (so that you can easily compare the "before" and "after" results), making sure to pay close attention to the 4 fields noted above, as well as the sid field. (Please note that it is possible to create Users without Logins and those will not show up, obviously, in a query that JOINs to sys.server_principals, but this question is dealing specifically with Logins).
From all of this you should see that specifying a Login to be the "owner" of a database does not, in fact, create a User for that Login: it merely updates the definition of the dbo User. Hence, the Login that owns the database does technically exist in that database, but always with the name of dbo instead of its actual name. This is why you are getting the following error:
The login already has an account under a different user name.
As a Database Role that any User in the database can be added to in order to be given those permissions.
To fix:
Remove your CREATE USER script from the \Security folder.
Use AUTHORIZATION [dbo] instead.

How to give permission to rename a database sql-server

I have a user who needs to rename a database. I could give dbcreator privileges, but this would allow the user to rename any database, and even create new ones.
So I tried to create a stored procedure that the user would call to do the job.
CREATE PROCEDURE SPMyRenameDB
WITH EXECUTE AS 'MySuperUser' -- MySuperUser is a SQL user with dbcreator permission
AS
ALTER DATABASE A MODIFY NAME = B
GO
I get an error :
The server principal "MySuperUser" is not able to access the database "A" under the current security context.
I tried with sp_renamedb, I get : User does not have permission to perform this action.
Even a simple SELECT statement to a table in database A is not allowed : The server principal "MySuperUser" is not able to access the database "A" under the current security context.
When I connect as MySuperUser and query the database A, it works as expected. (MySuperUser is a SQL user with dbCreator and sysAdmin privileges on the server).
I suspect that the "WITH EXECUTE AS" statement has some security restrictions that do not allow to use it outside of the current database.
The Stored Procedure is in a database (other than A and B) where the user has db_owner permissions.
Any suggestions ? I do not need to stick with my "WITH EXECUTE AS" approach. Anything that would do the trick is welcome.
Thanks,
Yves
Check ALTER DATABASE in MSDN -> Permissions
Requires ALTER permission on the database.
So just query as following
USE A
GO
GRANT ALTER TO 'someuser'
GO
User must be member of dbcreator server role. (MSDN documentation is wrong!).

Cannot Find Stored Procedure Error

I recently did an import of database from a sql server 2000 database to a sql server 2005 database. I've gone through and setup what I thought were the same login credentials and owner permissions that I had previously setup in my old database.
All of the code base I'm working has stored procedures listed simply by stored procedure name.
In order to make sure I have the proper logins created, I am logging into the SQL Server Management studio with the connection information my application is using (i.e. using the username "licensemgr" and it's associated password). I can see all the tables, stored procedures, etc... in my database when I log in with combination. When I try to run a stored procedure, Sql Server Management Studio uses the following syntax to execute it:
EXEC: #return_value = [licensemgr].[Stored_Procedure_Name]
and it executes without error.
If I try to remove the [licensemgr]. from before the [Stored_Procedure_Name], however I get the error "Cannot find stored procedure: Stored_Procedure_Name". This is the same error I get when running my application off this database. I changed one stored procedure call in my application to have "licensemgr." in front of the stored procedure name and that seemed to correct the problem, however, I don't want to do that for each and every stored procedure call in my application. I am therefore wondering what type of setup / permissions type issue I might be missing in my SQL Server instance so that even when I'm logged into the database as licensemgr, I cannot see the stored procedure which is in the schema "licensemgr".
In SQL server 2000 the [licensemgr] referred to the owner of the table. So when you are logged in as [licensemgr] you do not need the prefix.
In SQL Server 2005 this has been changed to the schema, therefore it must be specified. See:
http://msdn.microsoft.com/en-us/library/ms190387.aspx
EDIT
There are two things that you need to watch out for:
If the user is in the sysadmin role, he will always default to the dbo schema, therefore you need to prefix
If your user needs to run code that is in different schemas you will need to prefix
If none of the two above it should work by setting the default schema for the user
When you created your user, did you specify DEFAULT_SCHEMA?
CREATE USER ... WITH DEFAULT_SCHEMA = "licensemgr"
If not, you may need to use ALTER USER to fix this for your user in the new system.

Resources