comparison schema/manage_users.sql @ 307:750a9c9cd965

Use SQL UPDATE to update users This implies it's not a database error anymore to try to update a non-existent user. Thus, handle this as a HTTP-404 in the backend, which is in line with what GET does. Using UPDATE here will allow to GRANT column-wise privileges. The password has become part of the view to be updatable as well.
author Tom Gottfried <tom@intevation.de>
date Wed, 01 Aug 2018 15:49:38 +0200
parents 0b2d9f96ddb8
children 0745b4d336c4
comparison
equal deleted inserted replaced
306:70592a18c5c6 307:750a9c9cd965
36 SECURITY DEFINER 36 SECURITY DEFINER
37 STABLE PARALLEL SAFE; 37 STABLE PARALLEL SAFE;
38 38
39 39
40 CREATE OR REPLACE VIEW users.list_users WITH (security_barrier) AS 40 CREATE OR REPLACE VIEW users.list_users WITH (security_barrier) AS
41 SELECT r.rolname, p.* 41 SELECT
42 r.rolname,
43 p.username,
44 CAST('' AS varchar) AS pw,
45 p.country,
46 p.map_extent,
47 p.email_address
42 FROM internal.user_profiles p 48 FROM internal.user_profiles p
43 JOIN pg_roles u ON p.username = u.rolname 49 JOIN pg_roles u ON p.username = u.rolname
44 JOIN pg_auth_members a ON u.oid = a.member 50 JOIN pg_auth_members a ON u.oid = a.member
45 JOIN pg_roles r ON a.roleid = r.oid 51 JOIN pg_roles r ON a.roleid = r.oid
46 WHERE p.username = current_user 52 WHERE p.username = current_user
77 $$ 83 $$
78 LANGUAGE plpgsql 84 LANGUAGE plpgsql
79 SECURITY DEFINER; 85 SECURITY DEFINER;
80 86
81 87
82 CREATE OR REPLACE FUNCTION sys_admin.update_user( 88 CREATE OR REPLACE FUNCTION internal.update_user() RETURNS trigger
83 username internal.user_profiles.username%TYPE,
84 new_userrole varchar,
85 new_username internal.user_profiles.username%TYPE,
86 new_pw varchar,
87 new_country internal.user_profiles.country%TYPE,
88 new_map_extent internal.user_profiles.map_extent%TYPE,
89 new_email_address internal.user_profiles.email_address%TYPE
90 )
91 RETURNS void
92 AS $$ 89 AS $$
93 DECLARE 90 DECLARE
94 cur_username name; 91 cur_username varchar;
95 cur_userrole name;
96 BEGIN 92 BEGIN
97 cur_username = username; 93 cur_username = OLD.username;
98 94
99 UPDATE internal.user_profiles p 95 UPDATE internal.user_profiles p
100 SET (username, country, map_extent, email_address) 96 SET (username, country, map_extent, email_address)
101 = (new_username, new_country, new_map_extent, new_email_address) 97 = (NEW.username, NEW.country, NEW.map_extent, NEW.email_address)
102 WHERE p.username = cur_username; 98 WHERE p.username = cur_username;
103 99
104 IF new_username <> cur_username 100 IF NEW.username <> cur_username
105 THEN 101 THEN
106 EXECUTE format( 102 EXECUTE format(
107 'ALTER ROLE %I RENAME TO %I', username, new_username); 103 'ALTER ROLE %I RENAME TO %I', cur_username, NEW.username);
108 cur_username = new_username; 104 cur_username = NEW.username;
109 END IF; 105 END IF;
110 106
111 cur_userrole = rolname FROM pg_roles r 107 IF NEW.rolname <> OLD.rolname
112 JOIN pg_auth_members a ON r.oid = a.roleid
113 WHERE member = (
114 SELECT oid FROM pg_roles WHERE rolname = cur_username);
115 IF new_userrole <> cur_userrole
116 THEN 108 THEN
117 EXECUTE format( 109 EXECUTE format(
118 'REVOKE %I FROM %I', cur_userrole, cur_username); 110 'REVOKE %I FROM %I', OLD.rolname, cur_username);
111 EXECUTE format(
112 'GRANT %I TO %I', NEW.rolname, cur_username);
119 END IF; 113 END IF;
120 -- GRANT new_userrole unconditionally to ensure it's an error to upgrade
121 -- a non-existent cur_username (GRANTing a role twice is not an error)
122 EXECUTE format(
123 'GRANT %I TO %I', new_userrole, cur_username);
124 114
125 IF new_pw IS NOT NULL AND new_pw <> '' 115 IF NEW.pw IS NOT NULL AND NEW.pw <> ''
126 THEN 116 THEN
127 EXECUTE format( 117 EXECUTE format(
128 'ALTER ROLE %I PASSWORD %L', 118 'ALTER ROLE %I PASSWORD %L',
129 cur_username, 119 cur_username,
130 users.check_password(new_pw)); 120 users.check_password(NEW.pw));
131 END IF; 121 END IF;
122
123 -- Do not leak new password
124 NEW.pw = '';
125 RETURN NEW;
132 END; 126 END;
133 $$ 127 $$
134 LANGUAGE plpgsql 128 LANGUAGE plpgsql
135 SECURITY DEFINER; 129 SECURITY DEFINER;
130
131 CREATE TRIGGER update_user INSTEAD OF UPDATE ON users.list_users FOR EACH ROW
132 EXECUTE PROCEDURE internal.update_user();
136 133
137 134
138 CREATE OR REPLACE FUNCTION sys_admin.delete_user( 135 CREATE OR REPLACE FUNCTION sys_admin.delete_user(
139 username internal.user_profiles.username%TYPE 136 username internal.user_profiles.username%TYPE
140 ) 137 )