From 6ae7f98274c6e254f84a9b8349b4a4eed0bee8a5 Mon Sep 17 00:00:00 2001 From: Gert-Jan Timmer Date: Wed, 30 May 2018 22:36:49 +0200 Subject: ADD: User authentication * User Authentication Implementation * Rename file to conform to fileformat `sqlite3_*_omit.go` * Updated sqlite3-binding.* with new upgrade tool * Add: callbackRetNil required for error type return because of adding `RegisterFunc`s directly on the connection. * Add: TestCreateAuthDatabase --- sqlite3_opt_userauth.go | 127 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 sqlite3_opt_userauth.go (limited to 'sqlite3_opt_userauth.go') diff --git a/sqlite3_opt_userauth.go b/sqlite3_opt_userauth.go new file mode 100644 index 0000000..3572f87 --- /dev/null +++ b/sqlite3_opt_userauth.go @@ -0,0 +1,127 @@ +// Copyright (C) 2018 G.J.R. Timmer . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +// +build sqlite_userauth + +package sqlite3 + +/* +#cgo CFLAGS: -DSQLITE_USER_AUTHENTICATION +#cgo LDFLAGS: -lm +#ifndef USE_LIBSQLITE3 +#include +#else +#include +#endif +#include + +static int +_sqlite3_user_authenticate(sqlite3* db, const char* zUsername, const char* aPW, int nPW) +{ + return sqlite3_user_authenticate(db, zUsername, aPW, nPW); +} + +static int +_sqlite3_user_add(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin) +{ + return sqlite3_user_add(db, zUsername, aPW, nPW, isAdmin); +} + +static int +_sqlite3_user_change(sqlite3* db, const char* zUsername, const char* aPW, int nPW, int isAdmin) +{ + return sqlite3_user_change(db, zUsername, aPW, nPW, isAdmin); +} + +static int +_sqlite3_user_delete(sqlite3* db, const char* zUsername) +{ + return sqlite3_user_delete(db, zUsername); +} +*/ +import "C" + +const ( + SQLITE_AUTH = C.SQLITE_AUTH +) + +// Authenticate will perform an authentication of the provided username +// and password against the database. +// +// If a database contains the SQLITE_USER table, then the +// call to Authenticate must be invoked with an +// appropriate username and password prior to enable read and write +//access to the database. +// +// Return SQLITE_OK on success or SQLITE_ERROR if the username/password +// combination is incorrect or unknown. +// +// If the SQLITE_USER table is not present in the database file, then +// this interface is a harmless no-op returnning SQLITE_OK. +func (c *SQLiteConn) Authenticate(username, password string) error { + rv := C._sqlite3_user_authenticate(c.db, C.CString(username), C.CString(password), C.int(len(password))) + if rv != C.SQLITE_OK { + return c.lastError() + } + + return nil +} + +// AuthUserAdd can be used (by an admin user only) +// to create a new user. When called on a no-authentication-required +// database, this routine converts the database into an authentication- +// required database, automatically makes the added user an +// administrator, and logs in the current connection as that user. +// The AuthUserAdd only works for the "main" database, not +// for any ATTACH-ed databases. Any call to AuthUserAdd by a +// non-admin user results in an error. +func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error { + isAdmin := 0 + if admin { + isAdmin = 1 + } + + rv := C._sqlite3_user_add(c.db, C.CString(username), C.CString(password), C.int(len(password)), C.int(isAdmin)) + if rv != C.SQLITE_OK { + return c.lastError() + } + + return nil +} + +// AuthUserChange can be used to change a users +// login credentials or admin privilege. Any user can change their own +// login credentials. Only an admin user can change another users login +// credentials or admin privilege setting. No user may change their own +// admin privilege setting. +func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error { + isAdmin := 0 + if admin { + isAdmin = 1 + } + + rv := C._sqlite3_user_change(c.db, C.CString(username), C.CString(password), C.int(len(password)), C.int(isAdmin)) + if rv != C.SQLITE_OK { + return c.lastError() + } + + return nil +} + +// AuthUserDelete can be used (by an admin user only) +// to delete a user. The currently logged-in user cannot be deleted, +// which guarantees that there is always an admin user and hence that +// the database cannot be converted into a no-authentication-required +// database. +func (c *SQLiteConn) AuthUserDelete(username string) error { + rv := C._sqlite3_user_delete(c.db, C.CString(username)) + if rv != C.SQLITE_OK { + return c.lastError() + } + + return nil +} + +// EOF -- cgit v1.2.3 From 2d9b52a48268af5ae75da998c2cf4a4bfd195e83 Mon Sep 17 00:00:00 2001 From: Gert-Jan Timmer Date: Thu, 31 May 2018 09:46:38 +0200 Subject: Fix: Free memory --- sqlite3_opt_userauth.go | 49 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) (limited to 'sqlite3_opt_userauth.go') diff --git a/sqlite3_opt_userauth.go b/sqlite3_opt_userauth.go index 3572f87..2892dd0 100644 --- a/sqlite3_opt_userauth.go +++ b/sqlite3_opt_userauth.go @@ -42,6 +42,9 @@ _sqlite3_user_delete(sqlite3* db, const char* zUsername) } */ import "C" +import ( + "unsafe" +) const ( SQLITE_AUTH = C.SQLITE_AUTH @@ -61,7 +64,17 @@ const ( // If the SQLITE_USER table is not present in the database file, then // this interface is a harmless no-op returnning SQLITE_OK. func (c *SQLiteConn) Authenticate(username, password string) error { - rv := C._sqlite3_user_authenticate(c.db, C.CString(username), C.CString(password), C.int(len(password))) + // Allocate C Variables + cuser := C.CString(username) + cpass := C.CString(password) + + // Free C Variables + defer func() { + C.free(unsafe.Pointer(cuser)) + C.free(unsafe.Pointer(cpass)) + }() + + rv := C._sqlite3_user_authenticate(c.db, cuser, cpass, C.int(len(password))) if rv != C.SQLITE_OK { return c.lastError() } @@ -83,7 +96,17 @@ func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error { isAdmin = 1 } - rv := C._sqlite3_user_add(c.db, C.CString(username), C.CString(password), C.int(len(password)), C.int(isAdmin)) + // Allocate C Variables + cuser := C.CString(username) + cpass := C.CString(password) + + // Free C Variables + defer func() { + C.free(unsafe.Pointer(cuser)) + C.free(unsafe.Pointer(cpass)) + }() + + rv := C._sqlite3_user_add(c.db, cuser, cpass, C.int(len(password)), C.int(isAdmin)) if rv != C.SQLITE_OK { return c.lastError() } @@ -102,7 +125,17 @@ func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error isAdmin = 1 } - rv := C._sqlite3_user_change(c.db, C.CString(username), C.CString(password), C.int(len(password)), C.int(isAdmin)) + // Allocate C Variables + cuser := C.CString(username) + cpass := C.CString(password) + + // Free C Variables + defer func() { + C.free(unsafe.Pointer(cuser)) + C.free(unsafe.Pointer(cpass)) + }() + + rv := C._sqlite3_user_change(c.db, cuser, cpass, C.int(len(password)), C.int(isAdmin)) if rv != C.SQLITE_OK { return c.lastError() } @@ -116,7 +149,15 @@ func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error // the database cannot be converted into a no-authentication-required // database. func (c *SQLiteConn) AuthUserDelete(username string) error { - rv := C._sqlite3_user_delete(c.db, C.CString(username)) + // Allocate C Variables + cuser := C.CString(username) + + // Free C Variables + defer func() { + C.free(unsafe.Pointer(cuser)) + }() + + rv := C._sqlite3_user_delete(c.db, cuser) if rv != C.SQLITE_OK { return c.lastError() } -- cgit v1.2.3 From 183e7d61d12d767363bf91073584300a2d470507 Mon Sep 17 00:00:00 2001 From: Gert-Jan Timmer Date: Thu, 31 May 2018 14:55:22 +0200 Subject: UPD: User Authentication Implemented table check; only activate User Authentication on a database which has no UA enabled. Closes #582 --- sqlite3.go | 10 ++-------- sqlite3_opt_userauth.go | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) (limited to 'sqlite3_opt_userauth.go') diff --git a/sqlite3.go b/sqlite3.go index 8a15696..56cb262 100644 --- a/sqlite3.go +++ b/sqlite3.go @@ -1368,14 +1368,8 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { return nil, fmt.Errorf("Missing '_auth_pass' while user authentication was requested with '_auth'") } - // TODO: Table exists check for table 'sqlite_user' - // replace 'authExists := false' with return value of table exists check - // - // REPLACE BY RESULT FROM TABLE EXISTS - // SELECT count(type) as exists FROM sqlite_master WHERE type='table' AND name='sqlite_user'; - // Scan result 'exists' and use it instead of boolean below. - authExists := false - + // Check if User Authentication is Enabled + authExists := conn.AuthIsEnabled() if !authExists { if err := conn.AuthUserAdd(authUser, authPass, true); err != nil { return nil, err diff --git a/sqlite3_opt_userauth.go b/sqlite3_opt_userauth.go index 2892dd0..2f5da0e 100644 --- a/sqlite3_opt_userauth.go +++ b/sqlite3_opt_userauth.go @@ -40,6 +40,23 @@ _sqlite3_user_delete(sqlite3* db, const char* zUsername) { return sqlite3_user_delete(db, zUsername); } + +static int +_sqlite3_auth_is_enabled(sqlite3* db) +{ + int exists = -1; + + sqlite3_stmt *stmt; + sqlite3_prepare_v2(db, "select count(type) from sqlite_master WHERE type='table' and name='sqlite_user';", -1, &stmt, NULL); + + while ( sqlite3_step(stmt) == SQLITE_ROW) { + exists = sqlite3_column_int(stmt, 0); + } + + sqlite3_finalize(stmt); + + return exists; +} */ import "C" import ( @@ -165,4 +182,14 @@ func (c *SQLiteConn) AuthUserDelete(username string) error { return nil } +// Check is database is protected by user authentication +func (c *SQLiteConn) AuthIsEnabled() (exists bool) { + rv := C._sqlite3_auth_is_enabled(c.db) + if rv == 1 { + exists = true + } + + return +} + // EOF -- cgit v1.2.3 From 4a33fcc1d2d467144ec063576131d346efb1f345 Mon Sep 17 00:00:00 2001 From: Gert-Jan Timmer Date: Thu, 31 May 2018 16:42:03 +0200 Subject: Stash [ci skip] --- sqlite3.go | 8 +++---- sqlite3_opt_userauth.go | 34 +++++++++++++++++++++++----- sqlite3_opt_userauth_omit.go | 5 ++++ sqlite3_opt_userauth_test.go | 54 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 86 insertions(+), 15 deletions(-) (limited to 'sqlite3_opt_userauth.go') diff --git a/sqlite3.go b/sqlite3.go index 56cb262..79b96ab 100644 --- a/sqlite3.go +++ b/sqlite3.go @@ -1308,7 +1308,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { // // If the SQLITE_USER table is not present in the database file, then // this interface is a harmless no-op returnning SQLITE_OK. - if err := conn.RegisterFunc("authenticate", conn.Authenticate, true); err != nil { + if err := conn.RegisterFunc("authenticate", conn.Authenticate, false); err != nil { return nil, err } // @@ -1321,7 +1321,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { // The AuthUserAdd only works for the "main" database, not // for any ATTACH-ed databases. Any call to AuthUserAdd by a // non-admin user results in an error. - if err := conn.RegisterFunc("auth_user_add", conn.AuthUserAdd, true); err != nil { + if err := conn.RegisterFunc("auth_user_add", conn.AuthUserAdd, false); err != nil { return nil, err } // @@ -1330,7 +1330,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { // login credentials. Only an admin user can change another users login // credentials or admin privilege setting. No user may change their own // admin privilege setting. - if err := conn.RegisterFunc("auth_user_change", conn.AuthUserChange, true); err != nil { + if err := conn.RegisterFunc("auth_user_change", conn.AuthUserChange, false); err != nil { return nil, err } // @@ -1339,7 +1339,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { // which guarantees that there is always an admin user and hence that // the database cannot be converted into a no-authentication-required // database. - if err := conn.RegisterFunc("auth_user_delete", conn.AuthUserDelete, true); err != nil { + if err := conn.RegisterFunc("auth_user_delete", conn.AuthUserDelete, false); err != nil { return nil, err } diff --git a/sqlite3_opt_userauth.go b/sqlite3_opt_userauth.go index 2f5da0e..197938b 100644 --- a/sqlite3_opt_userauth.go +++ b/sqlite3_opt_userauth.go @@ -60,6 +60,7 @@ _sqlite3_auth_is_enabled(sqlite3* db) */ import "C" import ( + "errors" "unsafe" ) @@ -67,6 +68,11 @@ const ( SQLITE_AUTH = C.SQLITE_AUTH ) +var ( + ErrUnauthorized = errors.New("SQLITE_AUTH: Unauthorized") + ErrAdminRequired = errors.New("SQLITE_AUTH: Unauthorized; Admin Privileges Required") +) + // Authenticate will perform an authentication of the provided username // and password against the database. // @@ -92,6 +98,9 @@ func (c *SQLiteConn) Authenticate(username, password string) error { }() rv := C._sqlite3_user_authenticate(c.db, cuser, cpass, C.int(len(password))) + if rv == C.SQLITE_AUTH { + return ErrUnauthorized + } if rv != C.SQLITE_OK { return c.lastError() } @@ -113,6 +122,18 @@ func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error { isAdmin = 1 } + rv := c.authUserAdd(username, password, isAdmin) + switch rv { + case C.SQLITE_AUTH: + return ErrAdminRequired + case C.SQLITE_OK: + return nil + default: + return c.lastError() + } +} + +func (c *SQLiteConn) authUserAdd(username, password string, admin int) int { // Allocate C Variables cuser := C.CString(username) cpass := C.CString(password) @@ -123,12 +144,7 @@ func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error { C.free(unsafe.Pointer(cpass)) }() - rv := C._sqlite3_user_add(c.db, cuser, cpass, C.int(len(password)), C.int(isAdmin)) - if rv != C.SQLITE_OK { - return c.lastError() - } - - return nil + return int(C._sqlite3_user_add(c.db, cuser, cpass, C.int(len(password)), C.int(admin))) } // AuthUserChange can be used to change a users @@ -153,6 +169,9 @@ func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error }() rv := C._sqlite3_user_change(c.db, cuser, cpass, C.int(len(password)), C.int(isAdmin)) + if rv == C.SQLITE_AUTH { + return ErrAdminRequired + } if rv != C.SQLITE_OK { return c.lastError() } @@ -175,6 +194,9 @@ func (c *SQLiteConn) AuthUserDelete(username string) error { }() rv := C._sqlite3_user_delete(c.db, cuser) + if rv == SQLITE_AUTH { + return ErrAdminRequired + } if rv != C.SQLITE_OK { return c.lastError() } diff --git a/sqlite3_opt_userauth_omit.go b/sqlite3_opt_userauth_omit.go index 0ae92da..3d1c758 100644 --- a/sqlite3_opt_userauth_omit.go +++ b/sqlite3_opt_userauth_omit.go @@ -62,4 +62,9 @@ func (c *SQLiteConn) AuthUserDelete(username string) error { return nil } +// Check is database is protected by user authentication +func (c *SQLiteConn) AuthIsEnabled() (exists bool) { + return +} + // EOF diff --git a/sqlite3_opt_userauth_test.go b/sqlite3_opt_userauth_test.go index 649d10e..fcbcd56 100644 --- a/sqlite3_opt_userauth_test.go +++ b/sqlite3_opt_userauth_test.go @@ -9,6 +9,7 @@ package sqlite3 import ( "database/sql" + "fmt" "os" "testing" ) @@ -23,11 +24,6 @@ func TestAuthCreateDatabase(t *testing.T) { } defer db.Close() - // Ping database - if err := db.Ping(); err != nil { - t.Fatal(err) - } - var exists bool err = db.QueryRow("select count(type) from sqlite_master WHERE type='table' and name='sqlite_user';").Scan(&exists) if err != nil { @@ -38,3 +34,51 @@ func TestAuthCreateDatabase(t *testing.T) { t.Fatal("failed to enable User Authentication") } } + +func TestAuthorization(t *testing.T) { + tempFilename := TempFilename(t) + fmt.Println(tempFilename) + //defer os.Remove(tempFilename) + + db, err := sql.Open("sqlite3", "file:"+tempFilename+"?_auth&_auth_user=admin&_auth_pass=admin") + if err != nil { + t.Fatal("Failed to open database:", err) + } + + if _, err := db.Exec("select auth_user_add('user', 'user', false);"); err != nil { + t.Fatal(err) + } + + var uname string + if err := db.QueryRow("select uname from sqlite_user where uname = 'user';").Scan(&uname); err != nil { + t.Fatal(err) + } + + if uname != "user" { + t.Fatal("Failed to create normal user") + } + db.Close() + + // Re-Open Database as User + // Add User should now fail because we are not admin + db, err = sql.Open("sqlite3", "file:"+tempFilename+"?_auth_user=user&_auth_pass=user") + if err != nil { + t.Fatal("Failed to open database:", err) + } + defer db.Close() + + // Try to create normal user + var rv string + if err := db.QueryRow("select auth_user_add('user2', 'user2', false);").Scan(&rv); err != nil { + t.Fatal(err) + } + fmt.Printf("RV: %v\n", rv) + // if rv != SQLITE_AUTH { + // t.Fatal("Succeeded creating user while not admin") + // } + + // // Try to create admin user + // if _, err := db.Exec("select auth_user_add('admin2', 'admin2', true);"); err != nil { + // t.Fatal(err) + // } +} -- cgit v1.2.3 From 0e289439a27f126dcc2fa96b2dd2d4cc9ecbbf7c Mon Sep 17 00:00:00 2001 From: Gert-Jan Timmer Date: Fri, 1 Jun 2018 11:28:04 +0200 Subject: Update User Authentication * Update bindings * Add user authentication sql functions Reference #579 --- sqlite3.go | 30 ++++++---- sqlite3_opt_userauth.go | 136 +++++++++++++++++++++++++++++++++---------- sqlite3_opt_userauth_omit.go | 88 +++++++++++++++++++++++++++- 3 files changed, 207 insertions(+), 47 deletions(-) (limited to 'sqlite3_opt_userauth.go') diff --git a/sqlite3.go b/sqlite3.go index 79b96ab..4b33726 100644 --- a/sqlite3.go +++ b/sqlite3.go @@ -1292,9 +1292,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { return nil, err } - // Register Authentication Functions into connection - // - // Register Authentication function + // Register: authenticate // Authenticate will perform an authentication of the provided username // and password against the database. // @@ -1308,12 +1306,12 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { // // If the SQLITE_USER table is not present in the database file, then // this interface is a harmless no-op returnning SQLITE_OK. - if err := conn.RegisterFunc("authenticate", conn.Authenticate, false); err != nil { + if err := conn.RegisterFunc("authenticate", conn.authenticate, false); err != nil { return nil, err } // - // Register AuthUserAdd - // AuthUserAdd can be used (by an admin user only) + // Register: auth_user_add + // auth_user_add can be used (by an admin user only) // to create a new user. When called on a no-authentication-required // database, this routine converts the database into an authentication- // required database, automatically makes the added user an @@ -1321,25 +1319,33 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { // The AuthUserAdd only works for the "main" database, not // for any ATTACH-ed databases. Any call to AuthUserAdd by a // non-admin user results in an error. - if err := conn.RegisterFunc("auth_user_add", conn.AuthUserAdd, false); err != nil { + if err := conn.RegisterFunc("auth_user_add", conn.authUserAdd, false); err != nil { return nil, err } // - // AuthUserChange can be used to change a users + // Register: auth_user_change + // auth_user_change can be used to change a users // login credentials or admin privilege. Any user can change their own // login credentials. Only an admin user can change another users login // credentials or admin privilege setting. No user may change their own // admin privilege setting. - if err := conn.RegisterFunc("auth_user_change", conn.AuthUserChange, false); err != nil { + if err := conn.RegisterFunc("auth_user_change", conn.authUserChange, false); err != nil { return nil, err } // - // AuthUserDelete can be used (by an admin user only) + // Register: auth_user_delete + // auth_user_delete can be used (by an admin user only) // to delete a user. The currently logged-in user cannot be deleted, // which guarantees that there is always an admin user and hence that // the database cannot be converted into a no-authentication-required // database. - if err := conn.RegisterFunc("auth_user_delete", conn.AuthUserDelete, false); err != nil { + if err := conn.RegisterFunc("auth_user_delete", conn.authUserDelete, false); err != nil { + return nil, err + } + + // Register: auth_enabled + // auth_enabled can be used to check if user authentication is enabled + if err := conn.RegisterFunc("auth_enabled", conn.authEnabled, false); err != nil { return nil, err } @@ -1369,7 +1375,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { } // Check if User Authentication is Enabled - authExists := conn.AuthIsEnabled() + authExists := conn.AuthEnabled() if !authExists { if err := conn.AuthUserAdd(authUser, authPass, true); err != nil { return nil, err diff --git a/sqlite3_opt_userauth.go b/sqlite3_opt_userauth.go index 197938b..94203b3 100644 --- a/sqlite3_opt_userauth.go +++ b/sqlite3_opt_userauth.go @@ -42,7 +42,7 @@ _sqlite3_user_delete(sqlite3* db, const char* zUsername) } static int -_sqlite3_auth_is_enabled(sqlite3* db) +_sqlite3_auth_enabled(sqlite3* db) { int exists = -1; @@ -87,6 +87,26 @@ var ( // If the SQLITE_USER table is not present in the database file, then // this interface is a harmless no-op returnning SQLITE_OK. func (c *SQLiteConn) Authenticate(username, password string) error { + rv := c.authenticate(username, password) + switch rv { + case C.SQLITE_ERROR, C.SQLITE_AUTH: + return ErrUnauthorized + case C.SQLITE_OK: + return nil + default: + return c.lastError() + } +} + +// authenticate provides the actual authentication to SQLite. +// This is not exported for usage in Go. +// It is however exported for usage within SQL by the user. +// +// Returns: +// C.SQLITE_OK (0) +// C.SQLITE_ERROR (1) +// C.SQLITE_AUTH (23) +func (c *SQLiteConn) authenticate(username, password string) int { // Allocate C Variables cuser := C.CString(username) cpass := C.CString(password) @@ -97,15 +117,7 @@ func (c *SQLiteConn) Authenticate(username, password string) error { C.free(unsafe.Pointer(cpass)) }() - rv := C._sqlite3_user_authenticate(c.db, cuser, cpass, C.int(len(password))) - if rv == C.SQLITE_AUTH { - return ErrUnauthorized - } - if rv != C.SQLITE_OK { - return c.lastError() - } - - return nil + return int(C._sqlite3_user_authenticate(c.db, cuser, cpass, C.int(len(password)))) } // AuthUserAdd can be used (by an admin user only) @@ -124,7 +136,7 @@ func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error { rv := c.authUserAdd(username, password, isAdmin) switch rv { - case C.SQLITE_AUTH: + case C.SQLITE_ERROR, C.SQLITE_AUTH: return ErrAdminRequired case C.SQLITE_OK: return nil @@ -133,6 +145,19 @@ func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error { } } +// authUserAdd enables the User Authentication if not enabled. +// Otherwise it will add a user. +// +// When user authentication is already enabled then this function +// can only be called by an admin. +// +// This is not exported for usage in Go. +// It is however exported for usage within SQL by the user. +// +// Returns: +// C.SQLITE_OK (0) +// C.SQLITE_ERROR (1) +// C.SQLITE_AUTH (23) func (c *SQLiteConn) authUserAdd(username, password string, admin int) int { // Allocate C Variables cuser := C.CString(username) @@ -158,6 +183,34 @@ func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error isAdmin = 1 } + rv := c.authUserChange(username, password, isAdmin) + switch rv { + case C.SQLITE_ERROR, C.SQLITE_AUTH: + return ErrAdminRequired + case C.SQLITE_OK: + return nil + default: + return c.lastError() + } +} + +// authUserChange allows to modify a user. +// Users can change their own password. +// +// Only admins can change passwords for other users +// and modify the admin flag. +// +// The admin flag of the current logged in user cannot be changed. +// THis ensures that their is always an admin. +// +// This is not exported for usage in Go. +// It is however exported for usage within SQL by the user. +// +// Returns: +// C.SQLITE_OK (0) +// C.SQLITE_ERROR (1) +// C.SQLITE_AUTH (23) +func (c *SQLiteConn) authUserChange(username, password string, admin int) int { // Allocate C Variables cuser := C.CString(username) cpass := C.CString(password) @@ -168,15 +221,7 @@ func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error C.free(unsafe.Pointer(cpass)) }() - rv := C._sqlite3_user_change(c.db, cuser, cpass, C.int(len(password)), C.int(isAdmin)) - if rv == C.SQLITE_AUTH { - return ErrAdminRequired - } - if rv != C.SQLITE_OK { - return c.lastError() - } - - return nil + return int(C._sqlite3_user_change(c.db, cuser, cpass, C.int(len(password)), C.int(admin))) } // AuthUserDelete can be used (by an admin user only) @@ -185,6 +230,29 @@ func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error // the database cannot be converted into a no-authentication-required // database. func (c *SQLiteConn) AuthUserDelete(username string) error { + rv := c.authUserDelete(username) + switch rv { + case C.SQLITE_ERROR, C.SQLITE_AUTH: + return ErrAdminRequired + case C.SQLITE_OK: + return nil + default: + return c.lastError() + } +} + +// authUserDelete can be used to delete a user. +// +// This function can only be executed by an admin. +// +// This is not exported for usage in Go. +// It is however exported for usage within SQL by the user. +// +// Returns: +// C.SQLITE_OK (0) +// C.SQLITE_ERROR (1) +// C.SQLITE_AUTH (23) +func (c *SQLiteConn) authUserDelete(username string) int { // Allocate C Variables cuser := C.CString(username) @@ -193,20 +261,12 @@ func (c *SQLiteConn) AuthUserDelete(username string) error { C.free(unsafe.Pointer(cuser)) }() - rv := C._sqlite3_user_delete(c.db, cuser) - if rv == SQLITE_AUTH { - return ErrAdminRequired - } - if rv != C.SQLITE_OK { - return c.lastError() - } - - return nil + return int(C._sqlite3_user_delete(c.db, cuser)) } -// Check is database is protected by user authentication -func (c *SQLiteConn) AuthIsEnabled() (exists bool) { - rv := C._sqlite3_auth_is_enabled(c.db) +// AuthEnabled checks if the database is protected by user authentication +func (c *SQLiteConn) AuthEnabled() (exists bool) { + rv := c.authEnabled() if rv == 1 { exists = true } @@ -214,4 +274,16 @@ func (c *SQLiteConn) AuthIsEnabled() (exists bool) { return } +// authEnabled perform the actual check for user authentication. +// +// This is not exported for usage in Go. +// It is however exported for usage within SQL by the user. +// +// Returns: +// 0 - Disabled +// 1 - Enabled +func (c *SQLiteConn) authEnabled() int { + return int(C._sqlite3_auth_enabled(c.db)) +} + // EOF diff --git a/sqlite3_opt_userauth_omit.go b/sqlite3_opt_userauth_omit.go index 3d1c758..302cd57 100644 --- a/sqlite3_opt_userauth_omit.go +++ b/sqlite3_opt_userauth_omit.go @@ -29,6 +29,19 @@ func (c *SQLiteConn) Authenticate(username, password string) error { return nil } +// authenticate provides the actual authentication to SQLite. +// This is not exported for usage in Go. +// It is however exported for usage within SQL by the user. +// +// Returns: +// C.SQLITE_OK (0) +// C.SQLITE_ERROR (1) +// C.SQLITE_AUTH (23) +func (c *SQLiteConn) authenticate(username, password string) int { + // NOOP + return 0 +} + // AuthUserAdd can be used (by an admin user only) // to create a new user. When called on a no-authentication-required // database, this routine converts the database into an authentication- @@ -42,6 +55,24 @@ func (c *SQLiteConn) AuthUserAdd(username, password string, admin bool) error { return nil } +// authUserAdd enables the User Authentication if not enabled. +// Otherwise it will add a user. +// +// When user authentication is already enabled then this function +// can only be called by an admin. +// +// This is not exported for usage in Go. +// It is however exported for usage within SQL by the user. +// +// Returns: +// C.SQLITE_OK (0) +// C.SQLITE_ERROR (1) +// C.SQLITE_AUTH (23) +func (c *SQLiteConn) authUserAdd(username, password string, admin int) int { + // NOOP + return 0 +} + // AuthUserChange can be used to change a users // login credentials or admin privilege. Any user can change their own // login credentials. Only an admin user can change another users login @@ -52,6 +83,27 @@ func (c *SQLiteConn) AuthUserChange(username, password string, admin bool) error return nil } +// authUserChange allows to modify a user. +// Users can change their own password. +// +// Only admins can change passwords for other users +// and modify the admin flag. +// +// The admin flag of the current logged in user cannot be changed. +// THis ensures that their is always an admin. +// +// This is not exported for usage in Go. +// It is however exported for usage within SQL by the user. +// +// Returns: +// C.SQLITE_OK (0) +// C.SQLITE_ERROR (1) +// C.SQLITE_AUTH (23) +func (c *SQLiteConn) authUserChange(username, password string, admin int) int { + // NOOP + return 0 +} + // AuthUserDelete can be used (by an admin user only) // to delete a user. The currently logged-in user cannot be deleted, // which guarantees that there is always an admin user and hence that @@ -62,9 +114,39 @@ func (c *SQLiteConn) AuthUserDelete(username string) error { return nil } -// Check is database is protected by user authentication -func (c *SQLiteConn) AuthIsEnabled() (exists bool) { - return +// authUserDelete can be used to delete a user. +// +// This function can only be executed by an admin. +// +// This is not exported for usage in Go. +// It is however exported for usage within SQL by the user. +// +// Returns: +// C.SQLITE_OK (0) +// C.SQLITE_ERROR (1) +// C.SQLITE_AUTH (23) +func (c *SQLiteConn) authUserDelete(username string) int { + // NOOP + return 0 +} + +// AuthEnabled checks if the database is protected by user authentication +func (c *SQLiteConn) AuthEnabled() (exists bool) { + // NOOP + return false +} + +// authEnabled perform the actual check for user authentication. +// +// This is not exported for usage in Go. +// It is however exported for usage within SQL by the user. +// +// Returns: +// 0 - Disabled +// 1 - Enabled +func (c *SQLiteConn) authEnabled() int { + // NOOP + return 0 } // EOF -- cgit v1.2.3