1d39c40ffSdrh# 2014-09-10 2d39c40ffSdrh# 3d39c40ffSdrh# The author disclaims copyright to this source code. In place of 4d39c40ffSdrh# a legal notice, here is a blessing: 5d39c40ffSdrh# 6d39c40ffSdrh# May you do good and not evil. 7d39c40ffSdrh# May you find forgiveness for yourself and forgive others. 8d39c40ffSdrh# May you share freely, never taking more than you give. 9d39c40ffSdrh# 10d39c40ffSdrh#*********************************************************************** 11d39c40ffSdrh# 12d39c40ffSdrh# This file implements tests of the SQLITE_USER_AUTHENTICATION extension. 13d39c40ffSdrh# 14d39c40ffSdrh 15d39c40ffSdrhset testdir [file dirname $argv0] 16d39c40ffSdrhsource $testdir/tester.tcl 17d39c40ffSdrhset testprefix userauth01 18d39c40ffSdrh 19d39c40ffSdrhifcapable !userauth { 20d39c40ffSdrh finish_test 21d39c40ffSdrh return 22d39c40ffSdrh} 23d39c40ffSdrh 24d39c40ffSdrh# Create a no-authentication-required database 25d39c40ffSdrh# 26d39c40ffSdrhdo_execsql_test userauth01-1.0 { 27d39c40ffSdrh CREATE TABLE t1(x); 28d39c40ffSdrh INSERT INTO t1 VALUES(1),(2.5),('three'),(x'4444'),(NULL); 29d39c40ffSdrh SELECT quote(x) FROM t1 ORDER BY x; 30d39c40ffSdrh SELECT name FROM sqlite_master; 31d39c40ffSdrh} {NULL 1 2.5 'three' X'4444' t1} 32d39c40ffSdrh 33d39c40ffSdrh# Calling sqlite3_user_authenticate() on a no-authentication-required 34d39c40ffSdrh# database connection is a harmless no-op. 35d39c40ffSdrh# 36d39c40ffSdrhdo_test userauth01-1.1 { 37d39c40ffSdrh sqlite3_user_authenticate db alice pw-4-alice 38d39c40ffSdrh execsql { 39d39c40ffSdrh SELECT quote(x) FROM t1 ORDER BY x; 40d39c40ffSdrh SELECT name FROM sqlite_master; 41d39c40ffSdrh } 42d39c40ffSdrh} {NULL 1 2.5 'three' X'4444' t1} 43d39c40ffSdrh 44d39c40ffSdrh# If sqlite3_user_add(D,U,P,N,A) is called on a no-authentication-required 45d39c40ffSdrh# database and A is false, then the call fails with an SQLITE_AUTH error. 46d39c40ffSdrh# 47d39c40ffSdrhdo_test userauth01-1.2 { 48d39c40ffSdrh sqlite3_user_add db bob pw-4-bob 0 49d39c40ffSdrh} {SQLITE_AUTH} 50d39c40ffSdrhdo_test userauth01-1.3 { 51d39c40ffSdrh execsql { 52d39c40ffSdrh SELECT quote(x) FROM t1 ORDER BY x; 53d39c40ffSdrh SELECT name FROM sqlite_master; 54d39c40ffSdrh } 55d39c40ffSdrh} {NULL 1 2.5 'three' X'4444' t1} 56d39c40ffSdrh 57d39c40ffSdrh# When called on a no-authentication-required 58d39c40ffSdrh# database and when A is true, the sqlite3_user_add(D,U,P,N,A) routine 59d39c40ffSdrh# converts the database into an authentication-required database and 60d39c40ffSdrh# logs the database connection D in using user U with password P,N. 61d39c40ffSdrh# 62d39c40ffSdrhdo_test userauth01-1.4 { 63d39c40ffSdrh sqlite3_user_add db alice pw-4-alice 1 64d39c40ffSdrh} {SQLITE_OK} 65d39c40ffSdrhdo_test userauth01-1.5 { 66d39c40ffSdrh execsql { 67d39c40ffSdrh SELECT quote(x) FROM t1 ORDER BY x; 68d39c40ffSdrh SELECT uname, isadmin FROM sqlite_user ORDER BY uname; 69d39c40ffSdrh SELECT name FROM sqlite_master ORDER BY name; 70d39c40ffSdrh } 71d39c40ffSdrh} {NULL 1 2.5 'three' X'4444' alice 1 sqlite_user t1} 72d39c40ffSdrh 73570f187fSdrh# The sqlite3_user_add() interface can be used (by an admin user only) 74570f187fSdrh# to create a new user. 75570f187fSdrh# 76570f187fSdrhdo_test userauth01-1.6 { 77570f187fSdrh sqlite3_user_add db bob pw-4-bob 0 78570f187fSdrh sqlite3_user_add db cindy pw-4-cindy 0 79570f187fSdrh sqlite3_user_add db david pw-4-david 0 80570f187fSdrh execsql { 81570f187fSdrh SELECT uname, isadmin FROM sqlite_user ORDER BY uname; 82570f187fSdrh } 83570f187fSdrh} {alice 1 bob 0 cindy 0 david 0} 84570f187fSdrh 85570f187fSdrh# The sqlite_user table is inaccessible (unreadable and unwriteable) to 86570f187fSdrh# non-admin users and is read-only for admin users. However, if the same 87570f187fSdrh# 88570f187fSdrhdo_test userauth01-1.7 { 89570f187fSdrh sqlite3 db2 test.db 90570f187fSdrh sqlite3_user_authenticate db2 cindy pw-4-cindy 91570f187fSdrh db2 eval { 92570f187fSdrh SELECT quote(x) FROM t1 ORDER BY x; 93570f187fSdrh SELECT name FROM sqlite_master ORDER BY name; 94570f187fSdrh } 95570f187fSdrh} {NULL 1 2.5 'three' X'4444' sqlite_user t1} 96570f187fSdrhdo_test userauth01-1.8 { 97570f187fSdrh catchsql { 98570f187fSdrh SELECT uname, isadmin FROM sqlite_user ORDER BY uname; 99570f187fSdrh } db2 100570f187fSdrh} {1 {no such table: sqlite_user}} 101570f187fSdrh 102570f187fSdrh# Any user can change their own password. 103570f187fSdrh# 104570f187fSdrhdo_test userauth01-1.9 { 105570f187fSdrh sqlite3_user_change db2 cindy xyzzy-cindy 0 106570f187fSdrh} {SQLITE_OK} 107570f187fSdrhdo_test userauth01-1.10 { 108570f187fSdrh sqlite3_user_authenticate db2 cindy pw-4-cindy 109570f187fSdrh} {SQLITE_AUTH} 110570f187fSdrhdo_test userauth01-1.11 { 111570f187fSdrh sqlite3_user_authenticate db2 cindy xyzzy-cindy 112570f187fSdrh} {SQLITE_OK} 1139d5b0df1Sdrhdo_test userauth01-1.12 { 1149d5b0df1Sdrh sqlite3_user_change db alice xyzzy-alice 1 1159d5b0df1Sdrh} {SQLITE_OK} 1169d5b0df1Sdrhdo_test userauth01-1.13 { 1179d5b0df1Sdrh sqlite3_user_authenticate db alice pw-4-alice 1189d5b0df1Sdrh} {SQLITE_AUTH} 1199d5b0df1Sdrhdo_test userauth01-1.14 { 1209d5b0df1Sdrh sqlite3_user_authenticate db alice xyzzy-alice 1219d5b0df1Sdrh} {SQLITE_OK} 122570f187fSdrh 1239d5b0df1Sdrh# No user may change their own admin privilege setting. 1249d5b0df1Sdrh# 1259d5b0df1Sdrhdo_test userauth01-1.15 { 1269d5b0df1Sdrh sqlite3_user_change db alice xyzzy-alice 0 1279d5b0df1Sdrh} {SQLITE_AUTH} 1289d5b0df1Sdrhdo_test userauth01-1.16 { 1299d5b0df1Sdrh db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname} 1309d5b0df1Sdrh} {alice 1 bob 0 cindy 0 david 0} 1319d5b0df1Sdrhdo_test userauth01-1.17 { 1329d5b0df1Sdrh sqlite3_user_change db2 cindy xyzzy-cindy 1 1339d5b0df1Sdrh} {SQLITE_AUTH} 1349d5b0df1Sdrhdo_test userauth01-1.18 { 1359d5b0df1Sdrh db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname} 1369d5b0df1Sdrh} {alice 1 bob 0 cindy 0 david 0} 1379d5b0df1Sdrh 1389d5b0df1Sdrh# The sqlite3_user_change() interface can be used to change a users 1399d5b0df1Sdrh# login credentials or admin privilege. 1409d5b0df1Sdrh# 1419d5b0df1Sdrhdo_test userauth01-1.20 { 1429d5b0df1Sdrh sqlite3_user_change db david xyzzy-david 1 1439d5b0df1Sdrh} {SQLITE_OK} 1449d5b0df1Sdrhdo_test userauth01-1.21 { 1459d5b0df1Sdrh db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname} 1469d5b0df1Sdrh} {alice 1 bob 0 cindy 0 david 1} 1479d5b0df1Sdrhdo_test userauth01-1.22 { 1489d5b0df1Sdrh sqlite3_user_authenticate db2 david xyzzy-david 1499d5b0df1Sdrh} {SQLITE_OK} 1509d5b0df1Sdrhdo_test userauth01-1.23 { 1519d5b0df1Sdrh db2 eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname} 1529d5b0df1Sdrh} {alice 1 bob 0 cindy 0 david 1} 1539d5b0df1Sdrhdo_test userauth01-1.24 { 1549d5b0df1Sdrh sqlite3_user_change db david pw-4-david 0 1559d5b0df1Sdrh} {SQLITE_OK} 1569d5b0df1Sdrhdo_test userauth01-1.25 { 1579d5b0df1Sdrh sqlite3_user_authenticate db2 david pw-4-david 1589d5b0df1Sdrh} {SQLITE_OK} 1599d5b0df1Sdrhdo_test userauth01-1.26 { 1609d5b0df1Sdrh db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname} 1619d5b0df1Sdrh} {alice 1 bob 0 cindy 0 david 0} 1629d5b0df1Sdrhdo_test userauth01-1.27 { 1639d5b0df1Sdrh catchsql {SELECT uname, isadmin FROM sqlite_user ORDER BY uname} db2 1649d5b0df1Sdrh} {1 {no such table: sqlite_user}} 1659d5b0df1Sdrh 1669d5b0df1Sdrh# Only an admin user can change another users login 1679d5b0df1Sdrh# credentials or admin privilege setting. 1689d5b0df1Sdrh# 1699d5b0df1Sdrhdo_test userauth01-1.30 { 1709d5b0df1Sdrh sqlite3_user_change db2 bob xyzzy-bob 1 1719d5b0df1Sdrh} {SQLITE_AUTH} 1729d5b0df1Sdrhdo_test userauth01-1.31 { 1739d5b0df1Sdrh db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname} 1749d5b0df1Sdrh} {alice 1 bob 0 cindy 0 david 0} 1759d5b0df1Sdrh 1769d5b0df1Sdrh# The sqlite3_user_delete() interface can be used (by an admin user only) 1779d5b0df1Sdrh# to delete a user. 1789d5b0df1Sdrh# 1799d5b0df1Sdrhdo_test userauth01-1.40 { 1809d5b0df1Sdrh sqlite3_user_delete db bob 1819d5b0df1Sdrh} {SQLITE_OK} 1829d5b0df1Sdrhdo_test userauth01-1.41 { 1839d5b0df1Sdrh db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname} 1849d5b0df1Sdrh} {alice 1 cindy 0 david 0} 1859d5b0df1Sdrhdo_test userauth01-1.42 { 1869d5b0df1Sdrh sqlite3_user_delete db2 cindy 1879d5b0df1Sdrh} {SQLITE_AUTH} 1889d5b0df1Sdrhdo_test userauth01-1.43 { 1899d5b0df1Sdrh sqlite3_user_delete db2 alice 1909d5b0df1Sdrh} {SQLITE_AUTH} 1919d5b0df1Sdrhdo_test userauth01-1.44 { 1929d5b0df1Sdrh db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname} 1939d5b0df1Sdrh} {alice 1 cindy 0 david 0} 1949d5b0df1Sdrh 1959d5b0df1Sdrh# The currently logged-in user cannot be deleted 1969d5b0df1Sdrh# 1979d5b0df1Sdrhdo_test userauth01-1.50 { 1989d5b0df1Sdrh sqlite3_user_delete db alice 1999d5b0df1Sdrh} {SQLITE_AUTH} 2009d5b0df1Sdrhdo_test userauth01-1.51 { 2019d5b0df1Sdrh db eval {SELECT uname, isadmin FROM sqlite_user ORDER BY uname} 2029d5b0df1Sdrh} {alice 1 cindy 0 david 0} 203570f187fSdrh 204a000ca68Sdrh# When ATTACH-ing new database files to a connection, each newly attached 205a000ca68Sdrh# database that is an authentication-required database is checked using 206a000ca68Sdrh# the same username and password as supplied to the main database. If that 207a000ca68Sdrh# check fails, then the ATTACH command fails with an SQLITE_AUTH error. 208a000ca68Sdrh# 209a000ca68Sdrhdo_test userauth01-1.60 { 210a000ca68Sdrh forcedelete test3.db 211a000ca68Sdrh sqlite3 db3 test3.db 212*7883ecfcSdrh sqlite3_user_add db3 alice xyzzy-alice 1 213*7883ecfcSdrh} {SQLITE_OK} 214*7883ecfcSdrhdo_test userauth01-1.61 { 215a000ca68Sdrh db3 eval { 216a000ca68Sdrh CREATE TABLE t3(a,b,c); INSERT INTO t3 VALUES(1,2,3); 217a000ca68Sdrh SELECT * FROM t3; 218a000ca68Sdrh } 219a000ca68Sdrh} {1 2 3} 220a000ca68Sdrhdo_test userauth01-1.62 { 221a000ca68Sdrh db eval { 222a000ca68Sdrh ATTACH 'test3.db' AS aux; 223a000ca68Sdrh SELECT * FROM t1, t3 ORDER BY x LIMIT 1; 224a000ca68Sdrh DETACH aux; 225a000ca68Sdrh } 226a000ca68Sdrh} {{} 1 2 3} 227a000ca68Sdrhdo_test userauth01-1.63 { 228a000ca68Sdrh sqlite3_user_change db alice pw-4-alice 1 229a000ca68Sdrh sqlite3_user_authenticate db alice pw-4-alice 230a000ca68Sdrh catchsql { 231a000ca68Sdrh ATTACH 'test3.db' AS aux; 232a000ca68Sdrh } 233a000ca68Sdrh} {1 {unable to open database: test3.db}} 234a000ca68Sdrhdo_test userauth01-1.64 { 235a000ca68Sdrh sqlite3_extended_errcode db 236a000ca68Sdrh} {SQLITE_AUTH} 237a000ca68Sdrhdo_test userauth01-1.65 { 238a000ca68Sdrh db eval {PRAGMA database_list} 239a000ca68Sdrh} {~/test3.db/} 240d39c40ffSdrh 241*7883ecfcSdrh# The sqlite3_set_authorizer() callback is modified to take a 7th parameter 242*7883ecfcSdrh# which is the username of the currently logged in user, or NULL for a 243*7883ecfcSdrh# no-authentication-required database. 244*7883ecfcSdrh# 245*7883ecfcSdrhproc auth {args} { 246*7883ecfcSdrh lappend ::authargs $args 247*7883ecfcSdrh return SQLITE_OK 248*7883ecfcSdrh} 249*7883ecfcSdrhdo_test authuser01-2.1 { 250*7883ecfcSdrh unset -nocomplain ::authargs 251*7883ecfcSdrh db auth auth 252*7883ecfcSdrh db eval {SELECT x FROM t1} 253*7883ecfcSdrh set ::authargs 254*7883ecfcSdrh} {/SQLITE_SELECT {} {} {} {} alice/} 255*7883ecfcSdrh 256*7883ecfcSdrh 257d39c40ffSdrhfinish_test 258