github.com/cactusblossom/fabric-ca@v0.0.0-20200611062428-0082fc643826/lib/dbaccessor_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lib_test
     8  
     9  import (
    10  	"fmt"
    11  	"os"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/hyperledger/fabric-ca/api"
    16  	. "github.com/hyperledger/fabric-ca/lib"
    17  	"github.com/hyperledger/fabric-ca/lib/server/db"
    18  	"github.com/hyperledger/fabric-ca/lib/server/db/sqlite"
    19  	cadbuser "github.com/hyperledger/fabric-ca/lib/server/user"
    20  	"github.com/jmoiron/sqlx"
    21  	_ "github.com/mattn/go-sqlite3"
    22  	"github.com/stretchr/testify/assert"
    23  )
    24  
    25  const (
    26  	dbPath = "/tmp/dbtesting"
    27  
    28  	sqliteTruncateTables = `
    29  DELETE FROM Users;
    30  DELETE FROM affiliations;
    31  `
    32  
    33  	rootDB = "rootDir/fabric_ca.db"
    34  )
    35  
    36  type TestAccessor struct {
    37  	Accessor *Accessor
    38  	DB       *db.DB
    39  }
    40  
    41  func (ta *TestAccessor) Truncate() {
    42  	Truncate(ta.DB)
    43  }
    44  
    45  func TestSQLite(t *testing.T) {
    46  	cleanTestSlateSQ(t)
    47  	defer cleanTestSlateSQ(t)
    48  
    49  	if _, err := os.Stat(dbPath); err != nil {
    50  		if os.IsNotExist(err) {
    51  			os.MkdirAll(dbPath, 0755)
    52  		}
    53  	} else {
    54  		err = os.RemoveAll(dbPath)
    55  		if err != nil {
    56  			t.Errorf("RemoveAll failed: %s", err)
    57  		}
    58  		os.MkdirAll(dbPath, 0755)
    59  	}
    60  	dataSource := dbPath + "/fabric-ca.db"
    61  	sqlitedb, err := getSqliteDb(dataSource)
    62  	if err != nil {
    63  		t.Error("Failed to open connection to DB")
    64  	}
    65  	accessor := NewDBAccessor(sqlitedb)
    66  
    67  	ta := TestAccessor{
    68  		Accessor: accessor,
    69  		DB:       sqlitedb,
    70  	}
    71  	testEverything(ta, t)
    72  }
    73  
    74  // Truncate truncates the DB
    75  func Truncate(db *db.DB) {
    76  	var sql []string
    77  	sql = []string{sqliteTruncateTables}
    78  
    79  	for _, expr := range sql {
    80  		if len(strings.TrimSpace(expr)) == 0 {
    81  			continue
    82  		}
    83  		if _, err := db.Exec("", expr); err != nil {
    84  			panic(err)
    85  		}
    86  	}
    87  }
    88  
    89  func TestEmptyAccessor(t *testing.T) {
    90  	a := &Accessor{}
    91  	ui := cadbuser.Info{}
    92  	err := a.InsertUser(nil)
    93  	if err == nil {
    94  		t.Error("Passing in nil should have resulted in an error")
    95  	}
    96  
    97  	err = a.InsertUser(&ui)
    98  	if err == nil {
    99  		t.Error("Empty Accessor InsertUser should have failed")
   100  	}
   101  }
   102  
   103  func TestDBCreation(t *testing.T) {
   104  	cleanTestSlateSQ(t)
   105  	defer cleanTestSlateSQ(t)
   106  
   107  	os.Mkdir(rootDir, 0755)
   108  
   109  	testWithExistingDbAndTablesAndUser(t)
   110  	testWithExistingDbAndTable(t)
   111  	testWithExistingDb(t)
   112  }
   113  
   114  func createSQLiteDB(path string, t *testing.T) (*db.DB, *TestAccessor) {
   115  	sqlxdb, err := sqlx.Open("sqlite3", path)
   116  	assert.NoError(t, err, "Failed to open SQLite database")
   117  
   118  	sqlitedb := db.New(sqlxdb, "", nil)
   119  	accessor := NewDBAccessor(sqlitedb)
   120  
   121  	ta := &TestAccessor{
   122  		Accessor: accessor,
   123  		DB:       sqlitedb,
   124  	}
   125  
   126  	return sqlitedb, ta
   127  }
   128  
   129  // Test that an already bootstrapped database properly get inspected and bootstrapped with any new identities on the
   130  // next server start
   131  func testWithExistingDbAndTablesAndUser(t *testing.T) {
   132  	var err error
   133  
   134  	err = os.RemoveAll(rootDB)
   135  	if err != nil {
   136  		t.Errorf("RemoveAll failed: %s", err)
   137  	}
   138  	db, acc := createSQLiteDB(rootDB, t)
   139  
   140  	_, err = db.Exec("", "CREATE TABLE IF NOT EXISTS users (id VARCHAR(64), token bytea, type VARCHAR(64), affiliation VARCHAR(64), attributes VARCHAR(256), state INTEGER,  max_enrollments INTEGER, level INTEGER DEFAULT 0)")
   141  	assert.NoError(t, err, "Error creating users table")
   142  
   143  	srv := TestGetServer2(false, rootPort, rootDir, "", -1, t)
   144  	srv.CA.Config.DB.Datasource = "fabric_ca.db"
   145  
   146  	err = srv.Start()
   147  	assert.NoError(t, err, "Failed to start server")
   148  
   149  	err = srv.Stop()
   150  	assert.NoError(t, err, "Failed to stop server")
   151  
   152  	// Add additional user to registry and start server and confirm that it correctly get added
   153  	srv.RegisterBootstrapUser("admin2", "admin2pw", "")
   154  
   155  	err = srv.Start()
   156  	assert.NoError(t, err, "Failed to start server")
   157  
   158  	_, err = acc.Accessor.GetUser("admin2", nil)
   159  	assert.NoError(t, err, "Failed to correctly insert 'admin2' during second server bootstrap")
   160  
   161  	err = srv.Stop()
   162  	assert.NoError(t, err, "Failed to stop server")
   163  
   164  	err = db.Close()
   165  	assert.NoError(t, err, "Failed to close DB")
   166  }
   167  
   168  // Test starting a server with an already existing database and tables, but not bootstrapped
   169  func testWithExistingDbAndTable(t *testing.T) {
   170  	var err error
   171  
   172  	err = os.RemoveAll(rootDB)
   173  	if err != nil {
   174  		t.Errorf("RemoveAll failed: %s", err)
   175  	}
   176  	db, acc := createSQLiteDB(rootDB, t)
   177  
   178  	srv := TestGetServer2(false, rootPort, rootDir, "", -1, t)
   179  	srv.CA.Config.DB.Datasource = "fabric_ca.db"
   180  
   181  	_, err = db.Exec("", "CREATE TABLE IF NOT EXISTS users (id VARCHAR(64), token bytea, type VARCHAR(64), affiliation VARCHAR(64), attributes VARCHAR(256), state INTEGER,  max_enrollments INTEGER, level INTEGER DEFAULT 0)")
   182  	assert.NoError(t, err, "Error creating users table")
   183  
   184  	err = srv.Start()
   185  	assert.NoError(t, err, "Failed to start server")
   186  
   187  	_, err = acc.Accessor.GetUser("admin", nil)
   188  	assert.NoError(t, err, "Failed to correctly insert 'admin' during second server bootstrap")
   189  
   190  	err = srv.Stop()
   191  	assert.NoError(t, err, "Failed to stop server")
   192  
   193  	err = db.Close()
   194  	assert.NoError(t, err, "Failed to close DB")
   195  }
   196  
   197  // Test starting a server with an already existing database, but no tables or users
   198  func testWithExistingDb(t *testing.T) {
   199  	var err error
   200  
   201  	err = os.RemoveAll(rootDB)
   202  	if err != nil {
   203  		t.Errorf("RemoveAll failed: %s", err)
   204  	}
   205  	db, acc := createSQLiteDB(rootDB, t)
   206  
   207  	srv := TestGetServer2(false, rootPort, rootDir, "", -1, t)
   208  	srv.CA.Config.DB.Datasource = "fabric_ca.db"
   209  
   210  	err = srv.Start()
   211  	assert.NoError(t, err, "Failed to start server")
   212  
   213  	_, err = acc.Accessor.GetUser("admin", nil)
   214  	assert.NoError(t, err, "Failed to correctly insert 'admin' during second server bootstrap")
   215  
   216  	err = srv.Stop()
   217  	assert.NoError(t, err, "Failed to stop server")
   218  
   219  	err = db.Close()
   220  	assert.NoError(t, err, "Failed to close DB")
   221  }
   222  
   223  func cleanTestSlateSQ(t *testing.T) {
   224  	err := os.RemoveAll(rootDir)
   225  	if err != nil {
   226  		t.Errorf("RemoveAll failed: %s", err)
   227  	}
   228  	err = os.RemoveAll(dbPath)
   229  	if err != nil {
   230  		t.Errorf("RemoveAll failed: %s", err)
   231  	}
   232  }
   233  
   234  func testEverything(ta TestAccessor, t *testing.T) {
   235  	testInsertAndGetUser(ta, t)
   236  	testModifyAttribute(ta, t)
   237  	testDeleteUser(ta, t)
   238  	testUpdateUser(ta, t)
   239  	testInsertAndGetAffiliation(ta, t)
   240  	testDeleteAffiliation(ta, t)
   241  }
   242  
   243  func testInsertAndGetUser(ta TestAccessor, t *testing.T) {
   244  	t.Log("TestInsertAndGetUser")
   245  	ta.Truncate()
   246  
   247  	insert := cadbuser.Info{
   248  		Name: "testId",
   249  		Pass: "123456",
   250  		Type: "client",
   251  		Attributes: []api.Attribute{
   252  			api.Attribute{
   253  				Name:  "hf.Registrar.Roles",
   254  				Value: "peer,client,orderer,user",
   255  			},
   256  			api.Attribute{
   257  				Name:  "hf.Revoker",
   258  				Value: "false",
   259  			},
   260  			api.Attribute{
   261  				Name:  "hf.Registrar.Attributes",
   262  				Value: "*",
   263  			},
   264  			api.Attribute{
   265  				Name:  "xyz",
   266  				Value: "xyz",
   267  			},
   268  		},
   269  	}
   270  
   271  	err := ta.Accessor.InsertUser(&insert)
   272  	if err != nil {
   273  		t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err)
   274  	}
   275  
   276  	user, err := ta.Accessor.GetUser(insert.Name, nil)
   277  	if err != nil {
   278  		t.Errorf("Error occured during querying of id: %s, error: %s", insert.Name, err)
   279  	}
   280  
   281  	if user.GetName() != insert.Name {
   282  		t.Error("Incorrect ID retrieved")
   283  	}
   284  }
   285  
   286  func testModifyAttribute(ta TestAccessor, t *testing.T) {
   287  
   288  	user, err := ta.Accessor.GetUser("testId", nil)
   289  	assert.NoError(t, err, "Failed to get user")
   290  
   291  	err = user.ModifyAttributes([]api.Attribute{
   292  		api.Attribute{
   293  			Name:  "hf.Registrar.Roles",
   294  			Value: "peer",
   295  		},
   296  		api.Attribute{
   297  			Name:  "hf.Revoker",
   298  			Value: "",
   299  		},
   300  		api.Attribute{
   301  			Name:  "xyz",
   302  			Value: "",
   303  		},
   304  		api.Attribute{
   305  			Name:  "hf.IntermediateCA",
   306  			Value: "true",
   307  		},
   308  	})
   309  	assert.NoError(t, err, "Failed to modify user's attributes")
   310  
   311  	user, err = ta.Accessor.GetUser("testId", nil)
   312  	assert.NoError(t, err, "Failed to get user")
   313  
   314  	_, err = user.GetAttribute("hf.Revoker")
   315  	assert.Error(t, err, "Should have returned an error, attribute should have been deleted")
   316  
   317  	// Removes last attribute in the slice, should have correctly removed it
   318  	_, err = user.GetAttribute("xyz")
   319  	assert.Error(t, err, "Should have returned an error, attribute should have been deleted")
   320  
   321  	attr, err := user.GetAttribute("hf.IntermediateCA")
   322  	assert.NoError(t, err, "Failed to add attribute")
   323  	assert.Equal(t, "true", attr.Value, "Incorrect value for attribute 'hf.IntermediateCA")
   324  
   325  	attr, err = user.GetAttribute("hf.Registrar.Roles")
   326  	assert.NoError(t, err, "Failed to get attribute")
   327  	assert.Equal(t, "peer", attr.Value, "Incorrect value for attribute 'hf.Registrar.Roles")
   328  
   329  	// Test to make sure that any existing attributes that were not modified continue to exist in there original state
   330  	attr, err = user.GetAttribute("hf.Registrar.Attributes")
   331  	assert.NoError(t, err, "Failed to get attribute")
   332  	assert.Equal(t, "*", attr.Value)
   333  }
   334  
   335  func testDeleteUser(ta TestAccessor, t *testing.T) {
   336  	t.Log("TestDeleteUser")
   337  	ta.Truncate()
   338  
   339  	insert := cadbuser.Info{
   340  		Name:       "testId",
   341  		Pass:       "123456",
   342  		Type:       "client",
   343  		Attributes: []api.Attribute{},
   344  	}
   345  
   346  	err := ta.Accessor.InsertUser(&insert)
   347  	if err != nil {
   348  		t.Errorf("Error occured during insert query of id: %s, error: %s", insert.Name, err)
   349  	}
   350  
   351  	_, err = ta.Accessor.DeleteUser(insert.Name)
   352  	if err != nil {
   353  		t.Errorf("Error occured during deletion of ID: %s, error: %s", insert.Name, err)
   354  	}
   355  
   356  	_, err = ta.Accessor.GetUser(insert.Name, nil)
   357  	if err == nil {
   358  		t.Error("Should have errored, and not returned any results")
   359  	}
   360  }
   361  
   362  func testUpdateUser(ta TestAccessor, t *testing.T) {
   363  	t.Log("TestUpdateUser")
   364  	ta.Truncate()
   365  
   366  	insert := cadbuser.Info{
   367  		Name:           "testId",
   368  		Pass:           "123456",
   369  		Type:           "client",
   370  		Attributes:     []api.Attribute{},
   371  		MaxEnrollments: 1,
   372  	}
   373  
   374  	err := ta.Accessor.InsertUser(&insert)
   375  	if err != nil {
   376  		t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err)
   377  	}
   378  
   379  	insert.Pass = "654321"
   380  
   381  	err = ta.Accessor.UpdateUser(nil, true)
   382  	if err == nil {
   383  		t.Error("Passing in nil should have resulted in an error")
   384  	}
   385  
   386  	err = ta.Accessor.UpdateUser(&insert, true)
   387  	if err != nil {
   388  		t.Errorf("Error occured during update query of ID: %s, error: %s", insert.Name, err)
   389  	}
   390  
   391  	user, err := ta.Accessor.GetUser(insert.Name, nil)
   392  	if err != nil {
   393  		t.Errorf("Error occured during querying of ID: %s, error: %s", insert.Name, err)
   394  	}
   395  
   396  	err = user.Login(insert.Pass, -1)
   397  	if err != nil {
   398  		t.Error("Failed to login in user: ", err)
   399  	}
   400  
   401  }
   402  
   403  func testInsertAndGetAffiliation(ta TestAccessor, t *testing.T) {
   404  	ta.Truncate()
   405  
   406  	err := ta.Accessor.InsertAffiliation("Bank1", "Banks", 0)
   407  	if err != nil {
   408  		t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank1", err)
   409  	}
   410  
   411  	group, err := ta.Accessor.GetAffiliation("Bank1")
   412  	if err != nil {
   413  		t.Errorf("Error occured during querying of name: %s, error: %s", "Bank1", err)
   414  	}
   415  
   416  	if group.GetName() != "Bank1" {
   417  		t.Error("Failed to query")
   418  	}
   419  
   420  }
   421  
   422  func testDeleteAffiliation(ta TestAccessor, t *testing.T) {
   423  	ta.Truncate()
   424  
   425  	err := ta.Accessor.InsertAffiliation("Banks.Bank2", "Banks", 0)
   426  	if err != nil {
   427  		t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank2", err)
   428  	}
   429  
   430  	_, err = ta.Accessor.DeleteAffiliation("Banks.Bank2", true, true, true)
   431  	if err != nil {
   432  		t.Errorf("Error occured during deletion of group: %s, error: %s", "Bank2", err)
   433  	}
   434  
   435  	_, err = ta.Accessor.GetAffiliation("Banks.Bank2")
   436  	if err == nil {
   437  		t.Error("Should have errored, and not returned any results")
   438  	}
   439  }
   440  
   441  func TestDBErrorMessages(t *testing.T) {
   442  	var err error
   443  
   444  	cleanTestSlateSQ(t)
   445  	defer cleanTestSlateSQ(t)
   446  
   447  	if _, err = os.Stat(dbPath); err != nil {
   448  		if os.IsNotExist(err) {
   449  			os.MkdirAll(dbPath, 0755)
   450  		}
   451  	} else {
   452  		err = os.RemoveAll(dbPath)
   453  		if err != nil {
   454  			t.Errorf("RemoveAll failed: %s", err)
   455  		}
   456  		os.MkdirAll(dbPath, 0755)
   457  	}
   458  
   459  	dataSource := dbPath + "/fabric-ca.db"
   460  	sqlitedb, err := getSqliteDb(dataSource)
   461  	if err != nil {
   462  		t.Error("Failed to open connection to DB")
   463  	}
   464  	accessor := NewDBAccessor(sqlitedb)
   465  
   466  	ta := TestAccessor{
   467  		Accessor: accessor,
   468  		DB:       sqlitedb,
   469  	}
   470  
   471  	expectedErr := "Failed to get %s"
   472  	_, err = ta.Accessor.GetAffiliation("hyperledger")
   473  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   474  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "Affiliation"))
   475  	}
   476  
   477  	_, err = ta.Accessor.GetUser("testuser", []string{})
   478  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   479  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "User"))
   480  	}
   481  
   482  	newCertDBAcc := NewCertDBAccessor(sqlitedb, 0)
   483  	_, err = newCertDBAcc.GetCertificateWithID("serial", "aki")
   484  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   485  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "Certificate"))
   486  	}
   487  }
   488  
   489  func getSqliteDb(datasource string) (*db.DB, error) {
   490  	sqliteDB := sqlite.NewDB(datasource, "", nil)
   491  	err := sqliteDB.Connect()
   492  	if err != nil {
   493  		return nil, err
   494  	}
   495  	testdb, err := sqliteDB.Create()
   496  	if err != nil {
   497  		return nil, err
   498  	}
   499  	return testdb, nil
   500  }