From 2824a9c4575db2f833255215d9fce4040242cd26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 09:53:04 +0200 Subject: [PATCH 01/88] Ignore vim temporal files --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 549ecfa..1a2219a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ results/ regression.* expected/test sql/test -.idea/* \ No newline at end of file +.idea/* +*.swp From 42e72ac9d5a12feb82b6f5539100c241d9c26808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 11:07:41 +0200 Subject: [PATCH 02/88] cartodb.CDB_Group_CreateGroup cartodb.CDB_Group_DropGroup --- scripts-available/CDB_Groups.sql | 31 +++++++++++++++++++++++++++++++ test/organization/test.sh | 10 ++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 scripts-available/CDB_Groups.sql diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql new file mode 100644 index 0000000..b393f91 --- /dev/null +++ b/scripts-available/CDB_Groups.sql @@ -0,0 +1,31 @@ +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_GroupRole(group_name text) + RETURNS TEXT AS $$ +BEGIN + RETURN cartoDB.CDB_Organization_Member_Group_Role_Member_Name() || '_g_' || group_name; +END +$$ LANGUAGE PLPGSQL; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_CreateGroup(group_name text) + RETURNS TEXT AS $$ +DECLARE + cdb_group_role TEXT; +BEGIN + -- TODO: escape group_name + cdb_group_role := cartodb.CDB_Group_GroupRole(group_name); + IF NOT EXISTS ( SELECT 1 FROM pg_roles WHERE rolname = cdb_group_role ) + THEN + EXECUTE 'CREATE ROLE "' || cdb_group_role || '" NOLOGIN;'; + END IF; + RETURN cdb_group_role; +END +$$ LANGUAGE PLPGSQL; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_DropGroup(group_name text) + RETURNS VOID AS $$ +BEGIN + EXECUTE 'DROP ROLE IF EXISTS "' || cartodb.CDB_Group_GroupRole(group_name) || '"'; +END +$$ LANGUAGE PLPGSQL; diff --git a/test/organization/test.sh b/test/organization/test.sh index 60e577e..0842c4c 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -11,6 +11,8 @@ DATABASE=test_organizations CMD='echo psql' CMD=psql +GROUP_A="group_a" + OK=0 PARTIALOK=0 @@ -137,7 +139,7 @@ function setup() { log_info "########################### BOOTSTRAP ###########################" ${CMD} -d ${DATABASE} -f scripts-available/CDB_Organizations.sql - + ${CMD} -d ${DATABASE} -f scripts-available/CDB_Groups.sql log_info "############################# SETUP #############################" create_role_and_schema cdb_testmember_1 @@ -152,8 +154,11 @@ function setup() { create_table cdb_testmember_2 bar sql cdb_testmember_2 'INSERT INTO bar VALUES (1), (2), (3), (4), (5);' sql cdb_testmember_2 'SELECT * FROM cdb_testmember_2.bar;' + + sql "SELECT cartodb.CDB_Group_CreateGroup('${GROUP_A}')" } + function tear_down() { log_info "########################### USER TEAR DOWN ###########################" sql cdb_testmember_1 "SELECT * FROM cartodb.CDB_Organization_Remove_Access_Permission('cdb_testmember_1', 'foo', 'cdb_testmember_2');" @@ -162,6 +167,8 @@ function tear_down() { sql cdb_testmember_1 'DROP TABLE cdb_testmember_1.foo;' sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.bar;' + sql "select cartodb.CDB_Group_DropGroup('${GROUP_A}')" + sql "DROP SCHEMA cartodb CASCADE" log_info "########################### TEAR DOWN ###########################" @@ -393,7 +400,6 @@ function test_cdb_usertables_should_work_with_orgusers() { sql cdb_testmember_1 "DROP TABLE test_perms_priv" } - #################################################### TESTS END HERE #################################################### From eafb0f45570ed9678e3aa00c444a864dee0b47d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 11:17:41 +0200 Subject: [PATCH 03/88] Groups API extension version --- Makefile | 2 +- NEWS.md | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b0241fd..1720026 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # cartodb/Makefile EXTENSION = cartodb -EXTVERSION = 0.8.3 +EXTVERSION = 0.9.0 SED = sed diff --git a/NEWS.md b/NEWS.md index 6d68994..ed14499 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,12 @@ +0.9.0 (2015-mm-dd) +------------------ +* Groups API + 0.8.3 (2015-mm-dd) ------------------ * Fixes CDB_UserDataSize failing due `ERROR: relation "*" does not exist.` [#108](https://github.com/CartoDB/cartodb-postgresql/issues/108) + 0.8.2 (2015-07-27) ------------------ * Fix for CDB_UserTables returning wrong listings when publicuser is used From 5afdd77dcf10429f331f8501c7b84338ece7c434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 11:21:57 +0200 Subject: [PATCH 04/88] Rename group --- scripts-available/CDB_Groups.sql | 28 ++++++++++++++++++++-------- test/organization/test.sh | 3 ++- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index b393f91..751a86b 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -1,11 +1,3 @@ -CREATE OR REPLACE -FUNCTION cartodb.CDB_Group_GroupRole(group_name text) - RETURNS TEXT AS $$ -BEGIN - RETURN cartoDB.CDB_Organization_Member_Group_Role_Member_Name() || '_g_' || group_name; -END -$$ LANGUAGE PLPGSQL; - CREATE OR REPLACE FUNCTION cartodb.CDB_Group_CreateGroup(group_name text) RETURNS TEXT AS $$ @@ -29,3 +21,23 @@ BEGIN EXECUTE 'DROP ROLE IF EXISTS "' || cartodb.CDB_Group_GroupRole(group_name) || '"'; END $$ LANGUAGE PLPGSQL; + + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_RenameGroup(old_group_name text, new_group_name text) + RETURNS VOID AS $$ +BEGIN + EXECUTE 'ALTER ROLE "' || cartodb.CDB_Group_GroupRole(old_group_name) || '" RENAME TO "' || cartodb.CDB_Group_GroupRole(new_group_name) || '"'; +END +$$ LANGUAGE PLPGSQL; + +----------------------- +-- Private functions +----------------------- +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_GroupRole(group_name text) + RETURNS TEXT AS $$ +BEGIN + RETURN cartoDB.CDB_Organization_Member_Group_Role_Member_Name() || '_g_' || group_name; +END +$$ LANGUAGE PLPGSQL; diff --git a/test/organization/test.sh b/test/organization/test.sh index 0842c4c..9e68d61 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -155,7 +155,8 @@ function setup() { sql cdb_testmember_2 'INSERT INTO bar VALUES (1), (2), (3), (4), (5);' sql cdb_testmember_2 'SELECT * FROM cdb_testmember_2.bar;' - sql "SELECT cartodb.CDB_Group_CreateGroup('${GROUP_A}')" + sql "SELECT cartodb.CDB_Group_CreateGroup('${GROUP_A}_tmp')" + sql "SELECT cartodb.CDB_Group_RenameGroup('${GROUP_A}_tmp', '${GROUP_A}')" } From e04f0caa6c300576d241a6abdd7eaf8e39af1fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 13:40:59 +0200 Subject: [PATCH 05/88] Permission granting --- README.md | 5 +++ scripts-available/CDB_Groups.sql | 63 ++++++++++++++++++++++++++++++++ test/organization/test.sh | 35 +++++++++++++----- 3 files changed, 94 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 771fe12..ec166ca 100644 --- a/README.md +++ b/README.md @@ -98,3 +98,8 @@ ls `pg_config --sharedir`/extension/cartodb* During development the cartodb extension version doesn't change with every commit, so testing latest change requires special steps documented in the CONTRIBUTING document, under "Testing changes live". + +Limitations +----------- + +- The main schema of an organization user must have one only owner (the user). diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 751a86b..ebf824c 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -14,10 +14,12 @@ BEGIN END $$ LANGUAGE PLPGSQL; +-- Drops group and everything that role owns CREATE OR REPLACE FUNCTION cartodb.CDB_Group_DropGroup(group_name text) RETURNS VOID AS $$ BEGIN + EXECUTE 'DROP OWNED BY "' || cartodb.CDB_Group_GroupRole(group_name) || '"'; EXECUTE 'DROP ROLE IF EXISTS "' || cartodb.CDB_Group_GroupRole(group_name) || '"'; END $$ LANGUAGE PLPGSQL; @@ -31,6 +33,55 @@ BEGIN END $$ LANGUAGE PLPGSQL; +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_AddMember(group_name text, username text) + RETURNS VOID AS $$ +DECLARE + cdb_group_role TEXT; + cdb_user_role TEXT; +BEGIN + cdb_group_role := cartodb.CDB_Group_GroupRole(group_name); + cdb_user_role := cartodb.CDB_User_RoleFromUsername(username); + EXECUTE 'GRANT "' || cdb_group_role || '" TO "' || cdb_user_role || '"'; +END +$$ LANGUAGE PLPGSQL; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_RemoveMember(group_name text, username text) + RETURNS VOID AS $$ +DECLARE + cdb_group_role TEXT; + cdb_user_role TEXT; +BEGIN + cdb_group_role := cartodb.CDB_Group_GroupRole(group_name); + cdb_user_role := cartodb.CDB_User_RoleFromUsername(username); + EXECUTE 'REVOKE "' || cdb_group_role || '" FROM "' || cdb_user_role || '"'; +END +$$ LANGUAGE PLPGSQL; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_Table_GrantRead(group_name text, username text, table_name text) + RETURNS VOID AS $$ +DECLARE + cdb_group_role TEXT; +BEGIN + cdb_group_role := cartodb.CDB_Group_GroupRole(group_name); + EXECUTE 'GRANT USAGE ON SCHEMA "' || username || '" TO "' || cdb_group_role || '"'; + EXECUTE 'GRANT SELECT ON TABLE "' || username || '"."' || table_name || '" TO "' || cdb_group_role || '"'; +END +$$ LANGUAGE PLPGSQL; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_Table_RevokeAll(group_name text, username text, table_name text) + RETURNS VOID AS $$ +DECLARE + cdb_group_role TEXT; +BEGIN + cdb_group_role := cartodb.CDB_Group_GroupRole(group_name); + EXECUTE 'REVOKE ALL ON TABLE "' || username || '"."' || table_name || '" FROM "' || cdb_group_role || '"'; +END +$$ LANGUAGE PLPGSQL; + ----------------------- -- Private functions ----------------------- @@ -41,3 +92,15 @@ BEGIN RETURN cartoDB.CDB_Organization_Member_Group_Role_Member_Name() || '_g_' || group_name; END $$ LANGUAGE PLPGSQL; + +-- Returns the first owner of the schema matching username. Organization user schemas must have one only owner. +CREATE OR REPLACE +FUNCTION cartodb.CDB_User_RoleFromUsername(username text) + RETURNS TEXT AS $$ +DECLARE + user_role TEXT; +BEGIN + EXECUTE 'SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ''' || username || ''' LIMIT 1' INTO user_role; + RETURN user_role; +END +$$ LANGUAGE PLPGSQL; diff --git a/test/organization/test.sh b/test/organization/test.sh index 9e68d61..f19f236 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -11,8 +11,6 @@ DATABASE=test_organizations CMD='echo psql' CMD=psql -GROUP_A="group_a" - OK=0 PARTIALOK=0 @@ -144,8 +142,8 @@ function setup() { log_info "############################# SETUP #############################" create_role_and_schema cdb_testmember_1 create_role_and_schema cdb_testmember_2 - sql "CREATE ROLE publicuser LOGIN;" - sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" + #sql "CREATE ROLE publicuser LOGIN;" + #sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" create_table cdb_testmember_1 foo sql cdb_testmember_1 'INSERT INTO cdb_testmember_1.foo VALUES (1), (2), (3), (4), (5);' @@ -155,8 +153,10 @@ function setup() { sql cdb_testmember_2 'INSERT INTO bar VALUES (1), (2), (3), (4), (5);' sql cdb_testmember_2 'SELECT * FROM cdb_testmember_2.bar;' - sql "SELECT cartodb.CDB_Group_CreateGroup('${GROUP_A}_tmp')" - sql "SELECT cartodb.CDB_Group_RenameGroup('${GROUP_A}_tmp', '${GROUP_A}')" + sql "SELECT cartodb.CDB_Group_CreateGroup('group_a_tmp')" + sql "SELECT cartodb.CDB_Group_RenameGroup('group_a_tmp', 'group_a')" + + sql "SELECT cartodb.CDB_Group_AddMember('group_a', 'cdb_testmember_1')" } @@ -168,7 +168,9 @@ function tear_down() { sql cdb_testmember_1 'DROP TABLE cdb_testmember_1.foo;' sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.bar;' - sql "select cartodb.CDB_Group_DropGroup('${GROUP_A}')" + sql "SELECT cartodb.CDB_Group_RemoveMember('group_a', 'cdb_testmember_1')" + + sql "select cartodb.CDB_Group_DropGroup('group_a')" sql "DROP SCHEMA cartodb CASCADE" @@ -178,11 +180,11 @@ function tear_down() { sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_1;" sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_2;" - sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" + #sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" sql 'DROP ROLE cdb_testmember_1;' sql 'DROP ROLE cdb_testmember_2;' - sql 'DROP ROLE publicuser;' + #sql 'DROP ROLE publicuser;' ${CMD} -c "DROP DATABASE ${DATABASE}" } @@ -401,6 +403,21 @@ function test_cdb_usertables_should_work_with_orgusers() { sql cdb_testmember_1 "DROP TABLE test_perms_priv" } +function test_CDB_Group_Table_GrantRead_should_grant_select_and_RevokeAll_should_remove() { + create_table cdb_testmember_2 shared_with_group + + sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' fails + sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' + sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group')" + sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' + sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' + sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_RevokeAll('group_a', 'cdb_testmember_2', 'shared_with_group')" + sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' fails + sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' + + sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' +} + #################################################### TESTS END HERE #################################################### From b6334667240a89bc400d6991a5052594e2448600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 13:42:27 +0200 Subject: [PATCH 06/88] Non-public API method naming --- scripts-available/CDB_Groups.sql | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index ebf824c..0ea8ab2 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -5,7 +5,7 @@ DECLARE cdb_group_role TEXT; BEGIN -- TODO: escape group_name - cdb_group_role := cartodb.CDB_Group_GroupRole(group_name); + cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); IF NOT EXISTS ( SELECT 1 FROM pg_roles WHERE rolname = cdb_group_role ) THEN EXECUTE 'CREATE ROLE "' || cdb_group_role || '" NOLOGIN;'; @@ -19,8 +19,8 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_DropGroup(group_name text) RETURNS VOID AS $$ BEGIN - EXECUTE 'DROP OWNED BY "' || cartodb.CDB_Group_GroupRole(group_name) || '"'; - EXECUTE 'DROP ROLE IF EXISTS "' || cartodb.CDB_Group_GroupRole(group_name) || '"'; + EXECUTE 'DROP OWNED BY "' || cartodb._CDB_Group_GroupRole(group_name) || '"'; + EXECUTE 'DROP ROLE IF EXISTS "' || cartodb._CDB_Group_GroupRole(group_name) || '"'; END $$ LANGUAGE PLPGSQL; @@ -29,7 +29,7 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_RenameGroup(old_group_name text, new_group_name text) RETURNS VOID AS $$ BEGIN - EXECUTE 'ALTER ROLE "' || cartodb.CDB_Group_GroupRole(old_group_name) || '" RENAME TO "' || cartodb.CDB_Group_GroupRole(new_group_name) || '"'; + EXECUTE 'ALTER ROLE "' || cartodb._CDB_Group_GroupRole(old_group_name) || '" RENAME TO "' || cartodb._CDB_Group_GroupRole(new_group_name) || '"'; END $$ LANGUAGE PLPGSQL; @@ -40,8 +40,8 @@ DECLARE cdb_group_role TEXT; cdb_user_role TEXT; BEGIN - cdb_group_role := cartodb.CDB_Group_GroupRole(group_name); - cdb_user_role := cartodb.CDB_User_RoleFromUsername(username); + cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); + cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); EXECUTE 'GRANT "' || cdb_group_role || '" TO "' || cdb_user_role || '"'; END $$ LANGUAGE PLPGSQL; @@ -53,8 +53,8 @@ DECLARE cdb_group_role TEXT; cdb_user_role TEXT; BEGIN - cdb_group_role := cartodb.CDB_Group_GroupRole(group_name); - cdb_user_role := cartodb.CDB_User_RoleFromUsername(username); + cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); + cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); EXECUTE 'REVOKE "' || cdb_group_role || '" FROM "' || cdb_user_role || '"'; END $$ LANGUAGE PLPGSQL; @@ -65,7 +65,7 @@ FUNCTION cartodb.CDB_Group_Table_GrantRead(group_name text, username text, table DECLARE cdb_group_role TEXT; BEGIN - cdb_group_role := cartodb.CDB_Group_GroupRole(group_name); + cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); EXECUTE 'GRANT USAGE ON SCHEMA "' || username || '" TO "' || cdb_group_role || '"'; EXECUTE 'GRANT SELECT ON TABLE "' || username || '"."' || table_name || '" TO "' || cdb_group_role || '"'; END @@ -77,7 +77,7 @@ FUNCTION cartodb.CDB_Group_Table_RevokeAll(group_name text, username text, table DECLARE cdb_group_role TEXT; BEGIN - cdb_group_role := cartodb.CDB_Group_GroupRole(group_name); + cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); EXECUTE 'REVOKE ALL ON TABLE "' || username || '"."' || table_name || '" FROM "' || cdb_group_role || '"'; END $$ LANGUAGE PLPGSQL; @@ -86,7 +86,7 @@ $$ LANGUAGE PLPGSQL; -- Private functions ----------------------- CREATE OR REPLACE -FUNCTION cartodb.CDB_Group_GroupRole(group_name text) +FUNCTION cartodb._CDB_Group_GroupRole(group_name text) RETURNS TEXT AS $$ BEGIN RETURN cartoDB.CDB_Organization_Member_Group_Role_Member_Name() || '_g_' || group_name; @@ -95,7 +95,7 @@ $$ LANGUAGE PLPGSQL; -- Returns the first owner of the schema matching username. Organization user schemas must have one only owner. CREATE OR REPLACE -FUNCTION cartodb.CDB_User_RoleFromUsername(username text) +FUNCTION cartodb._CDB_User_RoleFromUsername(username text) RETURNS TEXT AS $$ DECLARE user_role TEXT; From 1279742e500fc0f91057d141b4afd2067f30b2c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 13:44:06 +0200 Subject: [PATCH 07/88] CDB_Group_CreateGroup should not return role, since it's an internal implementation detail --- scripts-available/CDB_Groups.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 0ea8ab2..c534391 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -1,6 +1,7 @@ +-- Creates a new group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_CreateGroup(group_name text) - RETURNS TEXT AS $$ + RETURNS VOID AS $$ DECLARE cdb_group_role TEXT; BEGIN @@ -10,7 +11,6 @@ BEGIN THEN EXECUTE 'CREATE ROLE "' || cdb_group_role || '" NOLOGIN;'; END IF; - RETURN cdb_group_role; END $$ LANGUAGE PLPGSQL; From 28af048c92f3173e61dabbc914d4f421756ef51f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 13:46:35 +0200 Subject: [PATCH 08/88] Methods doc --- scripts-available/CDB_Groups.sql | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index c534391..af0e53a 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -24,7 +24,7 @@ BEGIN END $$ LANGUAGE PLPGSQL; - +-- Renames a group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_RenameGroup(old_group_name text, new_group_name text) RETURNS VOID AS $$ @@ -33,6 +33,7 @@ BEGIN END $$ LANGUAGE PLPGSQL; +-- Adds a user to a group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_AddMember(group_name text, username text) RETURNS VOID AS $$ @@ -46,6 +47,7 @@ BEGIN END $$ LANGUAGE PLPGSQL; +-- Removes a user from a group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_RemoveMember(group_name text, username text) RETURNS VOID AS $$ @@ -59,6 +61,7 @@ BEGIN END $$ LANGUAGE PLPGSQL; +-- Grants table read permission to a group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_Table_GrantRead(group_name text, username text, table_name text) RETURNS VOID AS $$ @@ -71,6 +74,7 @@ BEGIN END $$ LANGUAGE PLPGSQL; +-- Revokes all permissions on a table from a group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_Table_RevokeAll(group_name text, username text, table_name text) RETURNS VOID AS $$ @@ -85,6 +89,7 @@ $$ LANGUAGE PLPGSQL; ----------------------- -- Private functions ----------------------- +-- Given a group name returns a role CREATE OR REPLACE FUNCTION cartodb._CDB_Group_GroupRole(group_name text) RETURNS TEXT AS $$ From 52f73b1a011d9480907c961d24ba0e67f5cd52aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 13:53:57 +0200 Subject: [PATCH 09/88] CDB_Group_Table_GrantReadWrite --- scripts-available/CDB_Groups.sql | 13 +++++++++++++ test/organization/test.sh | 17 ++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index af0e53a..00cc8c7 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -74,6 +74,19 @@ BEGIN END $$ LANGUAGE PLPGSQL; +-- 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 + cdb_group_role TEXT; +BEGIN + cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); + EXECUTE 'GRANT USAGE ON SCHEMA "' || username || '" TO "' || cdb_group_role || '"'; + EXECUTE 'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "' || username || '"."' || table_name || '" TO "' || cdb_group_role || '"'; +END +$$ LANGUAGE PLPGSQL; + -- Revokes all permissions on a table from a group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_Table_RevokeAll(group_name text, username text, table_name text) diff --git a/test/organization/test.sh b/test/organization/test.sh index f19f236..2c2340d 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -403,7 +403,7 @@ function test_cdb_usertables_should_work_with_orgusers() { sql cdb_testmember_1 "DROP TABLE test_perms_priv" } -function test_CDB_Group_Table_GrantRead_should_grant_select_and_RevokeAll_should_remove() { +function test_CDB_Group_Table_GrantRead_should_grant_select_and_RevokeAll_should_remove_it() { create_table cdb_testmember_2 shared_with_group sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' fails @@ -418,6 +418,21 @@ function test_CDB_Group_Table_GrantRead_should_grant_select_and_RevokeAll_should sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' } +function test_CDB_Group_Table_GrantReadWrite_should_grant_insert_and_RevokeAll_should_remove_it() { + create_table cdb_testmember_2 shared_with_group + + sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' fails + sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' + sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group')" + sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' + sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' + sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_RevokeAll('group_a', 'cdb_testmember_2', 'shared_with_group')" + sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' fails + sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' + + sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' +} + #################################################### TESTS END HERE #################################################### From c29733eb877f8fb45a9eb44dca39899909987fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 14:04:41 +0200 Subject: [PATCH 10/88] publicuser uncommenting --- test/organization/test.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/organization/test.sh b/test/organization/test.sh index 2c2340d..e439783 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -142,8 +142,8 @@ function setup() { log_info "############################# SETUP #############################" create_role_and_schema cdb_testmember_1 create_role_and_schema cdb_testmember_2 - #sql "CREATE ROLE publicuser LOGIN;" - #sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" + sql "CREATE ROLE publicuser LOGIN;" + sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" create_table cdb_testmember_1 foo sql cdb_testmember_1 'INSERT INTO cdb_testmember_1.foo VALUES (1), (2), (3), (4), (5);' @@ -180,11 +180,11 @@ function tear_down() { sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_1;" sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_2;" - #sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" + sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" sql 'DROP ROLE cdb_testmember_1;' sql 'DROP ROLE cdb_testmember_2;' - #sql 'DROP ROLE publicuser;' + sql 'DROP ROLE publicuser;' ${CMD} -c "DROP DATABASE ${DATABASE}" } From 6baa6267560806ba1b8dabdb7d0b8bf542b48119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 15:46:01 +0200 Subject: [PATCH 11/88] Groups will be 0.9.0 --- NEWS.md | 1 - 1 file changed, 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index ed14499..bb85419 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,7 +6,6 @@ ------------------ * Fixes CDB_UserDataSize failing due `ERROR: relation "*" does not exist.` [#108](https://github.com/CartoDB/cartodb-postgresql/issues/108) - 0.8.2 (2015-07-27) ------------------ * Fix for CDB_UserTables returning wrong listings when publicuser is used From 9a3fbb668cbfadd16581da7a3343349c7fbb1df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 16:01:47 +0200 Subject: [PATCH 12/88] Dynamic variable binding --- scripts-available/CDB_Groups.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 00cc8c7..d87c2f3 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -118,7 +118,7 @@ FUNCTION cartodb._CDB_User_RoleFromUsername(username text) DECLARE user_role TEXT; BEGIN - EXECUTE 'SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ''' || username || ''' LIMIT 1' INTO user_role; + EXECUTE 'SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $1 LIMIT 1' INTO user_role USING username; RETURN user_role; END $$ LANGUAGE PLPGSQL; From 154f6df1dcae4c99c00cdaff624d55b3acab5f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 10 Aug 2015 16:15:04 +0200 Subject: [PATCH 13/88] _CDB_Group_GroupRole based on current database m5 --- scripts-available/CDB_Groups.sql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index d87c2f3..e232768 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -106,8 +106,10 @@ $$ LANGUAGE PLPGSQL; CREATE OR REPLACE FUNCTION cartodb._CDB_Group_GroupRole(group_name text) RETURNS TEXT AS $$ +DECLARE + group_role TEXT; BEGIN - RETURN cartoDB.CDB_Organization_Member_Group_Role_Member_Name() || '_g_' || group_name; + RETURN 'g_' || md5(current_database()) || '_' || group_name; END $$ LANGUAGE PLPGSQL; From 898d3c14fd6ecc98f62e01ea90b106f018943eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 11 Aug 2015 13:56:03 +0200 Subject: [PATCH 14/88] test_group_management_functions_cant_be_used_by_normal_members and warning -> error processing --- test/organization/test.sh | 66 ++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/test/organization/test.sh b/test/organization/test.sh index e439783..c3ca449 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -28,6 +28,7 @@ function clear_partial_result() { function sql() { local ROLE local QUERY + ERROR_OUTPUT_FILE='/tmp/test_error.log' if [[ $# -ge 2 ]] then ROLE="$1" @@ -38,15 +39,41 @@ function sql() { if [ -n "${ROLE}" ]; then log_debug "Executing query '${QUERY}' as ${ROLE}" - RESULT=`${CMD} -U "${ROLE}" ${DATABASE} -c "${QUERY}" -A -t` + RESULT=`${CMD} -U "${ROLE}" ${DATABASE} -c "${QUERY}" -A -t 2>"${ERROR_OUTPUT_FILE}"` else log_debug "Executing query '${QUERY}'" - RESULT=`${CMD} ${DATABASE} -c "${QUERY}" -A -t` + RESULT=`${CMD} ${DATABASE} -c "${QUERY}" -A -t 2>"${ERROR_OUTPUT_FILE}"` fi CODERESULT=$? + ERROR_OUTPUT=`cat "${ERROR_OUTPUT_FILE}"` + rm ${ERROR_OUTPUT_FILE} + echo -n "- Code Result: " + echo ${CODERESULT} + echo -n "- Result: " echo ${RESULT} - echo + echo -n "- Error output: " + echo ${ERROR_OUTPUT} + + # Some warnings should actually be failures + if [[ ${CODERESULT} == "0" ]] + then + case "${ERROR_OUTPUT}" in + WARNING:*no*privileges*were*granted*for*) + echo -n "FAILED BECAUSE OF PRIVILEGES GRANTING WARNING" + CODERESULT=1 + ;; + WARNING:*no*privileges*could*be*revoked*for*) + echo -n "FAILED BECAUSE OF PRIVILEGES REVOKING WARNING" + CODERESULT=1 + ;; + *) echo "All ok" ;; + esac + fi + + echo "- New code result: " + echo ${CODERESULT} + echo "-------------" if [[ ${CODERESULT} -ne 0 ]] then @@ -142,8 +169,8 @@ function setup() { log_info "############################# SETUP #############################" create_role_and_schema cdb_testmember_1 create_role_and_schema cdb_testmember_2 - sql "CREATE ROLE publicuser LOGIN;" - sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" + #publicuser# sql "CREATE ROLE publicuser LOGIN;" + #publicuser# sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" create_table cdb_testmember_1 foo sql cdb_testmember_1 'INSERT INTO cdb_testmember_1.foo VALUES (1), (2), (3), (4), (5);' @@ -157,6 +184,8 @@ function setup() { sql "SELECT cartodb.CDB_Group_RenameGroup('group_a_tmp', 'group_a')" sql "SELECT cartodb.CDB_Group_AddMember('group_a', 'cdb_testmember_1')" + + sql "SELECT cartodb.CDB_Group_CreateGroup('group_b')" } @@ -168,6 +197,8 @@ function tear_down() { sql cdb_testmember_1 'DROP TABLE cdb_testmember_1.foo;' sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.bar;' + sql "select cartodb.CDB_Group_DropGroup('group_b')" + sql "SELECT cartodb.CDB_Group_RemoveMember('group_a', 'cdb_testmember_1')" sql "select cartodb.CDB_Group_DropGroup('group_a')" @@ -180,11 +211,11 @@ function tear_down() { sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_1;" sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_2;" - sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" + #publicuser# sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" sql 'DROP ROLE cdb_testmember_1;' sql 'DROP ROLE cdb_testmember_2;' - sql 'DROP ROLE publicuser;' + #publicuser# sql 'DROP ROLE publicuser;' ${CMD} -c "DROP DATABASE ${DATABASE}" } @@ -433,6 +464,27 @@ function test_CDB_Group_Table_GrantReadWrite_should_grant_insert_and_RevokeAll_s sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' } +function test_group_management_functions_cant_be_used_by_normal_members() { + sql cdb_testmember_1 "SELECT cartodb.CDB_Group_CreateGroup('group_x_1');" fails + sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RenameGroup('group_a', 'group_x_2');" fails + sql cdb_testmember_1 "SELECT cartodb.CDB_Group_DropGroup('group_a');" fails + sql cdb_testmember_1 "SELECT cartodb.CDB_Group_AddMember('group_a', 'cdb_testmember_2');" fails + sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RemoveMember('group_a', 'cdb_testmember_1');" fails + + create_table cdb_testmember_2 shared_with_group + + sql cdb_testmember_1 "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group');" fails + sql cdb_testmember_1 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group');" fails + + # Checks that you can't grant even if your group has RW permissions + sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group')" + sql cdb_testmember_1 "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group');" fails + sql cdb_testmember_1 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_b', 'cdb_testmember_2', 'shared_with_group');" fails + sql cdb_testmember_1 "select cartoDB.CDB_Group_Table_RevokeAll('group_b', 'cdb_testmember_2', 'shared_with_group');" fails + + sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' +} + #################################################### TESTS END HERE #################################################### From bd46796bb704400c98ebd99898b0d4f8e7c5c713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 11 Aug 2015 14:08:55 +0200 Subject: [PATCH 15/88] Fix spacing --- scripts-available/CDB_Groups.sql | 46 ++++++++++----------- test/organization/test.sh | 70 ++++++++++++++++---------------- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index e232768..152ba82 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -3,14 +3,14 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_CreateGroup(group_name text) RETURNS VOID AS $$ DECLARE - cdb_group_role TEXT; + cdb_group_role TEXT; BEGIN - -- TODO: escape group_name - cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - IF NOT EXISTS ( SELECT 1 FROM pg_roles WHERE rolname = cdb_group_role ) - THEN - EXECUTE 'CREATE ROLE "' || cdb_group_role || '" NOLOGIN;'; - END IF; + -- TODO: escape group_name + cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); + IF NOT EXISTS ( SELECT 1 FROM pg_roles WHERE rolname = cdb_group_role ) + THEN + EXECUTE 'CREATE ROLE "' || cdb_group_role || '" NOLOGIN;'; + END IF; END $$ LANGUAGE PLPGSQL; @@ -19,8 +19,8 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_DropGroup(group_name text) RETURNS VOID AS $$ BEGIN - EXECUTE 'DROP OWNED BY "' || cartodb._CDB_Group_GroupRole(group_name) || '"'; - EXECUTE 'DROP ROLE IF EXISTS "' || cartodb._CDB_Group_GroupRole(group_name) || '"'; + EXECUTE 'DROP OWNED BY "' || cartodb._CDB_Group_GroupRole(group_name) || '"'; + EXECUTE 'DROP ROLE IF EXISTS "' || cartodb._CDB_Group_GroupRole(group_name) || '"'; END $$ LANGUAGE PLPGSQL; @@ -29,7 +29,7 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_RenameGroup(old_group_name text, new_group_name text) RETURNS VOID AS $$ BEGIN - EXECUTE 'ALTER ROLE "' || cartodb._CDB_Group_GroupRole(old_group_name) || '" RENAME TO "' || cartodb._CDB_Group_GroupRole(new_group_name) || '"'; + EXECUTE 'ALTER ROLE "' || cartodb._CDB_Group_GroupRole(old_group_name) || '" RENAME TO "' || cartodb._CDB_Group_GroupRole(new_group_name) || '"'; END $$ LANGUAGE PLPGSQL; @@ -38,12 +38,12 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_AddMember(group_name text, username text) RETURNS VOID AS $$ DECLARE - cdb_group_role TEXT; - cdb_user_role TEXT; + cdb_group_role TEXT; + cdb_user_role TEXT; BEGIN - cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); - EXECUTE 'GRANT "' || cdb_group_role || '" TO "' || cdb_user_role || '"'; + cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); + cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); + EXECUTE 'GRANT "' || cdb_group_role || '" TO "' || cdb_user_role || '"'; END $$ LANGUAGE PLPGSQL; @@ -52,12 +52,12 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_RemoveMember(group_name text, username text) RETURNS VOID AS $$ DECLARE - cdb_group_role TEXT; - cdb_user_role TEXT; + cdb_group_role TEXT; + cdb_user_role TEXT; BEGIN - cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); - EXECUTE 'REVOKE "' || cdb_group_role || '" FROM "' || cdb_user_role || '"'; + cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); + cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); + EXECUTE 'REVOKE "' || cdb_group_role || '" FROM "' || cdb_user_role || '"'; END $$ LANGUAGE PLPGSQL; @@ -118,9 +118,9 @@ CREATE OR REPLACE FUNCTION cartodb._CDB_User_RoleFromUsername(username text) RETURNS TEXT AS $$ DECLARE - user_role TEXT; + user_role TEXT; BEGIN - EXECUTE 'SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $1 LIMIT 1' INTO user_role USING username; - RETURN user_role; + EXECUTE 'SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $1 LIMIT 1' INTO user_role USING username; + RETURN user_role; END $$ LANGUAGE PLPGSQL; diff --git a/test/organization/test.sh b/test/organization/test.sh index c3ca449..64b9b10 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -38,11 +38,11 @@ function sql() { fi if [ -n "${ROLE}" ]; then - log_debug "Executing query '${QUERY}' as ${ROLE}" - RESULT=`${CMD} -U "${ROLE}" ${DATABASE} -c "${QUERY}" -A -t 2>"${ERROR_OUTPUT_FILE}"` + log_debug "Executing query '${QUERY}' as ${ROLE}" + RESULT=`${CMD} -U "${ROLE}" ${DATABASE} -c "${QUERY}" -A -t 2>"${ERROR_OUTPUT_FILE}"` else - log_debug "Executing query '${QUERY}'" - RESULT=`${CMD} ${DATABASE} -c "${QUERY}" -A -t 2>"${ERROR_OUTPUT_FILE}"` + log_debug "Executing query '${QUERY}'" + RESULT=`${CMD} ${DATABASE} -c "${QUERY}" -A -t 2>"${ERROR_OUTPUT_FILE}"` fi CODERESULT=$? ERROR_OUTPUT=`cat "${ERROR_OUTPUT_FILE}"` @@ -58,17 +58,17 @@ function sql() { # Some warnings should actually be failures if [[ ${CODERESULT} == "0" ]] then - case "${ERROR_OUTPUT}" in - WARNING:*no*privileges*were*granted*for*) - echo -n "FAILED BECAUSE OF PRIVILEGES GRANTING WARNING" - CODERESULT=1 - ;; - WARNING:*no*privileges*could*be*revoked*for*) - echo -n "FAILED BECAUSE OF PRIVILEGES REVOKING WARNING" - CODERESULT=1 - ;; - *) echo "All ok" ;; - esac + case "${ERROR_OUTPUT}" in + WARNING:*no*privileges*were*granted*for*) + echo -n "FAILED BECAUSE OF PRIVILEGES GRANTING WARNING" + CODERESULT=1 + ;; + WARNING:*no*privileges*could*be*revoked*for*) + echo -n "FAILED BECAUSE OF PRIVILEGES REVOKING WARNING" + CODERESULT=1 + ;; + *) echo "All ok" ;; + esac fi echo "- New code result: " @@ -435,33 +435,33 @@ function test_cdb_usertables_should_work_with_orgusers() { } function test_CDB_Group_Table_GrantRead_should_grant_select_and_RevokeAll_should_remove_it() { - create_table cdb_testmember_2 shared_with_group + create_table cdb_testmember_2 shared_with_group - sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' fails - sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' - sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group')" - sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' - sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' - sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_RevokeAll('group_a', 'cdb_testmember_2', 'shared_with_group')" - sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' fails - sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' + sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' fails + sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' + sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group')" + sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' + sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' + sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_RevokeAll('group_a', 'cdb_testmember_2', 'shared_with_group')" + sql cdb_testmember_1 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' fails + sql cdb_testmember_2 'SELECT count(*) FROM cdb_testmember_2.shared_with_group;' - sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' + sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' } function test_CDB_Group_Table_GrantReadWrite_should_grant_insert_and_RevokeAll_should_remove_it() { - create_table cdb_testmember_2 shared_with_group + create_table cdb_testmember_2 shared_with_group - sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' fails - sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' - sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group')" - sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' - sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' - sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_RevokeAll('group_a', 'cdb_testmember_2', 'shared_with_group')" - sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' fails - sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' + sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' fails + sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' + sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group')" + sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' + sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' + sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_RevokeAll('group_a', 'cdb_testmember_2', 'shared_with_group')" + sql cdb_testmember_1 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' fails + sql cdb_testmember_2 'INSERT INTO cdb_testmember_2.shared_with_group VALUES (1), (2), (3), (4), (5)' - sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' + sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' } function test_group_management_functions_cant_be_used_by_normal_members() { From 1915e28a0ff0a8c6d9e540bb4d5944aad6202061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 11 Aug 2015 14:20:38 +0200 Subject: [PATCH 16/88] Cleaner debug output --- test/organization/test.sh | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/test/organization/test.sh b/test/organization/test.sh index 64b9b10..8407b21 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -48,12 +48,12 @@ function sql() { ERROR_OUTPUT=`cat "${ERROR_OUTPUT_FILE}"` rm ${ERROR_OUTPUT_FILE} - echo -n "- Code Result: " - echo ${CODERESULT} - echo -n "- Result: " - echo ${RESULT} - echo -n "- Error output: " - echo ${ERROR_OUTPUT} + echo -n "> Code Result: " + echo -n ${CODERESULT} + echo -n "; Result: " + echo -n ${RESULT} + echo -n "; Error output: " + echo -n ${ERROR_OUTPUT} # Some warnings should actually be failures if [[ ${CODERESULT} == "0" ]] @@ -67,13 +67,12 @@ function sql() { echo -n "FAILED BECAUSE OF PRIVILEGES REVOKING WARNING" CODERESULT=1 ;; - *) echo "All ok" ;; + *) ;; esac fi - echo "- New code result: " + echo -n "; New code result: " echo ${CODERESULT} - echo "-------------" if [[ ${CODERESULT} -ne 0 ]] then From e2dd1e014e23c02d6b3a5e2fdbe93be2fccbb945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 11 Aug 2015 14:49:12 +0200 Subject: [PATCH 17/88] test_valid_group_names and test_not_valid_group_names --- scripts-available/CDB_Groups.sql | 6 +++++- test/organization/test.sh | 22 +++++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 152ba82..fffa9a5 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -102,13 +102,17 @@ $$ LANGUAGE PLPGSQL; ----------------------- -- Private functions ----------------------- --- Given a group name returns a role +-- 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 CREATE OR REPLACE FUNCTION cartodb._CDB_Group_GroupRole(group_name text) RETURNS TEXT AS $$ DECLARE group_role TEXT; BEGIN + IF group_name !~ '^[a-zA-Z_][a-zA-Z0-9_]*$' + THEN + RAISE EXCEPTION 'Group name (%) must be a valid identifier. See http://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS', group_name; + END IF; RETURN 'g_' || md5(current_database()) || '_' || group_name; END $$ LANGUAGE PLPGSQL; diff --git a/test/organization/test.sh b/test/organization/test.sh index 8407b21..38cf199 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -69,10 +69,10 @@ function sql() { ;; *) ;; esac + echo -n "; Code result after warnings: " + echo -n ${CODERESULT} fi - - echo -n "; New code result: " - echo ${CODERESULT} + echo if [[ ${CODERESULT} -ne 0 ]] then @@ -238,6 +238,7 @@ function run_tests() { echo "####################################################################" clear_partial_result setup + log_info "############################# TESTS #############################" eval ${t} if [[ ${PARTIALOK} -ne 0 ]] then @@ -484,6 +485,21 @@ function test_group_management_functions_cant_be_used_by_normal_members() { sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' } +function test_valid_group_names() { + sql "select cartodb._CDB_Group_GroupRole('group_1$_a');" + sql "select cartodb._CDB_Group_GroupRole('GROUP_1$_A');" + sql "select cartodb._CDB_Group_GroupRole('_group_1$_a');" +} + +function test_not_valid_group_names() { + sql postgres "select cartodb._CDB_Group_GroupRole('1$_a');" fails + sql postgres "select cartodb._CDB_Group_GroupRole(' group_1$_a');" fails + sql postgres "select cartodb._CDB_Group_GroupRole('group_1$_a ');" fails + sql postgres "select cartodb._CDB_Group_GroupRole(' group_1$_a ');" fails + sql postgres "select cartodb._CDB_Group_GroupRole('group _1$_a');" fails + sql postgres "select cartodb._CDB_Group_GroupRole('groupña');" fails +} + #################################################### TESTS END HERE #################################################### From 79e19267668f5bd558ec2334073258e5ad19fc70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 11 Aug 2015 19:54:27 +0200 Subject: [PATCH 18/88] Group management done by organization admin --- scripts-available/CDB_Groups.sql | 16 ++++++-- scripts-available/CDB_Organizations.sql | 51 +++++++++++++++++++++++++ test/organization/test.sh | 36 ++++++++++++++++- 3 files changed, 97 insertions(+), 6 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index fffa9a5..4efe102 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -5,7 +5,6 @@ FUNCTION cartodb.CDB_Group_CreateGroup(group_name text) DECLARE cdb_group_role TEXT; BEGIN - -- TODO: escape group_name cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); IF NOT EXISTS ( SELECT 1 FROM pg_roles WHERE rolname = cdb_group_role ) THEN @@ -15,12 +14,19 @@ END $$ LANGUAGE PLPGSQL; -- Drops group and everything that role owns +-- 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. CREATE OR REPLACE FUNCTION cartodb.CDB_Group_DropGroup(group_name text) RETURNS VOID AS $$ +DECLARE + cdb_group_role TEXT; BEGIN - EXECUTE 'DROP OWNED BY "' || cartodb._CDB_Group_GroupRole(group_name) || '"'; - EXECUTE 'DROP ROLE IF EXISTS "' || cartodb._CDB_Group_GroupRole(group_name) || '"'; + cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); + EXECUTE 'DROP OWNED BY "' || cdb_group_role || '"'; + EXECUTE 'DROP ROLE IF EXISTS "' || cdb_group_role || '"'; END $$ LANGUAGE PLPGSQL; @@ -124,7 +130,9 @@ FUNCTION cartodb._CDB_User_RoleFromUsername(username text) DECLARE user_role TEXT; BEGIN - EXECUTE 'SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $1 LIMIT 1' INTO user_role USING username; + -- This was preferred, but non-superadmins won't get results + --EXECUTE 'SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $1 LIMIT 1' INTO user_role USING username; + EXECUTE 'SELECT pg_get_userbyid(nspowner) FROM pg_namespace WHERE nspname = $1;' INTO user_role USING username; RETURN user_role; END $$ LANGUAGE PLPGSQL; diff --git a/scripts-available/CDB_Organizations.sql b/scripts-available/CDB_Organizations.sql index 4328fe4..6ca48c2 100644 --- a/scripts-available/CDB_Organizations.sql +++ b/scripts-available/CDB_Organizations.sql @@ -25,6 +25,57 @@ BEGIN END $$ LANGUAGE PLPGSQL VOLATILE; +------------------------------------------------------------------------------- +-- Administrator +------------------------------------------------------------------------------- +CREATE OR REPLACE +FUNCTION cartodb._CDB_Organization_Admin_Role_Name() + RETURNS TEXT +AS 'SELECT ''cdb_org_admin''::text || ''_'' || md5(current_database());' +LANGUAGE SQL IMMUTABLE; + +DO LANGUAGE 'plpgsql' $$ +DECLARE + cdb_org_admin_role_name TEXT; +BEGIN + cdb_org_admin_role_name := cartodb._CDB_Organization_Admin_Role_Name(); + IF NOT EXISTS ( SELECT * FROM pg_roles WHERE rolname= cdb_org_admin_role_name ) + THEN + EXECUTE 'CREATE ROLE "' || cdb_org_admin_role_name || '" CREATEROLE NOLOGIN;'; + END IF; +END +$$; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Organization_AddAdmin(username text) + RETURNS void +AS $$ +DECLARE + cdb_user_role TEXT; + cdb_admin_role TEXT; +BEGIN + cdb_admin_role := cartodb._CDB_Organization_Admin_Role_Name(); + cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); + EXECUTE 'GRANT "' || cdb_admin_role || '" TO "' || cdb_user_role || '" WITH ADMIN OPTION'; + -- CREATEROLE is not inherited, and is needed for user creation + EXECUTE 'ALTER ROLE "' || cdb_user_role || '" CREATEROLE'; +END +$$ LANGUAGE PLPGSQL; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Organization_RemoveAdmin(username text) + RETURNS void +AS $$ +DECLARE + cdb_user_role TEXT; + cdb_admin_role TEXT; +BEGIN + cdb_admin_role := cartodb._CDB_Organization_Admin_Role_Name(); + cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); + EXECUTE 'ALTER ROLE "' || cdb_user_role || '" NOCREATEROLE'; + EXECUTE 'REVOKE "' || cdb_admin_role || '" FROM "' || cdb_user_role || '"'; +END +$$ LANGUAGE PLPGSQL; ------------------------------------------------------------------------------- -- Sharing tables diff --git a/test/organization/test.sh b/test/organization/test.sh index 38cf199..595124f 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -166,6 +166,8 @@ function setup() { ${CMD} -d ${DATABASE} -f scripts-available/CDB_Groups.sql log_info "############################# SETUP #############################" + create_role_and_schema cdb_org_admin + sql "SELECT cartodb.CDB_Organization_AddAdmin('cdb_org_admin');" create_role_and_schema cdb_testmember_1 create_role_and_schema cdb_testmember_2 #publicuser# sql "CREATE ROLE publicuser LOGIN;" @@ -201,20 +203,24 @@ function tear_down() { sql "SELECT cartodb.CDB_Group_RemoveMember('group_a', 'cdb_testmember_1')" sql "select cartodb.CDB_Group_DropGroup('group_a')" - - sql "DROP SCHEMA cartodb CASCADE" + sql "SELECT cartodb.CDB_Organization_RemoveAdmin('cdb_org_admin');" log_info "########################### TEAR DOWN ###########################" sql 'DROP SCHEMA cdb_testmember_1;' sql 'DROP SCHEMA cdb_testmember_2;' + sql 'DROP SCHEMA cdb_org_admin;' sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_1;" sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_2;" #publicuser# sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" + sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_org_admin;" sql 'DROP ROLE cdb_testmember_1;' sql 'DROP ROLE cdb_testmember_2;' #publicuser# sql 'DROP ROLE publicuser;' + sql 'DROP ROLE cdb_org_admin;' + + sql "DROP SCHEMA cartodb CASCADE" ${CMD} -c "DROP DATABASE ${DATABASE}" } @@ -470,7 +476,9 @@ function test_group_management_functions_cant_be_used_by_normal_members() { sql cdb_testmember_1 "SELECT cartodb.CDB_Group_DropGroup('group_a');" fails sql cdb_testmember_1 "SELECT cartodb.CDB_Group_AddMember('group_a', 'cdb_testmember_2');" fails sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RemoveMember('group_a', 'cdb_testmember_1');" fails +} +function test_group_permission_functions_cant_be_used_by_normal_members() { create_table cdb_testmember_2 shared_with_group sql cdb_testmember_1 "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group');" fails @@ -485,6 +493,30 @@ function test_group_management_functions_cant_be_used_by_normal_members() { sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' } +function test_group_management_functions_can_be_used_by_org_admin() { + sql cdb_org_admin "SELECT cartodb.CDB_Group_CreateGroup('group_x_tmp');" + sql cdb_org_admin "SELECT cartodb.CDB_Group_RenameGroup('group_x_tmp', 'group_x');" + sql cdb_org_admin "SELECT cartodb.CDB_Group_AddMember('group_x', 'cdb_testmember_1');" + sql cdb_org_admin "SELECT cartodb.CDB_Group_RemoveMember('group_x', 'cdb_testmember_1');" + # TODO: workaround superadmin limitation + sql "SELECT cartodb.CDB_Group_DropGroup('group_x');" +} + +function test_org_admin_cant_grant_permissions_on_tables_he_does_not_own() { + create_table cdb_testmember_2 shared_with_group + + sql cdb_org_admin "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group');" fails + sql cdb_org_admin "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group');" fails + + # Checks that you can't grant even if your group has RW permissions + sql cdb_testmember_2 "select cartoDB.CDB_Group_Table_GrantReadWrite('group_a', 'cdb_testmember_2', 'shared_with_group')" + sql cdb_org_admin "select cartoDB.CDB_Group_Table_GrantRead('group_a', 'cdb_testmember_2', 'shared_with_group');" fails + sql cdb_org_admin "select cartoDB.CDB_Group_Table_GrantReadWrite('group_b', 'cdb_testmember_2', 'shared_with_group');" fails + sql cdb_org_admin "select cartoDB.CDB_Group_Table_RevokeAll('group_b', 'cdb_testmember_2', 'shared_with_group');" fails + + sql cdb_testmember_2 'DROP TABLE cdb_testmember_2.shared_with_group;' +} + function test_valid_group_names() { sql "select cartodb._CDB_Group_GroupRole('group_1$_a');" sql "select cartodb._CDB_Group_GroupRole('GROUP_1$_A');" From 401d3e90661dde9cd24999840cb36e2c61ab76cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 11 Aug 2015 20:01:05 +0200 Subject: [PATCH 19/88] publicuser back --- test/organization/test.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/organization/test.sh b/test/organization/test.sh index 595124f..4002325 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -170,8 +170,8 @@ function setup() { sql "SELECT cartodb.CDB_Organization_AddAdmin('cdb_org_admin');" create_role_and_schema cdb_testmember_1 create_role_and_schema cdb_testmember_2 - #publicuser# sql "CREATE ROLE publicuser LOGIN;" - #publicuser# sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" + sql "CREATE ROLE publicuser LOGIN;" + sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" create_table cdb_testmember_1 foo sql cdb_testmember_1 'INSERT INTO cdb_testmember_1.foo VALUES (1), (2), (3), (4), (5);' @@ -212,12 +212,12 @@ function tear_down() { sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_1;" sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_2;" - #publicuser# sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" + sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_org_admin;" sql 'DROP ROLE cdb_testmember_1;' sql 'DROP ROLE cdb_testmember_2;' - #publicuser# sql 'DROP ROLE publicuser;' + sql 'DROP ROLE publicuser;' sql 'DROP ROLE cdb_org_admin;' sql "DROP SCHEMA cartodb CASCADE" From 2ece2979a654c7dddb16d662ed4c7133f7d9b7bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 11 Aug 2015 20:11:54 +0200 Subject: [PATCH 20/88] Drop cartodb schema before dropping publicuser --- test/organization/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/organization/test.sh b/test/organization/test.sh index 4002325..bf62953 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -205,6 +205,8 @@ function tear_down() { sql "select cartodb.CDB_Group_DropGroup('group_a')" sql "SELECT cartodb.CDB_Organization_RemoveAdmin('cdb_org_admin');" + sql "DROP SCHEMA cartodb CASCADE" + log_info "########################### TEAR DOWN ###########################" sql 'DROP SCHEMA cdb_testmember_1;' sql 'DROP SCHEMA cdb_testmember_2;' @@ -220,8 +222,6 @@ function tear_down() { sql 'DROP ROLE publicuser;' sql 'DROP ROLE cdb_org_admin;' - sql "DROP SCHEMA cartodb CASCADE" - ${CMD} -c "DROP DATABASE ${DATABASE}" } From 3ee49782409a80724d11e4ad07458389242ea11b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 12 Aug 2015 20:01:07 +0200 Subject: [PATCH 21/88] Roles simplification, without md5 and prepending database name --- scripts-available/CDB_Groups.sql | 16 ++++++++-------- scripts-available/CDB_Organizations.sql | 3 ++- test/organization/test.sh | 5 +++++ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 4efe102..af45c15 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -2,14 +2,8 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_CreateGroup(group_name text) RETURNS VOID AS $$ -DECLARE - cdb_group_role TEXT; BEGIN - cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - IF NOT EXISTS ( SELECT 1 FROM pg_roles WHERE rolname = cdb_group_role ) - THEN - EXECUTE 'CREATE ROLE "' || cdb_group_role || '" NOLOGIN;'; - END IF; + EXECUTE 'CREATE ROLE "' || cartodb._CDB_Group_GroupRole(group_name) || '" NOLOGIN;'; END $$ LANGUAGE PLPGSQL; @@ -114,12 +108,18 @@ FUNCTION cartodb._CDB_Group_GroupRole(group_name text) RETURNS TEXT AS $$ DECLARE group_role TEXT; + max_length constant INTEGER := 60; BEGIN IF group_name !~ '^[a-zA-Z_][a-zA-Z0-9_]*$' THEN RAISE EXCEPTION 'Group name (%) must be a valid identifier. See http://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS', group_name; END IF; - RETURN 'g_' || md5(current_database()) || '_' || group_name; + group_role := current_database() || '_g_' || group_name; + IF LENGTH(group_role) > max_length + THEN + RAISE EXCEPTION 'Group name should be shorter. Resulting role must have less than % characters, but it is longer: %', max_length, group_role; + END IF; + RETURN group_role; END $$ LANGUAGE PLPGSQL; diff --git a/scripts-available/CDB_Organizations.sql b/scripts-available/CDB_Organizations.sql index 6ca48c2..3de6cf5 100644 --- a/scripts-available/CDB_Organizations.sql +++ b/scripts-available/CDB_Organizations.sql @@ -31,9 +31,10 @@ $$ LANGUAGE PLPGSQL VOLATILE; CREATE OR REPLACE FUNCTION cartodb._CDB_Organization_Admin_Role_Name() RETURNS TEXT -AS 'SELECT ''cdb_org_admin''::text || ''_'' || md5(current_database());' +AS 'SELECT current_database() || ''_admin''::text;' LANGUAGE SQL IMMUTABLE; +-- Administrator role creation on extension install DO LANGUAGE 'plpgsql' $$ DECLARE cdb_org_admin_role_name TEXT; diff --git a/test/organization/test.sh b/test/organization/test.sh index bf62953..f7354d1 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -530,6 +530,11 @@ function test_not_valid_group_names() { sql postgres "select cartodb._CDB_Group_GroupRole(' group_1$_a ');" fails sql postgres "select cartodb._CDB_Group_GroupRole('group _1$_a');" fails sql postgres "select cartodb._CDB_Group_GroupRole('groupña');" fails + sql postgres "select cartodb._CDB_Group_GroupRole('a123456789012345678901234567890123456789012345678901234567890');" fails +} + +function test_administrator_name_generation() { + sql postgres "select cartodb._CDB_Organization_Admin_Role_Name();" } #################################################### TESTS END HERE #################################################### From 7262d34b068ca220c7195f2d2698f3fa7588f7d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 13 Aug 2015 15:20:20 +0200 Subject: [PATCH 22/88] IMMUTABLE-STABLE-VOLATILE specification --- scripts-available/CDB_Groups.sql | 24 +++++++++++++----------- test/organization/test.sh | 1 + 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index af45c15..9aec6c1 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -2,10 +2,12 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_CreateGroup(group_name text) RETURNS VOID AS $$ +DECLARE + cdb_group_role TEXT; BEGIN - EXECUTE 'CREATE ROLE "' || cartodb._CDB_Group_GroupRole(group_name) || '" NOLOGIN;'; + EXECUTE 'CREATE ROLE "' || cdb_group_role || '" NOLOGIN;'; END -$$ LANGUAGE PLPGSQL; +$$ LANGUAGE PLPGSQL VOLATILE; -- Drops group and everything that role owns -- TODO: LIMITATION: in order to drop a role all its owned objects must be dropped before. @@ -22,7 +24,7 @@ BEGIN EXECUTE 'DROP OWNED BY "' || cdb_group_role || '"'; EXECUTE 'DROP ROLE IF EXISTS "' || cdb_group_role || '"'; END -$$ LANGUAGE PLPGSQL; +$$ LANGUAGE PLPGSQL VOLATILE; -- Renames a group CREATE OR REPLACE @@ -31,7 +33,7 @@ FUNCTION cartodb.CDB_Group_RenameGroup(old_group_name text, new_group_name text) BEGIN EXECUTE 'ALTER ROLE "' || cartodb._CDB_Group_GroupRole(old_group_name) || '" RENAME TO "' || cartodb._CDB_Group_GroupRole(new_group_name) || '"'; END -$$ LANGUAGE PLPGSQL; +$$ LANGUAGE PLPGSQL VOLATILE; -- Adds a user to a group CREATE OR REPLACE @@ -45,7 +47,7 @@ BEGIN cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); EXECUTE 'GRANT "' || cdb_group_role || '" TO "' || cdb_user_role || '"'; END -$$ LANGUAGE PLPGSQL; +$$ LANGUAGE PLPGSQL VOLATILE; -- Removes a user from a group CREATE OR REPLACE @@ -59,7 +61,7 @@ BEGIN cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); EXECUTE 'REVOKE "' || cdb_group_role || '" FROM "' || cdb_user_role || '"'; END -$$ LANGUAGE PLPGSQL; +$$ LANGUAGE PLPGSQL VOLATILE; -- Grants table read permission to a group CREATE OR REPLACE @@ -72,7 +74,7 @@ BEGIN EXECUTE 'GRANT USAGE ON SCHEMA "' || username || '" TO "' || cdb_group_role || '"'; EXECUTE 'GRANT SELECT ON TABLE "' || username || '"."' || table_name || '" TO "' || cdb_group_role || '"'; END -$$ LANGUAGE PLPGSQL; +$$ LANGUAGE PLPGSQL VOLATILE; -- Grants table write permission to a group CREATE OR REPLACE @@ -85,7 +87,7 @@ BEGIN EXECUTE 'GRANT USAGE ON SCHEMA "' || username || '" TO "' || cdb_group_role || '"'; EXECUTE 'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "' || username || '"."' || table_name || '" TO "' || cdb_group_role || '"'; END -$$ LANGUAGE PLPGSQL; +$$ LANGUAGE PLPGSQL VOLATILE; -- Revokes all permissions on a table from a group CREATE OR REPLACE @@ -97,7 +99,7 @@ BEGIN cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); EXECUTE 'REVOKE ALL ON TABLE "' || username || '"."' || table_name || '" FROM "' || cdb_group_role || '"'; END -$$ LANGUAGE PLPGSQL; +$$ LANGUAGE PLPGSQL VOLATILE; ----------------------- -- Private functions @@ -121,7 +123,7 @@ BEGIN END IF; RETURN group_role; END -$$ LANGUAGE PLPGSQL; +$$ LANGUAGE PLPGSQL IMMUTABLE; -- Returns the first owner of the schema matching username. Organization user schemas must have one only owner. CREATE OR REPLACE @@ -135,4 +137,4 @@ BEGIN EXECUTE 'SELECT pg_get_userbyid(nspowner) FROM pg_namespace WHERE nspname = $1;' INTO user_role USING username; RETURN user_role; END -$$ LANGUAGE PLPGSQL; +$$ LANGUAGE PLPGSQL IMMUTABLE; diff --git a/test/organization/test.sh b/test/organization/test.sh index f7354d1..4cb1cc3 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -164,6 +164,7 @@ function setup() { log_info "########################### BOOTSTRAP ###########################" ${CMD} -d ${DATABASE} -f scripts-available/CDB_Organizations.sql ${CMD} -d ${DATABASE} -f scripts-available/CDB_Groups.sql + ${CMD} -d ${DATABASE} -f scripts-available/CDB_Groups_API.sql log_info "############################# SETUP #############################" create_role_and_schema cdb_org_admin From 725453ce2be9a48ae5e854abb54c08b515a2f1da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 13 Aug 2015 20:43:17 +0200 Subject: [PATCH 23/88] Configuration table and functions --- scripts-available/CDB_Conf.sql | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 scripts-available/CDB_Conf.sql diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql new file mode 100644 index 0000000..440f51f --- /dev/null +++ b/scripts-available/CDB_Conf.sql @@ -0,0 +1,33 @@ +DO LANGUAGE 'plpgsql' $$ +BEGIN + CREATE TABLE IF NOT EXISTS CDB_CONF ( PARAM TEXT PRIMARY KEY, VALUE TEXT NOT NULL ); +END +$$; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Conf_SetParam(param text, value text) + RETURNS void AS $$ +BEGIN + PERFORM cartodb.CDB_Conf_RemoveParam(param); + EXECUTE 'INSERT INTO CDB_CONF (PARAM, VALUE) VALUES ($1, $2);' USING param, value; +END +$$ LANGUAGE PLPGSQL VOLATILE; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Conf_RemoveParam(param text) + RETURNS void AS $$ +BEGIN + EXECUTE 'DELETE FROM CDB_CONF WHERE PARAM = $1;' USING param; +END +$$ LANGUAGE PLPGSQL VOLATILE; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Conf_GetParam(param text) + RETURNS TEXT AS $$ +DECLARE + value TEXT; +BEGIN + EXECUTE 'SELECT VALUE FROM CDB_CONF WHERE PARAM = $1;' INTO value USING param; + RETURN value; +END +$$ LANGUAGE PLPGSQL STABLE; From a0aac4e9c935a5dfb0109d6f51c22abd74c13f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Fri, 14 Aug 2015 10:12:10 +0200 Subject: [PATCH 24/88] Info about if not exist log output --- scripts-available/CDB_Conf.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index 440f51f..ff22588 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -1,3 +1,4 @@ +-- This will trigger NOTICE if CDB_CONF already exists DO LANGUAGE 'plpgsql' $$ BEGIN CREATE TABLE IF NOT EXISTS CDB_CONF ( PARAM TEXT PRIMARY KEY, VALUE TEXT NOT NULL ); From d4bcb97f9b26dee5b0eca91d65d3a0d734b560ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Fri, 14 Aug 2015 13:55:52 +0200 Subject: [PATCH 25/88] CDB_CONF and create and drop group api calls --- scripts-available/CDB_Conf.sql | 20 +++++----- scripts-available/CDB_Groups.sql | 27 +++++++++++--- scripts-available/CDB_Groups_API.sql | 55 ++++++++++++++++++++++++++++ test/organization/test.sh | 18 ++++++--- 4 files changed, 99 insertions(+), 21 deletions(-) create mode 100644 scripts-available/CDB_Groups_API.sql diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index ff22588..a51136b 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -1,34 +1,34 @@ -- This will trigger NOTICE if CDB_CONF already exists DO LANGUAGE 'plpgsql' $$ BEGIN - CREATE TABLE IF NOT EXISTS CDB_CONF ( PARAM TEXT PRIMARY KEY, VALUE TEXT NOT NULL ); + CREATE TABLE IF NOT EXISTS cartodb.CDB_CONF ( PARAM TEXT PRIMARY KEY, CONF TEXT NOT NULL ); END $$; CREATE OR REPLACE -FUNCTION cartodb.CDB_Conf_SetParam(param text, value text) +FUNCTION cartodb.CDB_Conf_SetConf(param text, conf text) RETURNS void AS $$ BEGIN - PERFORM cartodb.CDB_Conf_RemoveParam(param); - EXECUTE 'INSERT INTO CDB_CONF (PARAM, VALUE) VALUES ($1, $2);' USING param, value; + PERFORM cartodb.CDB_Conf_RemoveConf(param); + EXECUTE 'INSERT INTO cartodb.CDB_CONF (PARAM, CONF) VALUES ($1, $2);' USING param, conf; END $$ LANGUAGE PLPGSQL VOLATILE; CREATE OR REPLACE -FUNCTION cartodb.CDB_Conf_RemoveParam(param text) +FUNCTION cartodb.CDB_Conf_RemoveConf(param text) RETURNS void AS $$ BEGIN - EXECUTE 'DELETE FROM CDB_CONF WHERE PARAM = $1;' USING param; + EXECUTE 'DELETE FROM cartodb.CDB_CONF WHERE PARAM = $1;' USING param; END $$ LANGUAGE PLPGSQL VOLATILE; CREATE OR REPLACE -FUNCTION cartodb.CDB_Conf_GetParam(param text) +FUNCTION cartodb.CDB_Conf_GetConf(param text) RETURNS TEXT AS $$ DECLARE - value TEXT; + conf TEXT; BEGIN - EXECUTE 'SELECT VALUE FROM CDB_CONF WHERE PARAM = $1;' INTO value USING param; - RETURN value; + EXECUTE 'SELECT CONF FROM cartodb.CDB_CONF WHERE PARAM = $1;' INTO conf USING param; + RETURN conf; END $$ LANGUAGE PLPGSQL STABLE; diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 9aec6c1..e036531 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -3,9 +3,11 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_CreateGroup(group_name text) RETURNS VOID AS $$ DECLARE - cdb_group_role TEXT; + group_role TEXT; BEGIN - EXECUTE 'CREATE ROLE "' || cdb_group_role || '" NOLOGIN;'; + group_role := cartodb._CDB_Group_GroupRole(group_name); + PERFORM cartodb._CDB_Group_CreateGroup_API(current_database(), group_name, group_role); + EXECUTE 'CREATE ROLE "' || group_role || '" NOLOGIN;'; END $$ LANGUAGE PLPGSQL VOLATILE; @@ -21,6 +23,7 @@ DECLARE cdb_group_role TEXT; BEGIN cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); + PERFORM cartodb._CDB_Group_DropGroup_API(current_database(), group_name); EXECUTE 'DROP OWNED BY "' || cdb_group_role || '"'; EXECUTE 'DROP ROLE IF EXISTS "' || cdb_group_role || '"'; END @@ -110,16 +113,18 @@ FUNCTION cartodb._CDB_Group_GroupRole(group_name text) RETURNS TEXT AS $$ DECLARE group_role TEXT; - max_length constant INTEGER := 60; + prefix TEXT; + max_length constant INTEGER := 63; BEGIN IF group_name !~ '^[a-zA-Z_][a-zA-Z0-9_]*$' THEN RAISE EXCEPTION 'Group name (%) must be a valid identifier. See http://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS', group_name; END IF; - group_role := current_database() || '_g_' || group_name; + prefix = cartodb._CDB_Group_ShortDatabaseName() || '_g_'; + group_role := prefix || group_name; IF LENGTH(group_role) > max_length THEN - RAISE EXCEPTION 'Group name should be shorter. Resulting role must have less than % characters, but it is longer: %', max_length, group_role; + 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; END IF; RETURN group_role; END @@ -138,3 +143,15 @@ BEGIN RETURN user_role; END $$ LANGUAGE PLPGSQL IMMUTABLE; + +-- 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 + EXECUTE 'SELECT md5(current_database())' INTO short_database_name; + RETURN short_database_name; +END +$$ LANGUAGE PLPGSQL IMMUTABLE; diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql new file mode 100644 index 0000000..5f82706 --- /dev/null +++ b/scripts-available/CDB_Groups_API.sql @@ -0,0 +1,55 @@ +-- Sends the create group request +CREATE OR REPLACE +FUNCTION cartodb._CDB_Group_CreateGroup_API(database_name text, group_name text, group_role text) + RETURNS VOID AS +$$ + import httplib + import base64 + import string + import json + + try: + conf = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('groups_api') conf")[0]['conf'] + if conf is None: + return + params = json.loads(conf) + client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) + url = '/api/v1/databases/%s/groups' % database_name + body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role) + auth = base64.encodestring('%s:%s' % (params['username'], params['password'])).replace('\n', '') + headers = { 'Authorization': ('Basic %s' % auth), 'Content-Type': 'application/json' } + client.request('POST', url, body, headers) + response = client.getresponse() + assert response.status == 200 + except Exception as err: + plpy.warning('group creation error: ' + str(err)) + raise err + +$$ LANGUAGE 'plpythonu' VOLATILE; + +CREATE OR REPLACE +FUNCTION cartodb._CDB_Group_DropGroup_API(database_name text, group_name text) + RETURNS VOID AS +$$ + import httplib + import base64 + import string + import json + + try: + conf = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('groups_api') conf")[0]['conf'] + if conf is None: + return + params = json.loads(conf) + client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) + url = '/api/v1/databases/%s/groups/%s' % (database_name, group_name) + auth = base64.encodestring('%s:%s' % (params['username'], params['password'])).replace('\n', '') + headers = { 'Authorization': ('Basic %s' % auth), 'Content-Type': 'application/json' } + client.request('DELETE', url, '', headers) + response = client.getresponse() + assert response.status == 200 + except Exception as err: + plpy.warning('group creation error: ' + str(err)) + raise err + +$$ LANGUAGE 'plpythonu' VOLATILE; diff --git a/test/organization/test.sh b/test/organization/test.sh index 4cb1cc3..c1e86f3 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -159,9 +159,11 @@ function create_table() { function setup() { ${CMD} -c "CREATE DATABASE ${DATABASE}" sql "CREATE SCHEMA cartodb;" + sql "CREATE EXTENSION plpythonu;" sql "GRANT USAGE ON SCHEMA cartodb TO public;" log_info "########################### BOOTSTRAP ###########################" + ${CMD} -d ${DATABASE} -f scripts-available/CDB_Conf.sql ${CMD} -d ${DATABASE} -f scripts-available/CDB_Organizations.sql ${CMD} -d ${DATABASE} -f scripts-available/CDB_Groups.sql ${CMD} -d ${DATABASE} -f scripts-available/CDB_Groups_API.sql @@ -378,21 +380,18 @@ function test_user_can_read_when_it_has_permission_after_organization_permission } function test_cdb_querytables_returns_schema_and_table_name() { - sql "CREATE EXTENSION plpythonu;" ${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryStatements.sql ${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryTables.sql sql cdb_testmember_1 "select * from CDB_QueryTables('select * from foo');" should "{cdb_testmember_1.foo}" } function test_cdb_querytables_returns_schema_and_table_name_for_several_schemas() { - sql "CREATE EXTENSION plpythonu;" ${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryStatements.sql ${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryTables.sql sql postgres "select * from CDB_QueryTables('select * from cdb_testmember_1.foo, cdb_testmember_2.bar');" should "{cdb_testmember_1.foo,cdb_testmember_2.bar}" } function test_cdb_querytables_does_not_return_functions_as_part_of_the_resultset() { - sql "CREATE EXTENSION plpythonu;" ${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryStatements.sql ${CMD} -d ${DATABASE} -f scripts-available/CDB_QueryTables.sql sql postgres "select * from CDB_QueryTables('select * from cdb_testmember_1.foo, cdb_testmember_2.bar, plainto_tsquery(''foo'')');" should "{cdb_testmember_1.foo,cdb_testmember_2.bar}" @@ -519,9 +518,9 @@ function test_org_admin_cant_grant_permissions_on_tables_he_does_not_own() { } function test_valid_group_names() { - sql "select cartodb._CDB_Group_GroupRole('group_1$_a');" - sql "select cartodb._CDB_Group_GroupRole('GROUP_1$_A');" - sql "select cartodb._CDB_Group_GroupRole('_group_1$_a');" + sql postgres "select cartodb._CDB_Group_GroupRole('group_1$_a');" + sql postgres "select cartodb._CDB_Group_GroupRole('GROUP_1$_A');" + sql postgres "select cartodb._CDB_Group_GroupRole('_group_1$_a');" } function test_not_valid_group_names() { @@ -538,6 +537,13 @@ function test_administrator_name_generation() { sql postgres "select cartodb._CDB_Organization_Admin_Role_Name();" } +function test_conf() { + sql postgres "SELECT cartodb.CDB_Conf_SetConf('test_conf', 'test_val')" + sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should 'test_val' + sql postgres "SELECT cartodb.CDB_Conf_RemoveConf('test_conf')" + sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should '' +} + #################################################### TESTS END HERE #################################################### From d1f19a0234a28d5f2c6a1200b19ad527ebd432f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Fri, 14 Aug 2015 14:03:53 +0200 Subject: [PATCH 26/88] Groups API configuration example --- scripts-available/CDB_Groups_API.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 5f82706..4aa4880 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -1,3 +1,5 @@ +-- Requires configuration parameter. Example: SELECT cartodb.CDB_Conf_SetConf('groups_api', '{ "host": "127.0.0.1", "port": 3000, "timeout": 10, "username": "superadmin", "password": "monkey" }'); + -- Sends the create group request CREATE OR REPLACE FUNCTION cartodb._CDB_Group_CreateGroup_API(database_name text, group_name text, group_role text) From ae634e7814bfe39c3c74598a35b0f4400e69a682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Fri, 14 Aug 2015 15:04:14 +0200 Subject: [PATCH 27/88] Server notification must happen after role creation --- scripts-available/CDB_Groups.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index e036531..31b0145 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -6,8 +6,8 @@ DECLARE group_role TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); - PERFORM cartodb._CDB_Group_CreateGroup_API(current_database(), group_name, group_role); EXECUTE 'CREATE ROLE "' || group_role || '" NOLOGIN;'; + PERFORM cartodb._CDB_Group_CreateGroup_API(current_database(), group_name, group_role); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -23,9 +23,9 @@ DECLARE cdb_group_role TEXT; BEGIN cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - PERFORM cartodb._CDB_Group_DropGroup_API(current_database(), group_name); EXECUTE 'DROP OWNED BY "' || cdb_group_role || '"'; EXECUTE 'DROP ROLE IF EXISTS "' || cdb_group_role || '"'; + PERFORM cartodb._CDB_Group_DropGroup_API(current_database(), group_name); END $$ LANGUAGE PLPGSQL VOLATILE; From 466e4d81c62428ac823251380c59bb3bbd01cef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Fri, 14 Aug 2015 15:22:00 +0200 Subject: [PATCH 28/88] format instead of string concatenation --- scripts-available/CDB_Groups.sql | 30 ++++++++++++------------- scripts-available/CDB_Organizations.sql | 10 ++++----- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 31b0145..eb35792 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -6,7 +6,7 @@ DECLARE group_role TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE 'CREATE ROLE "' || group_role || '" NOLOGIN;'; + EXECUTE format('CREATE ROLE "%s" NOLOGIN;', group_role); PERFORM cartodb._CDB_Group_CreateGroup_API(current_database(), group_name, group_role); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -20,11 +20,11 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_DropGroup(group_name text) RETURNS VOID AS $$ DECLARE - cdb_group_role TEXT; + group_role TEXT; BEGIN - cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE 'DROP OWNED BY "' || cdb_group_role || '"'; - EXECUTE 'DROP ROLE IF EXISTS "' || cdb_group_role || '"'; + group_role := cartodb._CDB_Group_GroupRole(group_name); + EXECUTE format('DROP OWNED BY "%s"', group_role); + EXECUTE format('DROP ROLE IF EXISTS "%s"', group_role); PERFORM cartodb._CDB_Group_DropGroup_API(current_database(), group_name); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -34,7 +34,7 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_RenameGroup(old_group_name text, new_group_name text) RETURNS VOID AS $$ BEGIN - EXECUTE 'ALTER ROLE "' || cartodb._CDB_Group_GroupRole(old_group_name) || '" RENAME TO "' || cartodb._CDB_Group_GroupRole(new_group_name) || '"'; + EXECUTE format('ALTER ROLE "%s" RENAME TO "%s"', cartodb._CDB_Group_GroupRole(old_group_name), cartodb._CDB_Group_GroupRole(new_group_name)); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -48,7 +48,7 @@ DECLARE BEGIN cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); - EXECUTE 'GRANT "' || cdb_group_role || '" TO "' || cdb_user_role || '"'; + EXECUTE format('GRANT "%s" TO "%s"', cdb_group_role, cdb_user_role); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -62,7 +62,7 @@ DECLARE BEGIN cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); - EXECUTE 'REVOKE "' || cdb_group_role || '" FROM "' || cdb_user_role || '"'; + EXECUTE format('REVOKE "%s" FROM "%s"', cdb_group_role, cdb_user_role); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -74,8 +74,8 @@ DECLARE cdb_group_role TEXT; BEGIN cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE 'GRANT USAGE ON SCHEMA "' || username || '" TO "' || cdb_group_role || '"'; - EXECUTE 'GRANT SELECT ON TABLE "' || username || '"."' || table_name || '" TO "' || cdb_group_role || '"'; + EXECUTE format('GRANT USAGE ON SCHEMA "%s" TO "%s"', username, cdb_group_role); + EXECUTE format('GRANT SELECT ON TABLE "%s"."%s" TO "%s"', username, table_name, cdb_group_role ); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -87,8 +87,8 @@ DECLARE cdb_group_role TEXT; BEGIN cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE 'GRANT USAGE ON SCHEMA "' || username || '" TO "' || cdb_group_role || '"'; - EXECUTE 'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "' || username || '"."' || table_name || '" TO "' || cdb_group_role || '"'; + EXECUTE format('GRANT USAGE ON SCHEMA "%s" TO "%s"', username, cdb_group_role); + EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "%s"."%s" TO "%s"', username, table_name, cdb_group_role); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -100,7 +100,7 @@ DECLARE cdb_group_role TEXT; BEGIN cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE 'REVOKE ALL ON TABLE "' || username || '"."' || table_name || '" FROM "' || cdb_group_role || '"'; + EXECUTE format('REVOKE ALL ON TABLE "%s"."%s" FROM "%s"', username, table_name, cdb_group_role); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -120,8 +120,8 @@ BEGIN THEN RAISE EXCEPTION 'Group name (%) must be a valid identifier. See http://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS', group_name; END IF; - prefix = cartodb._CDB_Group_ShortDatabaseName() || '_g_'; - group_role := prefix || group_name; + prefix = format('%s_g_', cartodb._CDB_Group_ShortDatabaseName()); + group_role := format('%s%s', prefix, group_name); IF LENGTH(group_role) > max_length THEN 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; diff --git a/scripts-available/CDB_Organizations.sql b/scripts-available/CDB_Organizations.sql index 3de6cf5..a47c78d 100644 --- a/scripts-available/CDB_Organizations.sql +++ b/scripts-available/CDB_Organizations.sql @@ -42,7 +42,7 @@ BEGIN cdb_org_admin_role_name := cartodb._CDB_Organization_Admin_Role_Name(); IF NOT EXISTS ( SELECT * FROM pg_roles WHERE rolname= cdb_org_admin_role_name ) THEN - EXECUTE 'CREATE ROLE "' || cdb_org_admin_role_name || '" CREATEROLE NOLOGIN;'; + EXECUTE format('CREATE ROLE "%s" CREATEROLE NOLOGIN;', cdb_org_admin_role_name); END IF; END $$; @@ -57,9 +57,9 @@ DECLARE BEGIN cdb_admin_role := cartodb._CDB_Organization_Admin_Role_Name(); cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); - EXECUTE 'GRANT "' || cdb_admin_role || '" TO "' || cdb_user_role || '" WITH ADMIN OPTION'; + EXECUTE format('GRANT "%s" TO "%s" WITH ADMIN OPTION', cdb_admin_role, cdb_user_role); -- CREATEROLE is not inherited, and is needed for user creation - EXECUTE 'ALTER ROLE "' || cdb_user_role || '" CREATEROLE'; + EXECUTE format('ALTER ROLE "%s" CREATEROLE', cdb_user_role); END $$ LANGUAGE PLPGSQL; @@ -73,8 +73,8 @@ DECLARE BEGIN cdb_admin_role := cartodb._CDB_Organization_Admin_Role_Name(); cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); - EXECUTE 'ALTER ROLE "' || cdb_user_role || '" NOCREATEROLE'; - EXECUTE 'REVOKE "' || cdb_admin_role || '" FROM "' || cdb_user_role || '"'; + EXECUTE format('ALTER ROLE "%s" NOCREATEROLE', cdb_user_role); + EXECUTE format('REVOKE "%s" FROM "%s"', cdb_admin_role, cdb_user_role); END $$ LANGUAGE PLPGSQL; From db89bf1a94266913852d5f9d40f90f4c843a542b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Fri, 14 Aug 2015 15:28:19 +0200 Subject: [PATCH 29/88] Grant select on configuration table to org members --- scripts-available/CDB_Conf.sql | 1 + test/organization/test.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index a51136b..8f347d7 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -2,6 +2,7 @@ DO LANGUAGE 'plpgsql' $$ BEGIN CREATE TABLE IF NOT EXISTS cartodb.CDB_CONF ( PARAM TEXT PRIMARY KEY, CONF TEXT NOT NULL ); + EXECUTE format('GRANT SELECT ON cartodb.CDB_CONF TO %s', cartodb.CDB_Organization_Member_Group_Role_Member_Name()); END $$; diff --git a/test/organization/test.sh b/test/organization/test.sh index c1e86f3..7a80484 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -163,8 +163,8 @@ function setup() { sql "GRANT USAGE ON SCHEMA cartodb TO public;" log_info "########################### BOOTSTRAP ###########################" - ${CMD} -d ${DATABASE} -f scripts-available/CDB_Conf.sql ${CMD} -d ${DATABASE} -f scripts-available/CDB_Organizations.sql + ${CMD} -d ${DATABASE} -f scripts-available/CDB_Conf.sql ${CMD} -d ${DATABASE} -f scripts-available/CDB_Groups.sql ${CMD} -d ${DATABASE} -f scripts-available/CDB_Groups_API.sql From e11f4ef169a933897d23b513067e485f548c0e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Fri, 14 Aug 2015 15:40:36 +0200 Subject: [PATCH 30/88] Group name validation delegated to role creation --- scripts-available/CDB_Groups.sql | 4 ---- test/organization/test.sh | 10 ---------- 2 files changed, 14 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index eb35792..439431c 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -116,10 +116,6 @@ DECLARE prefix TEXT; max_length constant INTEGER := 63; BEGIN - IF group_name !~ '^[a-zA-Z_][a-zA-Z0-9_]*$' - THEN - RAISE EXCEPTION 'Group name (%) must be a valid identifier. See http://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS', group_name; - END IF; prefix = format('%s_g_', cartodb._CDB_Group_ShortDatabaseName()); group_role := format('%s%s', prefix, group_name); IF LENGTH(group_role) > max_length diff --git a/test/organization/test.sh b/test/organization/test.sh index 7a80484..abfc7a5 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -523,16 +523,6 @@ function test_valid_group_names() { sql postgres "select cartodb._CDB_Group_GroupRole('_group_1$_a');" } -function test_not_valid_group_names() { - sql postgres "select cartodb._CDB_Group_GroupRole('1$_a');" fails - sql postgres "select cartodb._CDB_Group_GroupRole(' group_1$_a');" fails - sql postgres "select cartodb._CDB_Group_GroupRole('group_1$_a ');" fails - sql postgres "select cartodb._CDB_Group_GroupRole(' group_1$_a ');" fails - sql postgres "select cartodb._CDB_Group_GroupRole('group _1$_a');" fails - sql postgres "select cartodb._CDB_Group_GroupRole('groupña');" fails - sql postgres "select cartodb._CDB_Group_GroupRole('a123456789012345678901234567890123456789012345678901234567890');" fails -} - function test_administrator_name_generation() { sql postgres "select cartodb._CDB_Organization_Admin_Role_Name();" } From a08600a1f84b96a1368bb861307d75f80db1d737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Fri, 14 Aug 2015 16:31:19 +0200 Subject: [PATCH 31/88] Exclude cartodb schema from CDB_UserTables --- scripts-available/CDB_UserTables.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts-available/CDB_UserTables.sql b/scripts-available/CDB_UserTables.sql index bfa5165..c140f4a 100644 --- a/scripts-available/CDB_UserTables.sql +++ b/scripts-available/CDB_UserTables.sql @@ -15,7 +15,7 @@ FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = 'r' AND c.relname NOT IN ('cdb_tablemetadata', 'spatial_ref_sys') -AND n.nspname NOT IN ('pg_catalog', 'information_schema', 'topology') +AND n.nspname NOT IN ('pg_catalog', 'information_schema', 'topology', 'cartodb') AND CASE WHEN perm = 'public' THEN has_table_privilege('publicuser', c.oid, 'SELECT') WHEN perm = 'private' THEN has_table_privilege(current_user, c.oid, 'SELECT') AND NOT has_table_privilege('publicuser', c.oid, 'SELECT') WHEN perm = 'all' THEN has_table_privilege(current_user, c.oid, 'SELECT') OR has_table_privilege('publicuser', c.oid, 'SELECT') From 6c3555f21a20b4ca2c24d94a3fa3de5b5f6c31e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 17 Aug 2015 11:49:31 +0200 Subject: [PATCH 32/88] Configuration parameters refactor --- scripts-available/CDB_Groups_API.sql | 65 +++++++++++++++++++++------- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 4aa4880..74a2a41 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -6,21 +6,18 @@ FUNCTION cartodb._CDB_Group_CreateGroup_API(database_name text, group_name text, RETURNS VOID AS $$ import httplib - import base64 import string - import json try: - conf = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('groups_api') conf")[0]['conf'] - if conf is None: + params = plpy.execute("select c.host, c.port, c.timeout, c.username, c.password from cartodb._CDB_Group_API_Conf() c;")[0] + if params['host'] is None: return - params = json.loads(conf) + client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) - url = '/api/v1/databases/%s/groups' % database_name body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role) - auth = base64.encodestring('%s:%s' % (params['username'], params['password'])).replace('\n', '') + auth = plpy.execute("SELECT cartodb._CDB_Group_API_Auth('%s', '%s') as auth" % (params['username'], params['password']))[0]['auth'] headers = { 'Authorization': ('Basic %s' % auth), 'Content-Type': 'application/json' } - client.request('POST', url, body, headers) + client.request('POST', '/api/v1/databases/%s/groups' % database_name, body, headers) response = client.getresponse() assert response.status == 200 except Exception as err: @@ -34,20 +31,17 @@ FUNCTION cartodb._CDB_Group_DropGroup_API(database_name text, group_name text) RETURNS VOID AS $$ import httplib - import base64 import string - import json try: - conf = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('groups_api') conf")[0]['conf'] - if conf is None: + params = plpy.execute("select c.host, c.port, c.timeout, c.username, c.password from cartodb._CDB_Group_API_Conf() c;")[0] + if params['host'] is None: return - params = json.loads(conf) + client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) - url = '/api/v1/databases/%s/groups/%s' % (database_name, group_name) - auth = base64.encodestring('%s:%s' % (params['username'], params['password'])).replace('\n', '') + auth = plpy.execute("SELECT cartodb._CDB_Group_API_Auth('%s', '%s') as auth" % (params['username'], params['password']))[0]['auth'] headers = { 'Authorization': ('Basic %s' % auth), 'Content-Type': 'application/json' } - client.request('DELETE', url, '', headers) + client.request('DELETE', '/api/v1/databases/%s/groups/%s' % (database_name, group_name), '', headers) response = client.getresponse() assert response.status == 200 except Exception as err: @@ -55,3 +49,42 @@ $$ raise err $$ LANGUAGE 'plpythonu' VOLATILE; + +DO LANGUAGE 'plpgsql' $$ +BEGIN + DROP FUNCTION IF EXISTS cartodb._CDB_Group_API_Conf(); + DROP TYPE IF EXISTS _CDB_Group_API_Params; +END +$$; + +CREATE TYPE _CDB_Group_API_Params AS ( + host text, + port int, + timeout int, + username text, + password text +); + +-- This must be explicitally extracted because "composite types are currently not supported". +-- See http://www.postgresql.org/docs/9.3/static/plpython-database.html. +CREATE OR REPLACE +FUNCTION cartodb._CDB_Group_API_Conf() + RETURNS _CDB_Group_API_Params AS +$$ + conf = plpy.execute("SELECT cartodb.CDB_Conf_GetConf('groups_api') conf")[0]['conf'] + if conf is None: + return None + else: + import json + params = json.loads(conf) + return { "host": params['host'], "port": params['port'], 'timeout': params['timeout'], 'username': params['username'], 'password': params['password'] } + # return params +$$ LANGUAGE 'plpythonu' VOLATILE; + +CREATE OR REPLACE +FUNCTION cartodb._CDB_Group_API_Auth(username text, password text) + RETURNS TEXT AS +$$ + import base64 + base64.encodestring('%s:%s' % (username, password)).replace('\n', '') +$$ LANGUAGE 'plpythonu' IMMUTABLE; From df531e9e37de445e043c514ca2b720df585f43c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 17 Aug 2015 12:26:38 +0200 Subject: [PATCH 33/88] auth inside param reading --- scripts-available/CDB_Groups_API.sql | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 74a2a41..0b24ae9 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -9,21 +9,19 @@ $$ import string try: - params = plpy.execute("select c.host, c.port, c.timeout, c.username, c.password from cartodb._CDB_Group_API_Conf() c;")[0] + params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._CDB_Group_API_Conf() c;")[0] if params['host'] is None: return client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role) - auth = plpy.execute("SELECT cartodb._CDB_Group_API_Auth('%s', '%s') as auth" % (params['username'], params['password']))[0]['auth'] - headers = { 'Authorization': ('Basic %s' % auth), 'Content-Type': 'application/json' } + headers = { 'Authorization': ('Basic %s' % params['auth']), 'Content-Type': 'application/json' } client.request('POST', '/api/v1/databases/%s/groups' % database_name, body, headers) response = client.getresponse() assert response.status == 200 except Exception as err: plpy.warning('group creation error: ' + str(err)) raise err - $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE @@ -34,20 +32,18 @@ $$ import string try: - params = plpy.execute("select c.host, c.port, c.timeout, c.username, c.password from cartodb._CDB_Group_API_Conf() c;")[0] + params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._CDB_Group_API_Conf() c;")[0] if params['host'] is None: return client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) - auth = plpy.execute("SELECT cartodb._CDB_Group_API_Auth('%s', '%s') as auth" % (params['username'], params['password']))[0]['auth'] - headers = { 'Authorization': ('Basic %s' % auth), 'Content-Type': 'application/json' } + headers = { 'Authorization': ('Basic %s' % params['auth']), 'Content-Type': 'application/json' } client.request('DELETE', '/api/v1/databases/%s/groups/%s' % (database_name, group_name), '', headers) response = client.getresponse() assert response.status == 200 except Exception as err: plpy.warning('group creation error: ' + str(err)) raise err - $$ LANGUAGE 'plpythonu' VOLATILE; DO LANGUAGE 'plpgsql' $$ @@ -61,8 +57,7 @@ CREATE TYPE _CDB_Group_API_Params AS ( host text, port int, timeout int, - username text, - password text + auth text ); -- This must be explicitally extracted because "composite types are currently not supported". @@ -77,7 +72,8 @@ $$ else: import json params = json.loads(conf) - return { "host": params['host'], "port": params['port'], 'timeout': params['timeout'], 'username': params['username'], 'password': params['password'] } + auth = plpy.execute("SELECT cartodb._CDB_Group_API_Auth('%s', '%s') as auth" % (params['username'], params['password']))[0]['auth'] + return { "host": params['host'], "port": params['port'], 'timeout': params['timeout'], 'auth': auth } # return params $$ LANGUAGE 'plpythonu' VOLATILE; From 99641b827c3fa00ab2bf5c40a223895a4ee42ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 17 Aug 2015 12:55:42 +0200 Subject: [PATCH 34/88] Authorization type moved to function --- scripts-available/CDB_Groups_API.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 0b24ae9..7e70171 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -15,7 +15,7 @@ $$ client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role) - headers = { 'Authorization': ('Basic %s' % params['auth']), 'Content-Type': 'application/json' } + headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } client.request('POST', '/api/v1/databases/%s/groups' % database_name, body, headers) response = client.getresponse() assert response.status == 200 @@ -37,7 +37,7 @@ $$ return client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) - headers = { 'Authorization': ('Basic %s' % params['auth']), 'Content-Type': 'application/json' } + headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } client.request('DELETE', '/api/v1/databases/%s/groups/%s' % (database_name, group_name), '', headers) response = client.getresponse() assert response.status == 200 @@ -72,7 +72,7 @@ $$ else: import json params = json.loads(conf) - auth = plpy.execute("SELECT cartodb._CDB_Group_API_Auth('%s', '%s') as auth" % (params['username'], params['password']))[0]['auth'] + auth = 'Basic %s' % plpy.execute("SELECT cartodb._CDB_Group_API_Auth('%s', '%s') as auth" % (params['username'], params['password']))[0]['auth'] return { "host": params['host'], "port": params['port'], 'timeout': params['timeout'], 'auth': auth } # return params $$ LANGUAGE 'plpythonu' VOLATILE; From 566adfb0ce8d68505d8770183174c28d9dc290f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 17 Aug 2015 13:37:34 +0200 Subject: [PATCH 35/88] CDB_Group_RenameGroup_API --- scripts-available/CDB_Groups.sql | 8 +++++++- scripts-available/CDB_Groups_API.sql | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 439431c..d569dd3 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -33,8 +33,14 @@ $$ LANGUAGE PLPGSQL VOLATILE; CREATE OR REPLACE FUNCTION cartodb.CDB_Group_RenameGroup(old_group_name text, new_group_name text) RETURNS VOID AS $$ +DECLARE + old_group_role TEXT; + new_group_role TEXT; BEGIN - EXECUTE format('ALTER ROLE "%s" RENAME TO "%s"', cartodb._CDB_Group_GroupRole(old_group_name), cartodb._CDB_Group_GroupRole(new_group_name)); + old_group_role = cartodb._CDB_Group_GroupRole(old_group_name); + new_group_role = cartodb._CDB_Group_GroupRole(new_group_name); + EXECUTE format('ALTER ROLE "%s" RENAME TO "%s"', old_group_role, new_group_role); + PERFORM cartodb._CDB_Group_RenameGroup_API(current_database(), old_group_name, new_group_name, new_group_role); END $$ LANGUAGE PLPGSQL VOLATILE; diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 7e70171..be3583d 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -46,6 +46,29 @@ $$ raise err $$ LANGUAGE 'plpythonu' VOLATILE; +CREATE OR REPLACE +FUNCTION cartodb._CDB_Group_RenameGroup_API(database_name text, old_group_name text, new_group_name text, new_group_role text) + RETURNS VOID AS +$$ + import httplib + import string + + try: + params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._CDB_Group_API_Conf() c;")[0] + if params['host'] is None: + return + + client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) + body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role) + headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } + client.request('PUT', '/api/v1/databases/%s/groups/%s' % (database_name, old_group_name), body, headers) + response = client.getresponse() + assert response.status == 200 + except Exception as err: + plpy.warning('group creation error: ' + str(err)) + raise err +$$ LANGUAGE 'plpythonu' VOLATILE; + DO LANGUAGE 'plpgsql' $$ BEGIN DROP FUNCTION IF EXISTS cartodb._CDB_Group_API_Conf(); From 00e9cc5a79a6d7cbf75b73ac2a7e033e31ce6fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 17 Aug 2015 15:02:21 +0200 Subject: [PATCH 36/88] Explicit null check for not found role --- scripts-available/CDB_Groups.sql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index d569dd3..aabe6a4 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -54,6 +54,10 @@ DECLARE BEGIN cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); + IF(cdb_group_role IS NULL OR cdb_user_role IS NULL) + THEN + RAISE EXCEPTION 'Group role (%) and user role (%) must be already existing', cdb_group_role, cdb_user_role; + END IF; EXECUTE format('GRANT "%s" TO "%s"', cdb_group_role, cdb_user_role); END $$ LANGUAGE PLPGSQL VOLATILE; From e4a56371c045b26842a6536b6d1c43d70d9a3d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 17 Aug 2015 15:05:09 +0200 Subject: [PATCH 37/88] _CDB_Group_AddMember_API --- scripts-available/CDB_Groups.sql | 1 + scripts-available/CDB_Groups_API.sql | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index aabe6a4..a4244a7 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -59,6 +59,7 @@ BEGIN RAISE EXCEPTION 'Group role (%) and user role (%) must be already existing', cdb_group_role, cdb_user_role; END IF; EXECUTE format('GRANT "%s" TO "%s"', cdb_group_role, cdb_user_role); + PERFORM cartodb._CDB_Group_AddMember_API(current_database(), group_name, username); END $$ LANGUAGE PLPGSQL VOLATILE; diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index be3583d..bca575f 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -69,6 +69,29 @@ $$ raise err $$ LANGUAGE 'plpythonu' VOLATILE; +CREATE OR REPLACE +FUNCTION cartodb._CDB_Group_AddMember_API(database_name text, group_name text, username text) + RETURNS VOID AS +$$ + import httplib + import string + + try: + params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._CDB_Group_API_Conf() c;")[0] + if params['host'] is None: + return + + client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) + body = '{ "username": "%s" }' % username + headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } + client.request('POST', '/api/v1/databases/%s/groups/%s/users' % (database_name, group_name), body, headers) + response = client.getresponse() + assert response.status == 200 + except Exception as err: + plpy.warning('group creation error: ' + str(err)) + raise err +$$ LANGUAGE 'plpythonu' VOLATILE; + DO LANGUAGE 'plpgsql' $$ BEGIN DROP FUNCTION IF EXISTS cartodb._CDB_Group_API_Conf(); From 653eae21b332d30d944b9e53e986aa823a656864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 17 Aug 2015 15:20:15 +0200 Subject: [PATCH 38/88] _CDB_Group_RemoveMember_API --- scripts-available/CDB_Groups.sql | 1 + scripts-available/CDB_Groups_API.sql | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index a4244a7..b0b6d02 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -74,6 +74,7 @@ BEGIN cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); EXECUTE format('REVOKE "%s" FROM "%s"', cdb_group_role, cdb_user_role); + PERFORM cartodb._CDB_Group_RemoveMember_API(current_database(), group_name, username); END $$ LANGUAGE PLPGSQL VOLATILE; diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index bca575f..068fe2a 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -92,6 +92,28 @@ $$ raise err $$ LANGUAGE 'plpythonu' VOLATILE; +CREATE OR REPLACE +FUNCTION cartodb._CDB_Group_RemoveMember_API(database_name text, group_name text, username text) + RETURNS VOID AS +$$ + import httplib + import string + + try: + params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._CDB_Group_API_Conf() c;")[0] + if params['host'] is None: + return + + client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) + headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } + client.request('DELETE', '/api/v1/databases/%s/groups/%s/users/%s' % (database_name, group_name, username), '', headers) + response = client.getresponse() + assert response.status == 200 + except Exception as err: + plpy.warning('group creation error: ' + str(err)) + raise err +$$ LANGUAGE 'plpythonu' VOLATILE; + DO LANGUAGE 'plpgsql' $$ BEGIN DROP FUNCTION IF EXISTS cartodb._CDB_Group_API_Conf(); From 87a955b56aa15fdadfec8ddb084da5bb2ae9b048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 17 Aug 2015 15:23:39 +0200 Subject: [PATCH 39/88] Removed cdb_ prefix from local variables --- scripts-available/CDB_Groups.sql | 46 ++++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index b0b6d02..1fd3aef 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -49,16 +49,16 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_AddMember(group_name text, username text) RETURNS VOID AS $$ DECLARE - cdb_group_role TEXT; - cdb_user_role TEXT; + group_role TEXT; + user_role TEXT; BEGIN - cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); - IF(cdb_group_role IS NULL OR cdb_user_role IS NULL) + group_role := cartodb._CDB_Group_GroupRole(group_name); + 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', cdb_group_role, cdb_user_role; + RAISE EXCEPTION 'Group role (%) and user role (%) must be already existing', group_role, user_role; END IF; - EXECUTE format('GRANT "%s" TO "%s"', cdb_group_role, cdb_user_role); + EXECUTE format('GRANT "%s" TO "%s"', group_role, user_role); PERFORM cartodb._CDB_Group_AddMember_API(current_database(), group_name, username); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -68,12 +68,12 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_RemoveMember(group_name text, username text) RETURNS VOID AS $$ DECLARE - cdb_group_role TEXT; - cdb_user_role TEXT; + group_role TEXT; + user_role TEXT; BEGIN - cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); - EXECUTE format('REVOKE "%s" FROM "%s"', cdb_group_role, cdb_user_role); + group_role := cartodb._CDB_Group_GroupRole(group_name); + user_role := cartodb._CDB_User_RoleFromUsername(username); + EXECUTE format('REVOKE "%s" FROM "%s"', group_role, user_role); PERFORM cartodb._CDB_Group_RemoveMember_API(current_database(), group_name, username); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -83,11 +83,11 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_Table_GrantRead(group_name text, username text, table_name text) RETURNS VOID AS $$ DECLARE - cdb_group_role TEXT; + group_role TEXT; BEGIN - cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE format('GRANT USAGE ON SCHEMA "%s" TO "%s"', username, cdb_group_role); - EXECUTE format('GRANT SELECT ON TABLE "%s"."%s" TO "%s"', username, table_name, cdb_group_role ); + group_role := cartodb._CDB_Group_GroupRole(group_name); + EXECUTE format('GRANT USAGE ON SCHEMA "%s" TO "%s"', username, group_role); + EXECUTE format('GRANT SELECT ON TABLE "%s"."%s" TO "%s"', username, table_name, group_role ); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -96,11 +96,11 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_Table_GrantReadWrite(group_name text, username text, table_name text) RETURNS VOID AS $$ DECLARE - cdb_group_role TEXT; + group_role TEXT; BEGIN - cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE format('GRANT USAGE ON SCHEMA "%s" TO "%s"', username, cdb_group_role); - EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "%s"."%s" TO "%s"', username, table_name, cdb_group_role); + group_role := cartodb._CDB_Group_GroupRole(group_name); + EXECUTE format('GRANT USAGE ON SCHEMA "%s" TO "%s"', username, group_role); + EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "%s"."%s" TO "%s"', username, table_name, group_role); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -109,10 +109,10 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Group_Table_RevokeAll(group_name text, username text, table_name text) RETURNS VOID AS $$ DECLARE - cdb_group_role TEXT; + group_role TEXT; BEGIN - cdb_group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE format('REVOKE ALL ON TABLE "%s"."%s" FROM "%s"', username, table_name, cdb_group_role); + group_role := cartodb._CDB_Group_GroupRole(group_name); + EXECUTE format('REVOKE ALL ON TABLE "%s"."%s" FROM "%s"', username, table_name, group_role); END $$ LANGUAGE PLPGSQL VOLATILE; From 9d03e755b861252f709075dc0972478241b1070f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 18 Aug 2015 08:10:02 +0200 Subject: [PATCH 40/88] _CDB_Group_API_Request refactor --- scripts-available/CDB_Groups_API.sql | 123 +++++++++++---------------- 1 file changed, 50 insertions(+), 73 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 068fe2a..90d9f17 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -5,113 +5,58 @@ CREATE OR REPLACE FUNCTION cartodb._CDB_Group_CreateGroup_API(database_name text, group_name text, group_role text) RETURNS VOID AS $$ - import httplib import string - try: - params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._CDB_Group_API_Conf() c;")[0] - if params['host'] is None: - return - - client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) - body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role) - headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } - client.request('POST', '/api/v1/databases/%s/groups' % database_name, body, headers) - response = client.getresponse() - assert response.status == 200 - except Exception as err: - plpy.warning('group creation error: ' + str(err)) - raise err + url = '/api/v1/databases/%s/groups' % database_name + body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role) + query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s') as response_status" % (url, body) + plpy.execute(query)[0]['response_status'] $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE FUNCTION cartodb._CDB_Group_DropGroup_API(database_name text, group_name text) RETURNS VOID AS $$ - import httplib import string - try: - params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._CDB_Group_API_Conf() c;")[0] - if params['host'] is None: - return - - client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) - headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } - client.request('DELETE', '/api/v1/databases/%s/groups/%s' % (database_name, group_name), '', headers) - response = client.getresponse() - assert response.status == 200 - except Exception as err: - plpy.warning('group creation error: ' + str(err)) - raise err + url = '/api/v1/databases/%s/groups/%s' % (database_name, group_name) + query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '') as response_status" % url + plpy.execute(query)[0]['response_status'] $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE FUNCTION cartodb._CDB_Group_RenameGroup_API(database_name text, old_group_name text, new_group_name text, new_group_role text) RETURNS VOID AS $$ - import httplib import string - try: - params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._CDB_Group_API_Conf() c;")[0] - if params['host'] is None: - return - - client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) - body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role) - headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } - client.request('PUT', '/api/v1/databases/%s/groups/%s' % (database_name, old_group_name), body, headers) - response = client.getresponse() - assert response.status == 200 - except Exception as err: - plpy.warning('group creation error: ' + str(err)) - raise err + url = '/api/v1/databases/%s/groups/%s' % (database_name, old_group_name) + body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role) + query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s') as response_status" % (url, body) + plpy.execute(query)[0]['response_status'] $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE FUNCTION cartodb._CDB_Group_AddMember_API(database_name text, group_name text, username text) RETURNS VOID AS $$ - import httplib import string - try: - params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._CDB_Group_API_Conf() c;")[0] - if params['host'] is None: - return - - client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) - body = '{ "username": "%s" }' % username - headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } - client.request('POST', '/api/v1/databases/%s/groups/%s/users' % (database_name, group_name), body, headers) - response = client.getresponse() - assert response.status == 200 - except Exception as err: - plpy.warning('group creation error: ' + str(err)) - raise err + url = '/api/v1/databases/%s/groups/%s/users' % (database_name, group_name) + body = '{ "username": "%s" }' % username + query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s') as response_status" % (url, body) + plpy.execute(query)[0]['response_status'] $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE FUNCTION cartodb._CDB_Group_RemoveMember_API(database_name text, group_name text, username text) RETURNS VOID AS $$ - import httplib import string - try: - params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._CDB_Group_API_Conf() c;")[0] - if params['host'] is None: - return - - client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) - headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } - client.request('DELETE', '/api/v1/databases/%s/groups/%s/users/%s' % (database_name, group_name, username), '', headers) - response = client.getresponse() - assert response.status == 200 - except Exception as err: - plpy.warning('group creation error: ' + str(err)) - raise err + url = '/api/v1/databases/%s/groups/%s/users/%s' % (database_name, group_name, username) + query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '') as response_status" % url + plpy.execute(query)[0]['response_status'] $$ LANGUAGE 'plpythonu' VOLATILE; DO LANGUAGE 'plpgsql' $$ @@ -152,3 +97,35 @@ $$ import base64 base64.encodestring('%s:%s' % (username, password)).replace('\n', '') $$ LANGUAGE 'plpythonu' IMMUTABLE; + +CREATE OR REPLACE +FUNCTION cartodb._CDB_Group_API_Request(method text, url text, body text) + RETURNS int AS +$$ + import httplib + + params = plpy.execute("select c.host, c.port, c.timeout, c.auth from cartodb._CDB_Group_API_Conf() c;")[0] + if params['host'] is None: + return None + + client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) + headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } + + retry = 3 + + last_err = None + while retry > 0: + try: + client.request(method, url, body, headers) + response = client.getresponse() + assert response.status in [ 200, 409 ] + return response.status + except Exception as err: + retry -= 1 + last_err = err + plpy.warning('Retrying after: ' + str(err)) + + if last_err is not None: + plpy.error('Fatal Group API error: ' + str(last_err)) + raise last_err +$$ LANGUAGE 'plpythonu' VOLATILE; From d6410d91bd77a66ac7a9eb3d802bcfca16b7bac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 18 Aug 2015 08:24:30 +0200 Subject: [PATCH 41/88] Cache http client --- scripts-available/CDB_Groups_API.sql | 3 ++- test/organization/test.sh | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 90d9f17..08416a5 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -108,7 +108,6 @@ $$ if params['host'] is None: return None - client = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } retry = 3 @@ -116,6 +115,7 @@ $$ last_err = None while retry > 0: try: + client = GD['groups_api_client'] = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) client.request(method, url, body, headers) response = client.getresponse() assert response.status in [ 200, 409 ] @@ -124,6 +124,7 @@ $$ retry -= 1 last_err = err plpy.warning('Retrying after: ' + str(err)) + client = GD['groups_api_client'] = None if last_err is not None: plpy.error('Fatal Group API error: ' + str(last_err)) diff --git a/test/organization/test.sh b/test/organization/test.sh index abfc7a5..f0e41e6 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -173,8 +173,8 @@ function setup() { sql "SELECT cartodb.CDB_Organization_AddAdmin('cdb_org_admin');" create_role_and_schema cdb_testmember_1 create_role_and_schema cdb_testmember_2 - sql "CREATE ROLE publicuser LOGIN;" - sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" + #publicuser# sql "CREATE ROLE publicuser LOGIN;" + #publicuser# sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" create_table cdb_testmember_1 foo sql cdb_testmember_1 'INSERT INTO cdb_testmember_1.foo VALUES (1), (2), (3), (4), (5);' @@ -217,12 +217,12 @@ function tear_down() { sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_1;" sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_2;" - sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" + #publicuser# sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_org_admin;" sql 'DROP ROLE cdb_testmember_1;' sql 'DROP ROLE cdb_testmember_2;' - sql 'DROP ROLE publicuser;' + #publicuser# sql 'DROP ROLE publicuser;' sql 'DROP ROLE cdb_org_admin;' ${CMD} -c "DROP DATABASE ${DATABASE}" @@ -397,7 +397,7 @@ function test_cdb_querytables_does_not_return_functions_as_part_of_the_resultset sql postgres "select * from CDB_QueryTables('select * from cdb_testmember_1.foo, cdb_testmember_2.bar, plainto_tsquery(''foo'')');" should "{cdb_testmember_1.foo,cdb_testmember_2.bar}" } -function test_cdb_usertables_should_work_with_orgusers() { +function xtest_cdb_usertables_should_work_with_orgusers() { # This test validates the changes proposed in https://github.com/CartoDB/cartodb/pull/5021 @@ -528,6 +528,7 @@ function test_administrator_name_generation() { } function test_conf() { + sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should '' sql postgres "SELECT cartodb.CDB_Conf_SetConf('test_conf', 'test_val')" sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should 'test_val' sql postgres "SELECT cartodb.CDB_Conf_RemoveConf('test_conf')" From 1217b4e4a4d61b479e986218c7839963280dd457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 18 Aug 2015 08:27:14 +0200 Subject: [PATCH 42/88] Cache http client with private SD --- scripts-available/CDB_Groups_API.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 08416a5..d1c1ba4 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -115,7 +115,7 @@ $$ last_err = None while retry > 0: try: - client = GD['groups_api_client'] = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) + client = SD['groups_api_client'] = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) client.request(method, url, body, headers) response = client.getresponse() assert response.status in [ 200, 409 ] @@ -124,7 +124,7 @@ $$ retry -= 1 last_err = err plpy.warning('Retrying after: ' + str(err)) - client = GD['groups_api_client'] = None + client = SD['groups_api_client'] = None if last_err is not None: plpy.error('Fatal Group API error: ' + str(last_err)) From a75a3372964356d1768ab6038dd352eaee48b29f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 18 Aug 2015 10:44:10 +0200 Subject: [PATCH 43/88] _CDB_Conf_Cache SD-based --- scripts-available/CDB_Conf.sql | 25 ++++++++++++++++++++++++- scripts-available/CDB_Groups_API.sql | 12 +++++++----- test/organization/test.sh | 17 ++++++++++++----- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index 8f347d7..f685da3 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -19,6 +19,7 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Conf_RemoveConf(param text) RETURNS void AS $$ BEGIN + PERFORM cartodb._CDB_Conf_Cache('remove', param); EXECUTE 'DELETE FROM cartodb.CDB_CONF WHERE PARAM = $1;' USING param; END $$ LANGUAGE PLPGSQL VOLATILE; @@ -29,7 +30,29 @@ FUNCTION cartodb.CDB_Conf_GetConf(param text) DECLARE conf TEXT; BEGIN - EXECUTE 'SELECT CONF FROM cartodb.CDB_CONF WHERE PARAM = $1;' INTO conf USING param; + EXECUTE 'select cartodb._CDB_Conf_Cache(''get'', $1) as conf;' INTO conf USING param; RETURN conf; END $$ LANGUAGE PLPGSQL STABLE; + +-- Single cache function allowing SD private dict usage +CREATE OR REPLACE +FUNCTION cartodb._CDB_Conf_Cache(operation text, param text) + RETURNS TEXT AS +$$ + if 'conf' not in SD: + SD['conf'] = dict() + + if operation == 'remove': + SD['conf'][param] = None + elif operation == 'get': + if param not in SD['conf']: + value = None + response = plpy.execute("SELECT conf FROM cartodb.CDB_CONF WHERE PARAM = '%s'" % param); + if len(response) > 0: + value = response[0]['conf'] + SD['conf'][param] = value + return SD['conf'][param] + else: + raise Exception('Unknown operation: %s' % operation) +$$ LANGUAGE 'plpythonu' VOLATILE; diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index d1c1ba4..6a4416d 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -10,7 +10,7 @@ $$ url = '/api/v1/databases/%s/groups' % database_name body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role) query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s') as response_status" % (url, body) - plpy.execute(query)[0]['response_status'] + plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE @@ -21,7 +21,7 @@ $$ url = '/api/v1/databases/%s/groups/%s' % (database_name, group_name) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '') as response_status" % url - plpy.execute(query)[0]['response_status'] + plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE @@ -33,7 +33,7 @@ $$ url = '/api/v1/databases/%s/groups/%s' % (database_name, old_group_name) body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role) query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s') as response_status" % (url, body) - plpy.execute(query)[0]['response_status'] + plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE @@ -45,7 +45,7 @@ $$ url = '/api/v1/databases/%s/groups/%s/users' % (database_name, group_name) body = '{ "username": "%s" }' % username query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s') as response_status" % (url, body) - plpy.execute(query)[0]['response_status'] + plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE @@ -56,7 +56,7 @@ $$ url = '/api/v1/databases/%s/groups/%s/users/%s' % (database_name, group_name, username) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '') as response_status" % url - plpy.execute(query)[0]['response_status'] + plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; DO LANGUAGE 'plpgsql' $$ @@ -129,4 +129,6 @@ $$ if last_err is not None: plpy.error('Fatal Group API error: ' + str(last_err)) raise last_err + + return None $$ LANGUAGE 'plpythonu' VOLATILE; diff --git a/test/organization/test.sh b/test/organization/test.sh index f0e41e6..4277e6d 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -173,8 +173,8 @@ function setup() { sql "SELECT cartodb.CDB_Organization_AddAdmin('cdb_org_admin');" create_role_and_schema cdb_testmember_1 create_role_and_schema cdb_testmember_2 - #publicuser# sql "CREATE ROLE publicuser LOGIN;" - #publicuser# sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" + sql "CREATE ROLE publicuser LOGIN;" + sql "GRANT CONNECT ON DATABASE \"${DATABASE}\" TO publicuser;" create_table cdb_testmember_1 foo sql cdb_testmember_1 'INSERT INTO cdb_testmember_1.foo VALUES (1), (2), (3), (4), (5);' @@ -217,12 +217,12 @@ function tear_down() { sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_1;" sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_testmember_2;" - #publicuser# sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" + sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM publicuser;" sql "REVOKE CONNECT ON DATABASE \"${DATABASE}\" FROM cdb_org_admin;" sql 'DROP ROLE cdb_testmember_1;' sql 'DROP ROLE cdb_testmember_2;' - #publicuser# sql 'DROP ROLE publicuser;' + sql 'DROP ROLE publicuser;' sql 'DROP ROLE cdb_org_admin;' ${CMD} -c "DROP DATABASE ${DATABASE}" @@ -397,7 +397,7 @@ function test_cdb_querytables_does_not_return_functions_as_part_of_the_resultset sql postgres "select * from CDB_QueryTables('select * from cdb_testmember_1.foo, cdb_testmember_2.bar, plainto_tsquery(''foo'')');" should "{cdb_testmember_1.foo,cdb_testmember_2.bar}" } -function xtest_cdb_usertables_should_work_with_orgusers() { +function test_cdb_usertables_should_work_with_orgusers() { # This test validates the changes proposed in https://github.com/CartoDB/cartodb/pull/5021 @@ -529,10 +529,17 @@ function test_administrator_name_generation() { function test_conf() { sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should '' + sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf_2')" should '' + sql postgres "SELECT cartodb.CDB_Conf_SetConf('test_conf', 'test_val')" + sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should 'test_val' + sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf_2')" should '' + sql postgres "SELECT cartodb.CDB_Conf_RemoveConf('test_conf')" + sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should '' + sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf_2')" should '' } #################################################### TESTS END HERE #################################################### From a8b9ec345a1891439b31842954e362cb13d43b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 18 Aug 2015 11:53:38 +0200 Subject: [PATCH 44/88] valid_return_codes parameter --- scripts-available/CDB_Groups_API.sql | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 6a4416d..f91680f 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -9,7 +9,7 @@ $$ url = '/api/v1/databases/%s/groups' % database_name body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role) - query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s') as response_status" % (url, body) + query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; @@ -20,7 +20,7 @@ $$ import string url = '/api/v1/databases/%s/groups/%s' % (database_name, group_name) - query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '') as response_status" % url + query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; @@ -32,7 +32,7 @@ $$ url = '/api/v1/databases/%s/groups/%s' % (database_name, old_group_name) body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role) - query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s') as response_status" % (url, body) + query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200}') as response_status" % (url, body) plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; @@ -44,7 +44,7 @@ $$ url = '/api/v1/databases/%s/groups/%s/users' % (database_name, group_name) body = '{ "username": "%s" }' % username - query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s') as response_status" % (url, body) + query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; @@ -55,7 +55,7 @@ $$ import string url = '/api/v1/databases/%s/groups/%s/users/%s' % (database_name, group_name, username) - query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '') as response_status" % url + query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; @@ -99,7 +99,7 @@ $$ $$ LANGUAGE 'plpythonu' IMMUTABLE; CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_API_Request(method text, url text, body text) +FUNCTION cartodb._CDB_Group_API_Request(method text, url text, body text, valid_return_codes int[]) RETURNS int AS $$ import httplib @@ -118,7 +118,7 @@ $$ client = SD['groups_api_client'] = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) client.request(method, url, body, headers) response = client.getresponse() - assert response.status in [ 200, 409 ] + assert response.status in valid_return_codes return response.status except Exception as err: retry -= 1 From 67d7e28684c5c61fda62a95d05aa12bf0ca4bb47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 18 Aug 2015 13:26:23 +0200 Subject: [PATCH 45/88] 409 is a valid renaming response --- scripts-available/CDB_Groups_API.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index f91680f..6c3cdc2 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -32,7 +32,7 @@ $$ url = '/api/v1/databases/%s/groups/%s' % (database_name, old_group_name) body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role) - query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200}') as response_status" % (url, body) + query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; From 8a8d4b5b0049ef6c879173c533c039744e255050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Tue, 18 Aug 2015 16:09:34 +0200 Subject: [PATCH 46/88] Don't upgrade version until release is planned --- Makefile | 2 +- NEWS.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1720026..b0241fd 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # cartodb/Makefile EXTENSION = cartodb -EXTVERSION = 0.9.0 +EXTVERSION = 0.8.3 SED = sed diff --git a/NEWS.md b/NEWS.md index bb85419..e137502 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,4 @@ -0.9.0 (2015-mm-dd) +X.Y.Z (2015-mm-dd) ------------------ * Groups API From 0cb55d043aeb8a6f8db6f3f001fdbe8f26f07bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 19 Aug 2015 10:35:23 +0200 Subject: [PATCH 47/88] Revoke select on table and add security definer for conf getter --- scripts-available/CDB_Conf.sql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index f685da3..73d1424 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -2,7 +2,6 @@ DO LANGUAGE 'plpgsql' $$ BEGIN CREATE TABLE IF NOT EXISTS cartodb.CDB_CONF ( PARAM TEXT PRIMARY KEY, CONF TEXT NOT NULL ); - EXECUTE format('GRANT SELECT ON cartodb.CDB_CONF TO %s', cartodb.CDB_Organization_Member_Group_Role_Member_Name()); END $$; @@ -33,7 +32,7 @@ BEGIN EXECUTE 'select cartodb._CDB_Conf_Cache(''get'', $1) as conf;' INTO conf USING param; RETURN conf; END -$$ LANGUAGE PLPGSQL STABLE; +$$ LANGUAGE PLPGSQL STABLE SECURITY DEFINER; -- Single cache function allowing SD private dict usage CREATE OR REPLACE From 1fe9bb2e84fc1ce22c36605b6992cf9b0bbf555e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 19 Aug 2015 10:37:52 +0200 Subject: [PATCH 48/88] Don't allow users to pick database name, keeping group operations inside their org --- scripts-available/CDB_Groups.sql | 4 ++-- scripts-available/CDB_Groups_API.sql | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 1fd3aef..0d2b769 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -7,7 +7,7 @@ DECLARE BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); EXECUTE format('CREATE ROLE "%s" NOLOGIN;', group_role); - PERFORM cartodb._CDB_Group_CreateGroup_API(current_database(), group_name, group_role); + PERFORM cartodb._CDB_Group_CreateGroup_API(group_name, group_role); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -25,7 +25,7 @@ BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); EXECUTE format('DROP OWNED BY "%s"', group_role); EXECUTE format('DROP ROLE IF EXISTS "%s"', group_role); - PERFORM cartodb._CDB_Group_DropGroup_API(current_database(), group_name); + PERFORM cartodb._CDB_Group_DropGroup_API(group_name); END $$ LANGUAGE PLPGSQL VOLATILE; diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 6c3cdc2..9c16024 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -2,59 +2,59 @@ -- Sends the create group request CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_CreateGroup_API(database_name text, group_name text, group_role text) +FUNCTION cartodb._CDB_Group_CreateGroup_API(group_name text, group_role text) RETURNS VOID AS $$ import string - url = '/api/v1/databases/%s/groups' % database_name + url = '/api/v1/databases/%s/groups' body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role) query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_DropGroup_API(database_name text, group_name text) +FUNCTION cartodb._CDB_Group_DropGroup_API(group_name text) RETURNS VOID AS $$ import string - url = '/api/v1/databases/%s/groups/%s' % (database_name, group_name) + url = '/api/v1/databases/%s/groups/%s' % ('%s', group_name) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_RenameGroup_API(database_name text, old_group_name text, new_group_name text, new_group_role text) +FUNCTION cartodb._CDB_Group_RenameGroup_API(old_group_name text, new_group_name text, new_group_role text) RETURNS VOID AS $$ import string - url = '/api/v1/databases/%s/groups/%s' % (database_name, old_group_name) + url = '/api/v1/databases/%s/groups/%s' % ('%s', old_group_name) body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role) query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_AddMember_API(database_name text, group_name text, username text) +FUNCTION cartodb._CDB_Group_AddMember_API(group_name text, username text) RETURNS VOID AS $$ import string - url = '/api/v1/databases/%s/groups/%s/users' % (database_name, group_name) + url = '/api/v1/databases/%s/groups/%s/users' % ('%s', group_name) body = '{ "username": "%s" }' % username query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_RemoveMember_API(database_name text, group_name text, username text) +FUNCTION cartodb._CDB_Group_RemoveMember_API(group_name text, username text) RETURNS VOID AS $$ import string - url = '/api/v1/databases/%s/groups/%s/users/%s' % (database_name, group_name, username) + url = '/api/v1/databases/%s/groups/%s/users/%s' % ('%s', group_name, username) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE; @@ -116,7 +116,8 @@ $$ while retry > 0: try: client = SD['groups_api_client'] = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) - client.request(method, url, body, headers) + database_name = plpy.execute("select current_database();")[0]['current_database'] + client.request(method, url % database_name, body, headers) response = client.getresponse() assert response.status in valid_return_codes return response.status From 2245c05b1eabebee7c5bb1ecf38eb9173a22c9f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 19 Aug 2015 10:52:07 +0200 Subject: [PATCH 49/88] Don't allow users to pick database name, keeping group operations inside their org --- scripts-available/CDB_Groups.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 0d2b769..02da75f 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -40,7 +40,7 @@ BEGIN old_group_role = cartodb._CDB_Group_GroupRole(old_group_name); new_group_role = cartodb._CDB_Group_GroupRole(new_group_name); EXECUTE format('ALTER ROLE "%s" RENAME TO "%s"', old_group_role, new_group_role); - PERFORM cartodb._CDB_Group_RenameGroup_API(current_database(), old_group_name, new_group_name, new_group_role); + PERFORM cartodb._CDB_Group_RenameGroup_API(old_group_name, new_group_name, new_group_role); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -59,7 +59,7 @@ BEGIN RAISE EXCEPTION 'Group role (%) and user role (%) must be already existing', group_role, user_role; END IF; EXECUTE format('GRANT "%s" TO "%s"', group_role, user_role); - PERFORM cartodb._CDB_Group_AddMember_API(current_database(), group_name, username); + PERFORM cartodb._CDB_Group_AddMember_API(group_name, username); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -74,7 +74,7 @@ BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); user_role := cartodb._CDB_User_RoleFromUsername(username); EXECUTE format('REVOKE "%s" FROM "%s"', group_role, user_role); - PERFORM cartodb._CDB_Group_RemoveMember_API(current_database(), group_name, username); + PERFORM cartodb._CDB_Group_RemoveMember_API(group_name, username); END $$ LANGUAGE PLPGSQL VOLATILE; From 726f3c31f79794f6c53eef3d4eb9e069cd6a44e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 19 Aug 2015 11:03:07 +0200 Subject: [PATCH 50/88] Documentation about roles and functions --- scripts-available/CDB_Groups.sql | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 02da75f..220f403 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -1,3 +1,9 @@ +---------------------------------- +-- GROUP MANAGEMENT FUNCTIONS +-- +-- Meant to be used by org admin. See CDB_Organization_AddAdmin. +---------------------------------- + -- Creates a new group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_CreateGroup(group_name text) @@ -78,6 +84,12 @@ BEGIN END $$ LANGUAGE PLPGSQL VOLATILE; +---------------------------------- +-- TABLE MANAGEMENT FUNCTIONS +-- +-- Meant to be used by table owners. +---------------------------------- + -- Grants table read permission to a group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_Table_GrantRead(group_name text, username text, table_name text) @@ -117,7 +129,7 @@ END $$ LANGUAGE PLPGSQL VOLATILE; ----------------------- --- Private functions +-- Helper functions ----------------------- -- 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 CREATE OR REPLACE From 6c1369f2a9589b0f4301c2aad3b15608b5e2f802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 19 Aug 2015 11:05:32 +0200 Subject: [PATCH 51/88] Documentation about roles and functions --- scripts-available/CDB_Groups_API.sql | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 9c16024..5087ac7 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -1,4 +1,9 @@ +---------------------------------- +-- GROUP METADATA API FUNCTIONS +-- +-- Meant to be used by CDB_Group_* functions to sync data with the editor. -- Requires configuration parameter. Example: SELECT cartodb.CDB_Conf_SetConf('groups_api', '{ "host": "127.0.0.1", "port": 3000, "timeout": 10, "username": "superadmin", "password": "monkey" }'); +---------------------------------- -- Sends the create group request CREATE OR REPLACE From e1dde3c36c0480c9163f6886ae59d84853b203c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 19 Aug 2015 11:08:05 +0200 Subject: [PATCH 52/88] Removed old code --- scripts-available/CDB_Groups_API.sql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 5087ac7..4a1c9bb 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -66,7 +66,6 @@ $$ LANGUAGE 'plpythonu' VOLATILE; DO LANGUAGE 'plpgsql' $$ BEGIN - DROP FUNCTION IF EXISTS cartodb._CDB_Group_API_Conf(); DROP TYPE IF EXISTS _CDB_Group_API_Params; END $$; @@ -92,7 +91,6 @@ $$ params = json.loads(conf) auth = 'Basic %s' % plpy.execute("SELECT cartodb._CDB_Group_API_Auth('%s', '%s') as auth" % (params['username'], params['password']))[0]['auth'] return { "host": params['host'], "port": params['port'], 'timeout': params['timeout'], 'auth': auth } - # return params $$ LANGUAGE 'plpythonu' VOLATILE; CREATE OR REPLACE @@ -103,6 +101,7 @@ $$ base64.encodestring('%s:%s' % (username, password)).replace('\n', '') $$ LANGUAGE 'plpythonu' IMMUTABLE; +-- url must contain a '%s' placeholder that will be replaced by current_database, for security reasons. CREATE OR REPLACE FUNCTION cartodb._CDB_Group_API_Request(method text, url text, body text, valid_return_codes int[]) RETURNS int AS From 70fe432102539991a750eee5b9dc71a9628a232f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 19 Aug 2015 11:20:06 +0200 Subject: [PATCH 53/88] Secured configuration access --- scripts-available/CDB_Conf.sql | 9 ++++++++- scripts-available/CDB_Groups_API.sql | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index 73d1424..196f11d 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -1,3 +1,10 @@ +---------------------------------- +-- CONF MANAGEMENT FUNCTIONS +-- +-- Meant to be used by superadmin user. +-- Functions needing reading configuration should use SECURITY DEFINER. +---------------------------------- + -- This will trigger NOTICE if CDB_CONF already exists DO LANGUAGE 'plpgsql' $$ BEGIN @@ -32,7 +39,7 @@ BEGIN EXECUTE 'select cartodb._CDB_Conf_Cache(''get'', $1) as conf;' INTO conf USING param; RETURN conf; END -$$ LANGUAGE PLPGSQL STABLE SECURITY DEFINER; +$$ LANGUAGE PLPGSQL STABLE; -- Single cache function allowing SD private dict usage CREATE OR REPLACE diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 4a1c9bb..d36550e 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -66,6 +66,8 @@ $$ LANGUAGE 'plpythonu' VOLATILE; DO LANGUAGE 'plpgsql' $$ BEGIN + -- Needed for dropping type + DROP FUNCTION IF EXISTS cartodb._CDB_Group_API_Conf(); DROP TYPE IF EXISTS _CDB_Group_API_Params; END $$; @@ -136,4 +138,4 @@ $$ raise last_err return None -$$ LANGUAGE 'plpythonu' VOLATILE; +$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; From 75c4308ea9de5f1f0a3f0df50b4118663c9bb4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 19 Aug 2015 18:43:25 +0200 Subject: [PATCH 54/88] Grant and revoking permissions API sync --- scripts-available/CDB_Groups.sql | 5 +++- scripts-available/CDB_Groups_API.sql | 39 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 220f403..42e89da 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -100,6 +100,7 @@ BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); EXECUTE format('GRANT USAGE ON SCHEMA "%s" TO "%s"', username, group_role); EXECUTE format('GRANT SELECT ON TABLE "%s"."%s" TO "%s"', username, table_name, group_role ); + PERFORM cartodb._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'r'); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -113,6 +114,7 @@ BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); EXECUTE format('GRANT USAGE ON SCHEMA "%s" TO "%s"', username, group_role); EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "%s"."%s" TO "%s"', username, table_name, group_role); + PERFORM cartodb._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'w'); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -125,6 +127,7 @@ DECLARE BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); EXECUTE format('REVOKE ALL ON TABLE "%s"."%s" FROM "%s"', username, table_name, group_role); + PERFORM cartodb._CDB_Group_Table_RevokeAllPermission_API(group_name, username, table_name); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -158,7 +161,7 @@ DECLARE user_role TEXT; BEGIN -- This was preferred, but non-superadmins won't get results - --EXECUTE 'SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $1 LIMIT 1' INTO user_role USING username; + -- SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $1 LIMIT 1' EXECUTE 'SELECT pg_get_userbyid(nspowner) FROM pg_namespace WHERE nspname = $1;' INTO user_role USING username; RETURN user_role; END diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index d36550e..a7669c0 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -72,6 +72,45 @@ BEGIN END $$; +CREATE OR REPLACE +FUNCTION cartodb._CDB_Group_Table_GrantPermission_API(group_name text, username text, table_name text, access text) + RETURNS VOID AS +$$ + import string + + url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', group_name, username, table_name) + body = '{ "access": "%s" }' % access + query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body) + plpy.execute(query) +$$ LANGUAGE 'plpythonu' VOLATILE; + +DO LANGUAGE 'plpgsql' $$ +BEGIN + -- Needed for dropping type + DROP FUNCTION IF EXISTS cartodb._CDB_Group_API_Conf(); + DROP TYPE IF EXISTS _CDB_Group_API_Params; +END +$$; + +CREATE OR REPLACE +FUNCTION cartodb._CDB_Group_Table_RevokeAllPermission_API(group_name text, username text, table_name text) + RETURNS VOID AS +$$ + import string + + url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', group_name, username, table_name) + query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url + plpy.execute(query) +$$ LANGUAGE 'plpythonu' VOLATILE; + +DO LANGUAGE 'plpgsql' $$ +BEGIN + -- Needed for dropping type + DROP FUNCTION IF EXISTS cartodb._CDB_Group_API_Conf(); + DROP TYPE IF EXISTS _CDB_Group_API_Params; +END +$$; + CREATE TYPE _CDB_Group_API_Params AS ( host text, port int, From 97dd8e572048a8c2d630881d8118d139028e3e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 20 Aug 2015 08:44:59 +0200 Subject: [PATCH 55/88] Conf value type to json --- scripts-available/CDB_Conf.sql | 43 ++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index 196f11d..2948df1 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -8,57 +8,60 @@ -- This will trigger NOTICE if CDB_CONF already exists DO LANGUAGE 'plpgsql' $$ BEGIN - CREATE TABLE IF NOT EXISTS cartodb.CDB_CONF ( PARAM TEXT PRIMARY KEY, CONF TEXT NOT NULL ); + CREATE TABLE IF NOT EXISTS cartodb.CDB_CONF ( KEY TEXT PRIMARY KEY, VALUE JSON NOT NULL ); END $$; CREATE OR REPLACE -FUNCTION cartodb.CDB_Conf_SetConf(param text, conf text) +FUNCTION cartodb.CDB_Conf_SetConf(key TEXT, value JSON) RETURNS void AS $$ BEGIN - PERFORM cartodb.CDB_Conf_RemoveConf(param); - EXECUTE 'INSERT INTO cartodb.CDB_CONF (PARAM, CONF) VALUES ($1, $2);' USING param, conf; + PERFORM cartodb.CDB_Conf_RemoveConf(key); + EXECUTE 'INSERT INTO cartodb.CDB_CONF (KEY, VALUE) VALUES ($1, $2);' USING key, value; END $$ LANGUAGE PLPGSQL VOLATILE; CREATE OR REPLACE -FUNCTION cartodb.CDB_Conf_RemoveConf(param text) +FUNCTION cartodb.CDB_Conf_RemoveConf(key text) RETURNS void AS $$ BEGIN - PERFORM cartodb._CDB_Conf_Cache('remove', param); - EXECUTE 'DELETE FROM cartodb.CDB_CONF WHERE PARAM = $1;' USING param; + PERFORM cartodb._CDB_Conf_Cache('remove', key); + EXECUTE 'DELETE FROM cartodb.CDB_CONF WHERE KEY = $1;' USING key; END $$ LANGUAGE PLPGSQL VOLATILE; CREATE OR REPLACE -FUNCTION cartodb.CDB_Conf_GetConf(param text) - RETURNS TEXT AS $$ +FUNCTION cartodb.CDB_Conf_GetConf(key text) + RETURNS JSON AS $$ DECLARE - conf TEXT; + value JSON; BEGIN - EXECUTE 'select cartodb._CDB_Conf_Cache(''get'', $1) as conf;' INTO conf USING param; - RETURN conf; + EXECUTE 'select cartodb._CDB_Conf_Cache(''get'', $1);' INTO value USING key; + RETURN value; END $$ LANGUAGE PLPGSQL STABLE; -- Single cache function allowing SD private dict usage CREATE OR REPLACE -FUNCTION cartodb._CDB_Conf_Cache(operation text, param text) - RETURNS TEXT AS +FUNCTION cartodb._CDB_Conf_Cache(operation text, key text) + RETURNS JSON AS $$ if 'conf' not in SD: SD['conf'] = dict() if operation == 'remove': - SD['conf'][param] = None + if key in SD['conf']: + del(SD['conf'][key]) elif operation == 'get': - if param not in SD['conf']: + if key not in SD['conf'] or SD['conf'][key] == None: value = None - response = plpy.execute("SELECT conf FROM cartodb.CDB_CONF WHERE PARAM = '%s'" % param); + # Execute returns string, not json :( + response = plpy.execute("SELECT value FROM cartodb.CDB_CONF WHERE KEY = '%s'" % key); if len(response) > 0: - value = response[0]['conf'] - SD['conf'][param] = value - return SD['conf'][param] + import json + value = response[0]['value'] + SD['conf'][key] = value + return SD['conf'][key] else: raise Exception('Unknown operation: %s' % operation) $$ LANGUAGE 'plpythonu' VOLATILE; From 551e09ff6f632c9c90a55d934104140f529d11e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 20 Aug 2015 10:03:48 +0200 Subject: [PATCH 56/88] Secured _CDB_Group_API_Request --- scripts-available/CDB_Groups_API.sql | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index a7669c0..ace1ec4 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -16,7 +16,7 @@ $$ body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role) query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) -$$ LANGUAGE 'plpythonu' VOLATILE; +$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; CREATE OR REPLACE FUNCTION cartodb._CDB_Group_DropGroup_API(group_name text) @@ -27,7 +27,7 @@ $$ url = '/api/v1/databases/%s/groups/%s' % ('%s', group_name) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) -$$ LANGUAGE 'plpythonu' VOLATILE; +$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; CREATE OR REPLACE FUNCTION cartodb._CDB_Group_RenameGroup_API(old_group_name text, new_group_name text, new_group_role text) @@ -39,7 +39,7 @@ $$ body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role) query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) -$$ LANGUAGE 'plpythonu' VOLATILE; +$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; CREATE OR REPLACE FUNCTION cartodb._CDB_Group_AddMember_API(group_name text, username text) @@ -51,7 +51,7 @@ $$ body = '{ "username": "%s" }' % username query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) -$$ LANGUAGE 'plpythonu' VOLATILE; +$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; CREATE OR REPLACE FUNCTION cartodb._CDB_Group_RemoveMember_API(group_name text, username text) @@ -62,7 +62,7 @@ $$ url = '/api/v1/databases/%s/groups/%s/users/%s' % ('%s', group_name, username) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) -$$ LANGUAGE 'plpythonu' VOLATILE; +$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; DO LANGUAGE 'plpgsql' $$ BEGIN @@ -82,7 +82,7 @@ $$ body = '{ "access": "%s" }' % access query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) -$$ LANGUAGE 'plpythonu' VOLATILE; +$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; DO LANGUAGE 'plpgsql' $$ BEGIN @@ -101,7 +101,7 @@ $$ url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', group_name, username, table_name) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) -$$ LANGUAGE 'plpythonu' VOLATILE; +$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; DO LANGUAGE 'plpgsql' $$ BEGIN @@ -177,4 +177,5 @@ $$ raise last_err return None -$$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; +$$ LANGUAGE 'plpythonu' VOLATILE; +revoke all on function cartodb._CDB_Group_API_Request(text, text, text, int[]) from public; From eb912b48bf052fb5c5a08d2e10a080c5328ef494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 20 Aug 2015 10:22:44 +0200 Subject: [PATCH 57/88] Removed not needed json import --- scripts-available/CDB_Conf.sql | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index 2948df1..f6aa7fa 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -58,7 +58,6 @@ $$ # Execute returns string, not json :( response = plpy.execute("SELECT value FROM cartodb.CDB_CONF WHERE KEY = '%s'" % key); if len(response) > 0: - import json value = response[0]['value'] SD['conf'][key] = value return SD['conf'][key] From 600f9159fb99637da433318cebc61aee0bd2a1e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 20 Aug 2015 10:25:31 +0200 Subject: [PATCH 58/88] {} >> dict() --- scripts-available/CDB_Conf.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index f6aa7fa..7c9e3e8 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -47,7 +47,7 @@ FUNCTION cartodb._CDB_Conf_Cache(operation text, key text) RETURNS JSON AS $$ if 'conf' not in SD: - SD['conf'] = dict() + SD['conf'] = {} if operation == 'remove': if key in SD['conf']: From a885f5328e1f02706242853e92f59110d3535828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 20 Aug 2015 10:45:24 +0200 Subject: [PATCH 59/88] Fix conf tests (json values) --- test/organization/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/organization/test.sh b/test/organization/test.sh index 4277e6d..56a5b0d 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -531,9 +531,9 @@ function test_conf() { sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should '' sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf_2')" should '' - sql postgres "SELECT cartodb.CDB_Conf_SetConf('test_conf', 'test_val')" + sql postgres "SELECT cartodb.CDB_Conf_SetConf('test_conf', '{ \"a_key\": \"test_val\" }')" - sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should 'test_val' + sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf')" should '{ "a_key": "test_val" }' sql postgres "SELECT cartodb.CDB_Conf_GetConf('test_conf_2')" should '' sql postgres "SELECT cartodb.CDB_Conf_RemoveConf('test_conf')" From bd31419e94e7ff2d2d914aa7e6494ddd49feb631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 20 Aug 2015 12:54:46 +0200 Subject: [PATCH 60/88] Fixed return auth --- scripts-available/CDB_Groups_API.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index ace1ec4..ec01798 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -139,8 +139,8 @@ FUNCTION cartodb._CDB_Group_API_Auth(username text, password text) RETURNS TEXT AS $$ import base64 - base64.encodestring('%s:%s' % (username, password)).replace('\n', '') -$$ LANGUAGE 'plpythonu' IMMUTABLE; + return base64.encodestring('%s:%s' % (username, password)).replace('\n', '') +$$ LANGUAGE 'plpythonu' VOLATILE; -- url must contain a '%s' placeholder that will be replaced by current_database, for security reasons. CREATE OR REPLACE From 43d41e5c26725ef4023544910bc1a696afc13c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 20 Aug 2015 12:55:22 +0200 Subject: [PATCH 61/88] Removed cached (won't work between sessions) --- scripts-available/CDB_Conf.sql | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index 7c9e3e8..77cf758 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -13,11 +13,11 @@ END $$; CREATE OR REPLACE -FUNCTION cartodb.CDB_Conf_SetConf(key TEXT, value JSON) +FUNCTION cartodb.CDB_Conf_SetConf(key text, value JSON) RETURNS void AS $$ BEGIN PERFORM cartodb.CDB_Conf_RemoveConf(key); - EXECUTE 'INSERT INTO cartodb.CDB_CONF (KEY, VALUE) VALUES ($1, $2);' USING key, value; + EXECUTE 'INSERT INTO CDB_CONF (KEY, VALUE) VALUES ($1, $2);' USING key, value; END $$ LANGUAGE PLPGSQL VOLATILE; @@ -25,8 +25,7 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Conf_RemoveConf(key text) RETURNS void AS $$ BEGIN - PERFORM cartodb._CDB_Conf_Cache('remove', key); - EXECUTE 'DELETE FROM cartodb.CDB_CONF WHERE KEY = $1;' USING key; + EXECUTE 'DELETE FROM CDB_CONF WHERE KEY = $1;' USING key; END $$ LANGUAGE PLPGSQL VOLATILE; @@ -36,31 +35,7 @@ FUNCTION cartodb.CDB_Conf_GetConf(key text) DECLARE value JSON; BEGIN - EXECUTE 'select cartodb._CDB_Conf_Cache(''get'', $1);' INTO value USING key; + EXECUTE 'SELECT VALUE FROM CDB_CONF WHERE KEY = $1;' INTO value USING key; RETURN value; END $$ LANGUAGE PLPGSQL STABLE; - --- Single cache function allowing SD private dict usage -CREATE OR REPLACE -FUNCTION cartodb._CDB_Conf_Cache(operation text, key text) - RETURNS JSON AS -$$ - if 'conf' not in SD: - SD['conf'] = {} - - if operation == 'remove': - if key in SD['conf']: - del(SD['conf'][key]) - elif operation == 'get': - if key not in SD['conf'] or SD['conf'][key] == None: - value = None - # Execute returns string, not json :( - response = plpy.execute("SELECT value FROM cartodb.CDB_CONF WHERE KEY = '%s'" % key); - if len(response) > 0: - value = response[0]['value'] - SD['conf'][key] = value - return SD['conf'][key] - else: - raise Exception('Unknown operation: %s' % operation) -$$ LANGUAGE 'plpythonu' VOLATILE; From 66e2082266bd12c006189ab08e4ee5430a4e29b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 20 Aug 2015 13:02:02 +0200 Subject: [PATCH 62/88] Missing cartodb schema --- scripts-available/CDB_Conf.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index 77cf758..55059f3 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -5,7 +5,7 @@ -- Functions needing reading configuration should use SECURITY DEFINER. ---------------------------------- --- This will trigger NOTICE if CDB_CONF already exists +-- This will trigger NOTICE if cartodb.CDB_CONF already exists DO LANGUAGE 'plpgsql' $$ BEGIN CREATE TABLE IF NOT EXISTS cartodb.CDB_CONF ( KEY TEXT PRIMARY KEY, VALUE JSON NOT NULL ); @@ -17,7 +17,7 @@ FUNCTION cartodb.CDB_Conf_SetConf(key text, value JSON) RETURNS void AS $$ BEGIN PERFORM cartodb.CDB_Conf_RemoveConf(key); - EXECUTE 'INSERT INTO CDB_CONF (KEY, VALUE) VALUES ($1, $2);' USING key, value; + EXECUTE 'INSERT INTO cartodb.CDB_CONF (KEY, VALUE) VALUES ($1, $2);' USING key, value; END $$ LANGUAGE PLPGSQL VOLATILE; @@ -25,7 +25,7 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Conf_RemoveConf(key text) RETURNS void AS $$ BEGIN - EXECUTE 'DELETE FROM CDB_CONF WHERE KEY = $1;' USING key; + EXECUTE 'DELETE FROM cartodb.CDB_CONF WHERE KEY = $1;' USING key; END $$ LANGUAGE PLPGSQL VOLATILE; @@ -35,7 +35,7 @@ FUNCTION cartodb.CDB_Conf_GetConf(key text) DECLARE value JSON; BEGIN - EXECUTE 'SELECT VALUE FROM CDB_CONF WHERE KEY = $1;' INTO value USING key; + EXECUTE 'SELECT VALUE FROM cartodb.CDB_CONF WHERE KEY = $1;' INTO value USING key; RETURN value; END $$ LANGUAGE PLPGSQL STABLE; From faa4f203d69b5e5c85a05405b466775d84cc4d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 20 Aug 2015 17:32:36 +0200 Subject: [PATCH 63/88] Changed sample config --- scripts-available/CDB_Groups_API.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index ec01798..595a5d5 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -2,7 +2,7 @@ -- GROUP METADATA API FUNCTIONS -- -- Meant to be used by CDB_Group_* functions to sync data with the editor. --- Requires configuration parameter. Example: SELECT cartodb.CDB_Conf_SetConf('groups_api', '{ "host": "127.0.0.1", "port": 3000, "timeout": 10, "username": "superadmin", "password": "monkey" }'); +-- Requires configuration parameter. Example: SELECT cartodb.CDB_Conf_SetConf('groups_api', '{ "host": "127.0.0.1", "port": 3000, "timeout": 10, "username": "extension", "password": "elephant" }'); ---------------------------------- -- Sends the create group request From c6fa292f01c5516e073847e23d2af83672bb8a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 20 Aug 2015 17:39:28 +0200 Subject: [PATCH 64/88] Extension installation ready --- scripts-available/CDB_Conf.sql | 1 + scripts-enabled/CDB_Conf.sql | 1 + scripts-enabled/CDB_Groups.sql | 1 + scripts-enabled/CDB_Groups_API.sql | 1 + 4 files changed, 4 insertions(+) create mode 120000 scripts-enabled/CDB_Conf.sql create mode 120000 scripts-enabled/CDB_Groups.sql create mode 120000 scripts-enabled/CDB_Groups_API.sql diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index 55059f3..d2dfea1 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -9,6 +9,7 @@ DO LANGUAGE 'plpgsql' $$ BEGIN CREATE TABLE IF NOT EXISTS cartodb.CDB_CONF ( KEY TEXT PRIMARY KEY, VALUE JSON NOT NULL ); + PERFORM pg_catalog.pg_extension_config_dump('cartodb.CDB_CONF', ''); END $$; diff --git a/scripts-enabled/CDB_Conf.sql b/scripts-enabled/CDB_Conf.sql new file mode 120000 index 0000000..19578a9 --- /dev/null +++ b/scripts-enabled/CDB_Conf.sql @@ -0,0 +1 @@ +../scripts-available/CDB_Conf.sql \ No newline at end of file diff --git a/scripts-enabled/CDB_Groups.sql b/scripts-enabled/CDB_Groups.sql new file mode 120000 index 0000000..63d80a7 --- /dev/null +++ b/scripts-enabled/CDB_Groups.sql @@ -0,0 +1 @@ +../scripts-available/CDB_Groups.sql \ No newline at end of file diff --git a/scripts-enabled/CDB_Groups_API.sql b/scripts-enabled/CDB_Groups_API.sql new file mode 120000 index 0000000..2a80d8e --- /dev/null +++ b/scripts-enabled/CDB_Groups_API.sql @@ -0,0 +1 @@ +../scripts-available/CDB_Groups_API.sql \ No newline at end of file From 1f67b52bf7aa58358dac7b3871733f0dd7d1f10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 26 Aug 2015 13:23:32 +0200 Subject: [PATCH 65/88] Documented the need for create extension and separated from cdb_conf creation --- scripts-available/CDB_Conf.sql | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts-available/CDB_Conf.sql b/scripts-available/CDB_Conf.sql index d2dfea1..8206309 100644 --- a/scripts-available/CDB_Conf.sql +++ b/scripts-available/CDB_Conf.sql @@ -9,6 +9,12 @@ DO LANGUAGE 'plpgsql' $$ BEGIN CREATE TABLE IF NOT EXISTS cartodb.CDB_CONF ( KEY TEXT PRIMARY KEY, VALUE JSON NOT NULL ); +END +$$; + +-- This can only be called from an SQL script executed by CREATE EXTENSION +DO LANGUAGE 'plpgsql' $$ +BEGIN PERFORM pg_catalog.pg_extension_config_dump('cartodb.CDB_CONF', ''); END $$; From a4952f6a1e2b009f1e960725c332684a0c6297f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 26 Aug 2015 13:33:01 +0200 Subject: [PATCH 66/88] Granting RW permission on a table should also grant permission on default values sequences --- scripts-available/CDB_Groups.sql | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 42e89da..1cf7686 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -114,10 +114,36 @@ BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); EXECUTE format('GRANT USAGE ON SCHEMA "%s" TO "%s"', username, group_role); EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "%s"."%s" TO "%s"', username, table_name, group_role); + PERFORM cartodb._CDB_Group_TableSequences_Permission(group_name, username, table_name, true); PERFORM cartodb._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'w'); END $$ LANGUAGE PLPGSQL VOLATILE; +-- 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 + EXECUTE 'SELECT PG_GET_SERIAL_SEQUENCE($1, $2)' USING table_name, column_name INTO sequence_name; + IF sequence_name IS NOT NULL THEN + IF do_grant THEN + EXECUTE format('GRANT USAGE, SELECT, UPDATE ON SEQUENCE %s TO "%s"', sequence_name, group_role); + ELSE + EXECUTE format('REVOKE ALL ON SEQUENCE %s FROM "%s"', sequence_name, group_role); + END IF; + END IF; + END LOOP; + RETURN; +END +$$ LANGUAGE PLPGSQL VOLATILE; + -- Revokes all permissions on a table from a group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_Table_RevokeAll(group_name text, username text, table_name text) @@ -127,6 +153,7 @@ DECLARE BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); EXECUTE format('REVOKE ALL ON TABLE "%s"."%s" FROM "%s"', username, table_name, group_role); + PERFORM cartodb._CDB_Group_TableSequences_Permission(group_name, username, table_name, false); PERFORM cartodb._CDB_Group_Table_RevokeAllPermission_API(group_name, username, table_name); END $$ LANGUAGE PLPGSQL VOLATILE; From fc32d457eb3b60ca7cb5b411f1664d2aae05cdd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 27 Aug 2015 10:25:52 +0200 Subject: [PATCH 67/88] String interpolation with %I, which includes quoting --- scripts-available/CDB_Groups.sql | 26 ++++++++++++------------- scripts-available/CDB_Organizations.sql | 10 +++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 1cf7686..756775a 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -12,7 +12,7 @@ DECLARE group_role TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE format('CREATE ROLE "%s" NOLOGIN;', group_role); + EXECUTE format('CREATE ROLE %I NOLOGIN;', group_role); PERFORM cartodb._CDB_Group_CreateGroup_API(group_name, group_role); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -29,8 +29,8 @@ DECLARE group_role TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE format('DROP OWNED BY "%s"', group_role); - EXECUTE format('DROP ROLE IF EXISTS "%s"', group_role); + EXECUTE format('DROP OWNED BY %I', group_role); + EXECUTE format('DROP ROLE IF EXISTS %I', group_role); PERFORM cartodb._CDB_Group_DropGroup_API(group_name); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -45,7 +45,7 @@ DECLARE BEGIN old_group_role = cartodb._CDB_Group_GroupRole(old_group_name); new_group_role = cartodb._CDB_Group_GroupRole(new_group_name); - EXECUTE format('ALTER ROLE "%s" RENAME TO "%s"', old_group_role, new_group_role); + EXECUTE format('ALTER ROLE %I RENAME TO %I', old_group_role, new_group_role); PERFORM cartodb._CDB_Group_RenameGroup_API(old_group_name, new_group_name, new_group_role); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -64,7 +64,7 @@ BEGIN THEN RAISE EXCEPTION 'Group role (%) and user role (%) must be already existing', group_role, user_role; END IF; - EXECUTE format('GRANT "%s" TO "%s"', group_role, user_role); + EXECUTE format('GRANT %I TO %I', group_role, user_role); PERFORM cartodb._CDB_Group_AddMember_API(group_name, username); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -79,7 +79,7 @@ DECLARE BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); user_role := cartodb._CDB_User_RoleFromUsername(username); - EXECUTE format('REVOKE "%s" FROM "%s"', group_role, user_role); + EXECUTE format('REVOKE %I FROM %I', group_role, user_role); PERFORM cartodb._CDB_Group_RemoveMember_API(group_name, username); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -98,8 +98,8 @@ DECLARE group_role TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE format('GRANT USAGE ON SCHEMA "%s" TO "%s"', username, group_role); - EXECUTE format('GRANT SELECT ON TABLE "%s"."%s" TO "%s"', username, table_name, group_role ); + 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 ); PERFORM cartodb._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'r'); END $$ LANGUAGE PLPGSQL VOLATILE; @@ -112,8 +112,8 @@ DECLARE group_role TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE format('GRANT USAGE ON SCHEMA "%s" TO "%s"', username, group_role); - EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "%s"."%s" TO "%s"', username, table_name, group_role); + 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); PERFORM cartodb._CDB_Group_TableSequences_Permission(group_name, username, table_name, true); PERFORM cartodb._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'w'); END @@ -134,9 +134,9 @@ BEGIN EXECUTE 'SELECT PG_GET_SERIAL_SEQUENCE($1, $2)' USING table_name, column_name INTO sequence_name; IF sequence_name IS NOT NULL THEN IF do_grant THEN - EXECUTE format('GRANT USAGE, SELECT, UPDATE ON SEQUENCE %s TO "%s"', sequence_name, group_role); + EXECUTE format('GRANT USAGE, SELECT, UPDATE ON SEQUENCE %I TO %I', sequence_name, group_role); ELSE - EXECUTE format('REVOKE ALL ON SEQUENCE %s FROM "%s"', sequence_name, group_role); + EXECUTE format('REVOKE ALL ON SEQUENCE %I FROM %I', sequence_name, group_role); END IF; END IF; END LOOP; @@ -152,7 +152,7 @@ DECLARE group_role TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); - EXECUTE format('REVOKE ALL ON TABLE "%s"."%s" FROM "%s"', username, table_name, group_role); + EXECUTE format('REVOKE ALL ON TABLE %I.%I FROM %I', username, table_name, group_role); PERFORM cartodb._CDB_Group_TableSequences_Permission(group_name, username, table_name, false); PERFORM cartodb._CDB_Group_Table_RevokeAllPermission_API(group_name, username, table_name); END diff --git a/scripts-available/CDB_Organizations.sql b/scripts-available/CDB_Organizations.sql index a47c78d..ab2bbb6 100644 --- a/scripts-available/CDB_Organizations.sql +++ b/scripts-available/CDB_Organizations.sql @@ -42,7 +42,7 @@ BEGIN cdb_org_admin_role_name := cartodb._CDB_Organization_Admin_Role_Name(); IF NOT EXISTS ( SELECT * FROM pg_roles WHERE rolname= cdb_org_admin_role_name ) THEN - EXECUTE format('CREATE ROLE "%s" CREATEROLE NOLOGIN;', cdb_org_admin_role_name); + EXECUTE format('CREATE ROLE %I CREATEROLE NOLOGIN;', cdb_org_admin_role_name); END IF; END $$; @@ -57,9 +57,9 @@ DECLARE BEGIN cdb_admin_role := cartodb._CDB_Organization_Admin_Role_Name(); cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); - EXECUTE format('GRANT "%s" TO "%s" WITH ADMIN OPTION', cdb_admin_role, cdb_user_role); + EXECUTE format('GRANT %I TO %I WITH ADMIN OPTION', cdb_admin_role, cdb_user_role); -- CREATEROLE is not inherited, and is needed for user creation - EXECUTE format('ALTER ROLE "%s" CREATEROLE', cdb_user_role); + EXECUTE format('ALTER ROLE %I CREATEROLE', cdb_user_role); END $$ LANGUAGE PLPGSQL; @@ -73,8 +73,8 @@ DECLARE BEGIN cdb_admin_role := cartodb._CDB_Organization_Admin_Role_Name(); cdb_user_role := cartodb._CDB_User_RoleFromUsername(username); - EXECUTE format('ALTER ROLE "%s" NOCREATEROLE', cdb_user_role); - EXECUTE format('REVOKE "%s" FROM "%s"', cdb_admin_role, cdb_user_role); + EXECUTE format('ALTER ROLE %I NOCREATEROLE', cdb_user_role); + EXECUTE format('REVOKE %I FROM %I', cdb_admin_role, cdb_user_role); END $$ LANGUAGE PLPGSQL; From e1f8a65cceb523c2ebcc01c4dc6c8a682a3a28df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 27 Aug 2015 17:02:05 +0200 Subject: [PATCH 68/88] Use %s for sequence name, which is already quoted --- scripts-available/CDB_Groups.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 756775a..5a307cd 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -134,7 +134,8 @@ BEGIN EXECUTE 'SELECT PG_GET_SERIAL_SEQUENCE($1, $2)' USING table_name, column_name INTO sequence_name; IF sequence_name IS NOT NULL THEN IF do_grant THEN - EXECUTE format('GRANT USAGE, SELECT, UPDATE ON SEQUENCE %I TO %I', sequence_name, group_role); + -- Here %s is needed since sequence_name has quotes + EXECUTE format('GRANT USAGE, SELECT, UPDATE ON SEQUENCE %s TO %I', sequence_name, group_role); ELSE EXECUTE format('REVOKE ALL ON SEQUENCE %I FROM %I', sequence_name, group_role); END IF; From 15aece1fbc003fa199083937ba035ab93b2fbd9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 27 Aug 2015 17:03:13 +0200 Subject: [PATCH 69/88] Use %s for sequence name, which is already quoted --- scripts-available/CDB_Groups.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 5a307cd..41687fa 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -137,7 +137,7 @@ BEGIN -- Here %s is needed since sequence_name has quotes EXECUTE format('GRANT USAGE, SELECT, UPDATE ON SEQUENCE %s TO %I', sequence_name, group_role); ELSE - EXECUTE format('REVOKE ALL ON SEQUENCE %I FROM %I', sequence_name, group_role); + EXECUTE format('REVOKE ALL ON SEQUENCE %s FROM %I', sequence_name, group_role); END IF; END IF; END LOOP; From 1b5b3f741f6a02a423bcb1f370de31a445e87603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 3 Sep 2015 16:38:12 +0200 Subject: [PATCH 70/88] Support for spaces inside group names --- scripts-available/CDB_Groups_API.sql | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 595a5d5..70f185c 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -23,8 +23,9 @@ FUNCTION cartodb._CDB_Group_DropGroup_API(group_name text) RETURNS VOID AS $$ import string + import urllib - url = '/api/v1/databases/%s/groups/%s' % ('%s', group_name) + url = '/api/v1/databases/%s/groups/%s' % ('%s', urllib.quote_plus(group_name)) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; @@ -34,6 +35,7 @@ FUNCTION cartodb._CDB_Group_RenameGroup_API(old_group_name text, new_group_name RETURNS VOID AS $$ import string + import urllib url = '/api/v1/databases/%s/groups/%s' % ('%s', old_group_name) body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role) @@ -46,8 +48,9 @@ FUNCTION cartodb._CDB_Group_AddMember_API(group_name text, username text) RETURNS VOID AS $$ import string + import urllib - url = '/api/v1/databases/%s/groups/%s/users' % ('%s', group_name) + url = '/api/v1/databases/%s/groups/%s/users' % ('%s', urllib.quote_plus(group_name)) body = '{ "username": "%s" }' % username query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) @@ -58,8 +61,9 @@ FUNCTION cartodb._CDB_Group_RemoveMember_API(group_name text, username text) RETURNS VOID AS $$ import string + import urllib - url = '/api/v1/databases/%s/groups/%s/users/%s' % ('%s', group_name, username) + url = '/api/v1/databases/%s/groups/%s/users/%s' % ('%s', urllib.quote_plus(group_name), username) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; @@ -77,8 +81,9 @@ FUNCTION cartodb._CDB_Group_Table_GrantPermission_API(group_name text, username RETURNS VOID AS $$ import string + import urllib - url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', group_name, username, table_name) + url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', urllib.quote_plus(group_name), username, table_name) body = '{ "access": "%s" }' % access query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) @@ -97,8 +102,9 @@ FUNCTION cartodb._CDB_Group_Table_RevokeAllPermission_API(group_name text, usern RETURNS VOID AS $$ import string + import urllib - url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', group_name, username, table_name) + url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', urllib.quote_plus(group_name), username, table_name) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; From dfec191a9a7c4548157361c82a274d3473d91128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 3 Sep 2015 16:51:06 +0200 Subject: [PATCH 71/88] Support for spaces inside group names, fixed --- scripts-available/CDB_Groups_API.sql | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 70f185c..2b83400 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -25,7 +25,7 @@ $$ import string import urllib - url = '/api/v1/databases/%s/groups/%s' % ('%s', urllib.quote_plus(group_name)) + url = '/api/v1/databases/%s/groups/%s' % ('%s', urllib.quote(group_name)) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; @@ -50,7 +50,7 @@ $$ import string import urllib - url = '/api/v1/databases/%s/groups/%s/users' % ('%s', urllib.quote_plus(group_name)) + url = '/api/v1/databases/%s/groups/%s/users' % ('%s', urllib.quote(group_name)) body = '{ "username": "%s" }' % username query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) @@ -63,7 +63,7 @@ $$ import string import urllib - url = '/api/v1/databases/%s/groups/%s/users/%s' % ('%s', urllib.quote_plus(group_name), username) + url = '/api/v1/databases/%s/groups/%s/users/%s' % ('%s', urllib.quote(group_name), username) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; @@ -83,7 +83,7 @@ $$ import string import urllib - url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', urllib.quote_plus(group_name), username, table_name) + url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', urllib.quote(group_name), username, table_name) body = '{ "access": "%s" }' % access query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) @@ -104,7 +104,7 @@ $$ import string import urllib - url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', urllib.quote_plus(group_name), username, table_name) + url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', urllib.quote(group_name), username, table_name) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; From 0896b1451a2dce4b10baaf9ebef71ade9d2de762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Thu, 3 Sep 2015 20:41:19 +0200 Subject: [PATCH 72/88] Spaces support fixes #135 --- scripts-available/CDB_Groups_API.sql | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 2b83400..5287802 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -12,7 +12,7 @@ FUNCTION cartodb._CDB_Group_CreateGroup_API(group_name text, group_role text) $$ import string - url = '/api/v1/databases/%s/groups' + url = '/api/v1/databases/{0}/groups' body = '{ "name": "%s", "database_role": "%s" }' % (group_name, group_role) query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) @@ -25,7 +25,8 @@ $$ import string import urllib - url = '/api/v1/databases/%s/groups/%s' % ('%s', urllib.quote(group_name)) + url = '/api/v1/databases/{0}/groups/%s' % (urllib.pathname2url(group_name)) + query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; @@ -37,7 +38,7 @@ $$ import string import urllib - url = '/api/v1/databases/%s/groups/%s' % ('%s', old_group_name) + url = '/api/v1/databases/{0}/groups/%s' % (urllib.pathname2url(old_group_name)) body = '{ "name": "%s", "database_role": "%s" }' % (new_group_name, new_group_role) query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) @@ -50,7 +51,7 @@ $$ import string import urllib - url = '/api/v1/databases/%s/groups/%s/users' % ('%s', urllib.quote(group_name)) + url = '/api/v1/databases/{0}/groups/%s/users' % (urllib.pathname2url(group_name)) body = '{ "username": "%s" }' % username query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) @@ -63,7 +64,7 @@ $$ import string import urllib - url = '/api/v1/databases/%s/groups/%s/users/%s' % ('%s', urllib.quote(group_name), username) + url = '/api/v1/databases/{0}/groups/%s/users/%s' % (urllib.pathname2url(group_name), username) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; @@ -83,7 +84,7 @@ $$ import string import urllib - url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', urllib.quote(group_name), username, table_name) + url = '/api/v1/databases/{0}/groups/%s/permission/%s/tables/%s' % (urllib.pathname2url(group_name), username, table_name) body = '{ "access": "%s" }' % access query = "select cartodb._CDB_Group_API_Request('PUT', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) @@ -104,7 +105,7 @@ $$ import string import urllib - url = '/api/v1/databases/%s/groups/%s/permission/%s/tables/%s' % ('%s', urllib.quote(group_name), username, table_name) + url = '/api/v1/databases/{0}/groups/%s/permission/%s/tables/%s' % (urllib.pathname2url(group_name), username, table_name) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; @@ -168,7 +169,7 @@ $$ try: client = SD['groups_api_client'] = httplib.HTTPConnection(params['host'], params['port'], False, params['timeout']) database_name = plpy.execute("select current_database();")[0]['current_database'] - client.request(method, url % database_name, body, headers) + client.request(method, url.format(database_name), body, headers) response = client.getresponse() assert response.status in valid_return_codes return response.status From 428a2391ad8649d97e44dcf106f28ca89c102c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 7 Sep 2015 09:56:59 +0200 Subject: [PATCH 73/88] Refactor Member -> User --- scripts-available/CDB_Groups.sql | 8 ++++---- scripts-available/CDB_Groups_API.sql | 4 ++-- test/organization/test.sh | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 41687fa..06d4d03 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -52,7 +52,7 @@ $$ LANGUAGE PLPGSQL VOLATILE; -- Adds a user to a group CREATE OR REPLACE -FUNCTION cartodb.CDB_Group_AddMember(group_name text, username text) +FUNCTION cartodb.CDB_Group_AddUser(group_name text, username text) RETURNS VOID AS $$ DECLARE group_role TEXT; @@ -65,13 +65,13 @@ BEGIN 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); - PERFORM cartodb._CDB_Group_AddMember_API(group_name, username); + PERFORM cartodb._CDB_Group_AddUser_API(group_name, username); END $$ LANGUAGE PLPGSQL VOLATILE; -- Removes a user from a group CREATE OR REPLACE -FUNCTION cartodb.CDB_Group_RemoveMember(group_name text, username text) +FUNCTION cartodb.CDB_Group_RemoveUser(group_name text, username text) RETURNS VOID AS $$ DECLARE group_role TEXT; @@ -80,7 +80,7 @@ BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); user_role := cartodb._CDB_User_RoleFromUsername(username); EXECUTE format('REVOKE %I FROM %I', group_role, user_role); - PERFORM cartodb._CDB_Group_RemoveMember_API(group_name, username); + PERFORM cartodb._CDB_Group_RemoveUser_API(group_name, username); END $$ LANGUAGE PLPGSQL VOLATILE; diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 5287802..db3ad0e 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -45,7 +45,7 @@ $$ $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_AddMember_API(group_name text, username text) +FUNCTION cartodb._CDB_Group_AddUser_API(group_name text, username text) RETURNS VOID AS $$ import string @@ -58,7 +58,7 @@ $$ $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_RemoveMember_API(group_name text, username text) +FUNCTION cartodb._CDB_Group_RemoveUser_API(group_name text, username text) RETURNS VOID AS $$ import string diff --git a/test/organization/test.sh b/test/organization/test.sh index 56a5b0d..5d55115 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -187,7 +187,7 @@ function setup() { sql "SELECT cartodb.CDB_Group_CreateGroup('group_a_tmp')" sql "SELECT cartodb.CDB_Group_RenameGroup('group_a_tmp', 'group_a')" - sql "SELECT cartodb.CDB_Group_AddMember('group_a', 'cdb_testmember_1')" + sql "SELECT cartodb.CDB_Group_AddUser('group_a', 'cdb_testmember_1')" sql "SELECT cartodb.CDB_Group_CreateGroup('group_b')" } @@ -203,7 +203,7 @@ function tear_down() { sql "select cartodb.CDB_Group_DropGroup('group_b')" - sql "SELECT cartodb.CDB_Group_RemoveMember('group_a', 'cdb_testmember_1')" + sql "SELECT cartodb.CDB_Group_RemoveUser('group_a', 'cdb_testmember_1')" sql "select cartodb.CDB_Group_DropGroup('group_a')" sql "SELECT cartodb.CDB_Organization_RemoveAdmin('cdb_org_admin');" @@ -474,8 +474,8 @@ function test_group_management_functions_cant_be_used_by_normal_members() { sql cdb_testmember_1 "SELECT cartodb.CDB_Group_CreateGroup('group_x_1');" fails sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RenameGroup('group_a', 'group_x_2');" fails sql cdb_testmember_1 "SELECT cartodb.CDB_Group_DropGroup('group_a');" fails - sql cdb_testmember_1 "SELECT cartodb.CDB_Group_AddMember('group_a', 'cdb_testmember_2');" fails - sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RemoveMember('group_a', 'cdb_testmember_1');" fails + sql cdb_testmember_1 "SELECT cartodb.CDB_Group_AddUser('group_a', 'cdb_testmember_2');" fails + sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RemoveUser('group_a', 'cdb_testmember_1');" fails } function test_group_permission_functions_cant_be_used_by_normal_members() { @@ -496,8 +496,8 @@ function test_group_permission_functions_cant_be_used_by_normal_members() { function test_group_management_functions_can_be_used_by_org_admin() { sql cdb_org_admin "SELECT cartodb.CDB_Group_CreateGroup('group_x_tmp');" sql cdb_org_admin "SELECT cartodb.CDB_Group_RenameGroup('group_x_tmp', 'group_x');" - sql cdb_org_admin "SELECT cartodb.CDB_Group_AddMember('group_x', 'cdb_testmember_1');" - sql cdb_org_admin "SELECT cartodb.CDB_Group_RemoveMember('group_x', 'cdb_testmember_1');" + sql cdb_org_admin "SELECT cartodb.CDB_Group_AddUser('group_x', 'cdb_testmember_1');" + sql cdb_org_admin "SELECT cartodb.CDB_Group_RemoveUser('group_x', 'cdb_testmember_1');" # TODO: workaround superadmin limitation sql "SELECT cartodb.CDB_Group_DropGroup('group_x');" } From 59d144d91d69299ce0fa8c6f301ad93dcbef28cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 7 Sep 2015 10:35:04 +0200 Subject: [PATCH 74/88] Batch add/remove users support --- scripts-available/CDB_Groups.sql | 34 +++++++++++++++++----------- scripts-available/CDB_Groups_API.sql | 11 +++++---- test/organization/test.sh | 12 +++++----- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 06d4d03..253e72c 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -50,37 +50,45 @@ BEGIN END $$ LANGUAGE PLPGSQL VOLATILE; --- Adds a user to a group +-- Adds users to a group, comma-separated CREATE OR REPLACE -FUNCTION cartodb.CDB_Group_AddUser(group_name text, username text) +FUNCTION cartodb.CDB_Group_AddUsers(group_name text, usernames text) RETURNS VOID AS $$ DECLARE group_role TEXT; user_role TEXT; + username TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); - 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); - PERFORM cartodb._CDB_Group_AddUser_API(group_name, username); + foreach username in array string_to_array(usernames, ',') + 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); END $$ LANGUAGE PLPGSQL VOLATILE; -- Removes a user from a group CREATE OR REPLACE -FUNCTION cartodb.CDB_Group_RemoveUser(group_name text, username text) +FUNCTION cartodb.CDB_Group_RemoveUsers(group_name text, usernames text) RETURNS VOID AS $$ DECLARE group_role TEXT; user_role TEXT; + username TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); - user_role := cartodb._CDB_User_RoleFromUsername(username); - EXECUTE format('REVOKE %I FROM %I', group_role, user_role); - PERFORM cartodb._CDB_Group_RemoveUser_API(group_name, username); + foreach username in array string_to_array(usernames, ',') + 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); END $$ LANGUAGE PLPGSQL VOLATILE; diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index db3ad0e..79eb057 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -45,27 +45,28 @@ $$ $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_AddUser_API(group_name text, username text) +FUNCTION cartodb._CDB_Group_AddUsers_API(group_name text, usernames text) RETURNS VOID AS $$ import string import urllib url = '/api/v1/databases/{0}/groups/%s/users' % (urllib.pathname2url(group_name)) - body = '{ "username": "%s" }' % username + body = "{ \"users\": [\"%s\"] }" % "\",\"".join(usernames.split(',')) query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_RemoveUser_API(group_name text, username text) +FUNCTION cartodb._CDB_Group_RemoveUsers_API(group_name text, usernames text) RETURNS VOID AS $$ import string import urllib - url = '/api/v1/databases/{0}/groups/%s/users/%s' % (urllib.pathname2url(group_name), username) - query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url + url = '/api/v1/databases/{0}/groups/%s/users' % (urllib.pathname2url(group_name)) + body = "{ \"users\": [\"%s\"] }" % "\",\"".join(usernames.split(',')) + query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '%s', '{200, 404}') as response_status" % (url, body) plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; diff --git a/test/organization/test.sh b/test/organization/test.sh index 5d55115..17ec967 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -187,7 +187,7 @@ function setup() { sql "SELECT cartodb.CDB_Group_CreateGroup('group_a_tmp')" sql "SELECT cartodb.CDB_Group_RenameGroup('group_a_tmp', 'group_a')" - sql "SELECT cartodb.CDB_Group_AddUser('group_a', 'cdb_testmember_1')" + sql "SELECT cartodb.CDB_Group_AddUsers('group_a', 'cdb_testmember_1')" sql "SELECT cartodb.CDB_Group_CreateGroup('group_b')" } @@ -203,7 +203,7 @@ function tear_down() { sql "select cartodb.CDB_Group_DropGroup('group_b')" - sql "SELECT cartodb.CDB_Group_RemoveUser('group_a', 'cdb_testmember_1')" + sql "SELECT cartodb.CDB_Group_RemoveUsers('group_a', 'cdb_testmember_1')" sql "select cartodb.CDB_Group_DropGroup('group_a')" sql "SELECT cartodb.CDB_Organization_RemoveAdmin('cdb_org_admin');" @@ -474,8 +474,8 @@ function test_group_management_functions_cant_be_used_by_normal_members() { sql cdb_testmember_1 "SELECT cartodb.CDB_Group_CreateGroup('group_x_1');" fails sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RenameGroup('group_a', 'group_x_2');" fails sql cdb_testmember_1 "SELECT cartodb.CDB_Group_DropGroup('group_a');" fails - sql cdb_testmember_1 "SELECT cartodb.CDB_Group_AddUser('group_a', 'cdb_testmember_2');" fails - sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RemoveUser('group_a', 'cdb_testmember_1');" fails + sql cdb_testmember_1 "SELECT cartodb.CDB_Group_AddUsers('group_a', 'cdb_testmember_2');" fails + sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RemoveUsers('group_a', 'cdb_testmember_1');" fails } function test_group_permission_functions_cant_be_used_by_normal_members() { @@ -496,8 +496,8 @@ function test_group_permission_functions_cant_be_used_by_normal_members() { function test_group_management_functions_can_be_used_by_org_admin() { sql cdb_org_admin "SELECT cartodb.CDB_Group_CreateGroup('group_x_tmp');" sql cdb_org_admin "SELECT cartodb.CDB_Group_RenameGroup('group_x_tmp', 'group_x');" - sql cdb_org_admin "SELECT cartodb.CDB_Group_AddUser('group_x', 'cdb_testmember_1');" - sql cdb_org_admin "SELECT cartodb.CDB_Group_RemoveUser('group_x', 'cdb_testmember_1');" + sql cdb_org_admin "SELECT cartodb.CDB_Group_AddUsers('group_x', 'cdb_testmember_1');" + sql cdb_org_admin "SELECT cartodb.CDB_Group_RemoveUsers('group_x', 'cdb_testmember_1');" # TODO: workaround superadmin limitation sql "SELECT cartodb.CDB_Group_DropGroup('group_x');" } From b73eb486a59f9e9fe2e92fd32f3dc2aa2706bac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 7 Sep 2015 10:35:32 +0200 Subject: [PATCH 75/88] Old functions cleanup --- scripts-available/CDB_Groups_API.sql | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 79eb057..ed5447f 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -5,6 +5,12 @@ -- Requires configuration parameter. Example: SELECT cartodb.CDB_Conf_SetConf('groups_api', '{ "host": "127.0.0.1", "port": 3000, "timeout": 10, "username": "extension", "password": "elephant" }'); ---------------------------------- +-- TODO: delete this development cleanup before final merge +DROP FUNCTION IF EXISTS cartodb.CDB_Group_AddMember(group_name text, username text); +DROP FUNCTION IF EXISTS cartodb.CDB_Group_RemoveMember(group_name text, username text); +DROP FUNCTION IF EXISTS cartodb._CDB_Group_AddMember_API(group_name text, username text); +DROP FUNCTION IF EXISTS cartodb._CDB_Group_RemoveMember_API(group_name text, username text); + -- Sends the create group request CREATE OR REPLACE FUNCTION cartodb._CDB_Group_CreateGroup_API(group_name text, group_role text) From 154eff6d2599f5d55b1b708265f8c6d75a0a8ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 7 Sep 2015 11:43:46 +0200 Subject: [PATCH 76/88] Array notation for batch group functions --- scripts-available/CDB_Groups.sql | 8 ++++---- scripts-available/CDB_Groups_API.sql | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 253e72c..716032e 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -52,7 +52,7 @@ $$ LANGUAGE PLPGSQL VOLATILE; -- Adds users to a group, comma-separated CREATE OR REPLACE -FUNCTION cartodb.CDB_Group_AddUsers(group_name text, usernames text) +FUNCTION cartodb.CDB_Group_AddUsers(group_name text, usernames text[]) RETURNS VOID AS $$ DECLARE group_role TEXT; @@ -60,7 +60,7 @@ DECLARE username TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); - foreach username in array string_to_array(usernames, ',') + foreach username in array usernames loop user_role := cartodb._CDB_User_RoleFromUsername(username); IF(group_role IS NULL OR user_role IS NULL) @@ -75,7 +75,7 @@ $$ LANGUAGE PLPGSQL VOLATILE; -- Removes a user from a group CREATE OR REPLACE -FUNCTION cartodb.CDB_Group_RemoveUsers(group_name text, usernames text) +FUNCTION cartodb.CDB_Group_RemoveUsers(group_name text, usernames text[]) RETURNS VOID AS $$ DECLARE group_role TEXT; @@ -83,7 +83,7 @@ DECLARE username TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); - foreach username in array string_to_array(usernames, ',') + foreach username in array usernames loop user_role := cartodb._CDB_User_RoleFromUsername(username); EXECUTE format('REVOKE %I FROM %I', group_role, user_role); diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index ed5447f..136a969 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -51,27 +51,27 @@ $$ $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_AddUsers_API(group_name text, usernames text) +FUNCTION cartodb._CDB_Group_AddUsers_API(group_name text, usernames text[]) RETURNS VOID AS $$ import string import urllib url = '/api/v1/databases/{0}/groups/%s/users' % (urllib.pathname2url(group_name)) - body = "{ \"users\": [\"%s\"] }" % "\",\"".join(usernames.split(',')) + body = "{ \"users\": [\"%s\"] }" % "\",\"".join(usernames) query = "select cartodb._CDB_Group_API_Request('POST', '%s', '%s', '{200, 409}') as response_status" % (url, body) plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; CREATE OR REPLACE -FUNCTION cartodb._CDB_Group_RemoveUsers_API(group_name text, usernames text) +FUNCTION cartodb._CDB_Group_RemoveUsers_API(group_name text, usernames text[]) RETURNS VOID AS $$ import string import urllib url = '/api/v1/databases/{0}/groups/%s/users' % (urllib.pathname2url(group_name)) - body = "{ \"users\": [\"%s\"] }" % "\",\"".join(usernames.split(',')) + body = "{ \"users\": [\"%s\"] }" % "\",\"".join(usernames) query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '%s', '{200, 404}') as response_status" % (url, body) plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; From 4405ecb46644ec78cc717f8310e8b67cd3311e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 7 Sep 2015 11:43:57 +0200 Subject: [PATCH 77/88] Multiple users test --- test/organization/test.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/organization/test.sh b/test/organization/test.sh index 17ec967..7e54307 100644 --- a/test/organization/test.sh +++ b/test/organization/test.sh @@ -187,7 +187,7 @@ function setup() { sql "SELECT cartodb.CDB_Group_CreateGroup('group_a_tmp')" sql "SELECT cartodb.CDB_Group_RenameGroup('group_a_tmp', 'group_a')" - sql "SELECT cartodb.CDB_Group_AddUsers('group_a', 'cdb_testmember_1')" + sql "SELECT cartodb.CDB_Group_AddUsers('group_a', ARRAY['cdb_testmember_1'])" sql "SELECT cartodb.CDB_Group_CreateGroup('group_b')" } @@ -203,7 +203,7 @@ function tear_down() { sql "select cartodb.CDB_Group_DropGroup('group_b')" - sql "SELECT cartodb.CDB_Group_RemoveUsers('group_a', 'cdb_testmember_1')" + sql "SELECT cartodb.CDB_Group_RemoveUsers('group_a', ARRAY['cdb_testmember_1'])" sql "select cartodb.CDB_Group_DropGroup('group_a')" sql "SELECT cartodb.CDB_Organization_RemoveAdmin('cdb_org_admin');" @@ -474,8 +474,8 @@ function test_group_management_functions_cant_be_used_by_normal_members() { sql cdb_testmember_1 "SELECT cartodb.CDB_Group_CreateGroup('group_x_1');" fails sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RenameGroup('group_a', 'group_x_2');" fails sql cdb_testmember_1 "SELECT cartodb.CDB_Group_DropGroup('group_a');" fails - sql cdb_testmember_1 "SELECT cartodb.CDB_Group_AddUsers('group_a', 'cdb_testmember_2');" fails - sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RemoveUsers('group_a', 'cdb_testmember_1');" fails + sql cdb_testmember_1 "SELECT cartodb.CDB_Group_AddUsers('group_a', ARRAY['cdb_testmember_2']);" fails + sql cdb_testmember_1 "SELECT cartodb.CDB_Group_RemoveUsers('group_a', ARRAY['cdb_testmember_1']);" fails } function test_group_permission_functions_cant_be_used_by_normal_members() { @@ -496,8 +496,8 @@ function test_group_permission_functions_cant_be_used_by_normal_members() { function test_group_management_functions_can_be_used_by_org_admin() { sql cdb_org_admin "SELECT cartodb.CDB_Group_CreateGroup('group_x_tmp');" sql cdb_org_admin "SELECT cartodb.CDB_Group_RenameGroup('group_x_tmp', 'group_x');" - sql cdb_org_admin "SELECT cartodb.CDB_Group_AddUsers('group_x', 'cdb_testmember_1');" - sql cdb_org_admin "SELECT cartodb.CDB_Group_RemoveUsers('group_x', 'cdb_testmember_1');" + sql cdb_org_admin "SELECT cartodb.CDB_Group_AddUsers('group_x', ARRAY['cdb_testmember_1', 'cdb_testmember_2']);" + sql cdb_org_admin "SELECT cartodb.CDB_Group_RemoveUsers('group_x', ARRAY['cdb_testmember_1', 'cdb_testmember_2']);" # TODO: workaround superadmin limitation sql "SELECT cartodb.CDB_Group_DropGroup('group_x');" } From 275e5154fd09e18a31da1b06d01c479cd67c086c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 7 Sep 2015 11:48:18 +0200 Subject: [PATCH 78/88] Fixed comment --- scripts-available/CDB_Groups.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 716032e..cdc771a 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -50,7 +50,7 @@ BEGIN END $$ LANGUAGE PLPGSQL VOLATILE; --- Adds users to a group, comma-separated +-- Adds users to a group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_AddUsers(group_name text, usernames text[]) RETURNS VOID AS $$ @@ -73,7 +73,7 @@ BEGIN END $$ LANGUAGE PLPGSQL VOLATILE; --- Removes a user from a group +-- Removes users from a group CREATE OR REPLACE FUNCTION cartodb.CDB_Group_RemoveUsers(group_name text, usernames text[]) RETURNS VOID AS $$ From 206cee1647b5311104808842bd722d9cfaf12521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Wed, 9 Sep 2015 12:24:54 +0200 Subject: [PATCH 79/88] Deletion operations return 204 --- scripts-available/CDB_Groups_API.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 136a969..d4c1be5 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -33,7 +33,7 @@ $$ url = '/api/v1/databases/{0}/groups/%s' % (urllib.pathname2url(group_name)) - query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{200, 404}') as response_status" % url + query = "select cartodb._CDB_Group_API_Request('DELETE', '%s', '', '{204, 404}') as response_status" % url plpy.execute(query) $$ LANGUAGE 'plpythonu' VOLATILE SECURITY DEFINER; From 963f8ea97b75b55604b8082dbe99ef624936f8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 21 Sep 2015 12:54:14 +0200 Subject: [PATCH 80/88] #103 0.11.0 version --- Makefile | 3 ++- NEWS.md | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 107e94a..3663b57 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # cartodb/Makefile EXTENSION = cartodb -EXTVERSION = 0.10.1 +EXTVERSION = 0.11.0 SED = sed @@ -49,6 +49,7 @@ UPGRADABLE = \ 0.9.4 \ 0.10.0 \ 0.10.1 \ + 0.11.0 \ $(EXTVERSION)dev \ $(EXTVERSION)next \ $(END) diff --git a/NEWS.md b/NEWS.md index 69db4ec..67e9b56 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ next (2015-mm-dd) ----------------- + +0.11.0 (2015-09-dd) +------------------- * Groups API 0.10.1 (2015-09-16) From bf4f30c99dcdbfa80101dd1f87fa2723c85bbda0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 21 Sep 2015 14:35:28 +0200 Subject: [PATCH 81/88] Removed IMMUTABLE for functions depending on current database --- scripts-available/CDB_Groups.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index cdc771a..301531f 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -187,7 +187,7 @@ BEGIN END IF; RETURN group_role; END -$$ LANGUAGE PLPGSQL IMMUTABLE; +$$ LANGUAGE PLPGSQL; -- Returns the first owner of the schema matching username. Organization user schemas must have one only owner. CREATE OR REPLACE @@ -201,7 +201,7 @@ BEGIN EXECUTE 'SELECT pg_get_userbyid(nspowner) FROM pg_namespace WHERE nspname = $1;' INTO user_role USING username; RETURN user_role; END -$$ LANGUAGE PLPGSQL IMMUTABLE; +$$ LANGUAGE PLPGSQL; -- Database names are too long, we need a shorter version for composing role names CREATE OR REPLACE @@ -213,4 +213,4 @@ BEGIN EXECUTE 'SELECT md5(current_database())' INTO short_database_name; RETURN short_database_name; END -$$ LANGUAGE PLPGSQL IMMUTABLE; +$$ LANGUAGE PLPGSQL; From 0e4f3955f6976895e7ae5ac1f1c85e3649ec10f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 21 Sep 2015 15:37:10 +0200 Subject: [PATCH 82/88] 1108 separator for cleaner SQL --- scripts-available/CDB_Organizations.sql | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts-available/CDB_Organizations.sql b/scripts-available/CDB_Organizations.sql index ab2bbb6..b62902a 100644 --- a/scripts-available/CDB_Organizations.sql +++ b/scripts-available/CDB_Organizations.sql @@ -1,14 +1,16 @@ CREATE OR REPLACE FUNCTION cartodb.CDB_Organization_Member_Group_Role_Member_Name() RETURNS TEXT -AS 'SELECT ''cdb_org_member''::text || ''_'' || md5(current_database());' +AS $$ + SELECT 'cdb_org_member'::text || '_' || md5(current_database()); +$$ LANGUAGE SQL IMMUTABLE; DO LANGUAGE 'plpgsql' $$ DECLARE cdb_org_member_role_name TEXT; BEGIN - cdb_org_member_role_name := cartodb.CDB_Organization_Member_Group_Role_Member_Name(); + cdb_org_member_role_name := cartodb.CDB_Organization_Member_Group_Role_Member_Name(); IF NOT EXISTS ( SELECT * FROM pg_roles WHERE rolname= cdb_org_member_role_name ) THEN EXECUTE 'CREATE ROLE "' || cdb_org_member_role_name || '" NOLOGIN;'; @@ -31,7 +33,9 @@ $$ LANGUAGE PLPGSQL VOLATILE; CREATE OR REPLACE FUNCTION cartodb._CDB_Organization_Admin_Role_Name() RETURNS TEXT -AS 'SELECT current_database() || ''_admin''::text;' +AS $$ + SELECT current_database() || '_admin'::text; +$$ LANGUAGE SQL IMMUTABLE; -- Administrator role creation on extension install From cc1e357caad1ff64a5824bb5cd562b8da93faa4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 21 Sep 2015 15:47:52 +0200 Subject: [PATCH 83/88] Removed unnecessary EXECUTEs --- scripts-available/CDB_Groups.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 301531f..541264d 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -198,7 +198,7 @@ DECLARE BEGIN -- This was preferred, but non-superadmins won't get results -- SELECT SCHEMA_OWNER FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = $1 LIMIT 1' - EXECUTE 'SELECT pg_get_userbyid(nspowner) FROM pg_namespace WHERE nspname = $1;' INTO user_role USING username; + SELECT pg_get_userbyid(nspowner) FROM pg_namespace WHERE nspname = username INTO user_role; RETURN user_role; END $$ LANGUAGE PLPGSQL; @@ -210,7 +210,7 @@ FUNCTION cartodb._CDB_Group_ShortDatabaseName() DECLARE short_database_name TEXT; BEGIN - EXECUTE 'SELECT md5(current_database())' INTO short_database_name; + SELECT md5(current_database()) INTO short_database_name; RETURN short_database_name; END $$ LANGUAGE PLPGSQL; From a2ddb76ef3e74e1887beab7226988f310d476f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 21 Sep 2015 16:31:12 +0200 Subject: [PATCH 84/88] Shorter admin role name --- scripts-available/CDB_Organizations.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts-available/CDB_Organizations.sql b/scripts-available/CDB_Organizations.sql index b62902a..73063e3 100644 --- a/scripts-available/CDB_Organizations.sql +++ b/scripts-available/CDB_Organizations.sql @@ -34,7 +34,7 @@ CREATE OR REPLACE FUNCTION cartodb._CDB_Organization_Admin_Role_Name() RETURNS TEXT AS $$ - SELECT current_database() || '_admin'::text; + SELECT current_database() || '_a'::text; $$ LANGUAGE SQL IMMUTABLE; From a0204d50dbc6eb5c4401d61ccbb99c2a40c55334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Mon, 21 Sep 2015 19:01:40 +0200 Subject: [PATCH 85/88] X-Forwarded-Proto --- scripts-available/CDB_Groups_API.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index d4c1be5..a854225 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -167,7 +167,7 @@ $$ if params['host'] is None: return None - headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } + headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json', 'X-Forwarded-Proto': 'https' } retry = 3 From 3330421887673ab7efb58f96d17ccfb9767f34eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Fri, 25 Sep 2015 19:02:39 +0200 Subject: [PATCH 86/88] sync parameter at group functions closes #162 --- scripts-available/CDB_Groups.sql | 42 ++++++++++++++++++++++++++-- scripts-available/CDB_Groups_API.sql | 3 +- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 541264d..3bc50da 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -104,11 +104,23 @@ FUNCTION cartodb.CDB_Group_Table_GrantRead(group_name text, username text, table RETURNS VOID AS $$ DECLARE group_role TEXT; +BEGIN + PERFORM cartodb.CDB_Group_Table_GrantRead(group_name, username, table_name, true); +END +$$ LANGUAGE PLPGSQL VOLATILE; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_Table_GrantRead(group_name text, username text, table_name text, sync boolean) + RETURNS VOID AS $$ +DECLARE + group_role TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); 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 ); - PERFORM cartodb._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'r'); + IF(sync) THEN + PERFORM cartodb._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'r'); + END IF; END $$ LANGUAGE PLPGSQL VOLATILE; @@ -118,12 +130,24 @@ FUNCTION cartodb.CDB_Group_Table_GrantReadWrite(group_name text, username text, RETURNS VOID AS $$ DECLARE group_role TEXT; +BEGIN + PERFORM cartodb.CDB_Group_Table_GrantReadWrite(group_name, username, table_name, true); +END +$$ LANGUAGE PLPGSQL VOLATILE; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_Table_GrantReadWrite(group_name text, username text, table_name text, sync boolean) + RETURNS VOID AS $$ +DECLARE + group_role TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); 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); PERFORM cartodb._CDB_Group_TableSequences_Permission(group_name, username, table_name, true); - PERFORM cartodb._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'w'); + IF(sync) THEN + PERFORM cartodb._CDB_Group_Table_GrantPermission_API(group_name, username, table_name, 'w'); + END IF; END $$ LANGUAGE PLPGSQL VOLATILE; @@ -159,11 +183,23 @@ FUNCTION cartodb.CDB_Group_Table_RevokeAll(group_name text, username text, table RETURNS VOID AS $$ DECLARE group_role TEXT; +BEGIN + PERFORM cartodb.CDB_Group_Table_RevokeAll(group_name, username, table_name, true); +END +$$ LANGUAGE PLPGSQL VOLATILE; + +CREATE OR REPLACE +FUNCTION cartodb.CDB_Group_Table_RevokeAll(group_name text, username text, table_name text, sync boolean) + RETURNS VOID AS $$ +DECLARE + group_role TEXT; BEGIN group_role := cartodb._CDB_Group_GroupRole(group_name); EXECUTE format('REVOKE ALL ON TABLE %I.%I FROM %I', username, table_name, group_role); PERFORM cartodb._CDB_Group_TableSequences_Permission(group_name, username, table_name, false); - PERFORM cartodb._CDB_Group_Table_RevokeAllPermission_API(group_name, username, table_name); + IF(sync) THEN + PERFORM cartodb._CDB_Group_Table_RevokeAllPermission_API(group_name, username, table_name); + END IF; END $$ LANGUAGE PLPGSQL VOLATILE; diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index a854225..1416819 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -157,6 +157,7 @@ $$ $$ LANGUAGE 'plpythonu' VOLATILE; -- url must contain a '%s' placeholder that will be replaced by current_database, for security reasons. +-- headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json', 'X-Forwarded-Proto': 'https' } CREATE OR REPLACE FUNCTION cartodb._CDB_Group_API_Request(method text, url text, body text, valid_return_codes int[]) RETURNS int AS @@ -167,7 +168,7 @@ $$ if params['host'] is None: return None - headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json', 'X-Forwarded-Proto': 'https' } + headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } retry = 3 From e7008d04eed6006ebe6a1116dc8a12a691c52a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Fri, 25 Sep 2015 19:13:04 +0200 Subject: [PATCH 87/88] https support back --- scripts-available/CDB_Groups_API.sql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts-available/CDB_Groups_API.sql b/scripts-available/CDB_Groups_API.sql index 1416819..a854225 100644 --- a/scripts-available/CDB_Groups_API.sql +++ b/scripts-available/CDB_Groups_API.sql @@ -157,7 +157,6 @@ $$ $$ LANGUAGE 'plpythonu' VOLATILE; -- url must contain a '%s' placeholder that will be replaced by current_database, for security reasons. --- headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json', 'X-Forwarded-Proto': 'https' } CREATE OR REPLACE FUNCTION cartodb._CDB_Group_API_Request(method text, url text, body text, valid_return_codes int[]) RETURNS int AS @@ -168,7 +167,7 @@ $$ if params['host'] is None: return None - headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json' } + headers = { 'Authorization': params['auth'], 'Content-Type': 'application/json', 'X-Forwarded-Proto': 'https' } retry = 3 From 0081ec16a96a874cf81ecd47b02c390f45557605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Ignacio=20S=C3=A1nchez=20Lara?= Date: Sun, 27 Sep 2015 18:42:24 +0200 Subject: [PATCH 88/88] Sync-flag functions should be private --- scripts-available/CDB_Groups.sql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts-available/CDB_Groups.sql b/scripts-available/CDB_Groups.sql index 3bc50da..826c210 100644 --- a/scripts-available/CDB_Groups.sql +++ b/scripts-available/CDB_Groups.sql @@ -105,12 +105,12 @@ FUNCTION cartodb.CDB_Group_Table_GrantRead(group_name text, username text, table DECLARE group_role TEXT; BEGIN - PERFORM cartodb.CDB_Group_Table_GrantRead(group_name, username, table_name, true); + PERFORM cartodb._CDB_Group_Table_GrantRead(group_name, username, table_name, true); END $$ LANGUAGE PLPGSQL VOLATILE; CREATE OR REPLACE -FUNCTION cartodb.CDB_Group_Table_GrantRead(group_name text, username text, table_name text, sync boolean) +FUNCTION cartodb._CDB_Group_Table_GrantRead(group_name text, username text, table_name text, sync boolean) RETURNS VOID AS $$ DECLARE group_role TEXT; @@ -131,12 +131,12 @@ FUNCTION cartodb.CDB_Group_Table_GrantReadWrite(group_name text, username text, DECLARE group_role TEXT; BEGIN - PERFORM cartodb.CDB_Group_Table_GrantReadWrite(group_name, username, table_name, true); + PERFORM cartodb._CDB_Group_Table_GrantReadWrite(group_name, username, table_name, true); END $$ LANGUAGE PLPGSQL VOLATILE; CREATE OR REPLACE -FUNCTION cartodb.CDB_Group_Table_GrantReadWrite(group_name text, username text, table_name text, sync boolean) +FUNCTION cartodb._CDB_Group_Table_GrantReadWrite(group_name text, username text, table_name text, sync boolean) RETURNS VOID AS $$ DECLARE group_role TEXT; @@ -184,12 +184,12 @@ FUNCTION cartodb.CDB_Group_Table_RevokeAll(group_name text, username text, table DECLARE group_role TEXT; BEGIN - PERFORM cartodb.CDB_Group_Table_RevokeAll(group_name, username, table_name, true); + PERFORM cartodb._CDB_Group_Table_RevokeAll(group_name, username, table_name, true); END $$ LANGUAGE PLPGSQL VOLATILE; CREATE OR REPLACE -FUNCTION cartodb.CDB_Group_Table_RevokeAll(group_name text, username text, table_name text, sync boolean) +FUNCTION cartodb._CDB_Group_Table_RevokeAll(group_name text, username text, table_name text, sync boolean) RETURNS VOID AS $$ DECLARE group_role TEXT;