-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy path0001.sqlcode.sql
More file actions
136 lines (106 loc) · 5.18 KB
/
0001.sqlcode.sql
File metadata and controls
136 lines (106 loc) · 5.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
-- This user will own the sqlcode schemas, so that created stored procedures
-- by default is owned by a user without permissions; this means stored procedures
-- will not get more permissions than the user calling them already has
create user [sqlcode-user-with-no-permissions] without login;
-- This role will be granted execute permissions on all sqlcode schemas;
-- useful e.g. for humans logging in to debug
create role [sqlcode-execute-role];
-- Role for calling CreateCodeSchema / DropCodeSchema; the role will also be granted
-- control over all schemas created this way.
create role [sqlcode-deploy-role];
-- Make a user that *only* has this role. During deploys we drop permissions to this user so that we can
-- more safely deploy code with restricted permissions.
create user [sqlcode-deploy-sandbox-user] without login;
alter role [sqlcode-deploy-role] add member [sqlcode-deploy-sandbox-user];
-- If you are a member of [sqlcode-deploy-role], then you get to impersonate a user that *only* has that role;
-- seems fair...
grant impersonate on user::[sqlcode-deploy-sandbox-user] to [sqlcode-deploy-role];
go
create schema sqlcode;
go
create procedure sqlcode.CreateCodeSchema(@schemasuffix varchar(50))
as begin
set xact_abort, nocount on
begin try
if @@trancount = 0 throw 55001, 'You should run sqlcode.CreateCodeSchema within a transaction', 1;
declare @schemaname nvarchar(max) = concat('code@', @schemasuffix);
-- Create the schema owned by [sqlcode-user-with-no-permissions] so that
-- no owner chaining will happen for stored procedures
declare @sql nvarchar(max) = concat('create schema ', quotename(@schemaname), ' authorization [sqlcode-user-with-no-permissions];')
exec sp_executesql @sql;
set @sql = concat('grant select, execute, references, view definition on schema::', quotename(@schemaname), ' to [sqlcode-execute-role];');
exec sp_executesql @sql;
set @sql = concat('grant alter, select, execute, references, view definition on schema::', quotename(@schemaname), ' to [sqlcode-deploy-role];');
exec sp_executesql @sql;
end try
begin catch
if @@trancount > 0 rollback;
;throw
end catch
end
go
create procedure sqlcode.DropCodeSchema(@schemasuffix varchar(50))
as begin
set xact_abort, nocount on
begin try
declare @msg varchar(max)
declare @sql nvarchar(max)
if @@trancount = 0 throw 55001, 'You should run sqlcode.DropCodeSchema within a transaction', 1;
declare @schemaname nvarchar(max) = concat('code@', @schemasuffix)
declare @schemaid int = (select schema_id from sys.schemas where name = @schemaname);
if @schemaid is null
begin
set @msg = concat('Schema [code@', @schemasuffix, '] not found');
throw 55002, @msg, 1;
end
-- Drop views, functions, procedures
select
@sql = string_agg(
concat('drop ', v.DropType, ' ', quotename(@schemaname), '.', quotename(o.name)),
concat(';', char(10)))
from sys.objects as o
cross apply ( values ( case
when o.type = 'FN' then 'function'
when o.type = 'IF' then 'function'
when o.type = 'TF' then 'function'
when o.type = 'P' then 'procedure'
when o.type = 'PC' then 'procedure'
when o.type = 'V' then 'view'
end )) v(DropType)
where
o.schema_id = @schemaid and v.DropType is not null;
exec sp_executesql @sql;
-- Drop types
select
@sql = string_agg(
concat('drop type ', quotename(@schemaname), '.', quotename(t.name)),
concat(';', char(10)))
from sys.types as t
where
t.schema_id = @schemaid;
exec sp_executesql @sql;
-- Finally drop the schema itself
set @sql = concat('drop schema ', quotename(@schemaname))
exec sp_executesql @sql;
end try
begin catch
if @@trancount > 0 rollback;
;throw
end catch
end
go
-- In order to make the stored procedure above operate as db_owner, even if the
-- caller does not have permissions,
-- The password mentioned below is deleted after use in the "remove private key" command
create certificate [cert/sqlcode.CreateCodeSchema] encryption by password = 'SqlCodePw1%' with subject = '"sqlcode.CreateCodeSchema"';
add signature to sqlcode.CreateCodeSchema by certificate [cert/sqlcode.CreateCodeSchema] with password = 'SqlCodePw1%'
add signature to sqlcode.DropCodeSchema by certificate [cert/sqlcode.CreateCodeSchema] with password = 'SqlCodePw1%'
create user [certuser/sqlcode.CreateCodeSchema] from certificate [cert/sqlcode.CreateCodeSchema] ;
alter role db_owner add member [certuser/sqlcode.CreateCodeSchema];
alter certificate [cert/sqlcode.CreateCodeSchema] remove private key; -- password no longer usable after this
go
grant execute on sqlcode.CreateCodeSchema to [sqlcode-deploy-role];
grant execute on sqlcode.DropCodeSchema to [sqlcode-deploy-role];
grant create procedure to [sqlcode-deploy-role];
grant create function to [sqlcode-deploy-role];
grant create type to [sqlcode-deploy-role];