What is the diffrence between...
execute as user = 'testuser'
AND
execute as login = 'testuser'
I am executing a cross database procedure under these logins and it works with the exececute as login but not the execute as user. It is saying the server principal "testuser" is nt able to access the database "xxx" under the securty context.
When i SELECT SYSTEM_USER after both commands I see that it is set to 'testuser'
execute as login provides impersonation to the entire server, since logins are on a server level. Since users are defined per database, execute as user impersonation applies only to a specific database, which is why you see the error when you cross databases.
The EXECUTE AS can be added to stored procs, functions, triggers, etc.
Example to Execute As:
CREATE PROCEDURE dbo.MyProcedure
WITH EXECUTE AS OWNER
In this case you are impersonating the owner of the module being called.
You can also impersonate SELF, OR the USER creating or altering the module OR...
impersonate CALLER , which will enable to module to take on the permissions of the current user, OR...
impersonate OWNER, which will take on the permission of the owner of the procedure being called OR...
impersonate 'user_name', which will impersonate a specific user OR...
impersonate 'login_name' with will impersonate a specific login.
Setting permission on objects like stored procedures can be accomplished with
GRANT EXECUTE ON <schema>.<procedurename> to <username>;
However, you may also want to grant security rights at both the login and user level.
You will want to determine and grant ONLY the necessary rights
for the objects that require access (such as execution). Consider use of the "EXECUTE AS" capability which enables impersonation of another user
to validate permissions that are required to execute the code WITHOUT having to grant all of the necessary rights to all of the underlying objects (e.g. tables).
MOST of the time, you will only need to grant EXECUTE rights to stored procs and then rights are granted to all objects referenced within the stored proc.
In this way, you do not need to give implicit rights (example: to update data or call additional procs). Ownership chaining handles this for you.
This is especially helpful for dynamic sql or if you need to create elevated security tasks such as CREATE TABLE. EXECUTE AS is a handy tool to consider for these.
This example may help clarify all of this:
--Create a user called NoPrivUser with public access to a database (e.g. dbadb)
USE [master]
GO
CREATE LOGIN [NoPrivUser] WITH PASSWORD=N'ABC5%', DEFAULT_DATABASE=[dbadb], CHECK_EXPIRATION=ON, CHECK_POLICY=ON
GO
USE [DBAdb]
GO
CREATE USER [NoPrivUser] FOR LOGIN [NoPrivUser]
GO
NOTE: CREATOR OR OWNER OF THIS PROCEDURE WILL REQUIRE CREATE TABLE RIGHTS within the target database.
use DBAdb
go
CREATE PROCEDURE dbo.MyProcedure
WITH EXECUTE AS OWNER
AS
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].MyTable') AND type in (N'U'))
CREATE TABLE MyTable (PKid int, column1 char(10))
INSERT INTO MyTable
VALUES (1,'ABCDEF')
GO
GRANT EXEC ON dbo.MyProcedure TO NoPrivUser;
GO
-- Now log into your database server as NoPrivUser and run the following.
use dbadb
go
EXEC dbo.MyProcedure
--(1 row(s) affected)
Now try to select from the new table while logged on as NoPrivuser.
You will get the following:
select * from MyTable
go
Msg 229, Level 14, State 5, Line 1 The SELECT permission was denied on
the object 'MyTable', database 'DBAdb', schema 'dbo'.
That is expected since you only ran the procedure under the security context of Owner while logged on as NoPrivUser.
NoPrivUser as no rights to actually read the table, Just to execute the procedure which creates and inserts the rows.
With the EXECUTE AS clause the stored procedure is run under the context of the object owner. This code successfully creates dbo.MyTable and rows are inserted successfully.
In this example, the user "NoPrivUser" has absolutey no granted rights to modify the table, or read or modify any of the data in this table.
It only takes on the rights needed to complete this specific task coded WITHIN the context of this procedure.
This method of creating stored procedures that can perform tasks that require elevated security rights without permanently assigning those rights come be very useful.
Login scope is at the server level while user scope is at the current database level
http://msdn.microsoft.com/en-us/library/ms181362.aspx
Related
Requirement:
User A can log in to SS instance, but only has access to database X. User A has no other access to any objects.
database X has a stored_proc called "sp_exec_dml" which takes a DML string and executes it. This stored proc would(should?) run as the owner X.
does database X, or the stored procedure ""sp_exec_dml" then need access to other dbs/objects.
for example
user A executes
exec x..sp_exec_dml N"update z..table set ..................."
I hope this makes sense. I come from an Oracle background so exactly how permissions are granted and who the grantees can be is confusing.
do databases or stored procedures have access granted to them
thanks
According to the MSDN : (URL : https://msdn.microsoft.com/en-US/library/ms345484.aspx )
To grant permissions on a stored procedure
In Object Explorer, connect to an instance of Database Engine and then expand that instance.
Expand Databases, expand the database in which the procedure belongs, and then expand Programmability.
Expand Stored Procedures, right-click the procedure to grant permissions on, and then click Properties.
From Stored Procedure Properties, select the Permissions page.
To grant permissions to a user, database role, or application role, click Search.
In Select Users or Roles, click Object Types to add or clear the users and roles you want.
Click Browse to display the list of users or roles. Select the users or roles to whom permissions should be granted.
In the Explicit Permissions grid, select the permissions to grant to the specified user or role. For a description of the permissions,
see Permissions (Database Engine).
Selecting Grant indicates the grantee will be given the specified
permission. Selecting Grant With indicates that the grantee will also
be able to grant the specified permission to other principals.
This link also explains few concepts :
(URL : https://dba.stackexchange.com/questions/6878/sql-server-stored-procedure-permissions )
Stored procedures take advantage of ownership chaining to provide
access to data so that users do not need to have explicit permission
to access database objects. An ownership chain exists when objects
that access each other sequentially are owned by the same user. For
example, a stored procedure can call other stored procedures, or a
stored procedure can access multiple tables. If all objects in the
chain of execution have the same owner, then SQL Server only checks
the EXECUTE permission for the caller, not the caller's permissions on
other objects. Therefore you need to grant only EXECUTE permissions on
stored procedures; you can revoke or deny all permissions on the
underlying tables.
If database X has "table" in
exec x..sp_exec_dml N"update z..table set ..................."
then the user should have access.
We are building a management app for our system, and one of the app's abilities is to create new databases for new users. This app needs to CREATE DATABASE, RESTORE DATABASE, CREATE USER, grant permissions, etc - so the user needs to have some very strong permissions.
We are contracting these services to an external company and we do not want to give them unrestricted access to our system, we only want them to be able to do what we allow them to do. So we thought about encapsulating the entire process in a stored procedure, granting EXECUTE on this to a specific domain user, and running it with EXECUTE AS 'SA'.
Unfortunately that is not possible - SA is not a database user and when we try to define it as one, we get the error
Msg 15405, Level 16, State 1, Line 1
Cannot use the special principal 'sa'.
We then thought about using DBO and setting up cross-database ownership chaining, but this is all beginning to be a serious headache.
Does anyone know of an elegant way to do this?
This is perfectly possible with module signing.
Create a procedure that executes the elevated code.
Add EXECUTE AS CALLER to the procedure
Create a certificate and private key
Sign the procedure
Drop the private key
Export the certificate
Import the certificate in [master]
Create a login derived from the certificate
Grant the required privileges to the certificate derived login
Note that any alteration to the procedure will invalidate the signature and will require to redo the procedure. Dropping the private key is very important because otherwise the vendor can sign a different procedure and get the elevated permissions on arbitrary code. See Signing an Activated Procedure for an example.
To manage things inside a database, you can use EXECUTE AS OWNER and make sure dbo owns the stored procedure. No problems there
However, CREATE DATABASE etc requires server level permissions. Note: you don't need sysadmin permissions.
With SQL Server 2012 you can use server roles, and GRANT CREATE DATABASE to this server role. For earlier versions, you can grant this directly to the login. Or use dbcreator if your prefer.
If you decide they need to manage logins however, securityadmin has the same effective permissions as sysadmin
create database admin;
GO
alter database admin set trustworthy on
GO
alter authorization on database::admin to [sa]
GO
use admin
GO
create procedure adminProc
with execute as 'dbo'
as
create database test
GO
create login tmp with password = 'tmp', check_policy = off
GO
create user tmp
GO
grant execute on adminProc to tmp
GO
execute as login = 'tmp'
GO
-- This fails
create database test
-- This works
exec adminProc
GO
revert
GO
drop database test
GO
Does the following command effectively give the user, "MyUser," permission to execute ALL stored procedures in the database?
GRANT EXECUTE TO [MyDomain\MyUser]
SQL Server 2008 and Above:
/* CREATE A NEW ROLE */
CREATE ROLE db_executor
/* GRANT EXECUTE TO THE ROLE */
GRANT EXECUTE TO db_executor
For just a user (not a role):
USE [DBName]
GO
GRANT EXECUTE TO [user]
SQL Server 2005 introduced the ability to grant database execute permissions to a database principle, as you've described:
GRANT EXECUTE TO [MyDomain\MyUser]
That will grant permission at the database scope, which implicitly includes all stored procedures in all schemas. This means that you don't have to explicitly grant permissions per stored procedure.
You can also restrict by granting schema execute permissions if you want to be more granular:
GRANT EXECUTE ON SCHEMA ::dbo TO [MyDomain\MyUser]
In addition to the answers above, I'd like to add:
You might want to grant this to a role instead, and then assign the role to the user(s).
Suppose you have created a role myAppRights via
CREATE ROLE [myAppRights]
then you can give execute rights via
GRANT EXECUTE TO [myAppRights]
to that role.
Or, if you want to do it on schema level:
GRANT EXECUTE ON SCHEMA ::dbo TO [myAppRights]
also works (in this example, the role myAppRights will have execute rights on all elements of schema dbo afterwards).
This way, you only have to do it once and can assign/revoke all related application rights easily to/from a user if you need to change that later on - especially useful if you want to create more complex access profiles.
Note: If you grant a role to a schema, that affects also elements you will have created later - this might be beneficial or not depending on the design you intended, so keep that in mind.
I am looking for a way to have a database user only have rights to execute stored procedures and functions. This needs to be a dynamic setting so that every time i add a stored procedure or function they have rights to it.
Constraints
I cannot change the names of the schema or stored prcedures or functions.
In SQL Server 2005 and newer, you can create a new database role
CREATE ROLE db_executor
and then grant that role the permission to execute - without specifying anything.
GRANT EXECUTE TO db_executor
This role can now execute all stored procedures and function in the database - and it will be able to execute any future stored procedures you add to the database, too!
So now just add this role to your user and you're done:
exec sp_addrolemember #rolename = 'db_executor', #membername = 'your-user-name-here'
PS: of course, you could also grant this permission to just a single user:
GRANT EXECUTE TO your-user-name
This makes management a nightmare, however - so I wouldn't go down that path..
Inspired by various schema related questions I've seen...
Ownership chaining allows me to GRANT EXECUTE on a stored procedure without explicit permissions on tables I use, if both stored procedure and tables are in the same schema.
If we use separate schemas then I'd have to explicitly GRANT XXX on the the different-schema tables. The ownership chaining example demonstrates that. This means the stored proc executing user can read/write your tables directly.
This would be like having direct access to your instance variables in a class, bypassing getter/setters, breaking encapsulation.
We also use row level security to restrict what someone sees and we apply this in the stored procedures.
So, how can we maintain schema separation and prevent direct table access?
Of course, the question won't apply if you use an ORM or don't use stored procs. But I'm not asking if I should use an ORM or stored proc in case anyone feels the need to enlighten me...
Edit, example
CREATE USER OwnsMultiSchema WITHOUT LOGIN
GO
CREATE SCHEMA MultiSchema1 AUTHORIZATION OwnsMultiSchema
GO
CREATE SCHEMA MultiSchema2 AUTHORIZATION OwnsMultiSchema
GO
CREATE USER OwnsOtherSchema WITHOUT LOGIN
GO
CREATE SCHEMA OtherSchema AUTHORIZATION OwnsOtherSchema
GO
CREATE TABLE MultiSchema1.T1 (foo int)
GO
CREATE TABLE MultiSchema2.T2 (foo int)
GO
CREATE TABLE OtherSchema.TA (foo int)
GO
CREATE PROC MultiSchema1.P1
AS
SELECT * FROM MultiSchema1.T1
SELECT * FROM MultiSchema2.T2
SELECT * FROM OtherSchema.TA
Go
EXEC AS USER = 'OwnsMultiSchema'
GO
--gives error on OtherSchema
EXEC MultiSchema1.P1
GO
REVERT
GO
CREATE PROC OtherSchema.PA
AS
SELECT * FROM MultiSchema1.T1
SELECT * FROM MultiSchema2.T2
SELECT * FROM OtherSchema.TA
Go
GRANT EXEC ON OtherSchema.PA TO OwnsMultiSchema
GO
EXEC AS USER = 'OwnsMultiSchema'
GO
--works
EXEC OtherSchema.PA
GO
REVERT
GO
Edit 2:
We don't use "cross database ownership chaining"
Row level security is a red herring and irrelevant: we don't use it everywhere
I fear that either your description or your conception of Ownership Chaining is unclear, so let me start with that:
"Ownership Chaining" simply refers to that fact that when executing a Stored Procedure (or View) on SQL Server, the currently executing batch temporarily acquires the rights/permissions of the sProc's Owner (or the sProc's schema's Owner) while executing that SQL code. So in the case of a sProc, the User cannot use those privs to do anything that the sProc code does not implement for them. Note especially that it never acquires the Identity of the Owner, only it's rights, temporarily (however, EXECUTE AS... does do this).
So the typical approach to leverage this for security is to:
Put all of the Data Tables (and all non-security Views as well) into their own Schema, let's call it [data] (though typically [dbo] is used because it's already there and too privileged for the User's schema). Make sure that no existing Users, Schemas or Owners have access to this [data] schema.
Create a schema called [exec] for all of the sProcs (and/or possibly any security Views). Make sure that the owner of this schema has access to the [data] schema (this is easy if you make dbo the owner of this schema).
Create a new db-Role called "Users" and give it EXECUTE access to the [exec] schema. Now add all users to this role. Make sure that your users only have Connect rights and have no granted access to any other schema, including [dbo].
Now your users can access the data only by executing the sProcs in [exec]. They cannot access any other data or execute any other objects.
I am not sure if this answers your question (because I was uncertain what the question was exactly), so feel free to redirect me.
As for row-level security, here is how I always do it with the security scheme above:
I always implement row-level security as a series of Views that mirror-wrap every table and compare the User's identity (usually with Suser_Sname() or one of the others) to a security list keyed from a security code in the row itself. These are the Security-Views.
Create a new schema called [rows], give it's owner access to the [data] schema and nothing else. Put all of the Security-Views in this schema.
Revoke the [exec] owner's access to the [data] schema and instead grant it data access to the [rows] schema.
Done. Now row-level security has been implemented by transparently slipping it between the sProcs and the tables.
Finally, here is a stored procure that I use to help me remember how much of this obscure security stuff works and interacts with itself (oops, corrected version of code):
CREATE proc [TestCnxOnly].[spShowProc_Security_NoEX] as
--no "With Execute as Owner" for this version
--create User [UserNoLogin] without login
--Grant connect on database :: TestSecurity to Guest
--alter database TestSecurity set trustworthy on
--Show current user context:
select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (sproc)]
, suser_sname() as sname
, system_user as system_
--Execute As Login = 'UserNoLogin'
select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (after exec as)]
, suser_sname() as sname
, system_user as system_
EXEC('select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (in Exec(sql))]
, suser_sname() as sname
, system_user as system_')
EXEC sp_ExecuteSQL N'select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (in sp_Executesql)]
, suser_sname() as sname
, system_user as system_'
--Revert
select current_user as current_
, session_user as session
, user_name() as _name
, suser_name() as [suser (aftr revert)]
, suser_sname() as sname
, system_user as system_
[EDIT: corrected version of code)
My 2c: Ownership chaining is legacy. It dates from days when there was no alternatives, and compared with today's alternatives is unsecure and coarse.
I say the alternative is not schema permissions, the alternative is code signing. With code signing you can grant the needed permissions on the signature of the procedure, and grant wide execute access on the procedure while the data access is tightly controlled. Code signing offers more granular and more precise control, and it cannot be abused the way ownership chaining can. It works inside the schema, it works across the schema, it works across the database and does not require the huge security hole of cross database ownership chaining to be open. And it doesn't require the hijacking of the object ownership for access purposes: the owner of the procedure can be any user.
As for your second question about row level security: row level security doesn't really exist in SQL Server versions 2014 and earlier, as a feature offered by the engine. You have various workarounds, and those workarounds work actually better with code signing than with ownership chaining. Since sys.login_token contains the context signatures and countersignatures, you can actually do more complex checks than you could in an ownership chaining context.
Since version 2016 SQL Server fully supports row level security.
You can:
Grant Execute On Schema::[schema_name] To [user_name]
to allow the user to execute any procedures in the schema. If you don't want him to be able to execute all of them, you can explicitly deny execute on a particular procedure to the user. Deny will take precedence in this case.