Files
FT546-WCS/sql/shadow/V002__ft546_shadow_read_login.sql

193 lines
7.3 KiB
Transact-SQL

:setvar ShadowSourceLogin "ft546_shadow_ro"
:setvar ShadowSourceUser "ft546_shadow_ro"
:setvar ShadowSourcePassword "REPLACE_AT_DEPLOY_TIME"
:setvar ShadowSourceDatabase "FT546-wcs"
SET NOCOUNT ON;
SET XACT_ABORT ON;
IF N'$(ShadowSourcePassword)' = N'REPLACE_AT_DEPLOY_TIME'
THROW 51000, 'Supply ShadowSourcePassword through the approved secret channel.', 1;
IF DB_ID() <> DB_ID(N'$(ShadowSourceDatabase)')
THROW 51001, 'Run the shadow source-login script only in ShadowSourceDatabase.', 1;
DECLARE @sourceLoginCreated bit = 0;
IF NOT EXISTS (SELECT 1 FROM sys.server_principals
WHERE name = N'$(ShadowSourceLogin)')
BEGIN
DECLARE @createLogin nvarchar(max) =
N'CREATE LOGIN ' + QUOTENAME(N'$(ShadowSourceLogin)')
+ N' WITH PASSWORD = N'''
+ REPLACE(N'$(ShadowSourcePassword)', N'''', N'''''')
+ N''', CHECK_POLICY = ON, CHECK_EXPIRATION = ON';
EXEC sys.sp_executesql @createLogin;
SET @sourceLoginCreated = 1;
END;
BEGIN TRY
IF EXISTS (
SELECT 1
FROM sys.server_role_members rm
JOIN sys.server_principals role_principal
ON role_principal.principal_id = rm.role_principal_id
JOIN sys.server_principals login_principal
ON login_principal.principal_id = rm.member_principal_id
WHERE login_principal.name = N'$(ShadowSourceLogin)'
)
THROW 51002, 'The shadow source login must not belong to a server role.', 1;
DECLARE @serverContextSet bit = 0;
BEGIN TRY
EXECUTE AS LOGIN = N'$(ShadowSourceLogin)';
SET @serverContextSet = 1;
IF EXISTS (
SELECT 1
FROM sys.fn_my_permissions(NULL, N'SERVER')
WHERE permission_name NOT IN (N'CONNECT SQL', N'VIEW ANY DATABASE')
)
THROW 51007, 'The shadow source login retains forbidden server permissions.', 1;
REVERT;
SET @serverContextSet = 0;
END TRY
BEGIN CATCH
IF @serverContextSet = 1
REVERT;
THROW;
END CATCH;
BEGIN TRANSACTION;
IF NOT EXISTS (SELECT 1 FROM sys.database_principals
WHERE name = N'$(ShadowSourceUser)')
BEGIN
DECLARE @createUser nvarchar(max) =
N'CREATE USER ' + QUOTENAME(N'$(ShadowSourceUser)')
+ N' FOR LOGIN ' + QUOTENAME(N'$(ShadowSourceLogin)');
EXEC sys.sp_executesql @createUser;
END
ELSE IF SUSER_SID(N'$(ShadowSourceLogin)') <> USER_SID(N'$(ShadowSourceUser)')
THROW 51003, 'The existing shadow source user maps to a different login.', 1;
DECLARE @principal nvarchar(258) = QUOTENAME(N'$(ShadowSourceUser)');
DECLARE @permissions nvarchar(max) =
N'GRANT CONNECT TO ' + @principal + N';'
+ N'REVOKE CONTROL FROM ' + @principal + N';'
+ N'REVOKE SELECT FROM ' + @principal + N';'
+ N'GRANT SELECT ON SCHEMA::shadow_ro TO ' + @principal + N';'
+ N'DENY INSERT, UPDATE, DELETE, EXECUTE, ALTER, TAKE OWNERSHIP '
+ N'TO ' + @principal + N';'
+ N'DENY CONTROL ON OBJECT::dbo.wcs_srgv_queue TO ' + @principal + N';'
+ N'DENY CONTROL ON OBJECT::dbo.wcs_srgv_queue_finish TO ' + @principal + N';'
+ N'DENY CONTROL ON OBJECT::dbo.device_srgv TO ' + @principal + N';'
+ N'DENY CONTROL ON OBJECT::dbo.wcs_srgv_map TO ' + @principal + N';'
+ N'DENY CONTROL ON OBJECT::dbo.bas_cargo_space TO ' + @principal + N';'
+ N'DENY CONTROL ON OBJECT::dbo.tsj_device_execution_queue TO '
+ @principal + N';'
+ N'DENY SELECT ON OBJECT::dbo.wcs_srgv_queue TO ' + @principal + N';'
+ N'DENY SELECT ON OBJECT::dbo.wcs_srgv_queue_finish TO ' + @principal + N';'
+ N'DENY SELECT ON OBJECT::dbo.device_srgv TO ' + @principal + N';'
+ N'DENY SELECT ON OBJECT::dbo.wcs_srgv_map TO ' + @principal + N';'
+ N'DENY SELECT ON OBJECT::dbo.bas_cargo_space TO ' + @principal + N';'
+ N'DENY SELECT ON OBJECT::dbo.tsj_device_execution_queue TO '
+ @principal + N';';
EXEC sys.sp_executesql @permissions;
DECLARE @role sysname;
DECLARE forbidden_roles CURSOR LOCAL FAST_FORWARD FOR
SELECT role_principal.name
FROM sys.database_principals role_principal
JOIN sys.database_role_members rm
ON rm.role_principal_id = role_principal.principal_id
JOIN sys.database_principals member_principal
ON member_principal.principal_id = rm.member_principal_id
WHERE role_principal.type = 'R'
AND member_principal.name = N'$(ShadowSourceUser)';
OPEN forbidden_roles;
FETCH NEXT FROM forbidden_roles INTO @role;
WHILE @@FETCH_STATUS = 0
BEGIN
IF IS_ROLEMEMBER(@role, N'$(ShadowSourceUser)') = 1
BEGIN
DECLARE @dropRole nvarchar(max) = N'ALTER ROLE '
+ QUOTENAME(@role) + N' DROP MEMBER ' + @principal;
EXEC sys.sp_executesql @dropRole;
END;
FETCH NEXT FROM forbidden_roles INTO @role;
END;
CLOSE forbidden_roles;
DEALLOCATE forbidden_roles;
DECLARE @databaseContextSet bit = 0;
BEGIN TRY
EXECUTE AS USER = N'$(ShadowSourceUser)';
SET @databaseContextSet = 1;
IF HAS_PERMS_BY_NAME(DB_NAME(), N'DATABASE', N'SELECT') <> 0
OR HAS_PERMS_BY_NAME(DB_NAME(), N'DATABASE', N'INSERT') <> 0
OR HAS_PERMS_BY_NAME(DB_NAME(), N'DATABASE', N'UPDATE') <> 0
OR HAS_PERMS_BY_NAME(DB_NAME(), N'DATABASE', N'DELETE') <> 0
OR HAS_PERMS_BY_NAME(DB_NAME(), N'DATABASE', N'EXECUTE') <> 0
OR HAS_PERMS_BY_NAME(DB_NAME(), N'DATABASE', N'ALTER') <> 0
OR HAS_PERMS_BY_NAME(DB_NAME(), N'DATABASE', N'CONTROL') <> 0
OR HAS_PERMS_BY_NAME(DB_NAME(), N'DATABASE', N'TAKE OWNERSHIP') <> 0
THROW 51004, 'The shadow source login retains forbidden database permissions.', 1;
IF EXISTS (
SELECT 1
FROM sys.schemas s
CROSS APPLY sys.fn_my_permissions(QUOTENAME(s.name), N'SCHEMA') p
WHERE s.name NOT IN (N'sys', N'INFORMATION_SCHEMA')
AND NOT (s.name = N'shadow_ro' AND p.permission_name = N'SELECT')
)
THROW 51005, 'The shadow source login retains forbidden schema permissions.', 1;
IF EXISTS (
SELECT 1
FROM sys.objects o
JOIN sys.schemas s ON s.schema_id = o.schema_id
CROSS APPLY sys.fn_my_permissions(
QUOTENAME(s.name) + N'.' + QUOTENAME(o.name), N'OBJECT') p
WHERE o.is_ms_shipped = 0
AND NOT (
s.name = N'shadow_ro'
AND o.name IN (
N'v_wcs_srgv_queue', N'v_wcs_srgv_queue_finish',
N'v_device_srgv', N'v_wcs_srgv_map',
N'v_bas_cargo_space', N'v_tsj_execution',
N'v_current_database_clock')
AND p.permission_name = N'SELECT'
)
)
THROW 51006, 'The shadow source login retains forbidden object permissions.', 1;
SELECT TOP (0) * FROM shadow_ro.v_wcs_srgv_queue;
SELECT TOP (0) * FROM shadow_ro.v_wcs_srgv_queue_finish;
SELECT TOP (0) * FROM shadow_ro.v_device_srgv;
SELECT TOP (0) * FROM shadow_ro.v_wcs_srgv_map;
SELECT TOP (0) * FROM shadow_ro.v_bas_cargo_space;
SELECT TOP (0) * FROM shadow_ro.v_tsj_execution;
SELECT TOP (0) * FROM shadow_ro.v_current_database_clock;
REVERT;
SET @databaseContextSet = 0;
END TRY
BEGIN CATCH
IF @databaseContextSet = 1
REVERT;
THROW;
END CATCH;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK TRANSACTION;
IF @sourceLoginCreated = 1
BEGIN
DECLARE @dropSourceLogin nvarchar(max) =
N'DROP LOGIN ' + QUOTENAME(N'$(ShadowSourceLogin)');
EXEC sys.sp_executesql @dropSourceLogin;
END;
THROW;
END CATCH;