2015-08-19 17:03:07 +08:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --
-- GROUP MANAGEMENT FUNCTIONS
--
-- Meant to be used by org admin. See CDB_Organization_AddAdmin.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --
2015-08-10 19:44:06 +08:00
-- Creates a new group
2015-08-10 17:07:41 +08:00
CREATE OR REPLACE
FUNCTION cartodb . CDB_Group_CreateGroup ( group_name text )
2015-08-10 19:44:06 +08:00
RETURNS VOID AS $ $
2015-08-13 21:20:20 +08:00
DECLARE
2015-08-14 19:55:52 +08:00
group_role TEXT ;
2015-08-10 17:07:41 +08:00
BEGIN
2015-08-14 19:55:52 +08:00
group_role : = cartodb . _CDB_Group_GroupRole ( group_name ) ;
2015-08-27 16:25:52 +08:00
EXECUTE format ( ' CREATE ROLE %I NOLOGIN; ' , group_role ) ;
2015-08-19 16:37:52 +08:00
PERFORM cartodb . _CDB_Group_CreateGroup_API ( group_name , group_role ) ;
2015-08-10 17:07:41 +08:00
END
2015-08-13 21:20:20 +08:00
$ $ LANGUAGE PLPGSQL VOLATILE ;
2015-08-10 17:07:41 +08:00
2015-08-10 19:40:59 +08:00
-- Drops group and everything that role owns
2015-08-12 01:54:27 +08:00
-- TODO: LIMITATION: in order to drop a role all its owned objects must be dropped before.
-- Right now this is done with DROP OWNED, which can only be done by a superadmin.
-- Not even the role creator can drop the role and the objects it owns.
-- All group owned objects by the group are permissions.
2015-08-10 17:07:41 +08:00
CREATE OR REPLACE
FUNCTION cartodb . CDB_Group_DropGroup ( group_name text )
RETURNS VOID AS $ $
2015-08-12 01:54:27 +08:00
DECLARE
2015-08-14 21:22:00 +08:00
group_role TEXT ;
2015-08-10 17:07:41 +08:00
BEGIN
2015-08-14 21:22:00 +08:00
group_role : = cartodb . _CDB_Group_GroupRole ( group_name ) ;
2015-08-27 16:25:52 +08:00
EXECUTE format ( ' DROP OWNED BY %I ' , group_role ) ;
EXECUTE format ( ' DROP ROLE IF EXISTS %I ' , group_role ) ;
2015-08-19 16:37:52 +08:00
PERFORM cartodb . _CDB_Group_DropGroup_API ( group_name ) ;
2015-08-10 17:07:41 +08:00
END
2015-08-13 21:20:20 +08:00
$ $ LANGUAGE PLPGSQL VOLATILE ;
2015-08-10 17:21:57 +08:00
2015-08-10 19:46:35 +08:00
-- Renames a group
2015-08-10 17:21:57 +08:00
CREATE OR REPLACE
FUNCTION cartodb . CDB_Group_RenameGroup ( old_group_name text , new_group_name text )
RETURNS VOID AS $ $
2015-08-17 19:37:34 +08:00
DECLARE
old_group_role TEXT ;
new_group_role TEXT ;
2015-08-10 17:21:57 +08:00
BEGIN
2015-08-17 19:37:34 +08:00
old_group_role = cartodb . _CDB_Group_GroupRole ( old_group_name ) ;
new_group_role = cartodb . _CDB_Group_GroupRole ( new_group_name ) ;
2015-08-27 16:25:52 +08:00
EXECUTE format ( ' ALTER ROLE %I RENAME TO %I ' , old_group_role , new_group_role ) ;
2015-08-19 16:52:07 +08:00
PERFORM cartodb . _CDB_Group_RenameGroup_API ( old_group_name , new_group_name , new_group_role ) ;
2015-08-10 17:21:57 +08:00
END
2015-08-13 21:20:20 +08:00
$ $ LANGUAGE PLPGSQL VOLATILE ;
2015-08-10 17:21:57 +08:00
2015-09-07 17:48:18 +08:00
-- Adds users to a group
2015-08-10 19:40:59 +08:00
CREATE OR REPLACE
2015-09-07 17:43:46 +08:00
FUNCTION cartodb . CDB_Group_AddUsers ( group_name text , usernames text [ ] )
2015-08-10 19:40:59 +08:00
RETURNS VOID AS $ $
DECLARE
2015-08-17 21:23:39 +08:00
group_role TEXT ;
user_role TEXT ;
2015-09-07 16:35:04 +08:00
username TEXT ;
2015-08-10 19:40:59 +08:00
BEGIN
2015-08-17 21:23:39 +08:00
group_role : = cartodb . _CDB_Group_GroupRole ( group_name ) ;
2015-09-07 17:43:46 +08:00
foreach username in array usernames
2015-09-07 16:35:04 +08:00
loop
user_role : = cartodb . _CDB_User_RoleFromUsername ( username ) ;
IF ( group_role IS NULL OR user_role IS NULL )
THEN
RAISE EXCEPTION ' Group role (%) and user role (%) must be already existing ' , group_role , user_role ;
END IF ;
EXECUTE format ( ' GRANT %I TO %I ' , group_role , user_role ) ;
end loop ;
PERFORM cartodb . _CDB_Group_AddUsers_API ( group_name , usernames ) ;
2015-08-10 19:40:59 +08:00
END
2015-08-13 21:20:20 +08:00
$ $ LANGUAGE PLPGSQL VOLATILE ;
2015-08-10 19:40:59 +08:00
2015-09-07 17:48:18 +08:00
-- Removes users from a group
2015-08-10 19:40:59 +08:00
CREATE OR REPLACE
2015-09-07 17:43:46 +08:00
FUNCTION cartodb . CDB_Group_RemoveUsers ( group_name text , usernames text [ ] )
2015-08-10 19:40:59 +08:00
RETURNS VOID AS $ $
DECLARE
2015-08-17 21:23:39 +08:00
group_role TEXT ;
user_role TEXT ;
2015-09-07 16:35:04 +08:00
username TEXT ;
2015-08-10 19:40:59 +08:00
BEGIN
2015-08-17 21:23:39 +08:00
group_role : = cartodb . _CDB_Group_GroupRole ( group_name ) ;
2015-09-07 17:43:46 +08:00
foreach username in array usernames
2015-09-07 16:35:04 +08:00
loop
user_role : = cartodb . _CDB_User_RoleFromUsername ( username ) ;
EXECUTE format ( ' REVOKE %I FROM %I ' , group_role , user_role ) ;
end loop ;
PERFORM cartodb . _CDB_Group_RemoveUsers_API ( group_name , usernames ) ;
2015-08-10 19:40:59 +08:00
END
2015-08-13 21:20:20 +08:00
$ $ LANGUAGE PLPGSQL VOLATILE ;
2015-08-10 19:40:59 +08:00
2015-08-19 17:03:07 +08:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --
-- TABLE MANAGEMENT FUNCTIONS
--
-- Meant to be used by table owners.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --
2015-08-10 19:46:35 +08:00
-- Grants table read permission to a group
2015-08-10 19:40:59 +08:00
CREATE OR REPLACE
FUNCTION cartodb . CDB_Group_Table_GrantRead ( group_name text , username text , table_name text )
RETURNS VOID AS $ $
DECLARE
2015-08-17 21:23:39 +08:00
group_role TEXT ;
2015-09-26 01:02:39 +08:00
BEGIN
2015-09-28 00:42:24 +08:00
PERFORM cartodb . _CDB_Group_Table_GrantRead ( group_name , username , table_name , true ) ;
2015-09-26 01:02:39 +08:00
END
$ $ LANGUAGE PLPGSQL VOLATILE ;
CREATE OR REPLACE
2015-09-28 00:42:24 +08:00
FUNCTION cartodb . _CDB_Group_Table_GrantRead ( group_name text , username text , table_name text , sync boolean )
2015-09-26 01:02:39 +08:00
RETURNS VOID AS $ $
DECLARE
group_role TEXT ;
2015-08-10 19:40:59 +08:00
BEGIN
2015-08-17 21:23:39 +08:00
group_role : = cartodb . _CDB_Group_GroupRole ( group_name ) ;
2015-08-27 16:25:52 +08:00
EXECUTE format ( ' GRANT USAGE ON SCHEMA %I TO %I ' , username , group_role ) ;
EXECUTE format ( ' GRANT SELECT ON TABLE %I.%I TO %I ' , username , table_name , group_role ) ;
2015-09-26 01:02:39 +08:00
IF ( sync ) THEN
PERFORM cartodb . _CDB_Group_Table_GrantPermission_API ( group_name , username , table_name , ' r ' ) ;
END IF ;
2015-08-10 19:40:59 +08:00
END
2015-08-13 21:20:20 +08:00
$ $ LANGUAGE PLPGSQL VOLATILE ;
2015-08-10 19:40:59 +08:00
2015-08-10 19:53:57 +08:00
-- Grants table write permission to a group
CREATE OR REPLACE
FUNCTION cartodb . CDB_Group_Table_GrantReadWrite ( group_name text , username text , table_name text )
RETURNS VOID AS $ $
DECLARE
2015-08-17 21:23:39 +08:00
group_role TEXT ;
2015-09-26 01:02:39 +08:00
BEGIN
2015-09-28 00:42:24 +08:00
PERFORM cartodb . _CDB_Group_Table_GrantReadWrite ( group_name , username , table_name , true ) ;
2015-09-26 01:02:39 +08:00
END
$ $ LANGUAGE PLPGSQL VOLATILE ;
CREATE OR REPLACE
2015-09-28 00:42:24 +08:00
FUNCTION cartodb . _CDB_Group_Table_GrantReadWrite ( group_name text , username text , table_name text , sync boolean )
2015-09-26 01:02:39 +08:00
RETURNS VOID AS $ $
DECLARE
group_role TEXT ;
2015-08-10 19:53:57 +08:00
BEGIN
2015-08-17 21:23:39 +08:00
group_role : = cartodb . _CDB_Group_GroupRole ( group_name ) ;
2015-08-27 16:25:52 +08:00
EXECUTE format ( ' GRANT USAGE ON SCHEMA %I TO %I ' , username , group_role ) ;
EXECUTE format ( ' GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE %I.%I TO %I ' , username , table_name , group_role ) ;
2015-08-26 19:33:01 +08:00
PERFORM cartodb . _CDB_Group_TableSequences_Permission ( group_name , username , table_name , true ) ;
2015-09-26 01:02:39 +08:00
IF ( sync ) THEN
PERFORM cartodb . _CDB_Group_Table_GrantPermission_API ( group_name , username , table_name , ' w ' ) ;
END IF ;
2015-08-10 19:53:57 +08:00
END
2015-08-13 21:20:20 +08:00
$ $ LANGUAGE PLPGSQL VOLATILE ;
2015-08-10 19:53:57 +08:00
2015-08-26 19:33:01 +08:00
-- Granting and revoking permissions on sequences
CREATE OR REPLACE
FUNCTION cartodb . _CDB_Group_TableSequences_Permission ( group_name text , username text , table_name text , do_grant bool )
RETURNS VOID AS $ $
DECLARE
column_name TEXT ;
sequence_name TEXT ;
group_role TEXT ;
BEGIN
group_role : = cartodb . _CDB_Group_GroupRole ( group_name ) ;
FOR column_name IN EXECUTE ' SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG = current_database() AND TABLE_SCHEMA = $1 AND TABLE_NAME = $2 AND COLUMN_DEFAULT LIKE '' nextval% '' ' USING username , table_name
LOOP
2015-10-07 00:09:37 +08:00
EXECUTE format ( ' SELECT PG_GET_SERIAL_SEQUENCE( '' %I.%I '' , '' %I '' ) ' , username , table_name , column_name ) INTO sequence_name ;
2015-08-26 19:33:01 +08:00
IF sequence_name IS NOT NULL THEN
IF do_grant THEN
2015-08-27 23:02:05 +08:00
-- Here %s is needed since sequence_name has quotes
EXECUTE format ( ' GRANT USAGE, SELECT, UPDATE ON SEQUENCE %s TO %I ' , sequence_name , group_role ) ;
2015-08-26 19:33:01 +08:00
ELSE
2015-08-27 23:03:13 +08:00
EXECUTE format ( ' REVOKE ALL ON SEQUENCE %s FROM %I ' , sequence_name , group_role ) ;
2015-08-26 19:33:01 +08:00
END IF ;
END IF ;
END LOOP ;
RETURN ;
END
$ $ LANGUAGE PLPGSQL VOLATILE ;
2015-08-10 19:46:35 +08:00
-- Revokes all permissions on a table from a group
2015-08-10 19:40:59 +08:00
CREATE OR REPLACE
FUNCTION cartodb . CDB_Group_Table_RevokeAll ( group_name text , username text , table_name text )
RETURNS VOID AS $ $
DECLARE
2015-08-17 21:23:39 +08:00
group_role TEXT ;
2015-09-26 01:02:39 +08:00
BEGIN
2015-09-28 00:42:24 +08:00
PERFORM cartodb . _CDB_Group_Table_RevokeAll ( group_name , username , table_name , true ) ;
2015-09-26 01:02:39 +08:00
END
$ $ LANGUAGE PLPGSQL VOLATILE ;
CREATE OR REPLACE
2015-09-28 00:42:24 +08:00
FUNCTION cartodb . _CDB_Group_Table_RevokeAll ( group_name text , username text , table_name text , sync boolean )
2015-09-26 01:02:39 +08:00
RETURNS VOID AS $ $
DECLARE
group_role TEXT ;
2015-08-10 19:40:59 +08:00
BEGIN
2015-08-17 21:23:39 +08:00
group_role : = cartodb . _CDB_Group_GroupRole ( group_name ) ;
2015-08-27 16:25:52 +08:00
EXECUTE format ( ' REVOKE ALL ON TABLE %I.%I FROM %I ' , username , table_name , group_role ) ;
2015-08-26 19:33:01 +08:00
PERFORM cartodb . _CDB_Group_TableSequences_Permission ( group_name , username , table_name , false ) ;
2015-09-26 01:02:39 +08:00
IF ( sync ) THEN
PERFORM cartodb . _CDB_Group_Table_RevokeAllPermission_API ( group_name , username , table_name ) ;
END IF ;
2015-08-10 19:40:59 +08:00
END
2015-08-13 21:20:20 +08:00
$ $ LANGUAGE PLPGSQL VOLATILE ;
2015-08-10 19:40:59 +08:00
2015-08-10 17:21:57 +08:00
- - - - - - - - - - - - - - - - - - - - - --
2015-08-19 17:03:07 +08:00
-- Helper functions
2015-08-10 17:21:57 +08:00
- - - - - - - - - - - - - - - - - - - - - --
2015-08-11 20:49:12 +08:00
-- Given a group name returns a role. group_name must be a valid PostgreSQL idenfifier. See http://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
2015-08-10 17:21:57 +08:00
CREATE OR REPLACE
2015-08-10 19:42:27 +08:00
FUNCTION cartodb . _CDB_Group_GroupRole ( group_name text )
2015-08-10 17:21:57 +08:00
RETURNS TEXT AS $ $
2015-08-10 22:15:04 +08:00
DECLARE
group_role TEXT ;
2015-08-14 19:55:52 +08:00
prefix TEXT ;
max_length constant INTEGER : = 63 ;
2015-08-10 17:21:57 +08:00
BEGIN
2015-08-14 21:22:00 +08:00
prefix = format ( ' %s_g_ ' , cartodb . _CDB_Group_ShortDatabaseName ( ) ) ;
group_role : = format ( ' %s%s ' , prefix , group_name ) ;
2015-08-13 02:01:07 +08:00
IF LENGTH ( group_role ) > max_length
THEN
2015-08-14 19:55:52 +08:00
RAISE EXCEPTION ' Group name must be shorter. It can '' t have more than % characters, but it is longer (%): % ' , max_length - LENGTH ( prefix ) , length ( group_name ) , group_name ;
2015-08-13 02:01:07 +08:00
END IF ;
RETURN group_role ;
2015-08-10 17:21:57 +08:00
END
2015-09-21 20:35:28 +08:00
$ $ LANGUAGE PLPGSQL ;
2015-08-10 19:40:59 +08:00
-- Returns the first owner of the schema matching username. Organization user schemas must have one only owner.
CREATE OR REPLACE
2015-08-10 19:42:27 +08:00
FUNCTION cartodb . _CDB_User_RoleFromUsername ( username text )
2015-08-10 19:40:59 +08:00
RETURNS TEXT AS $ $
DECLARE
2015-08-11 20:08:55 +08:00
user_role TEXT ;
2015-08-10 19:40:59 +08:00
BEGIN
2015-08-12 01:54:27 +08:00
-- This was preferred, but non-superadmins won't get results
2015-08-20 00:43:25 +08:00
-- SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $1 LIMIT 1'
2015-09-21 21:47:52 +08:00
SELECT pg_get_userbyid ( nspowner ) FROM pg_namespace WHERE nspname = username INTO user_role ;
2015-08-11 20:08:55 +08:00
RETURN user_role ;
2015-08-10 19:40:59 +08:00
END
2015-09-21 20:35:28 +08:00
$ $ LANGUAGE PLPGSQL ;
2015-08-14 19:55:52 +08:00
-- Database names are too long, we need a shorter version for composing role names
CREATE OR REPLACE
FUNCTION cartodb . _CDB_Group_ShortDatabaseName ( )
RETURNS TEXT AS $ $
DECLARE
short_database_name TEXT ;
BEGIN
2015-09-21 21:47:52 +08:00
SELECT md5 ( current_database ( ) ) INTO short_database_name ;
2015-08-14 19:55:52 +08:00
RETURN short_database_name ;
END
2015-09-21 20:35:28 +08:00
$ $ LANGUAGE PLPGSQL ;