I have several stored procedures in my database that are used to load data from a datamart that is housed in a separate database. These procedures are, generally, in the form:
CREATE PROCEDURE load_stuff
WITH EXECUTE AS OWNER AS
INSERT INTO my_db.dbo.report_table
(
column_a
)
SELECT
column_b
FROM data_mart.dbo.source_table
WHERE
foo = 'bar';
These run fine when I execute the query in SQL Server Management Studio. When I try to execute them using EXEC load_stuff, the procedure fails with a security warning:
The server principal "the_user" is not able to access the database "data_mart" under the current security context.
The OWNER of the sproc is dbo, which is the_user (for the sake of our example). The OWNER of both databases is also the_user and the_user is mapped to dbo (which is what SQL Server should do).
Why would I be seeing this error in SQL Server? Is this because the user in question is being aliased as dbo and I should use a different user account for my cross-database data access?
Edit
I understand that this is because SQL Server disables cross database ownership chaining by default, which is good. However, I'm not sure of the best practice in this situation. If anyone has any input on the best practice for this scenario, it would be greatly appreciated.
Edit 2
The eventual solution was to set TRUSTWORTHY ON on both of the databases. This allows for limited ownership chaining between the two databases without resorting to full database ownership chaining.
Why not remove EXECUTE AS OWNER?
Usually, my user executing the SP would have appropriate rights in both databases, and I don't have to do that at all.
There is no need to create login, you can just enable guest user in target DB.
grant connect to guest
This allows executing user to enter DB under guest context, and when "db chaining is ON access will not be checked in target DB.
Actually, DBO is a role (you can consider it as a group of users), not a user in himself. (Unless you can connect to SQL SERVER using dbo:passwordfordbo it's not a user).
Usually, in the wonderful world of SQL Server, if you grant userX right to execute storedprocY then X gets the right to perform all the task Y contains even if he doesn't have all the permission on all the objects used in Y.
That's an extremely useful feature to encapsulate business logic in a stored procedure. (Your user have NO access on the table but they do can EXECUTE one stored proc).
When we talk about "ownership chaining" it means the following (please correct me if I am wrong though)
- If ownership chaining is disabled: the right to execute procedureX will work as long as all the required objects are in the same database
- Of chaining is enabled: That "privilege" will expands towards all databases.
Hope that helps,
Related
I have a Stored Procedure in Database A, that references 3 tables in Database B. Both Databases are on Server 1.
I gave the user:
public permission on Server 1
EXECUTE permissions on the Stored Procedure in Database A
An entry with no permissions on Database B
However, this isn't sufficient. I end up having to assign SELECT permissions to the user, for the 3 tables in Database B (plus SELECT permissions on the schema). Then things work - but why is that necessary?
Per Microsoft, this shouldn't be the case:
"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."
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql/managing-permissions-with-stored-procedures-in-sql-server
Googling, I see this concept confirmed.
This is my first time assigning permissions to anyone though, so obviously I'm missing something and/or misunderstanding.
Edit: "Permissions only chain within a single database." That explains it!
"Permissions only chain within a single database." per comment from Larnu. That explains it.
I am building an application consisting of an SQL Server 2008 R2 back-end and an MS Access front-end.
All data is kept in SQL Server.
MS Access is a just a bunch of forms, controls and VBA ADO objects that call stored procedures on the SQL server, ie. users interface with SQL server through stored procedures only.
These stored procedures are a combination of ones that don't alter the state of the database (eg. select from table/view/function) and some that do alter state (eg. insert/update/delete/merge)
On SQL Server, I have an AD Group called 'ADG', which is both a Server Login and a Database User. Users of the MS Access front-end are members of ADG.
All of the SQL Server database objects (tables, views, functions and stored procedures) are under a single, specific schema called 'ABC' that is owned by dbo. There are other schemas in the database, again, all owned by dbo.
I have been reading up on 'Ownership Chaining' and would like clarification of the following:
Is 'dbo' the 'owner' of the tables, views, functions and stored procedure under the 'ABC' schema by virtue of its ownership of the 'ABC' schema?
Given the above set up of the application and depending on the answer to 1., is 'EXECUTE' on the ABC schema, the only permission I
need granted to ADG or do I need any others?
Any help in clarification is appreciated.
Check out https://msdn.microsoft.com/en-us/library/ms191465.aspx for a good picture of the permission hierarchy.
If all your objects are in the same ABC schema, then the owner of the schema is effectively the owner of the underlying objects. Again, see the diagram in the link above for a clear picture.
EXECUTE is a specific permission to execute stored procedures. You can do the same for functions unless the function returns a table, then you need SELECT permissions. So if you GRANT EXECUTE on SCHEMA::ABC TO adg then you've just allowed adg to run sprocs. They still may not have access to data depending on how the sprocs were written. Look up details on permissions in SQL Server books online for details on what you need to grant (https://msdn.microsoft.com/en-us/library/ms191291.aspx)
I need to check whether a user is db owner.
I've found two methods:
look at "exec sp_helprolemember" output table
select count(*) from (select DbRole = g.name, MemberName = u.name, MemberSID = u.sid from sys.database_principals u, sys.database_principals g, sys.database_role_members m where g.principal_id = m.role_principal_id and u.principal_id = m.member_principal_id and g.name='db_owner') output where MemberName='user_to_be_checked'
Which is, in your opinion, the most long term supported method?
I mean: will it be more likely for Microsoft to commit design changes to system tables structures or stored procedures syntax/output?
And which one is the most portable across SQL Server versions?
Thnx
Raf
Both methods you list are incorrect.
To start with, is always incorrect to check for db_owner membership. The correct check is for CONTROL permission on the database, and the appropriate function to use is HAS_PERM_BY_NAME(). This will save you from the embarrassment of your application refusing to work with an user that has sufficient privileges (CONTROL) because the application uses an incorrect check (role/group membership). This is actually explicitly called out on MSDN:
If the user has the CONTROL DATABASE permission but is not a member of db_owner role, ... will correctly report that the user is not a member of the db_owner role, even though the user has the same permissions.
Finally, if you really need to know role/group membership, the appropriate function is IS_MEMBER()
I would recommend neither actually.
For the catalog view option, Microsoft says:
In future releases of SQL Server, Microsoft may augment the definition
of any system catalog view by adding columns to the end of the column
list. We recommend against using the syntax SELECT * FROM
sys.catalog_view_name in production code because the number of columns
returned might change and break your application.
I believe the same may hold for the system stored procedure.
Instead, I'd suggest using the IS_ROLEMEMBER function. For example:
SELECT IS_ROLEMEMBER('db_owner', 'user1');
It returns 1 if true and 0 if false.
http://technet.microsoft.com/en-us/library/ee677633.aspx
I would think that the system stored procedure - exec sp_helprolemember - would be the long term supported method.
I looked at the source code for exec sp_helprolemember and internally it has the check your are doing in your 2nd method (not verbatim, but it has other conditions also).
Moreover, using Microsoft provided system stored procedures is the recommended way of getting information unless their existing procedures do not give you all the information you want. In that case, you dig deeper and write your own queries against system tables and functions.
I need to restrict user access to SELECT, INSERT, UPDATE and DELETE, so that user should manage data only using stored procedures I provide.
So, for instance
SELECT * FROM Table1
should return
The SELECT permission was denied on the object 'Table1'
however, if there is stored procedure SelectTable1 defined as
CREATE PROCEDURE SelectTable1
AS
BEGIN
SELECT * FROM Table1
END
(the real one contains filtering and parameters, so it is not meaningless, like the one above)
user should execute it successfully and get the resultset.
But obviously, I have no success implementing this set of permissions. Can anybody point me to some specific tutorial? MSDN was not very helpful.
Database is SQL Server 2012 and all objects (tables and stored procedures) are in custom schema.
You can do it using GRANT EXEC either on specific procedures or on schemas or on a database.
The following example grants EXECUTE permission on stored procedure
HumanResources.uspUpdateEmployeeHireInfo to an application role called
Recruiting11.
USE AdventureWorks2012;
GRANT EXECUTE ON OBJECT::HumanResources.uspUpdateEmployeeHireInfo
TO Recruiting11;
GO
Thanks to Igor I've got to the right MSDN page, and followed rights links.
However, using ownership chains suggested was too complicated for me, so I used
WITH EXECUTE AS OWNER
on my stored procedures and that works very good. When I log on using restricted user I see only procedures, no tables at all and I can execute procedures, but not even select from tables.
Also, I want to mention this concept is very similar to setuid and thus was familiar to me.
I mark Igors reply as answer, because ownership chains seem to be more generic way, just wanted to share info I found.
I'm making a call to odbc32.dll (SQLBrowseConnect) to return a list of databases on a sql server.
From running a trace I can see the query being executed is
select name from master..sysdatabases where has_dbaccess(name)=1
If the credentials I pass aren't the sa user it returns just the system databases. Is there anyway I can use SQLBrowseConnect with another user (whose default database is also not guarenteed to be the master database) to return all databases on the server?
Also I want to avoid smo objects
The query does work without sysadmin credentials.
You need to ensure that you / the credentials you are using are at least in the public database role on each of the databases that you need to connect to.
As you would guess, select name from master..sysdatabases returns all database names irrespective of your access to the DB.