I am configuring the database accounts for some new users. I have come up with the following solution which is 99% of the way to getting the accounts to work but I have hit a problem which I cannot resolve.
Firstly, I created a new login with SQL Server authentication and then gave them the EXECUTE permission to all stored procedures. This allows them to run them all but they cannot view the code and they cannot view the database tables.
Inside the stored procedures I added the following:
WITH EXEC AS OWNER
This allowed the stored procedures to run as the default account we normally use and this has the role of db_owner. This allows the new users to run all the stored procedures and it works great until I hit the following problem:
Some of the stored procedures (all of which are using dynamic SQL) call some synonyms which link to tables in two other databases (history and a data mart database). This gives me the following error:
The server principal "{username}" is not able to access the database "{database name}" under the current security context.
The account which I am using in the WITH EXEC AS is the db_owner of all three databases I am working with.
What can I do to resolve this problem? Many thanks
EXECUTE AS Owner is a database sandbox. Think about it, it has to be. Otherwise a database administrator can issue and EXECUTE AS USER = 'somesystemadmin' and elevate himself to an instance level administrator. The details are described in Extending Database Impersonation by Using EXECUTE AS:
when impersonating a principal by using the EXECUTE AS USER statement, or within a database-scoped module by using the EXECUTE AS clause, the scope of impersonation is restricted to the database by default. This means that references to objects outside the scope of the database will return an error.
The solution is simple: sign the procedure. See Call a procedure in another database from an activated procedure for an example. Read more at Module Signing and Signing Stored Procedures in SQL Server.
Related
In UNIX (and, if my memory is not betraying me, in Linux too), there is a mechanism through which execute permission is given to users (that cannot access other files) but the program itself runs with different credentials, such that the same files the invoking users cannot access, the user of the program can.
Is there any similar (or equivalent) mechanism that would allow a DB-defined user only to execute a specific procedure and nothing else, while the same procedure would have permission to invoke any other procedure within the schema and, if needed, also access other DBs?
If you grant permissions to user to execute specific procedures then user will only be able to execute those procedures. Inside those procedures you can use same schema objects or call other procedures within same schema (called "ownership chaining") or other schema if that other schema is owned by same owner.
If needed, you can use "Execute As" for stored procedures so that user rights inside procedure are different from user that calls those procedures. That gets tricky in some more complex scenarios (e.g. dynamic SQL).
It gets more complicated if you want to call procedures from other database. In that case would recommend using certificates and procedure signing (Erland Sommarskog blog is execelent).
The Point: I want to be able to create a directory on the filesystem through a non-sysadmin SQL user.
I'm creating a web front-end for a deployment script which creates new databases from a specified template database.
Essentially I'm backing up said template database and then restoring this as a brand new database with a different name.
Our DB server has our client databases stored in sub-folders within our database store. If I were to use the default settings it would look something like:
D:\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\[ClientRef]\[ClientRef].mdf
D:\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\[ClientRef]\[ClientRef].ldf
I only have SQL access to the database server (via a programming language, hosted on a separate box) so I can't execute anything other than SQL.
My database user is extremely limited, however I would like to somehow grant this user to access/execute master.dbo.xp_create_subdir only. Is this possible at all?
I'm loathe to give our local DB user sys-admin rights, it has a limited user for a reason.
DB Server is Microsoft SQL Server 2008 R2.
Cheers, any help will be appreciated.
One possible solution is to write your own sproc that internally uses master.dbo.xp_create_subdir.
Create the sproc while logged in as an account that's a member of the sysadmin role and use "WITH EXECUTE AS SELF". Then grant permissions to that other account to execute this sproc. The database catalog where you create this wrapper-sproc must be marked as "trustworthy" or you'll still get the: User must be a member of 'sysadmin' server role. error.
E.g.
CREATE PROCEDURE [dbo].[sprocAssureDirectory] #directoryFullPath varchar(4000)
WITH EXECUTE AS SELF
AS
BEGIN
EXEC master.dbo.xp_create_subdir #directoryFullPath;
END
Just make sure you add any needed assertions/checks to your sproc that make sense for your application (e.g. the path can only be of a pattern that you expect).
Belated Update: Added the critical mention of marking the catalog as trustworthy.
You could give access for the user to use that stored proc explicitly. It is gonna be something like:
GRANT EXECUTE ON OBJECT::master.dbo.xp_create_subdir
TO <SQL USER>;
It sounds like that user is limited for a reason though and getting the extra permissions to run something like that can get a little push back from whoever is managing the DB. So be careful when dealing with getting the elevated privledges.
I've set up multiple views in a sql server database. These views are are selected from in a stored procedure which has WITH EXECUTE AS 'proxyuser' clause in it's declaration. The select statement it executes is created dynamically, and executed with the sp_executesql stored procedure. Everything has worked correctly until it became necessary to include a join to a table in a different database in the definition of one of those views, so that the view is selecting from both the database where it resides and another database on the same server.
The error I'm getting is this: The server principal "proxyuser" is not able to access the database "mydb" under the current security context.
This is what I've tried:
Deleting the proxyuser from the second database and mapping the login to the database as recommended here..
http://sqlmusings.wordpress.com/2008/06/12/issue-server-principal-is-not-able-to-access-the-database-under-the-current-security-context/
Enabling cross database ownership chaining as recommended here..
http://social.msdn.microsoft.com/Forums/en-US/sqlsecurity/thread/07dcab8c-b830-4ca9-8afc-3e75772f44d3/
and my scenario doesn't meet the requirements outlined by Microsoft Support Article #913422, which describes the same error message. The proxy uses Sql Server Authentication, not Windows Authentication.
Any ideas?
Thanks in advance.
I'm finally coming back to this after a long side-track working on a different project. I worked it out so that I'm no longer using the WITH EXECUTE AS 'proxyuser' syntax. The user I was connecting with had sufficient permissions to perform the action. I'm not sure why I didn't try that before.
I am using SQL Server 2008 Express edition.
I have created a Login , User, Role and Schema.
I have mapped the user to the login, and assigned the role to the user.
The schema contains a number of tables and stored procedures.
I would like the Role to have execute permissions on the entire schema.
I have tried granting execute permission through management studio and through entering the command in a query window.
GRANT EXEC ON SCHEMA::schema_name TO role_name
But When I connect to the database using SQL management studio (as the login I have created) firstly I cannot see the stored procedures, but more importantly I get a permission denied error when attempting to run them.
The stored procedure in question does nothing except select data from a table within the same schma.
I have tried creating the stored procedure with and without the line:
WITH EXECUTE AS OWNER
This doesn't make any difference.
I suspect that I have made an error when creating my schema, or there is an ownership issue somewhere, but I am really struggling to get something working.
The only way I have successfully managed to execute the stored procedures is by granting control permissions to the role as well as execute, but I don't believe this is the correct, secure way to proceed.
Any suggestions/comments would be really appreciated.
Thanks.
There are couple of issues that I can see in your case.
First of all you would need View Definition granted for you to be able to see the objects in the Management studio.
I would recommend this if you want the role to have all permissions,
GRANT EXECUTE, SELECT, INSERT, UPDATE, DELETE, VIEW DEFINITION
ON Schema::SchemaName TO [RoleName/LoginName]
Also make sure the owner of your user-defined schema is "dbo".
At the bottom of most of our stored procedures we have a grant similar to
GRANT EXECUTE ON [dbo].[uspFOO] TO [DOMAIN\SQLServerUsers]
Luckily for me, our domain is changing and we now need to go through and change the permissions. Does anyone know of an easy way to do this using the DB metadata so I can pull out all the places where [DOMAIN\SQLServerUsers] is given permission to run and substitute it with [DOMAIN2\SQLServerUsers]?
Thanks.
For those asking, this is on SQL Server 2005.
What version of SQL Server are you on??
In 2005 and up, you could
create a new database role "db_executor" and do
GRANT EXECUTE TO db_executor
grant that database role to all necessary users
This will create a "catch all" role that has execute rights on every existing and future (!!) stored proc in your database. Yes, that does include future stored procs, too! Very handy indeed (at least as long as every user is allowed to execute all stored procs)
That way, you don't have to create separate GRANT EXECUTE statements for each and every stored proc.......