ADD: User Authentication Password Encoders
Allow user to choose how to encode passwords with connection string overrides of embedded `sqlite_crypt` function.
This commit is contained in:
parent
9b30110b83
commit
7337e65c27
58
sqlite3.go
58
sqlite3.go
|
@ -894,6 +894,8 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
authCreate := false
|
authCreate := false
|
||||||
authUser := ""
|
authUser := ""
|
||||||
authPass := ""
|
authPass := ""
|
||||||
|
authCrypt := ""
|
||||||
|
authSalt := ""
|
||||||
mutex := C.int(C.SQLITE_OPEN_FULLMUTEX)
|
mutex := C.int(C.SQLITE_OPEN_FULLMUTEX)
|
||||||
txlock := "BEGIN"
|
txlock := "BEGIN"
|
||||||
|
|
||||||
|
@ -929,6 +931,12 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
if val := params.Get("_auth_pass"); val != "" {
|
if val := params.Get("_auth_pass"); val != "" {
|
||||||
authPass = val
|
authPass = val
|
||||||
}
|
}
|
||||||
|
if val := params.Get("_auth_crypt"); val != "" {
|
||||||
|
authCrypt = val
|
||||||
|
}
|
||||||
|
if val := params.Get("_auth_salt"); val != "" {
|
||||||
|
authSalt = val
|
||||||
|
}
|
||||||
|
|
||||||
// _loc
|
// _loc
|
||||||
if val := params.Get("_loc"); val != "" {
|
if val := params.Get("_loc"); val != "" {
|
||||||
|
@ -1287,6 +1295,56 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||||
// Create connection to SQLite
|
// Create connection to SQLite
|
||||||
conn := &SQLiteConn{db: db, loc: loc, txlock: txlock}
|
conn := &SQLiteConn{db: db, loc: loc, txlock: txlock}
|
||||||
|
|
||||||
|
// Password Cipher has to be registerd before authentication
|
||||||
|
if len(authCrypt) > 0 {
|
||||||
|
switch strings.ToUpper(authCrypt) {
|
||||||
|
case "SHA1":
|
||||||
|
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSHA1, true); err != nil {
|
||||||
|
return nil, fmt.Errorf("CryptEncoderSHA1: %s", err)
|
||||||
|
}
|
||||||
|
case "SSHA1":
|
||||||
|
if len(authSalt) == 0 {
|
||||||
|
return nil, fmt.Errorf("_auth_crypt=ssha1, requires _auth_salt")
|
||||||
|
}
|
||||||
|
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSSHA1(authSalt), true); err != nil {
|
||||||
|
return nil, fmt.Errorf("CryptEncoderSSHA1: %s", err)
|
||||||
|
}
|
||||||
|
case "SHA256":
|
||||||
|
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSHA256, true); err != nil {
|
||||||
|
return nil, fmt.Errorf("CryptEncoderSHA256: %s", err)
|
||||||
|
}
|
||||||
|
case "SSHA256":
|
||||||
|
if len(authSalt) == 0 {
|
||||||
|
return nil, fmt.Errorf("_auth_crypt=ssha256, requires _auth_salt")
|
||||||
|
}
|
||||||
|
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSSHA256(authSalt), true); err != nil {
|
||||||
|
return nil, fmt.Errorf("CryptEncoderSSHA256: %s", err)
|
||||||
|
}
|
||||||
|
case "SHA384":
|
||||||
|
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSHA384, true); err != nil {
|
||||||
|
return nil, fmt.Errorf("CryptEncoderSHA384: %s", err)
|
||||||
|
}
|
||||||
|
case "SSHA384":
|
||||||
|
if len(authSalt) == 0 {
|
||||||
|
return nil, fmt.Errorf("_auth_crypt=ssha384, requires _auth_salt")
|
||||||
|
}
|
||||||
|
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSSHA384(authSalt), true); err != nil {
|
||||||
|
return nil, fmt.Errorf("CryptEncoderSSHA384: %s", err)
|
||||||
|
}
|
||||||
|
case "SHA512":
|
||||||
|
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSHA512, true); err != nil {
|
||||||
|
return nil, fmt.Errorf("CryptEncoderSHA512: %s", err)
|
||||||
|
}
|
||||||
|
case "SSHA512":
|
||||||
|
if len(authSalt) == 0 {
|
||||||
|
return nil, fmt.Errorf("_auth_crypt=ssha512, requires _auth_salt")
|
||||||
|
}
|
||||||
|
if err := conn.RegisterFunc("sqlite_crypt", CryptEncoderSSHA512(authSalt), true); err != nil {
|
||||||
|
return nil, fmt.Errorf("CryptEncoderSSHA512: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Preform Authentication
|
// Preform Authentication
|
||||||
if err := conn.Authenticate(authUser, authPass); err != nil {
|
if err := conn.Authenticate(authUser, authPass); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by an MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/sha512"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file provides several different implementations for the
|
||||||
|
// default embedded sqlite_crypt function.
|
||||||
|
// This function is uses a ceasar-cypher by default
|
||||||
|
// and is used within the UserAuthentication module to encode
|
||||||
|
// the password.
|
||||||
|
//
|
||||||
|
// The provided functions can be used as an overload to the sqlite_crypt
|
||||||
|
// function through the use of the RegisterFunc on the connection.
|
||||||
|
//
|
||||||
|
// Because the functions can serv a purpose to an end-user
|
||||||
|
// without using the UserAuthentication module
|
||||||
|
// the functions are default compiled in.
|
||||||
|
//
|
||||||
|
// From SQLITE3 - user-auth.txt
|
||||||
|
// The sqlite_user.pw field is encoded by a built-in SQL function
|
||||||
|
// "sqlite_crypt(X,Y)". The two arguments are both BLOBs. The first argument
|
||||||
|
// is the plaintext password supplied to the sqlite3_user_authenticate()
|
||||||
|
// interface. The second argument is the sqlite_user.pw value and is supplied
|
||||||
|
// so that the function can extract the "salt" used by the password encoder.
|
||||||
|
// The result of sqlite_crypt(X,Y) is another blob which is the value that
|
||||||
|
// ends up being stored in sqlite_user.pw. To verify credentials X supplied
|
||||||
|
// by the sqlite3_user_authenticate() routine, SQLite runs:
|
||||||
|
//
|
||||||
|
// sqlite_user.pw == sqlite_crypt(X, sqlite_user.pw)
|
||||||
|
//
|
||||||
|
// To compute an appropriate sqlite_user.pw value from a new or modified
|
||||||
|
// password X, sqlite_crypt(X,NULL) is run. A new random salt is selected
|
||||||
|
// when the second argument is NULL.
|
||||||
|
//
|
||||||
|
// The built-in version of of sqlite_crypt() uses a simple Ceasar-cypher
|
||||||
|
// which prevents passwords from being revealed by searching the raw database
|
||||||
|
// for ASCII text, but is otherwise trivally broken. For better password
|
||||||
|
// security, the database should be encrypted using the SQLite Encryption
|
||||||
|
// Extension or similar technology. Or, the application can use the
|
||||||
|
// sqlite3_create_function() interface to provide an alternative
|
||||||
|
// implementation of sqlite_crypt() that computes a stronger password hash,
|
||||||
|
// perhaps using a cryptographic hash function like SHA1.
|
||||||
|
|
||||||
|
// CryptEncoderSHA1 encodes a password with SHA1
|
||||||
|
func CryptEncoderSHA1(pass []byte, hash interface{}) []byte {
|
||||||
|
h := sha1.Sum(pass)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSSHA1 encodes a password with SHA1 with the
|
||||||
|
// configured salt.
|
||||||
|
func CryptEncoderSSHA1(salt string) func(pass []byte, hash interface{}) []byte {
|
||||||
|
return func(pass []byte, hash interface{}) []byte {
|
||||||
|
s := []byte(salt)
|
||||||
|
p := append(pass, s...)
|
||||||
|
h := sha1.Sum(p)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSHA256 encodes a password with SHA256
|
||||||
|
func CryptEncoderSHA256(pass []byte, hash interface{}) []byte {
|
||||||
|
h := sha256.Sum256(pass)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSSHA256 encodes a password with SHA256
|
||||||
|
// with the configured salt
|
||||||
|
func CryptEncoderSSHA256(salt string) func(pass []byte, hash interface{}) []byte {
|
||||||
|
return func(pass []byte, hash interface{}) []byte {
|
||||||
|
s := []byte(salt)
|
||||||
|
p := append(pass, s...)
|
||||||
|
h := sha256.Sum256(p)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSHA384 encodes a password with SHA256
|
||||||
|
func CryptEncoderSHA384(pass []byte, hash interface{}) []byte {
|
||||||
|
h := sha512.Sum384(pass)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSSHA384 encodes a password with SHA256
|
||||||
|
// with the configured salt
|
||||||
|
func CryptEncoderSSHA384(salt string) func(pass []byte, hash interface{}) []byte {
|
||||||
|
return func(pass []byte, hash interface{}) []byte {
|
||||||
|
s := []byte(salt)
|
||||||
|
p := append(pass, s...)
|
||||||
|
h := sha512.Sum384(p)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSHA512 encodes a password with SHA256
|
||||||
|
func CryptEncoderSHA512(pass []byte, hash interface{}) []byte {
|
||||||
|
h := sha512.Sum512(pass)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptEncoderSSHA512 encodes a password with SHA256
|
||||||
|
// with the configured salt
|
||||||
|
func CryptEncoderSSHA512(salt string) func(pass []byte, hash interface{}) []byte {
|
||||||
|
return func(pass []byte, hash interface{}) []byte {
|
||||||
|
s := []byte(salt)
|
||||||
|
p := append(pass, s...)
|
||||||
|
h := sha512.Sum512(p)
|
||||||
|
return h[:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EOF
|
|
@ -1108,3 +1108,247 @@ func TestUserAuthenticationDeleteUser(t *testing.T) {
|
||||||
So(err, ShouldEqual, ErrAdminRequired)
|
So(err, ShouldEqual, ErrAdminRequired)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUserAuthenticationEncoder(t *testing.T) {
|
||||||
|
connectWithCrypt := func(t *testing.T, f string, username, password string, crypt string, salt string) (file string, db *sql.DB, c *SQLiteConn, err error) {
|
||||||
|
conn = nil // Clear connection
|
||||||
|
file = f // Copy provided file (f) => file
|
||||||
|
if file == "" {
|
||||||
|
// Create dummy file
|
||||||
|
file = TempFilename(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err = sql.Open("sqlite3_with_conn", "file:"+file+fmt.Sprintf("?_auth&_auth_user=%s&_auth_pass=%s&_auth_crypt=%s&_auth_salt=%s", username, password, crypt, salt))
|
||||||
|
if err != nil {
|
||||||
|
defer os.Remove(file)
|
||||||
|
return file, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dummy query to force connection and database creation
|
||||||
|
// Will return ErrUnauthorized (SQLITE_AUTH) if user authentication fails
|
||||||
|
if _, err = db.Exec("SELECT 1;"); err != nil {
|
||||||
|
defer os.Remove(file)
|
||||||
|
defer db.Close()
|
||||||
|
return file, nil, nil, err
|
||||||
|
}
|
||||||
|
c = conn
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Convey("SHA1 Encoder", t, func() {
|
||||||
|
f1, db1, c1, err := connectWithCrypt(t, "", "admin", "admin", "sha1", "")
|
||||||
|
So(f1, ShouldNotBeBlank)
|
||||||
|
So(db1, ShouldNotBeNil)
|
||||||
|
So(c1, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer os.Remove(f1)
|
||||||
|
|
||||||
|
e, err := userExists(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(e, ShouldEqual, 1)
|
||||||
|
|
||||||
|
a, err := isAdmin(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(a, ShouldEqual, true)
|
||||||
|
db1.Close()
|
||||||
|
|
||||||
|
// Preform authentication
|
||||||
|
f2, db2, c2, err := connectWithCrypt(t, f1, "admin", "admin", "sha1", "")
|
||||||
|
So(f2, ShouldNotBeBlank)
|
||||||
|
So(f1, ShouldEqual, f2)
|
||||||
|
So(db2, ShouldNotBeNil)
|
||||||
|
So(c2, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer db2.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("SSHA1 Encoder", t, func() {
|
||||||
|
f1, db1, c1, err := connectWithCrypt(t, "", "admin", "admin", "ssha1", "salted")
|
||||||
|
So(f1, ShouldNotBeBlank)
|
||||||
|
So(db1, ShouldNotBeNil)
|
||||||
|
So(c1, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer os.Remove(f1)
|
||||||
|
|
||||||
|
e, err := userExists(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(e, ShouldEqual, 1)
|
||||||
|
|
||||||
|
a, err := isAdmin(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(a, ShouldEqual, true)
|
||||||
|
db1.Close()
|
||||||
|
|
||||||
|
// Preform authentication
|
||||||
|
f2, db2, c2, err := connectWithCrypt(t, f1, "admin", "admin", "ssha1", "salted")
|
||||||
|
So(f2, ShouldNotBeBlank)
|
||||||
|
So(f1, ShouldEqual, f2)
|
||||||
|
So(db2, ShouldNotBeNil)
|
||||||
|
So(c2, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer db2.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("SHA256 Encoder", t, func() {
|
||||||
|
f1, db1, c1, err := connectWithCrypt(t, "", "admin", "admin", "sha256", "")
|
||||||
|
So(f1, ShouldNotBeBlank)
|
||||||
|
So(db1, ShouldNotBeNil)
|
||||||
|
So(c1, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer os.Remove(f1)
|
||||||
|
|
||||||
|
e, err := userExists(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(e, ShouldEqual, 1)
|
||||||
|
|
||||||
|
a, err := isAdmin(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(a, ShouldEqual, true)
|
||||||
|
db1.Close()
|
||||||
|
|
||||||
|
// Preform authentication
|
||||||
|
f2, db2, c2, err := connectWithCrypt(t, f1, "admin", "admin", "sha256", "")
|
||||||
|
So(f2, ShouldNotBeBlank)
|
||||||
|
So(f1, ShouldEqual, f2)
|
||||||
|
So(db2, ShouldNotBeNil)
|
||||||
|
So(c2, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer db2.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("SSHA256 Encoder", t, func() {
|
||||||
|
f1, db1, c1, err := connectWithCrypt(t, "", "admin", "admin", "ssha256", "salted")
|
||||||
|
So(f1, ShouldNotBeBlank)
|
||||||
|
So(db1, ShouldNotBeNil)
|
||||||
|
So(c1, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer os.Remove(f1)
|
||||||
|
|
||||||
|
e, err := userExists(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(e, ShouldEqual, 1)
|
||||||
|
|
||||||
|
a, err := isAdmin(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(a, ShouldEqual, true)
|
||||||
|
db1.Close()
|
||||||
|
|
||||||
|
// Preform authentication
|
||||||
|
f2, db2, c2, err := connectWithCrypt(t, f1, "admin", "admin", "ssha256", "salted")
|
||||||
|
So(f2, ShouldNotBeBlank)
|
||||||
|
So(f1, ShouldEqual, f2)
|
||||||
|
So(db2, ShouldNotBeNil)
|
||||||
|
So(c2, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer db2.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("SHA384 Encoder", t, func() {
|
||||||
|
f1, db1, c1, err := connectWithCrypt(t, "", "admin", "admin", "sha384", "")
|
||||||
|
So(f1, ShouldNotBeBlank)
|
||||||
|
So(db1, ShouldNotBeNil)
|
||||||
|
So(c1, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer os.Remove(f1)
|
||||||
|
|
||||||
|
e, err := userExists(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(e, ShouldEqual, 1)
|
||||||
|
|
||||||
|
a, err := isAdmin(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(a, ShouldEqual, true)
|
||||||
|
db1.Close()
|
||||||
|
|
||||||
|
// Preform authentication
|
||||||
|
f2, db2, c2, err := connectWithCrypt(t, f1, "admin", "admin", "sha384", "")
|
||||||
|
So(f2, ShouldNotBeBlank)
|
||||||
|
So(f1, ShouldEqual, f2)
|
||||||
|
So(db2, ShouldNotBeNil)
|
||||||
|
So(c2, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer db2.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("SSHA384 Encoder", t, func() {
|
||||||
|
f1, db1, c1, err := connectWithCrypt(t, "", "admin", "admin", "ssha384", "salted")
|
||||||
|
So(f1, ShouldNotBeBlank)
|
||||||
|
So(db1, ShouldNotBeNil)
|
||||||
|
So(c1, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer os.Remove(f1)
|
||||||
|
|
||||||
|
e, err := userExists(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(e, ShouldEqual, 1)
|
||||||
|
|
||||||
|
a, err := isAdmin(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(a, ShouldEqual, true)
|
||||||
|
db1.Close()
|
||||||
|
|
||||||
|
// Preform authentication
|
||||||
|
f2, db2, c2, err := connectWithCrypt(t, f1, "admin", "admin", "ssha384", "salted")
|
||||||
|
So(f2, ShouldNotBeBlank)
|
||||||
|
So(f1, ShouldEqual, f2)
|
||||||
|
So(db2, ShouldNotBeNil)
|
||||||
|
So(c2, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer db2.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("SHA512 Encoder", t, func() {
|
||||||
|
f1, db1, c1, err := connectWithCrypt(t, "", "admin", "admin", "sha512", "")
|
||||||
|
So(f1, ShouldNotBeBlank)
|
||||||
|
So(db1, ShouldNotBeNil)
|
||||||
|
So(c1, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer os.Remove(f1)
|
||||||
|
|
||||||
|
e, err := userExists(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(e, ShouldEqual, 1)
|
||||||
|
|
||||||
|
a, err := isAdmin(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(a, ShouldEqual, true)
|
||||||
|
db1.Close()
|
||||||
|
|
||||||
|
// Preform authentication
|
||||||
|
f2, db2, c2, err := connectWithCrypt(t, f1, "admin", "admin", "sha512", "")
|
||||||
|
So(f2, ShouldNotBeBlank)
|
||||||
|
So(f1, ShouldEqual, f2)
|
||||||
|
So(db2, ShouldNotBeNil)
|
||||||
|
So(c2, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer db2.Close()
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("SSHA512 Encoder", t, func() {
|
||||||
|
f1, db1, c1, err := connectWithCrypt(t, "", "admin", "admin", "ssha512", "salted")
|
||||||
|
So(f1, ShouldNotBeBlank)
|
||||||
|
So(db1, ShouldNotBeNil)
|
||||||
|
So(c1, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer os.Remove(f1)
|
||||||
|
|
||||||
|
e, err := userExists(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(e, ShouldEqual, 1)
|
||||||
|
|
||||||
|
a, err := isAdmin(db1, "admin")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(a, ShouldEqual, true)
|
||||||
|
db1.Close()
|
||||||
|
|
||||||
|
// Preform authentication
|
||||||
|
f2, db2, c2, err := connectWithCrypt(t, f1, "admin", "admin", "ssha512", "salted")
|
||||||
|
So(f2, ShouldNotBeBlank)
|
||||||
|
So(f1, ShouldEqual, f2)
|
||||||
|
So(db2, ShouldNotBeNil)
|
||||||
|
So(c2, ShouldNotBeNil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
defer db2.Close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue