view schema/updates/1465/01.delete_user.sql @ 5502:26b7921190fa deactivate-users

Login rights are now tracked by triggers.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 22 Sep 2021 16:57:45 +0200
parents 2ce85b6fcb76
children 076b6b17c4a9
line wrap: on
line source


CREATE OR REPLACE FUNCTION internal.create_user() RETURNS trigger
AS $$
BEGIN
    IF NEW.map_extent IS NULL
    THEN
        NEW.map_extent = ST_Extent(CAST(area AS geometry))
            FROM users.stretches st
                JOIN users.stretch_countries stc ON stc.stretch_id = st.id
            WHERE stc.country = NEW.country;
    END IF;

    IF NEW.username IS NOT NULL
    -- otherwise let the constraint on user_profiles speak
    THEN
        EXECUTE format(
            'CREATE ROLE %I IN ROLE %I LOGIN PASSWORD %L',
            NEW.username,
            NEW.rolname,
            internal.check_password(NEW.pw));
    END IF;

    INSERT INTO internal.user_profiles (
        username, country, map_extent, email_address,
        report_reciever, active)
        VALUES (NEW.username, NEW.country, NEW.map_extent, NEW.email_address,
                NEW.report_reciever, NEW.active);

    IF NEW.active THEN
        EXECUTE format(
            'ALTER ROLE %I LOGIN', NEW.username);
    ELSE
        EXECUTE format(
            'ALTER ROLE %I NOLOGIN', NEW.username);
    END IF;

    -- Do not leak new password
    NEW.pw = '';
    RETURN NEW;
END;
$$
    LANGUAGE plpgsql
    SECURITY DEFINER;

CREATE OR REPLACE FUNCTION internal.update_user() RETURNS trigger
AS $$
DECLARE
    cur_username varchar;
BEGIN
    cur_username = OLD.username;

    IF NEW.username <> cur_username
    THEN
        EXECUTE format(
            'ALTER ROLE %I RENAME TO %I', cur_username, NEW.username);
        cur_username = NEW.username;
    END IF;

    UPDATE internal.user_profiles p
        SET (username, country, map_extent, email_address,
             report_reciever, active)
        = (NEW.username, NEW.country, NEW.map_extent, NEW.email_address,
           NEW.report_reciever, NEW.active)
        WHERE p.username = cur_username;

    IF NEW.rolname <> OLD.rolname
    THEN
        EXECUTE format(
            'REVOKE %I FROM %I', OLD.rolname, cur_username);
        EXECUTE format(
            'GRANT %I TO %I', NEW.rolname, cur_username);
    END IF;

    IF NEW.pw IS NOT NULL AND NEW.pw <> ''
    THEN
        EXECUTE format(
            'ALTER ROLE %I PASSWORD %L',
            cur_username,
            internal.check_password(NEW.pw));
    END IF;

    IF NEW.active <> OLD.active THEN
        IF NEW.active THEN
            EXECUTE format(
                'ALTER ROLE %I LOGIN', cur_username);
        ELSE
            EXECUTE format(
                'ALTER ROLE %I NOLOGIN', cur_username);
        END IF;
    END IF;

    -- Do not leak new password
    NEW.pw = '';
    RETURN NEW;
END;
$$
    LANGUAGE plpgsql
    SECURITY DEFINER;


CREATE OR REPLACE FUNCTION delete_user(rolename text) RETURNS int
AS $$
DECLARE
    user_exists bool;
    is_admin    bool;
    has_imports bool;
BEGIN
    SELECT EXISTS (SELECT 1 FROM pg_roles
        WHERE rolname = rolename)
        INTO user_exists;

    IF NOT user_exists THEN
        RETURN 0;
    END IF;

    SELECT EXISTS (SELECT 1 FROM pg_roles
        WHERE pg_has_role(rolename, oid, 'member') AND
            rolname IN ('waterway_admin', 'sys_admin'))
        INTO is_admin;

    -- None admins can be deleted.
    IF NOT is_admin THEN
        DELETE FROM users.list_users WHERE username = rolename;
        RETURN 1;
    END IF;

    SELECT EXISTS (SELECT 1 FROM import.imports
        WHERE username = rolename)
        INTO has_imports;

    -- Admins w/o imports can be deleted.
    IF NOT has_imports THEN
        DELETE FROM users.list_users WHERE username = rolename;
        RETURN 1;
    END IF;

    -- Admins w/ imports have to be deactivated.
    UPDATE users.list_users
        SET (email_address, report_reciever, active) =
            ('nomail@example.com', false, false)
        WHERE username = rolename;

    RETURN 2;
END;
$$
LANGUAGE plpgsql
SECURITY DEFINER;

GRANT EXECUTE ON FUNCTION delete_user to sys_admin;