@@ -84,6 +84,8 @@ func CreateUser(c *resources.AppConfig, user resources.EphemeralUser) error {
84
84
query = superuserQuery (user .Name , user .Password )
85
85
}
86
86
87
+ log .Msg (query )
88
+
87
89
out , err := runSimpleSQL (query , getPgConnStr (c .Host , dbName , c .DB .Username , c .Port ))
88
90
if err != nil {
89
91
return errors .Wrap (err , "failed to run psql" )
@@ -98,50 +100,125 @@ func superuserQuery(username, password string) string {
98
100
return fmt .Sprintf (`create user "%s" with password '%s' login superuser;` , username , password )
99
101
}
100
102
101
- const restrictedTemplate = `
102
- -- create new user
103
- create user %[1]s with password '%s' createdb ;
103
+ const restrictionTemplate = `
104
+ -- create a new user
105
+ create user %[1]s with password '%s' login ;
104
106
105
- -- grant all privileges in the database
106
- grant all privileges on database %s to %[1]s;
107
+ -- change a database owner
108
+ alter database %s owner to %[1]s;
107
109
108
- -- grant all on all objects in all schemas in the database
109
110
do $$
111
+ declare
112
+ new_owner text;
113
+ object_type record;
114
+ r record;
110
115
begin
111
- -- grant usage on all schemas in the database
112
- execute (
113
- select string_agg(format('grant usage on schema %%I to %[1]s', nspname), '; ')
114
- from pg_namespace
115
- where nspname <> 'information_schema'
116
- and nspname not like 'pg\_%%'
117
- );
118
-
119
- -- grant all on all tables in all schemas in database
120
- execute (
121
- select string_agg(format('grant all on all tables in schema %%I to %[1]s', nspname), '; ')
122
- from pg_namespace
123
- where nspname <> 'information_schema'
124
- and nspname not like 'pg\_%%'
125
- );
126
-
127
- -- grant all on all sequences in all custom schemas in the database
128
- execute (
129
- select string_agg(format('grant all on all sequences in schema %%I to %[1]s', nspname), '; ')
130
- from pg_namespace
131
- where nspname <> 'information_schema'
132
- and nspname not like 'pg\_%%'
133
- );
134
-
135
- -- grant all on all functions in all schemas in the database
136
- execute (
137
- select string_agg(format('grant all on all functions in schema %%I to %[1]s', nspname), '; ')
138
- from pg_namespace
139
- where nspname <> 'information_schema'
140
- and nspname not like 'pg\_%%'
141
- );
142
- end $$;
116
+ new_owner := '%[1]s';
117
+
118
+ -- c: composite type
119
+ -- t: type (TOAST)
120
+ -- S: sequence
121
+ -- i: index
122
+ -- r: table
123
+ -- v: view
124
+ -- m: materialized view
125
+ for object_type in
126
+ select
127
+ unnest('{type,table,sequence,table,view,materialized view}'::text[]) type_name,
128
+ unnest('{c,t,S,r,v,m}'::text[]) code
129
+ loop
130
+ for r in
131
+ execute format(
132
+ $sql$
133
+ select n.nspname, c.relname
134
+ from pg_class c
135
+ join pg_namespace n on
136
+ n.oid = c.relnamespace
137
+ and not n.nspname in ('pg_catalog', 'information_schema')
138
+ and c.relkind = %%L
139
+ left join pg_class cc on
140
+ c.relkind = 't' /*leave 't' hardcoded!*/
141
+ and cc.oid = nullif(regexp_replace(c.relname, '^pg_toast_(.*)', '\1'), c.relname)::int8
142
+ left join pg_namespace nn on
143
+ nn.oid = cc.relnamespace
144
+ where
145
+ c.relkind <> 't' /*leave 't' hardcoded!*/
146
+ or not nn.nspname in ('pg_catalog', 'information_schema')
147
+ $sql$,
148
+ object_type.code
149
+ )
150
+ loop
151
+ raise debug 'Changing ownership of %% %%.%% to %%',
152
+ object_type.type_name, r.nspname, r.relname, new_owner;
153
+ execute format(
154
+ 'alter %%s %%I.%%I owner to %%I;',
155
+ object_type.type_name,
156
+ r.nspname,
157
+ r.relname,
158
+ new_owner
159
+ );
160
+ end loop;
161
+ end loop;
162
+
163
+ -- Functions,
164
+ for r in
165
+ select
166
+ p.proname,
167
+ n.nspname,
168
+ pg_catalog.pg_get_function_identity_arguments(p.oid) as args
169
+ from pg_catalog.pg_namespace as n
170
+ join pg_catalog.pg_proc as p on p.pronamespace = n.oid
171
+ where not n.nspname in ('pg_catalog', 'information_schema')
172
+ loop
173
+ raise debug 'Changing ownership of function %%.%%(%%) to %%',
174
+ r.nspname, r.proname, r.args, new_owner;
175
+ execute format(
176
+ 'alter function %%I.%%I(%%s) owner to %%I', -- todo: check support CamelStyle r.args
177
+ r.nspname,
178
+ r.proname,
179
+ r.args,
180
+ new_owner
181
+ );
182
+ end loop;
183
+
184
+ -- full text search dictionary
185
+ -- TODO: text search configuration
186
+ for r in
187
+ select *
188
+ from pg_catalog.pg_namespace n
189
+ join pg_catalog.pg_ts_dict d on d.dictnamespace = n.oid
190
+ where not n.nspname in ('pg_catalog', 'information_schema')
191
+ loop
192
+ raise debug 'Changing ownership of text search dictionary %%.%% to %%',
193
+ r.nspname, r.dictname, new_owner;
194
+ execute format(
195
+ 'alter text search dictionary %%I.%%I owner to %%I',
196
+ r.nspname,
197
+ r.dictname,
198
+ new_owner
199
+ );
200
+ end loop;
201
+
202
+ -- domain
203
+ for r in
204
+ select typname, nspname
205
+ from pg_catalog.pg_type
206
+ join pg_catalog.pg_namespace on pg_namespace.oid = pg_type.typnamespace
207
+ where typtype = 'd' and not nspname in ('pg_catalog', 'information_schema')
208
+ loop
209
+ raise debug 'Changing ownership of domain %%.%% to %%',
210
+ r.nspname, r.typname, new_owner;
211
+ execute format(
212
+ 'alter domain %%I.%%I owner to %%I',
213
+ r.nspname,
214
+ r.typname,
215
+ new_owner
216
+ );
217
+ end loop;
218
+ end
219
+ $$;
143
220
`
144
221
145
222
func restrictedUserQuery (username , password , database string ) string {
146
- return fmt .Sprintf (restrictedTemplate , username , password , database )
223
+ return fmt .Sprintf (restrictionTemplate , username , password , database )
147
224
}
0 commit comments