Mercurial > gemma
diff 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 |
line wrap: on
line diff
--- a/schema/manage_users.sql Wed Aug 01 15:18:26 2018 +0200 +++ b/schema/manage_users.sql Wed Aug 01 15:49:38 2018 +0200 @@ -38,7 +38,13 @@ CREATE OR REPLACE VIEW users.list_users WITH (security_barrier) AS - SELECT r.rolname, p.* + SELECT + r.rolname, + p.username, + CAST('' AS varchar) AS pw, + p.country, + p.map_extent, + p.email_address FROM internal.user_profiles p JOIN pg_roles u ON p.username = u.rolname JOIN pg_auth_members a ON u.oid = a.member @@ -79,61 +85,52 @@ SECURITY DEFINER; -CREATE OR REPLACE FUNCTION sys_admin.update_user( - username internal.user_profiles.username%TYPE, - new_userrole varchar, - new_username internal.user_profiles.username%TYPE, - new_pw varchar, - new_country internal.user_profiles.country%TYPE, - new_map_extent internal.user_profiles.map_extent%TYPE, - new_email_address internal.user_profiles.email_address%TYPE - ) - RETURNS void +CREATE OR REPLACE FUNCTION internal.update_user() RETURNS trigger AS $$ DECLARE - cur_username name; - cur_userrole name; + cur_username varchar; BEGIN - cur_username = username; + cur_username = OLD.username; UPDATE internal.user_profiles p SET (username, country, map_extent, email_address) - = (new_username, new_country, new_map_extent, new_email_address) + = (NEW.username, NEW.country, NEW.map_extent, NEW.email_address) WHERE p.username = cur_username; - IF new_username <> cur_username + IF NEW.username <> cur_username THEN EXECUTE format( - 'ALTER ROLE %I RENAME TO %I', username, new_username); - cur_username = new_username; + 'ALTER ROLE %I RENAME TO %I', cur_username, NEW.username); + cur_username = NEW.username; END IF; - cur_userrole = rolname FROM pg_roles r - JOIN pg_auth_members a ON r.oid = a.roleid - WHERE member = ( - SELECT oid FROM pg_roles WHERE rolname = cur_username); - IF new_userrole <> cur_userrole + IF NEW.rolname <> OLD.rolname THEN EXECUTE format( - 'REVOKE %I FROM %I', cur_userrole, cur_username); + 'REVOKE %I FROM %I', OLD.rolname, cur_username); + EXECUTE format( + 'GRANT %I TO %I', NEW.rolname, cur_username); END IF; - -- GRANT new_userrole unconditionally to ensure it's an error to upgrade - -- a non-existent cur_username (GRANTing a role twice is not an error) - EXECUTE format( - 'GRANT %I TO %I', new_userrole, cur_username); - IF new_pw IS NOT NULL AND new_pw <> '' + IF NEW.pw IS NOT NULL AND NEW.pw <> '' THEN EXECUTE format( 'ALTER ROLE %I PASSWORD %L', cur_username, - users.check_password(new_pw)); + users.check_password(NEW.pw)); END IF; + + -- Do not leak new password + NEW.pw = ''; + RETURN NEW; END; $$ LANGUAGE plpgsql SECURITY DEFINER; +CREATE TRIGGER update_user INSTEAD OF UPDATE ON users.list_users FOR EACH ROW + EXECUTE PROCEDURE internal.update_user(); + CREATE OR REPLACE FUNCTION sys_admin.delete_user( username internal.user_profiles.username%TYPE