I'm having trouble using the ALTER SEQUENCE statement in SQL Server.
This is the code I'm using:
ALTER SEQUENCE MakatiORSeries RESTART WITH 23;
And this is what I'm getting:
Msg 15151, Level 16, State 1, Line 7
Cannot alter the sequence 'MakatiORSeries', because it does not exist or you do not have permission.
But when I select all the sequences from sys.sequences, it is there
SELECT *
FROM sys.sequences
WHERE [name] = 'MakatiORSeries'
I tried these references too:
SQL Server sequence set current value
Use a variable or parameter to specify restart value for ALTER SEQUENCE
Any help is greatly appreciated. Thanks!
The ALTER permission on the sequence or the schema is required to change this. Ownership chaining in a procedure allows basic DML such as INSERT, UPDATE, DELETE, SELECT, and EXECUTE. It does not extend to ALTER. The account that runs the procedure will also need the ALTER permission on the sequence.
If there are permissions that can't be granted to the login because of security concerns, then you can sign the procedure to run as another credential.
If you want to restart the sequence to set it to a specific value use
SELECT setval('seq',0,false);
It sets the value of the sequence "seq" to 0.
Related
In SQL Server, is there a combination of permissions that will allow some user to run ALTER INDEX statements but not DROP INDEX/TABLE/etc statements? From what I've read, it looks like granting ALTER gives all the ALTER/DROP/TRUNCATE permissions, and indexes aren't a securable so I can't limit the acceptable statements to just ALTER/DROP indexes (this would be suboptimal, but would be better than just letting the user drop anything).
Thanks to the recommendation in the comments from Ben, I was able to achieve this through signed stored procedure functionality. I basically followed the instructions here, but in case that's gone in the future, these were the steps to get there (including some of the code from the linked tutorial):
Create Cert
CREATE CERTIFICATE TestCreditRatingCer
ENCRYPTION BY PASSWORD = 'pGFD4bb925DGvbd2439587y'
WITH SUBJECT = 'Credit Rating Records Access',
EXPIRY_DATE = '12/31/2021'; -- Error 3701 will occur if this date is not in the future
GO
Create Stored Procedure to do the narrow task (alter indexes in this case) and sign using the cert from step 1
ADD SIGNATURE TO TestCreditRatingSP
BY CERTIFICATE TestCreditRatingCer
WITH PASSWORD = 'pGFD4bb925DGvbd2439587y';
GO
Create login for running the stored procedure using the cert above and the new users for the applicable databases
CREATE USER TestCreditRatingcertificateAccount
FROM CERTIFICATE TestCreditRatingCer;
GO
Grant ALTER rights on the appropriate objects to the new certificate user and EXEC on the new stored proc to the user(s) you want to be able to run the ALTER statements.
Before each DAO test I clean my database and I need to reset the identity value of some tables. I've created the following stored procedure:
CREATE PROCEDURE SET_IDENTITY
#pTableName varchar(120),
#pSeedValue int
AS
BEGIN
DBCC CHECKIDENT(#pTableName, RESEED, #pSeedValue);
END
My problem is I need to call this stored procedure with a "normal" user. In order works, This user cannot be member of: sysadmin, db_owner, db_ddladmin.
I've tried with:
a) CREATE PROCEDURE WITH EXECUTE AS OWNER
b) EXECUTE AS USER = 'sa' before call DBCC CHECKIDENT
But in both cases I got back:
The server principal sa is not able to access the database my_db_name under the current security context.
I'm using Microsoft SQL Server Express (64-bit) 11.0.2100.60
Thank you in advance,
Abel
This is easy enough to do, but generally speaking you shouldn't need to reset identity values each time. Specific identity values shouldn't matter, so the only concern should be potentially reaching the max value due to repeated testing. And in that case I would not recommend resetting each time as it is also a good test to let IDs reach high values so you can make sure that all code paths handle them properly and find areas that don't before your users do ;-).
That being said, all you need to do (assuming this is localized to a single DB) is create an Asymmetric Key, then create a User from it, then add that User to the db_ddladmin fixed Database Role, and finally sign your Stored Procedure with that same Asymmetric Key.
The following example illustrates this behavior:
USE [tempdb];
CREATE TABLE dbo.CheckIdent
(
[ID] INT NOT NULL IDENTITY(1, 1) CONSTRAINT [PK_CheckIdentity] PRIMARY KEY,
[Something] VARCHAR(50)
);
EXEC(N'
CREATE PROCEDURE dbo.SET_IDENTITY
#pTableName sysname,
#pSeedValue int
AS
BEGIN
DBCC CHECKIDENT(#pTableName, RESEED, #pSeedValue);
END;
');
CREATE USER [MrNobody] WITHOUT LOGIN;
GRANT EXECUTE ON dbo.SET_IDENTITY TO [MrNobody];
-------
EXECUTE AS USER = N'MrNobody';
SELECT SESSION_USER AS [CurrentUser], ORIGINAL_LOGIN() AS [OriginalLogin];
EXEC dbo.SET_IDENTITY N'dbo.CheckIdent', 12;
/*
Msg 2557, Level 14, State 5, Procedure SET_IDENTITY, Line 7 [Batch Start Line 30]
User 'MrNobody' does not have permission to run DBCC CHECKIDENT for object 'CheckIdent'.
*/
REVERT;
SELECT SESSION_USER AS [CurrentUser], ORIGINAL_LOGIN() AS [OriginalLogin];
-------
CREATE ASYMMETRIC KEY [DdlAdminPermissionsKey]
WITH ALGORITHM = RSA_2048
ENCRYPTION BY PASSWORD = 'not_a_good_password';
CREATE USER [DdlAdminPermissions]
FROM ASYMMETRIC KEY [DdlAdminPermissionsKey];
ALTER ROLE [db_ddladmin] ADD MEMBER [DdlAdminPermissions];
ADD SIGNATURE
TO dbo.SET_IDENTITY
BY ASYMMETRIC KEY [DdlAdminPermissionsKey]
WITH PASSWORD = 'not_a_good_password';
-------
EXECUTE AS USER = N'MrNobody';
SELECT SESSION_USER AS [CurrentUser], ORIGINAL_LOGIN() AS [OriginalLogin];
EXEC dbo.SET_IDENTITY N'dbo.CheckIdent', 12;
-- Success!
REVERT;
SELECT SESSION_USER AS [CurrentUser], ORIGINAL_LOGIN() AS [OriginalLogin];
Other minor notes:
You cannot execute as User = sa since sa is a Login (server level) and not a User (database level). You can use EXECUTE AS LOGIN = 'sa'; but that then requires IMPERSONATE permission and is a security hole since the non-privileged Login can run EXECUTE AS LOGIN = 'sa' whenever they want. So don't do that.
For variables / parameters that hold names of SQL Server objects, indexes, etc, you should use NVARCHAR and not VARCHAR. Most internal names use sysname which is a system alias for NVARCHAR(128), so sysname is usually the preferred datatype.
Caller has to own schema or be db_owner:
From doc: DBCC CHECKIDENT
Permissions
Caller must own the schema that contains the table, or be a member of the sysadmin fixed server role, the db_owner fixed database role, or the db_ddladmin fixed database role.
LiveDemo
I created a stored procedure which performs a series of operations that require special permissions, e.g. create database, restore database, etc. I create this stored procedure with
execute as self
...so that it runs as SA. This is because I want to give a SQL user without any permissions the ability to run only these commands which I have defined.
But when I run this stored proc, I get
The server principal "sa" is not able to access the database "model" under the current security context.
How come SA can't access the model database? I actually ran the code in the stored proc on its own, under SA, and it ran fine.
Read Extending Database Impersonation by Using EXECUTE AS before you continue.
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.
You need to use module signing. Here is an example.
For anybody else coming here looking for this info, here is sample code that demonstrates exactly what OP (and I) wanted (based on excellent info from Remus above):
-- how to sign a stored procedure so it can access other Databases on same server
-- adapted from this very helpful article
-- http://rusanu.com/2006/03/01/signing-an-activated-procedure/
USE [master]
GO
CREATE DATABASE TempDB1
CREATE DATABASE OtherDB2
GO
USE TempDB1
GO
-- create a user for TempDB1
CREATE USER [foo] WITHOUT LOGIN
GO
CREATE PROCEDURE TempDB1_SP
AS
BEGIN
CREATE TABLE OtherDB2.dbo.TestTable (ID int NULL)
IF ##ERROR=0 PRINT 'Successfully created table.'
END
GO
GRANT EXECUTE ON dbo.TempDB1_SP TO [foo]
GO
EXECUTE AS User='foo'
PRINT 'Try to run an SP that accesses another database:'
EXECUTE dbo.TempDB1_SP
GO
REVERT
-- Output: Msg 916, Level 14, State 1, Procedure TempDB1_SP, Line 5
-- [Batch Start Line 14]
-- The server principal "..." is not able to access the database
-- "OtherDB2" under the current security context.
PRINT ''
PRINT 'Fix: Try again with signed SP...'
-- Create cert with private key to sign the SP with.
-- Password not important, will drop private key
USE TempDB1
GO
-- create a self-signed cert
CREATE CERTIFICATE [DB_Cert]
ENCRYPTION BY PASSWORD = 'Password1'
WITH SUBJECT = 'Signing for cross-DB SPs';
-- Sign the procedure with the certificate’s private key
ADD SIGNATURE TO OBJECT::[TempDB1_SP]
BY CERTIFICATE [DB_Cert]
WITH PASSWORD = 'Password1'
-- Drop the private key. This way it cannot be used again to sign other procedures.
ALTER CERTIFICATE [DB_Cert] REMOVE PRIVATE KEY
-- Copy the public key part of the cert to [master] database
-- backup to a file and create cert from file in [master]
BACKUP CERTIFICATE [DB_Cert] TO FILE = 'C:\Users\Public\DBCert.cer'
USE [OtherDB2] -- or use [master] = all DBs on server accessible
GO
CREATE CERTIFICATE [DB_Cert] FROM FILE = 'C:\Users\Public\DBCert.cer';
-- the 'certificate user' carries the permissions that are automatically granted
-- when the signed SP accesses other Databases
CREATE USER [DB_CertUser] FROM CERTIFICATE [DB_Cert]
GRANT CREATE TABLE TO [DB_CertUser] -- or whatever other permissions are needed
GO
USE TempDB1
EXECUTE dbo.TempDB1_SP
GO
-- output: 'Successfully created table.'
-- clean up: everything except the cert file, have to delete that yourself sorry
USE [master]
GO
DROP DATABASE TempDB1
DROP DATABASE OtherDB2
GO
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.
I have a SQL Server 2008 database where all access to the underlying tables is done through stored procedures. Some stored procedures simply SELECT records from the tables while others UPDATE, INSERT, and DELETE.
If a stored procedure UPDATES a table does the user executing the stored procedure also need UPDATE permissions to the affected tables or is the fact that they have EXECUTE permissions to the stored procedure enough?
Basically I am wondering if giving the user EXECUTE permissions to the stored procedures is enough or do I need to give them SELECT, UPDATE, DELETE, and INSERT permissions to the tables in order for the stored procedures to work. Thank you.
[EDIT] In most of my stored procedures it does indeed appear that EXECUTE is enough. However, I did find that in stored procedures where "Execute sp_Executesql" was used that EXECUTE was not enough. The tables involved needed to have permissions for the actions being performed within "sp_Executesql".
Permissions on tables are not checked (including DENY) if tables and proc have the same owner. They can be in different schemas too as long as the schemas have the same owner.
See Ownership chaining on MSDN
Edit, from a comment from a deleted answer.
The context is always the current login unless EXECUTE AS as been used: only referenced object DML permissions are not checked. Try OBJECT_ID(referencedtable) in a stored proc where no rights are assigned to referencedtable. It gives NULL. If executed by the owner of the stored proc then it would give a value because owener has rights on referencedtable
Execute permissions on the stored procedure is sufficient.
CREATE TABLE dbo.Temp(n int)
GO
DENY INSERT ON dbo.Temp TO <your role>
GO
CREATE PROCEDURE dbo.SPTemp(#Int int)
AS
INSERT dbo.Temp
SELECT #Int
GO
GRANT EXEC ON dbo.SPTemp TO <your role>
GO
Then the (non-db_owner) user will have the following rights:
EXEC dbo.SPTemp 10
GO
INSERT dbo.Temp --INSERT permission was denied on the object 'Temp'
SELECT 10
However, if there is dynamic SQL inside dbo.SPTemp that attempts to insert into dbo.Temp then that will fail. In this case direct permission on the table will need to be granted.
Maybe you can use
"with execute as owner"
when you create the stored procedure, such as below:
create procedure XXX
with execute as owner
as
begin
...
end
go
Then you only need to grant the user the EXECUTE permission for the stored procedure XXX.
Execute permission on a stored procedure that does an insert, update, or delete is sufficient. You do not need to grant those permissions at the table level. In fact, I would discourage that approach. Using a stored procedure gives you more control over how the change occurs. For instance, you may wish to do some checking prior to allowing the update. Using a stored procedure can also help prevent major accidents--like deleting all the rows in the table because someone forgot the WHERE clause!
THANK YOU SO MUCH! I had a similar problem. This lead me to the answer.
I was attempting to trunctate a table in a stored procedure that called other stored procedures that were nested in IF statements.
My error was
The server principal "domain\my_id" is not able to access the database "2nd_DB" under the current security context.
I had given the calling stored procedure rights to do the truncate (EXECUTE AS SELF), which then caused a problem because SELF didn't have rights to the 2nd DB. Our solution was to move the truncate to another SP, include the EXECUTE AS SELF. We now call the truncate SP, execute our data processing, make logic determination, and call the appropriate 3rd SP.