Stored procedure to act differently based on user role - sql-server

I'm trying to figure out if there is a way to achieve the converse of this:
can a SQL Server stored proc execute with higher permission than its caller?
I want to create a stored procedure which does one thing if the user is in a role, but a fallback option if they're not.
My first attempt tried to query the current user's roles, based on this:
How to query current user's roles
I tried to query what role a user was in, and decide what to do based on that. But if you set "mydomain\Domain Users" to a role (for example), users who belong to Domain Users aren't listed in the sys.database_role_members view. So users who were supposed to have permissions don't.
From here https://msdn.microsoft.com/en-us/library/ee677633.aspx
IS_ROLEMEMBER always returns 0 when a Windows group is used as the database
principal argument, and this Windows group is a member of another Windows
group which is, in turn, a member of the specified database role.
My next attempt works like this. Create a stored procedure with the actual permissions, and then a wrapper around it which calls the with lower permissions, and if that fails, perform the fallback action:
CREATE PROCEDURE [internal_myproc]
AS
BEGIN
-- do something here
END
GO
GRANT EXECUTE ON [internal_myproc] TO [Role1] AS [dbo]
GO
CREATE PROCEDURE [myproc]
AS
BEGIN
BEGIN TRY
EXEC [internal_myproc]
END TRY
BEGIN CATCH
-- perform fallback action
END CATCH
END
GO
GRANT EXECUTE ON [internal_myproc] TO [Role1] AS [dbo]
GO
GRANT EXECUTE ON [internal_myproc] TO [Role2] AS [dbo]
GO
GRANT EXECUTE ON [internal_myproc] TO [Role3] AS [dbo]
GO
The problem with this is that [Role1] and [Role2] both succeed in executing [internal_myproc] via [myproc]. If you take the code out of the stored procedure, it behaves the way it should, but because it's hidden inside a stored procedure, it gets implicit permissions to execute other stored procedures. I've experimented with "WITH EXECUTE AS" stuff, but it doesn't seem to change anything.
I also tried "IF HAS_PERMS_BY_NAME('internal_myproc', 'OBJECT', 'EXECUTE') = 1", suggested here MS SQL Server: Check to see if a user can execute a stored procedure , but that seems to not work in certain situations I haven't understood yet.
Is there a way to NOT grant those implicit permissions, to do a permission check inside a stored procedure? Or something equivalent?

Related

How can someone see all rows in sys.sysprocesses and not be SA?

The only user that can see the entire sys.sysprocesses is the SA. Is there a role I can place a user (or any other way) that a user can be made a member of so the user can see the entire sys.sysprocesses -all the rows for all users not just the processes for the user executing the select.
I connect to many SQL Server instances with a dbo account. I need to know if someone is connected to the instance. I cannot get SA privileges.
You can use code signing to accomplish what you're looking to do. Here's the code:
CREATE LOGIN [normalUser] WITH password = 'f00bar!23'
CREATE USER [normalUser]
GO
CREATE CERTIFICATE [codeSigningCert] WITH SUBJECT = 'Certificate for code signing', EXPIRY_DATE = '2099-01-01'
CREATE LOGIN [codeSigningLogin] FROM CERTIFICATE [codeSigningCert]
GRANT VIEW SERVER STATE TO [codeSigningLogin]
go
CREATE PROCEDURE dbo.processesProc
AS
BEGIN
SELECT *
FROM sys.sysprocesses AS s
END
GO
GRANT EXECUTE ON dbo.processesProc TO [normalUser]
GO
EXECUTE AS LOGIN = 'normalUser'
GO
EXEC dbo.processesProc
GO
REVERT
GO
ADD SIGNATURE TO processesProc BY CERTIFICATE [codeSigningCert]
GO
GRANT EXECUTE ON dbo.processesProc TO [normalUser]
GO
EXECUTE AS LOGIN = 'normalUser'
GO
EXEC dbo.processesProc
GO
REVERT
GO
By way of explanation, I'm creating an unprivileged login/user and a stored procedure for them to run. Without signing the procedure, the select exhibits the normal behavior (that is, it only displays the current process. But once I add a signature to the procedure using a certificate that has an associated login with the proper permissions, the result set blossoms.
Note: I created the procedure in master because I'm lazy. You can create the procedure anywhere you want so long as the certificate exists in the database you're creating the procedure in (so you can add the signature). Lastly, one gotacha with code signing is that the signature is lost when the procedure is modified. This makes sense as the signature is an attestation of the contents of the proc at the time of signing. If the body is changed, it will need to be re-signed.

How to set DENY permissions on a data user

For a .net application we can store database connectionstrings like so
<connectionstrings config="cnn.config" />
I am trying to get as little as permissions as possible but there always seems to be a different way. To get info.
I am using the settings because they are more secure for one and two I have other people working on my application.
So I've set
USE database_name;
GRANT EXECUTE TO [security_account];
So the user can execute commands that's fine.
Then I've got db_reader and db_writer so they can read and write and this seems like a perfect marriage.
Still bad news the user can login and see the tables and store procedures definitions but not alter them, however, they can still see them.
How can I set the permissions to where the user can read, write. execute, and that is it PERIOD!?
Being able to see the definition of tables, stored procedures, etc is governed by the VIEW DEFINITION permission. So you can do:
DENY VIEW DEFINITION TO [yourUser];
And that user won't be able to see the definition for any object in the database. This also includes the ability to see other users.
If you want to stop the user from viewing the sp definition you need to specify the WITH ENCRYPTION option in the sp.
Adding a user to the db_datareader and db_datawriter role and granting EXECUTE will limit the user to reading writing and executing but they will still be able to see the sp definition by using the sp_helptext stored procedure and sys.sql_modules catalog view. See here for more information on sp and funciton encryption.
exec sp_addrolemember #rolename = 'db_datareader', #membername = 'testUser'
exec sp_addrolemember #rolename = 'db_datawriter', #membername = 'testUser'
GRANT EXECUTE TO testUser;
You can create an sp the WITH ENCRYPTION option by adding it before the AS keyword like this. See the WITH ENCRYPTION section of the CREATE PROCEDURE definition here
CREATE PROCEDURE HumanResources.uspEncryptThis
WITH ENCRYPTION
AS
SET NOCOUNT ON;
SELECT BusinessEntityID, JobTitle, NationalIDNumber, VacationHours, SickLeaveHours
FROM HumanResources.Employee;
GO
You can also alter functions by adding it after the returns keyword.
ALTER FUNCTION dbo.getHash ( #inputString VARCHAR(20) )
RETURNS VARBINARY(8000) WITH ENCRYPTION

execute('tsql_string') inside stored procedure - what permissions/user is used for execute()?

I have a stored procedure where I'd like to save the execution of an update statement for further down in the procedure, which I'm doing by putting the sql into a varchar variable.
My problem is that the EXECUTE() seems to use the original caller's permissions and then gives an error, as the caller does not (and should not) have UPDATE permissions for table1.
Why doesn't it use the permissions of the stored procedure's owner?
And more importantly: how can I make it use those permissions?
The stored procedure looks basically like this: (except #tsql_string is set dynamically)
create procedure dbo.woopwoop() as
BEGIN
DECLARE #tsql_string varchar(max)
SET #tsql_string = 'UPDATE table1 set c1 = 1'
EXECUTE(#tsql_string)
END
I'm on SQL Server 2008, and the owner (me) of the stored procedure is a Windows Authentication user with domain\user.
Anyone?
That's what the EXECUTE AS clause exists for - to allow you to control this:
By specifying the context in which the module is executed, you can control which user account the Database Engine uses to validate permissions on objects that are referenced by the module.
CALLER
Specifies the statements inside the module are executed in the context of the caller of the module. The user executing the module must have appropriate permissions not only on the module itself, but also on any database objects that are referenced by the module.
CALLER is the default for all modules except queues
You would be wanting to specify that the stored procedure executes as OWNER (or possibly SELF, read the above page and decide which makes most sense for you) instead.
create procedure dbo.woopwoop()
with execute as owner
as
....
From MSDN (This example grants EXECUTE permission on the stored procedure HumanResources.uspUpdateEmployeeHireInfo to an application role named Recruiting11):
USE AdventureWorks2012;
GRANT EXECUTE ON OBJECT::HumanResources.uspUpdateEmployeeHireInfo
TO Recruiting11;
GO
Source
Of course you should have permission to grant the permission.

Difference EXECUTE AS targets

I am not quite clear about the difference between different EXECUTE AS targets in SQL Server : CALLER, SELF and OWNER, notably between the last two.
My understanding is that CALLER is the one who Execute/Call the procedure.
SELF is the specified user is the person creating or altering the module
OWNER is the current owner of the module
Could you explain and give some example who is the person creating/modifying and the owner of the module. Is 'module' here the stored procedure/function or the session or the database ? Including an example with SELF user will be great.
Being put very simple, SELF impersonates you as a database user who actually executed create / alter procedure the last time. It doesn't always have to be the schema owner, as you can imagine, it can be any person with permissions sufficient to create / modify given objects.
The OWNER mode impersonates you as the owner of the schema the procedure / function belongs to.
If you want to dig a little deeper (and is this case, there is always some room to dig in), below is a (relatively) simple example that can demonstrate you how things can work here. There are some shortcuts and implications that are specific to SQL Server which I omit deliberately because otherwise it would be too much to write. You can always read the documentation, though.
use master;
go
if db_id('TestDB') is not null
drop database TestDB;
go
create database TestDB;
go
use TestDB;
go
-- Just for the sake of example, so that everyone can create procs
grant create procedure to public;
go
-- Schema owner
create user [SomeUser] without login;
go
create schema [s1] authorization [SomeUser];
go
-- An ordinary user
create user [AnotherUser] without login;
go
grant execute on schema::s1 to AnotherUser as [SomeUser];
go
-- Database administrator
create user [DBA] without login;
go
alter role [db_owner] add member [DBA];
go
-- Although it's SomeUser that owns the schema, DBA creates objects in it
execute as user = 'DBA';
go
create procedure s1.SpCaller
as
select user_name() as [s1_caller];
return;
go
create procedure s1.SpSelf
with execute as self as
select user_name() as [s1_self];
return;
go
create procedure s1.SpOwner
with execute as owner as
select user_name() as [s1_owner];
return;
go
revert;
go
-- You can play with actual impersonation and look at results
execute as user = 'AnotherUser';
go
exec s1.SpCaller;
go
exec s1.SpSelf;
go
exec s1.SpOwner;
go
revert;
go

sql server default procedure permissions

I want to know what are the default permissions for sql server stored procedures.
For example, I created a user in database but no role or no permissions granted except execute permission like:
GRANT EXECUTE ON SCHEMA :: [dbo] TO [newUser]
later on me (as a sa login) created a stored procedure that makes just a select from a table like:
CREATE PROCEDURE dbo.selectX AS
BEGIN
SELECT ID, NAME FROM MyTable
END
and my user [newUser] can execute and see the result of select statement like:
EXEC dbo.selectX
up until now, I can assume that stored procedures have default permissions that my user don't have.
I tried other dmls like UPDATE, INSERT, DELETE and user managed to execute procedures successfully.
But! when I created a proceure with ddl as create table .. such as:
CREATE PROCEDURE dbo.crtNT AS
BEGIN
CREATE TABLE del(id int) --for test
END
and when the newUser executes this procedure error occurs like:
CREATE TABLE permission denied in database 'MyDb'
And here is my question: By default, do stored procedures have permission with DML(select, insert, update vs.) but not with DDL(create, drop table vs.)? Because I didn't see any explanation about this situation in Books Online or anywhere else.
Any comments will be welcomed.
You are correct in your assumption that DDL statements are treated differently.
The procedures with DML statements work through the mechanism of Ownership Chaining however as this quote from the EXECUTE AS documentation states
Remember that ownership chaining applies only to DML statements.

Resources