Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a0ba626

Browse files
committed
Merge branch '124-change-owner' into 'master'
fix: modify the restriction template to change table owners (joe#124) Closes #124 See merge request postgres-ai/database-lab!260
2 parents e925a34 + 6cf1f64 commit a0ba626

File tree

2 files changed

+117
-40
lines changed

2 files changed

+117
-40
lines changed

cmd/cli/commands/clone/command_list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func CommandList() []*cli.Command {
4949
},
5050
&cli.StringFlag{
5151
Name: "db-name",
52-
Usage: "available database for a user with restricted permissions",
52+
Usage: "database available to the user with restricted permissions",
5353
},
5454
&cli.StringFlag{
5555
Name: "id",

pkg/services/provision/databases/postgres/postgres_mgmt.go

Lines changed: 116 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ func CreateUser(c *resources.AppConfig, user resources.EphemeralUser) error {
8484
query = superuserQuery(user.Name, user.Password)
8585
}
8686

87+
log.Msg(query)
88+
8789
out, err := runSimpleSQL(query, getPgConnStr(c.Host, dbName, c.DB.Username, c.Port))
8890
if err != nil {
8991
return errors.Wrap(err, "failed to run psql")
@@ -98,50 +100,125 @@ func superuserQuery(username, password string) string {
98100
return fmt.Sprintf(`create user "%s" with password '%s' login superuser;`, username, password)
99101
}
100102

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;
104106
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;
107109
108-
-- grant all on all objects in all schemas in the database
109110
do $$
111+
declare
112+
new_owner text;
113+
object_type record;
114+
r record;
110115
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+
$$;
143220
`
144221

145222
func restrictedUserQuery(username, password, database string) string {
146-
return fmt.Sprintf(restrictedTemplate, username, password, database)
223+
return fmt.Sprintf(restrictionTemplate, username, password, database)
147224
}

0 commit comments

Comments
 (0)