Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
55 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,35 @@ | ||
create or replace procedure teleport_activate_user(username varchar, roles varchar[]) | ||
language plpgsql | ||
as $$ | ||
declare | ||
CREATE OR REPLACE PROCEDURE teleport_activate_user(username varchar, roles varchar[]) | ||
LANGUAGE plpgsql | ||
AS $$ | ||
DECLARE | ||
role_ varchar; | ||
cur_roles varchar[]; | ||
begin | ||
BEGIN | ||
-- If the user already exists and was provisioned by Teleport, reactivate | ||
-- it, otherwise provision a new one. | ||
if exists (select * from pg_auth_members where roleid = (select oid from pg_roles where rolname = 'teleport-auto-user') and member = (select oid from pg_roles where rolname = username)) then | ||
IF EXISTS (SELECT * FROM pg_auth_members WHERE roleid = (SELECT oid FROM pg_roles WHERE rolname = 'teleport-auto-user') and member = (SELECT oid FROM pg_roles WHERE rolname = username)) THEN | ||
-- If the user has active connections, make sure the provided roles | ||
-- match what the user currently has. | ||
if exists (select usename from pg_stat_activity where usename = username) then | ||
select cast(array_agg(rolname) as varchar[]) into cur_roles from pg_auth_members join pg_roles on roleid = oid where member=(select oid from pg_roles where rolname = username) and rolname != 'teleport-auto-user'; | ||
if roles <@ cur_roles AND cur_roles <@roles then | ||
return; | ||
end if; | ||
IF EXISTS (SELECT usename FROM pg_stat_activity WHERE usename = username) THEN | ||
SELECT CAST(array_agg(rolname) as varchar[]) INTO cur_roles FROM pg_auth_members JOIN pg_roles ON roleid = oid WHERE member=(SELECT oid FROM pg_roles WHERE rolname = username) AND rolname != 'teleport-auto-user'; | ||
-- "a <@ b" checks if all unique elements in "a" are contained by | ||
-- "b". Using length check plus "contains" check to avoid sorting. | ||
IF ARRAY_LENGTH(roles, 1) = ARRAY_LENGTH(cur_roles, 1) AND roles <@ cur_roles THEN | ||
RETURN; | ||
END IF; | ||
RAISE EXCEPTION SQLSTATE 'TP002' USING MESSAGE = 'TP002: User has active connections and roles have changed'; | ||
end if; | ||
END IF; | ||
-- Otherwise reactivate the user, but first strip if of all roles to | ||
-- account for scenarios with left-over roles if database agent crashed | ||
-- and failed to cleanup upon session termination. | ||
call teleport_deactivate_user(username); | ||
execute format('alter user %I with login', username); | ||
else | ||
execute format('create user %I in role "teleport-auto-user"', username); | ||
end if; | ||
CALL teleport_deactivate_user(username); | ||
EXECUTE FORMAT('ALTER USER %I WITH LOGIN', username); | ||
ELSE | ||
EXECUTE FORMAT('CREATE USER %I IN ROLE "teleport-auto-user"', username); | ||
END IF; | ||
-- Assign all roles to the created/activated user. | ||
foreach role_ in array roles | ||
loop | ||
execute format('grant %I to %I', role_, username); | ||
end loop; | ||
end;$$; | ||
FOREACH role_ IN ARRAY roles | ||
LOOP | ||
EXECUTE FORMAT('GRANT %I TO %I', role_, username); | ||
END LOOP; | ||
END;$$; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,19 @@ | ||
create or replace procedure teleport_deactivate_user(username varchar) | ||
language plpgsql | ||
as $$ | ||
declare | ||
CREATE OR REPLACE PROCEDURE teleport_deactivate_user(username varchar) | ||
LANGUAGE plpgsql | ||
AS $$ | ||
DECLARE | ||
role_ varchar; | ||
begin | ||
BEGIN | ||
-- Only deactivate if the user doesn't have other active sessions. | ||
if exists (select usename from pg_stat_activity where usename = username) then | ||
raise notice 'User has active connections'; | ||
else | ||
IF EXISTS (SELECT usename FROM pg_stat_activity WHERE usename = username) THEN | ||
RAISE NOTICE 'User has active connections'; | ||
ELSE | ||
-- Revoke all role memberships except teleport-auto-user group. | ||
for role_ in select a.rolname from pg_roles a where pg_has_role(username, a.oid, 'member') and a.rolname not in (username, 'teleport-auto-user') | ||
loop | ||
execute format('revoke %I from %I', role_, username); | ||
end loop; | ||
FOR role_ IN SELECT a.rolname FROM pg_roles a WHERE pg_has_role(username, a.oid, 'member') AND a.rolname NOT IN (username, 'teleport-auto-user') | ||
LOOP | ||
EXECUTE FORMAT('REVOKE %I FROM %I', role_, username); | ||
END LOOP; | ||
-- Disable ability to login for the user. | ||
execute format('alter user %I with nologin', username); | ||
end if; | ||
end;$$; | ||
EXECUTE FORMAT('ALTER USER %I WITH NOLOGIN', username); | ||
END IF; | ||
END;$$; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,21 @@ | ||
create or replace procedure teleport_delete_user(username varchar, inout state varchar default 'TP003') | ||
language plpgsql | ||
as $$ | ||
declare | ||
CREATE OR REPLACE PROCEDURE teleport_delete_user(username varchar, inout state varchar default 'TP003') | ||
LANGUAGE plpgsql | ||
AS $$ | ||
DECLARE | ||
role_ varchar; | ||
begin | ||
BEGIN | ||
-- Only drop if the user doesn't have other active sessions. | ||
if exists (select usename from pg_stat_activity where usename = username) then | ||
raise notice 'User has active connections'; | ||
else | ||
begin | ||
execute format('drop user %I', username); | ||
exception | ||
when SQLSTATE '2BP01' then | ||
IF EXISTS (SELECT usename FROM pg_stat_activity WHERE usename = username) THEN | ||
RAISE NOTICE 'User has active connections'; | ||
ELSE | ||
BEGIN | ||
EXECUTE FORMAT('DROP USER %I', username); | ||
EXCEPTION | ||
WHEN SQLSTATE '2BP01' THEN | ||
state := 'TP004'; | ||
-- Drop user/role will fail if user has dependent objects. | ||
-- In this scenario, fallback into disabling the user. | ||
call teleport_deactivate_user(username); | ||
end; | ||
end if; | ||
end;$$; | ||
CALL teleport_deactivate_user(username); | ||
END; | ||
END IF; | ||
END;$$; |