What is this row level security?
Suppose you got a requirement saying that there is a table and if a user from America selects that table he should get records only w.r.t America, if a user from Asia selects the table he should get records only w.r.t Asia and so on. So here we will see how do we implement this level of security.
Suppose you got a requirement saying that there is a table and if a user from America selects that table he should get records only w.r.t America, if a user from Asia selects the table he should get records only w.r.t Asia and so on. So here we will see how do we implement this level of security.
Step 1: Create database role
example :
Step 3: Create a generic security table as shown below. So this table can be used to apply security on any table and column.
example
Step 4: Now suppose assume that you have below table named TableName1 in which if a user from the respective region selects the table gets data of their region only.
Now create the below function. Actually you can just use IS_MEMBER(RoleName) function, which is a system built, but this dosent work for dbo user i.e. sysadmin user. The IS_MEMBER() function tells if the user is the member of specified role. If yes it returns 1 else 0. But for sysadmin user it return 0. So use the below function instead of system built.
Create a view on the top of the table where you want the security to be implemented, as shown below
Now if the user do a select query on Vw_TableName1 he/she will get the records only with respective to there region.
Now you have given the access to view, the user can open the view definition and see the source table from which the data is being pulled. So that he can take that table and see the data of another region. So to avoid that deny the user with view definition and grant only select.
******************************************************************************** **************************************************************************************
Some important SQL scripts related to row level security
******************************************************************************** ******************************************* *******************************************
CREATE ROLE Role_America;
GO
CREATE ROLE Role_Asia;
GO
Step 2: Add users to database role. Add America users in Role_America and Asia users in Role_Asia.
EXEC sp_addrolemember @membername = 'DomainName\UserName', @rolename = 'Role_America';
EXEC sp_addrolemember @membername = 'DomainName\UserName', @rolename = 'Role_Asia';
EXEC sp_addrolemember @membername = 'xyzCompany\John', @rolename = 'Role_America';
EXEC sp_addrolemember @membername = 'xyzCompany\Peter', @rolename = 'Role_Asia';
Step 3: Create a generic security table as shown below. So this table can be used to apply security on any table and column.
IF EXISTS(SELECT * FROM sys.tables WHERE name ='SK_RowLevelSecurity')
DROP TABLE SK_RowLevelSecurity
CREATE TABLE dbo.SK_RowLevelSecurity
(
TableName VARCHAR(500),
ColumnName VARCHAR(500),
SecurityFilterColumn VARCHAR(1000),
RoleName NVARCHAR(255),
CONSTRAINT PK_SecurityMap PRIMARY KEY CLUSTERED (SecurityFilterColumn,TableName, ColumnName,RoleName)
);
GO
INSERT INTO dbo.SK_RowLevelSecurity (TableName,ColumnName,SecurityFilterColumn,RoleName)
VALUES ('[Filter Table Name]','[Filter Column Name]','[Filter Column Value]','[Role Name]')
INSERT INTO dbo.SK_RowLevelSecurity
VALUES('TableName1','Region','America','Role_America')
INSERT INTO dbo.SK_RowLevelSecurity
VALUES('TableName1','Region','Asia','Role_Asia')
Now create the below function. Actually you can just use IS_MEMBER(RoleName) function, which is a system built, but this dosent work for dbo user i.e. sysadmin user. The IS_MEMBER() function tells if the user is the member of specified role. If yes it returns 1 else 0. But for sysadmin user it return 0. So use the below function instead of system built.
CREATE FUNCTION [dbo].[Is_Member2](@rolename VARCHAR(255))
RETURNS TINYINT
AS
BEGIN
DECLARE @roleExists BIT
SELECT @roleExists = 1 FROM sys.database_principals WHERE
name = @roleName
IF @roleExists IS NULL RETURN NULL
IF USER = 'dbo' RETURN 1
RETURN IS_MEMBER(@rolename)
END
GO
CREATE VIEW dbo.Vw_TableName1
AS
SELECT *
FROM dbo.TableName1 (NOLOCK)
WHERE Region IN (SELECT DISTINCT SecurityFilterColumn
FROM dbo.SK_RowLevelSecurity (NOLOCK)
WHERE TableName
='TableName1'
AND ColumnName='Region'
AND [dbo].[Is_Member2](RoleName) = 1)
DENY VIEW DEFINITION ON [dbo].Vw_TableName1 TO [DomainName\Users]
GRANT SELECT ON [dbo].Vw_TableName1 TO [DomainName\Users]
/********** CREATE or MODIFY or DROP
ROLE *************/
CREATE ROLE [Role Name];
GO
ALTER ROLE [Old Role name] WITH NAME = [New Role Name];
GO
DROP ROLE [Role Name]
GO
/********** Query to get memebers of
the Role *************/
SELECT * FROM sys.database_principals
WHERE type='R' AND is_fixed_role=0
SELECT rp.name AS database_role,
mp.name AS database_user
FROM sys.database_role_members
drm
JOIN sys.database_principals
rp ON (drm.role_principal_id = rp.principal_id)
JOIN sys.database_principals
mp ON (drm.member_principal_id = mp.principal_id)
WHERE rp.name='Role_America'
ORDER BY rp.name
/**** DROP a particular member from a
role *****/
EXEC sp_droprolemember '[Role Name]', '[Member Name]';
/******** To Drop all the members of
the Role **********/
EXEC usp_SK_Drop_All_Members_Of_Role '[Role Name]'
-------
CREATE PROC [dbo].[usp_SK_Drop_All_Members_Of_Role]
(@UserDefinedRoleName VARCHAR(500))
AS
DECLARE @RoleName VARCHAR(500)
DECLARE @UserName VARCHAR(500)
DECLARE @cnt INT
DECLARE @Incr INT
DECLARE @sql NVARCHAR(MAX)
DECLARE @sql1 NVARCHAR(MAX)
DECLARE @sql2 NVARCHAR(MAX)
DECLARE @sql3 NVARCHAR(MAX)
SET @Incr=1
SET @sql1='SELECT @cnt=COUNT(*)'+CHAR(13)+
'FROM sys.database_principals A'+CHAR(13)+
'JOIN sys.sysmembers B ON
A.principal_id=B.groupuid'+CHAR(13)+
'WHERE A.Name IN ('+dbo.Fn_SK_Split(@UserDefinedRoleName,',')+')'
EXECUTE sp_executesql @statement
= @sql1,
@params = N'@cnt
INT OUTPUT',
@cnt=@cnt OUTPUT
SET @sql2 =';WITH CTE'+CHAR(13)+
'AS'+CHAR(13)+
'('+CHAR(13)+
'SELECT A.Name AS RoleName,
USER_NAME(memberuid)UserName,ROW_NUMBER() OVER(ORDER BY A.Name ASC)rno'+CHAR(13)+
'FROM sys.database_principals A'+CHAR(13)+
'JOIN sys.sysmembers B ON A.principal_id=B.groupuid'+CHAR(13)+
'WHERE A.Name IN ('+dbo.Fn_SK_Split(@UserDefinedRoleName,',')+')'+CHAR(13)+
')'+CHAR(13)+
'SELECT * FROM CTE'+CHAR(13)
CREATE TABLE #temp (RoleName varchar(500), UserName varchar(500),rno INT)
INSERT INTO #temp
EXEC (@sql2)
WHILE @Incr<=@cnt
BEGIN
SET @sql3= 'SELECT @RoleName=RoleName,
@UserName =UserName FROM #temp WHERE rno='+CAST(@Incr AS VARCHAR(10))
EXECUTE sp_executesql @statement
= @sql3,
@params = N'@RoleName VARCHAR(500) OUTPUT,@UserName VARCHAR(500)
OUTPUT',
@RoleName=@RoleName OUTPUT,@UserName=@UserName OUTPUT
SET @sql='sp_droprolemember '''+@RoleName+''','''+@UserName+''''
EXEC(@sql)
SET @Incr=@Incr+1
END
No comments:
Post a Comment