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.
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 in the process of configuring database users for some new developers and I am running into some difficulties as I am reading lots of articles and it's not working out too well for me. I have tried various configurations manually and with T-SQL but I need a more efficient method.
My objective:
Some TSQL I can launch to give a database user the following permissions:
Grant permission to execute all Stored Procedures within the Database
Deny permission to View Definition of all of these stored procedures
Grant permission to SELECT, UPDATE, INSERT, DELETE from all tables within the database
Deny permission to View Definition of all of the tables in the database (I don't want them to view the data)
What I have tried:
I have achieved this manually but I have 200+ stored procedures and 100+ tables so I don't want to do it manually. From the T-SQL aspect I have managed to get the following to work:
USE database_name;
GRANT EXECUTE TO [security_account];
This works and allows the users to run the stored procedures but they cannot view the actual query code. I need the same logic for the tables as described above.
Thank you for your help.
I am not quite sure if this is a viable solution to your problem. But maybe it will get you at least closer to what you want. So, here is the setup I'd propose:
Do not grant anybody any permissions on any table.
Use stored procedures for DML.
Grant execute on all these stored procedures to public.
Setup one table in your database which lists all users which have access to your database including their login (suser_sname()) and their permissions (for example MayAlterTableUsers).
Implement into all stored procedures a check similar to this
if (
select isnull(MayAlterTableUsers, 0)
from tblUsers
where LoginName = suser_sname()
) > 0
begin
select N'Implementing the requested changes to tblUsers.'
end
else
begin
select N'You don''t have the required permission.'
end
Setup you views similar and grant select on all views to public
create view vShowAllUsers as
select *
from dbo.tblUsers
cross apply (
select MaySeeAllUsers
from dbo.tblUsers
where LoginName = suser_sname()
) as p
where p.MaySeeAllUsers = 1
In the end all views and all stored procedures will be publicly available but the handling of permission will be within each one of them. All permissions themselves will be within this table tblUsers. Since nobody has the possibility to alter this table tblUsers unless (of course) they are in this table with the appropriate permission, this DB setup is self-contained.
I am using insert statement and trying to insert data into the database table. I am using stored procedures.
But I am getting this error while doing so.
Message: ORA-00942: table or view does
not exist ORA-06512
I checked if the tables/stored procedures are present or not and everything is in place. Also there is no typo in table names or in sp. If I run the part of SP from query editor it works fine but when I execute the entire SP it throws an error.
I tried the steps provided by Stephen but since I have logged in with the same user/owner when I run Grant command it gives me an error saying 'Cannot Grant/revoke on own'.
One more addition to this. I have a stored procedure SP1 in which I am using a select statement as
Select a from table_name where condition;
When I execute this seperately, it returns me some results. But when I execute sp it gives an error at the same line where it is written.
Can anyone help me out to resolve this issue. I am using SQL +.
Thanks in advance
Vijay
Justin's answer is correct but let me expand a bit.
Everyone who said that the table doesn't exist didn't read your whole post. Since you are able to:
If I run the part of SP from query editor it works fine
Obviously the table is there.
Obviously you have some access to it. Otherwise this wouldn't work when it clearly does.
but when I execute the entire SP it throws an error.
This is because Oracle distinguishes between permissions granted directly and those granted via a role.
Say I do this:
Create Table TABLE_A
Create Role READ_ONLY
Grant Select on TABLE_A to READ_ONLY
Grant READ_ONLY to VIJAY
In a SQL Window/prompt you could query that table without issue. So now you need to create a view
Create VIJAY.VIEW_A as SELECT * FROM TABLE_A
You'll get the error that TABLE_A does exist. Because a view is compiled, like a procedure it runs without any roles. Since it runs without the READ_ONLY role, it's blind to the fact that TABLE_A exists. Now what I need to do is
Grant Select on TABLE_A to VIJAY.
Now that you have a direct permission, you can compile a view or procedure/package that uses that table.
Does the table exist in the schema where the stored procedure exists? If not, the simplest explanation is that the owner of your procedure has been granted access to the table via a role not via a direct grant. A definer's rights stored procedure needs to have direct access to the objects it accesses. A quick way to test this is to disable roles for the session, i.e.
SQL> set role none;
SQL> <<execute your query>>
If that generates the error, the problem is the lack of a direct grant.
In Oracle you can choose if the stored procedure is executed with the rights of the invoker or the definer: http://download.oracle.com/docs/cd/E11882_01/appdev.112/e17126/subprograms.htm#i18574
Check if the AUTHID property of the stored procedure is correct and if the resulting user has appropriate permissions.
Well, put very simply, the table that you are trying to insert data into does not exist in the database you are connected to. You need to check both those things (i.e. what are you connected to, and is the table there and accessible for the user context you are using).
As Joe Stefanelli said .. there are a lot of possibilities for the error being shown here.
Check whether:
You are connecting to the correct Oracle Instance.
You have permissions to query or perform processing on table that you are referencing in your query.
There is a difference between ordinary select statements and procedures. Procedures in oracle do not respect the roles assigned to a user; rather the permission needs to be explicitly granted to the user. For more information read the following linkORA-00942
I have a database where all access is controlled by stored procedures. The DBA would like to avoid giving users direct read/write access to the underlying tables, which I can understand. Hence all updating and selecting of data is done via stored procedures. Basically he has created one role that has EXECUTE permissions to all the stored procedures in the database and given users that role.
The problem is that one of the stored procedures dynamically builds a SQl Query and executes it via "Execute sp_Executesql". Without going into great detail the query is built dynamically because it changes significantly depending on many user input parameters. The stored procedure in question is only a SELECT sql statement however I am finding that just giving the stored procedure EXECUTE permission is not enough. The underlying tables referenced within the stored procedure that make use of "Execute sp_Executesql" need to have been given "datareader" access or else the stored procedure fails.
Any thoughts on how to correct this? I really wanted to restrict access to the tables to only stored procedures, but I need to find a way to work around the stored procedures that make use of "Execute sp_Executesq"l. Thank you.
In the wrapper proc you can use EXECUTE AS OWNER or EXECUTE AS SomeuserWithNoLogin
This will change the login context for the duration of the stored proc which includes sp_executesql.
If you use OWNER, it will work because you're already using ownership chaining.
If your DBA (good man!) does not want you running as dbo, then set up a user that has full read but no rights. EXECUTE AS <user> requires an entry is sys.database_principals
Like this:
CREATE USER SomeuserWithNoLogin WITH WITHOUT LOGIN
EXEC sp_addrolemember 'db_datareader', 'SomeuserWithNoLogin'
For more info, see EXECUTE AS Clause on MSDN and CREATE PROCEDURE
The real problem is that sp_Executesql is in the master database, not necessarily the database your working in. Your DBA has to give execute sp_Executesql permission to the calling procedure. Than anyone who has permission to call that procedure will be able to run the sp_Executesql.
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,