Skip to content

Commit

Permalink
Merge pull request #6917 from dolthub/macneale4/admin_procedures
Browse files Browse the repository at this point in the history
Dolt admin procedures are now protected with an extra level of protection. Each admin procedure requires users have grants directly on the resource in question.
  • Loading branch information
macneale4 authored Oct 31, 2023
2 parents 85155ed + bf9897e commit 6579e5b
Show file tree
Hide file tree
Showing 4 changed files with 358 additions and 14 deletions.
26 changes: 13 additions & 13 deletions go/libraries/doltcore/sqle/dprocedures/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,27 @@ import (

var DoltProcedures = []sql.ExternalStoredProcedureDetails{
{Name: "dolt_add", Schema: int64Schema("status"), Function: doltAdd},
{Name: "dolt_backup", Schema: int64Schema("status"), Function: doltBackup, ReadOnly: true},
{Name: "dolt_backup", Schema: int64Schema("status"), Function: doltBackup, ReadOnly: true, AdminOnly: true},
{Name: "dolt_branch", Schema: int64Schema("status"), Function: doltBranch},
{Name: "dolt_checkout", Schema: doltCheckoutSchema, Function: doltCheckout, ReadOnly: true},
{Name: "dolt_cherry_pick", Schema: cherryPickSchema, Function: doltCherryPick},
{Name: "dolt_clean", Schema: int64Schema("status"), Function: doltClean},
{Name: "dolt_clone", Schema: int64Schema("status"), Function: doltClone},
{Name: "dolt_clone", Schema: int64Schema("status"), Function: doltClone, AdminOnly: true},
{Name: "dolt_commit", Schema: stringSchema("hash"), Function: doltCommit},
{Name: "dolt_commit_hash_out", Schema: stringSchema("hash"), Function: doltCommitHashOut},
{Name: "dolt_conflicts_resolve", Schema: int64Schema("status"), Function: doltConflictsResolve},
{Name: "dolt_count_commits", Schema: int64Schema("ahead", "behind"), Function: doltCountCommits, ReadOnly: true},
{Name: "dolt_fetch", Schema: int64Schema("status"), Function: doltFetch},
{Name: "dolt_undrop", Schema: int64Schema("status"), Function: doltUndrop},
{Name: "dolt_purge_dropped_databases", Schema: int64Schema("status"), Function: doltPurgeDroppedDatabases},
{Name: "dolt_fetch", Schema: int64Schema("status"), Function: doltFetch, AdminOnly: true},
{Name: "dolt_undrop", Schema: int64Schema("status"), Function: doltUndrop, AdminOnly: true},
{Name: "dolt_purge_dropped_databases", Schema: int64Schema("status"), Function: doltPurgeDroppedDatabases, AdminOnly: true},

// dolt_gc is enabled behind a feature flag for now, see dolt_gc.go
{Name: "dolt_gc", Schema: int64Schema("status"), Function: doltGC, ReadOnly: true},
{Name: "dolt_gc", Schema: int64Schema("status"), Function: doltGC, ReadOnly: true, AdminOnly: true},

{Name: "dolt_merge", Schema: doltMergeSchema, Function: doltMerge},
{Name: "dolt_pull", Schema: int64Schema("fast_forward", "conflicts"), Function: doltPull},
{Name: "dolt_push", Schema: doltPushSchema, Function: doltPush},
{Name: "dolt_remote", Schema: int64Schema("status"), Function: doltRemote},
{Name: "dolt_pull", Schema: int64Schema("fast_forward", "conflicts"), Function: doltPull, AdminOnly: true},
{Name: "dolt_push", Schema: doltPushSchema, Function: doltPush, AdminOnly: true},
{Name: "dolt_remote", Schema: int64Schema("status"), Function: doltRemote, AdminOnly: true},
{Name: "dolt_reset", Schema: int64Schema("status"), Function: doltReset},
{Name: "dolt_revert", Schema: int64Schema("status"), Function: doltRevert},
{Name: "dolt_tag", Schema: int64Schema("status"), Function: doltTag},
Expand All @@ -56,14 +56,14 @@ var DoltProcedures = []sql.ExternalStoredProcedureDetails{
{Name: "dclean", Schema: int64Schema("status"), Function: doltClean},
{Name: "dclone", Schema: int64Schema("status"), Function: doltClone},
{Name: "dcommit", Schema: stringSchema("hash"), Function: doltCommit},
{Name: "dfetch", Schema: int64Schema("status"), Function: doltFetch},
{Name: "dfetch", Schema: int64Schema("status"), Function: doltFetch, AdminOnly: true},

// {Name: "dgc", Schema: int64Schema("status"), Function: doltGC},

{Name: "dmerge", Schema: doltMergeSchema, Function: doltMerge},
{Name: "dpull", Schema: int64Schema("fast_forward", "conflicts"), Function: doltPull},
{Name: "dpush", Schema: doltPushSchema, Function: doltPush},
{Name: "dremote", Schema: int64Schema("status"), Function: doltRemote},
{Name: "dpull", Schema: int64Schema("fast_forward", "conflicts"), Function: doltPull, AdminOnly: true},
{Name: "dpush", Schema: doltPushSchema, Function: doltPush, AdminOnly: true},
{Name: "dremote", Schema: int64Schema("status"), Function: doltRemote, AdminOnly: true},
{Name: "dreset", Schema: int64Schema("status"), Function: doltReset},
{Name: "drevert", Schema: int64Schema("status"), Function: doltRevert},
{Name: "dtag", Schema: int64Schema("status"), Function: doltTag},
Expand Down
186 changes: 186 additions & 0 deletions integration-tests/bats/sql-mysqldb-privs.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#!/usr/bin/env bats
load $BATS_TEST_DIRNAME/helper/common.bash

# This suite of tests is for testing the sql server's presentation of privledges, priviledge persisteance between
# CLI and server instances.
#
# Caring about privledges on the CLI isn't really the point, but working in both modes ensures that persistance
# is working correctly. You won't see mention of working with servers in these tests because it's handled by
# running tests in this file using helper/local-remote.bash

# working dir will be test_db
make_multi_test_repo() {
rm -rf test_db
mkdir test_db
cd test_db

mkdir db1
cd db1
dolt init
cd ..

mkdir db2
cd db2
dolt init
cd ..

## All tests need a user, or two.
dolt sql -q "CREATE USER tester1@localhost"
dolt sql -q "CREATE USER tester2@localhost"
}

# working dir will be dolt_repo$$
delete_test_repo() {
cd ..
rm -rf test_db
}

setup() {
setup_no_dolt_init
make_multi_test_repo
}

teardown() {
delete_test_repo
teardown_common
}

@test "sql-mysqldb-privs: smoke test for db table" {
dolt sql -q "GRANT SELECT ON db1.* TO tester1@localhost"
run dolt sql -q "SELECT host,user,db,select_priv as s,insert_priv as i from mysql.db"

[ $status -eq 0 ]
[[ $output =~ "localhost | tester1 | db1 | Y | N" ]] || false

run dolt sql -q "SHOW GRANTS FOR tester1@localhost"
[ $status -eq 0 ]
[[ $output =~ 'GRANT SELECT ON `db1`.* TO `tester1`@`localhost`' ]] || false

dolt sql -q "GRANT INSERT ON db2.* TO tester2@localhost"

run dolt sql -q "SELECT user FROM mysql.db"
[ $status -eq 0 ]
[[ $output =~ "tester1" ]] || false
[[ $output =~ "tester2" ]] || false

run dolt sql -q "SELECT db FROM mysql.db where user = 'tester2'"
[ $status -eq 0 ]
[[ $output =~ "db2" ]] || false
! [[ $output =~ "db1" ]] || false

run dolt sql -q "SHOW GRANTS FOR tester2@localhost"
[ $status -eq 0 ]
[[ $output =~ 'GRANT INSERT ON `db2`.* TO `tester2`@`localhost`' ]] || false

dolt sql -q "REVOKE SELECT ON db1.* FROM tester1@localhost"
run dolt sql -q "SELECT user FROM mysql.db"
[ $status -eq 0 ]
! [[ $output =~ "tester1" ]] || false
[[ $output =~ "tester2" ]] || false
}

@test "sql-mysqldb-privs: smoke test for tables_priv table" {
dolt sql -q "GRANT SELECT ON db1.tbl TO tester1@localhost"
run dolt sql -q "SELECT host,user,db,table_name as t,table_priv FROM mysql.tables_priv"

[ $status -eq 0 ]
[[ $output =~ "localhost | tester1 | db1 | tbl | Select" ]] || false

run dolt sql -q "SHOW GRANTS FOR tester1@localhost"
[ $status -eq 0 ]
[[ $output =~ 'GRANT SELECT ON `db1`.`tbl` TO `tester1`@`localhost`' ]] || false

dolt sql -q "GRANT INSERT ON db1.tbl TO tester2@localhost"

run dolt sql -q "SELECT user FROM mysql.tables_priv"
[ $status -eq 0 ]
[[ $output =~ "tester1" ]] || false
[[ $output =~ "tester2" ]] || false

run dolt sql -q "SELECT user,table_priv FROM mysql.tables_priv"
[ $status -eq 0 ]
[[ $output =~ "tester1 | Select" ]] || false
[[ $output =~ "tester2 | Insert" ]] || false

run dolt sql -q "SHOW GRANTS FOR tester2@localhost"
[ $status -eq 0 ]
[[ $output =~ 'GRANT INSERT ON `db1`.`tbl` TO `tester2`@`localhost`' ]] || false

dolt sql -q "REVOKE SELECT ON db1.tbl FROM tester1@localhost"
run dolt sql -q "SELECT user FROM mysql.tables_priv"
[ $status -eq 0 ]
! [[ $output =~ "tester1" ]] || false
[[ $output =~ "tester2" ]] || false
}

@test "sql-mysqldb-privs: smoke test for procs_priv table" {
dolt sql -q "GRANT EXECUTE ON PROCEDURE db1.dolt_log TO tester1@localhost"
run dolt sql -q "SELECT host,user,db,routine_name,routine_type,proc_priv FROM mysql.procs_priv"

[ $status -eq 0 ]
[[ $output =~ "localhost | tester1 | db1 | dolt_log | PROCEDURE | Execute" ]] || false

run dolt sql -q "SHOW GRANTS FOR tester1@localhost"
[ $status -eq 0 ]
[[ $output =~ 'GRANT EXECUTE ON PROCEDURE `db1`.`dolt_log` TO `tester1`@`localhost`' ]] || false

dolt sql -q "GRANT GRANT OPTION ON PROCEDURE db1.dolt_diff TO tester2@localhost"

run dolt sql -q "SELECT user FROM mysql.procs_priv"
[ $status -eq 0 ]
[[ $output =~ "tester1" ]] || false
[[ $output =~ "tester2" ]] || false

run dolt sql -q "SELECT routine_name FROM mysql.procs_priv where user = 'tester2'"
[ $status -eq 0 ]
[[ $output =~ "dolt_diff" ]] || false
! [[ $output =~ "dolt_log" ]] || false

run dolt sql -q "SHOW GRANTS FOR tester2@localhost"
[ $status -eq 0 ]

[[ $output =~ 'GRANT USAGE ON PROCEDURE `db1`.`dolt_diff` TO `tester2`@`localhost` WITH GRANT OPTION' ]] || false

dolt sql -q "REVOKE EXECUTE ON PROCEDURE db1.dolt_log FROM tester1@localhost"
run dolt sql -q "SELECT user FROM mysql.procs_priv"
[ $status -eq 0 ]
! [[ $output =~ "tester1" ]] || false
[[ $output =~ "tester2" ]] || false
}

@test "sql-mysqldb-privs: procs_priv table should differentiate between functions and procedures" {
skip "Function Support is currently disabled"

dolt sql -q "GRANT EXECUTE ON FUNCTION db1.dolt_log TO tester1@localhost"
run dolt sql -q "SELECT host,user,db,routine_name as name,routine_type as type,proc_priv FROM mysql.procs_priv"
[ $status -eq 0 ]
[[ $output =~ "localhost | tester1 | db1 | dolt_log | FUNCTION | Execute" ]] || false

# revoking a procedure by the same name should not revoke the function permission
dolt sql -q "REVOKE EXECUTE ON PROCEDURE db1.dolt_log FROM tester1@localhost"
run dolt sql -q "SELECT host,user,db,routine_name as name,routine_type as type,proc_priv FROM mysql.procs_priv"
[ $status -eq 0 ]
[[ $output =~ "localhost | tester1 | db1 | dolt_log | FUNCTION | Execute" ]] || false

dolt sql -q "REVOKE EXECUTE ON FUNCTION db1.dolt_log FROM tester1@localhost"
run dolt sql -q "SELECT host,user,db,routine_name as name,routine_type as type,proc_priv FROM mysql.procs_priv"
[ $status -eq 0 ]
! [[ $output =~ "localhost | tester1 | db1 | dolt_log | FUNCTION | Execute" ]] || false
}

@test "sql-mysqldb-privs: revoke of non-existent permissions" {
dolt sql -q "REVOKE INSERT ON db1.* FROM tester1@localhost"
run dolt sql -q "SELECT user FROM mysql.db"
[ $status -eq 0 ]
! [[ $output =~ "tester1" ]] || false

dolt sql -q "REVOKE INSERT ON db1.tbl FROM tester1@localhost"
run dolt sql -q "SELECT user FROM mysql.tables_priv"
[ $status -eq 0 ]
! [[ $output =~ "tester1" ]] || false

dolt sql -q "REVOKE EXECUTE ON PROCEDURE db1.dolt_log FROM tester1@localhost"
run dolt sql -q "SELECT user FROM mysql.procs_priv"
[ $status -eq 0 ]
! [[ $output =~ "tester1" ]] || false
}
2 changes: 1 addition & 1 deletion integration-tests/bats/sql-privs.bats
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ behavior:
! [[ $output =~ "UPDATE" ]] || false
}

@test "sql-privs: revoking all privleges doesn't result in a corrupted privileges file" {
@test "sql-privs: revoking all privileges doesn't result in a corrupted privileges file" {
make_test_repo

dolt sql -q "CREATE USER tester@localhost"
Expand Down
Loading

0 comments on commit 6579e5b

Please sign in to comment.