Grant Select To Synonym For Specified Columns - sql

I've been trying to restrict a user's select access to a synonym. Consider the following below:
CREATE USER Test_User WITHOUT LOGIN;
CREATE SYNONYM S_TEST FOR dbo.Items;
GRANT SELECT ON dbo.S_TEST (Id, [Name]) TO Test_User;
I get an error:
Msg 1020, Level 16, State 3, Line 4
Sub-entity lists (such as column or security expressions)
cannot be specified for entity-level permissions.
But if I change it to use dbo.Items directly then it works:
GRANT SELECT ON dbo.Items (Id, [Name]) TO Test_User;
How can I restrict the SELECT on a synonym for a specified user? Is this possible? If no, are there any alternatives?

"How can I restrict the SELECT on a synonym for a specified user? " You can't. A Synonym is just an alternative name for an object. The check to see if the object even exists is deferred till runtime when referencing the SYNONYM not when it's created. For example CREATE SYNONYM dbo.MySynonym FOR MadeUp.TableObject; will create the synonym even though the reference object doesn't exist.
CREATE SYNONYM dbo.MySynonym FOR MadeUp.TableObject;
GO
SELECT *
FROM dbo.MySynonym; --fails
GO
DROP SYNONYM dbo.MySynonym;
GO
All the permissions need to be set up the object that the Synonym references, not the synonym itself.

Related

How to allow a view to read from multiple schemas

I have two tables in different schemas, one owned by dbo, the other not. I have a third schema where I'm trying to create a view that reads from those two tables. My understanding is that if dbo is the owner of the view, because it has grant options to all objects in the database, users with only access to the view should be able to query it. But that isn't working, even when I explicitly grant dbo SELECT WITH GRANT to the underlying table in the schema it doesn't own.
I've read a few other posts, but don't see an answer that works: https://stackoverflow.com/a/4134892/1499015, Ownership Chaining and Tutorial: Ownership Chains and Context Switching
I assume I'm doing something wrong with permission chaining, but I can't figure out what the problem is.
--use master
--GO
--create login testuser with password='******************'
-- principal3 will own schema3
--create login principal3 with password='*****************'
--use testingDB
--GO
create user testuser for login testuser
create user principal3 for login principal3
GO
-- testrole that will only have select permissions on schema2
CREATE ROLE testrole
exec sp_addrolemember 'testrole', 'testuser'
GO
-- the first schema is owned by dbo
CREATE SCHEMA schema1 authorization dbo
GO
-- the schema where the view will live, also owned by dbo
create schema schema2 authorization dbo
GO
-- schema3 owned by principal3
create schema schema3 authorization principal3
go
-- tables in schema1 and schema3
CREATE TABLE schema1.testtable1 (
id int
, testvalue sysname
)
GO
CREATE TABLE schema3.testtable3 (
id int
, testvalue sysname
)
GO
-- some base data
INSERT schema1.testtable1
SELECT 1, 'a'
UNION SELECT 2, 'b'
UNION SELECT 3, 'c'
INSERT schema3.testtable3
SELECT 1, 'hot dogs rule'
UNION SELECT 2, 'pizza sucks'
UNION SELECT 3, 'haw just kidding that''s obviously backwards'
GO
-- view in schema2 that queries tables in schema1 and schema3, owned by dbo
CREATE VIEW schema2.testview
AS
SELECT t1.testvalue as v1
, t3.testvalue as v3
FROM schema1.testtable1 t1
INNER JOIN schema3.testtable3 t3 ON t1.id = t3.id
GO
GRANT SELECT ON schema::schema1 TO dbo WITH GRANT OPTION
GRANT SELECT ON schema::schema3 TO dbo WITH GRANT OPTION
ALTER AUTHORIZATION ON schema2.testview TO dbo
-- give testrole permission to query the view
GRANT SELECT ON schema2.testview to testrole
GO
EXECUTE AS USER = 'testuser';
SELECT USER_NAME();
BEGIN TRY
select top 100 * from schema2.testview
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_MESSAGE() AS ErrorMessage;
END CATCH
REVERT;
SELECT USER_NAME();
When I run this code, I get
The SELECT permission was denied on the object 'testtable3', database 'testingDb', schema 'schema3'.
I've also tried to create a schema owner user for the schema that the view lives in, and granting that user select with grant to the underlying tables, but it's still not working.
Any ideas what I'm doing wrong?
Thanks!
The documentation says:
When an object is accessed through a chain, SQL Server first compares
the object's owner to the owner of the calling object (the previous
link in the chain). If both objects have the same owner, permissions
on the referenced object are not checked. Whenever an object accesses
another object that has a different owner, the ownership chain is
broken and SQL Server must check the caller's security context.
In this case, when the object testtable3 is accessed, SQL Server first compares testtable3 owner to the owner of the testview. If both objects have the same owner, permissions on the referenced object are not checked. It does not matter if you GRANT dbo rights on testtable3, even WITH GRANT (he this right anyway). It matters that the owner of testtable3 is the same as the owner of the testview.
For example, try:
ALTER AUTHORIZATION ON SCHEMA::schema3 TO dbo
And it will work.
If the owners are different, the ownership chain is broken and SQL Server must check the caller's security context. In this case: does testuser have rights to select from testtable3?.
Therefore, if the owners are different you need to do this to make it work:
GRANT SELECT ON schema3.testtable3 TO testuser

Row level policy doesn't work on my table

I have a table which I'm trying to apply a policy on, the setup looks something like this:
create role anonymous nologin;
create schema api;
create schema private;
create table private.mytable(
id serial primary key,
description text default ''
);
create view api.mytable as select * from private.mytable;
insert into api.mytable (description) values ('row 1'), ('row 2');
grant usage on schema api to anonymous;
grant select on api.mytable to anonymous;
alter table private.mytable enable row level security;
create policy mytable_policy on private.mytable
for select
using (null);
When I set the role to anonymous and select all records from mytable:
set role anonymous;
select * from api.mytable;
I excpect no rows to be returned since my expression in the using clause in the policy is null but I get everything.
I tried different postgresql versions (9.5, 9.6, 10.3) but they all have the same behaviour, am I doing something wrong here?
update
https://stackoverflow.com/a/33863371/5315974
RLS won't work with views like that. You can use RLS for views though it is limited.
what you can do is
alter view api.mytable owner to anonymous ;

can I give SQL Server database name with hyphen like abc-123?

I created a sql server database with name of abc-123, in that I created a table Emp, when I run likeselect * from abc-123.emp; I am getting the results.
But when I am trying to grant some privilege to the user I unable to do that, getting syntax error near hyphen .
will any one help me?
Make sure you are escaping the names with [] (T-SQL) or "" (ANSI SQL). You are using non-standard naming.
-- Sample select
SELECT * FROM [abc-123].[dbo].[emp];
SELECT * FROM "abc-123"."dbo"."emp";
1 - Can you send me an example of the grant TSQL? If you are doing the action from SSMS, right click and script the code.
2 - Here is the link to the GRANT TSQL command. I do not see any syntax like you are trying.
http://technet.microsoft.com/en-us/library/ms188371.aspx
TO 'drupal'#'localhost' IDENTIFIED BY 'Drup#l';
First, it should be [drupal#localhost]. Second, I never seen the IDENTIFIED BY clause. Where are you getting that information from?
3 - Here is a quick TSQL script that creates a badly named database and user. If possible, change the name of the database and user.
Also, if you are granting permissions at the table level other than db_owner (very granular and a-lot of maintenance), then create an user defined database role. Add securables to the role and add your user to the role.
http://technet.microsoft.com/en-us/library/ms187936.aspx
Sample code.
-- Create new database
create database [abc-123]
go
-- Use new database
use [abc-123];
go
-- Create table from sample data
select
[BusinessEntityID]
,[PersonType]
,[NameStyle]
,[Title]
,[FirstName]
,[MiddleName]
,[LastName]
,[Suffix]
,[EmailPromotion]
, cast([AdditionalContactInfo] as varchar(max))
as [AdditionalContactInfoTxt]
, cast([Demographics] as varchar(max))
as [DemographicsTxt]
,[rowguid]
,[ModifiedDate]
into
[abc-123].[dbo].[emp]
from
AdventureWorks2012.Person.Person;
-- Create a login
CREATE LOGIN [drupal#localhost] WITH PASSWORD=N'Ja08n13$', DEFAULT_DATABASE=[abc-123]
GO
-- Create a user
CREATE USER [drupal#localhost] FOR LOGIN [drupal#localhost] WITH DEFAULT_SCHEMA=[dbo]
GO
-- Add to database owner role
EXEC sp_addrolemember 'db_owner', [drupal#localhost]
GO
Output with user in db_owner group.
Use Back Quote for the DB name
select * from `abc-123`.emp;
or, select the existing database with a USE statement and run the query.
USE `abc-123`;
select * from emp;
Use [] round the database name:
SELECT * FROM [abc-123].[dbo].emp;
OR
SELECT * FROM [abc-123].dbo.emp;
if you are using databasename with table name then suppose to specify the schema name also.select * from [abc-123].dbo.emp

Avoid alter and drop command on a Table and SP in SQL Server

I have a table and a SP in SQL Server. I want to add Permissions on a table and SP that no one can change the Structure of table and Logic of SP. Is there any way to specify such type of Permissions. Any Trigger which avoids drop and alter commands, or any other way to do this.
Thanks in Advance.
You need to create and use a separate user that has only privileges that you explicitly allow it to (eg GRANT SELECT from table or GRANT EXECUTE on your stored procedure).
Rather than looking at it as disallowing certain actions you should consider what actions are allowed (see Principle of Least Privilege).
It is highly recommended that you manage the permissions on the objects. However, if you have no control over the permissions, consider setting up a database DDL trigger to at least log the events.
create table AuditTable
(
event_type varchar(max) not null
, tsql_command varchar(max) not null
, modified_by varchar(128) not null default (current_user)
, modified_time datetime not null default (getdate())
)
go
create trigger log_database_level_event
on database
for ddl_database_level_events
as
insert AuditTable
(
event_type
, tsql_command
)
values
(
eventdata().value('(/EVENT_INSTANCE/EventType)[1]', 'varchar(max)')
, eventdata().value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'varchar(max)')
)
go
create user tester without login
go
execute as user = 'tester'
go
create proc test_proc
as
select ##version
go
alter proc test_proc
as
select 1
go
revert
go
select * from AuditTable
go
Yes, this is possible but not using constraint . Constraint is a bussiness rule kind of validation and here your question about Permission on Objects so now
this is clear that you need to define permission on object for specific user.If you want to
secure your Table and Stored Procedure then please follow this step.
Create one new User/Login with specific Database/Objects permission.
Give grant on your Secure table using - GRANT SELECT ON <TableName> TO <Username>
GIVE grant on your Secure Stored Procedure using - GRANT EXECUTE ON <SP Name> TO <Username>
for further regarding permission please do some search on Google .

Using synonyms in stored procedures

I have a synonym for a table in another DB defined
using
create synonym TableA for otherDb.dbo.TableA
I have a locally defined stored procedure
CREATE PROCEDURE dbo.spGetTableA
AS
BEGIN
SELECT * FROM TableA
END
Now when I call the SP
EXEC spGetTableA
I get the following error
Invalid object name 'TableA'
While calling the SQL directly SELECT * FROM TableA
works perfectly.
Any idea what I'm missing for this to work?
You are probably calling the stored procedure from a user whose default schema is not dbo. Therefore you should always reference the schema both when you create the synonym and when you reference the table in a query.
DROP SYNONYM TableA;
GO
CREATE SYNONYM dbo.TableA FOR OtherDB.dbo.TableA;
GO
ALTER PROCEDURE dbo.spGetTableA
AS
BEGIN
SELECT * FROM dbo.TableA;
END
GO
EXEC dbo.spGetTableA;
I wish I could bold all of those dbo. references within the code. They are important and should ALWAYS be there.
Please read:
Bad habits to kick : avoiding the schema prefix