github.com/ldc1995/fabric-ca@v2.0.0-alpha.0.20200422214819-8d49c278c386+incompatible/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  	testInsertAndGetFilteredUsers(ta, t)
   242  }
   243  
   244  func testInsertAndGetUser(ta TestAccessor, t *testing.T) {
   245  	t.Log("TestInsertAndGetUser")
   246  	ta.Truncate()
   247  
   248  	insert := cadbuser.Info{
   249  		Name: "testId",
   250  		Pass: "123456",
   251  		Type: "client",
   252  		Attributes: []api.Attribute{
   253  			api.Attribute{
   254  				Name:  "hf.Registrar.Roles",
   255  				Value: "peer,client,orderer,user",
   256  			},
   257  			api.Attribute{
   258  				Name:  "hf.Revoker",
   259  				Value: "false",
   260  			},
   261  			api.Attribute{
   262  				Name:  "hf.Registrar.Attributes",
   263  				Value: "*",
   264  			},
   265  			api.Attribute{
   266  				Name:  "xyz",
   267  				Value: "xyz",
   268  			},
   269  		},
   270  	}
   271  
   272  	err := ta.Accessor.InsertUser(&insert)
   273  	if err != nil {
   274  		t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err)
   275  	}
   276  
   277  	user, err := ta.Accessor.GetUser(insert.Name, nil)
   278  	if err != nil {
   279  		t.Errorf("Error occured during querying of id: %s, error: %s", insert.Name, err)
   280  	}
   281  
   282  	if user.GetName() != insert.Name {
   283  		t.Error("Incorrect ID retrieved")
   284  	}
   285  }
   286  
   287  func testInsertAndGetFilteredUsers(ta TestAccessor, t *testing.T) {
   288  	t.Log("TestInsertAndGetFilteredUsers")
   289  	ta.Truncate()
   290  	// test type=* and affiliation is not nil
   291  	// insert affiliation
   292  	err := ta.Accessor.InsertAffiliation("Bank1", "Banks", 0)
   293  	if err != nil {
   294  		t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank1", err)
   295  	}
   296  	// create user
   297  	insert := cadbuser.Info{
   298  		Name:        "testTypes",
   299  		Pass:        "123456",
   300  		Type:        "*",
   301  		Affiliation: "Bank1",
   302  		Attributes: []api.Attribute{
   303  			api.Attribute{
   304  				Name:  "hf.Registrar.Roles",
   305  				Value: "peer,client,orderer,user",
   306  			},
   307  			api.Attribute{
   308  				Name:  "hf.Revoker",
   309  				Value: "false",
   310  			},
   311  			api.Attribute{
   312  				Name:  "hf.Registrar.Attributes",
   313  				Value: "*",
   314  			},
   315  			api.Attribute{
   316  				Name:  "xyz",
   317  				Value: "xyz",
   318  			},
   319  		},
   320  	}
   321  	// insert user
   322  	err = ta.Accessor.InsertUser(&insert)
   323  	if err != nil {
   324  		t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err)
   325  	}
   326  	// test get the user
   327  	rows, err := ta.Accessor.GetFilteredUsers(insert.Affiliation, "*")
   328  	if err != nil {
   329  		t.Errorf("Error occured during querying of id: %s, error: %s", insert.Name, err)
   330  	}
   331  	// use the success flag to tag success
   332  	successFlag := false
   333  	for rows.Next() {
   334  		var id cadbuser.Record
   335  		err := rows.StructScan(&id)
   336  		if err != nil {
   337  			t.Errorf("Error occured during parser the rows data: %s, error: %s", insert.Name, err)
   338  		}
   339  		// get the target user
   340  		if id.Affiliation == "Bank1" && id.Name == insert.Name {
   341  			successFlag = true
   342  		}
   343  	}
   344  	// not success
   345  	if !successFlag {
   346  		t.Errorf("Test InsertAndGetFilteredUsers Failed!")
   347  	}
   348  }
   349  
   350  func testModifyAttribute(ta TestAccessor, t *testing.T) {
   351  
   352  	user, err := ta.Accessor.GetUser("testId", nil)
   353  	assert.NoError(t, err, "Failed to get user")
   354  
   355  	err = user.ModifyAttributes([]api.Attribute{
   356  		api.Attribute{
   357  			Name:  "hf.Registrar.Roles",
   358  			Value: "peer",
   359  		},
   360  		api.Attribute{
   361  			Name:  "hf.Revoker",
   362  			Value: "",
   363  		},
   364  		api.Attribute{
   365  			Name:  "xyz",
   366  			Value: "",
   367  		},
   368  		api.Attribute{
   369  			Name:  "hf.IntermediateCA",
   370  			Value: "true",
   371  		},
   372  	})
   373  	assert.NoError(t, err, "Failed to modify user's attributes")
   374  
   375  	user, err = ta.Accessor.GetUser("testId", nil)
   376  	assert.NoError(t, err, "Failed to get user")
   377  
   378  	_, err = user.GetAttribute("hf.Revoker")
   379  	assert.Error(t, err, "Should have returned an error, attribute should have been deleted")
   380  
   381  	// Removes last attribute in the slice, should have correctly removed it
   382  	_, err = user.GetAttribute("xyz")
   383  	assert.Error(t, err, "Should have returned an error, attribute should have been deleted")
   384  
   385  	attr, err := user.GetAttribute("hf.IntermediateCA")
   386  	assert.NoError(t, err, "Failed to add attribute")
   387  	assert.Equal(t, "true", attr.Value, "Incorrect value for attribute 'hf.IntermediateCA")
   388  
   389  	attr, err = user.GetAttribute("hf.Registrar.Roles")
   390  	assert.NoError(t, err, "Failed to get attribute")
   391  	assert.Equal(t, "peer", attr.Value, "Incorrect value for attribute 'hf.Registrar.Roles")
   392  
   393  	// Test to make sure that any existing attributes that were not modified continue to exist in there original state
   394  	attr, err = user.GetAttribute("hf.Registrar.Attributes")
   395  	assert.NoError(t, err, "Failed to get attribute")
   396  	assert.Equal(t, "*", attr.Value)
   397  }
   398  
   399  func testDeleteUser(ta TestAccessor, t *testing.T) {
   400  	t.Log("TestDeleteUser")
   401  	ta.Truncate()
   402  
   403  	insert := cadbuser.Info{
   404  		Name:       "testId",
   405  		Pass:       "123456",
   406  		Type:       "client",
   407  		Attributes: []api.Attribute{},
   408  	}
   409  
   410  	err := ta.Accessor.InsertUser(&insert)
   411  	if err != nil {
   412  		t.Errorf("Error occured during insert query of id: %s, error: %s", insert.Name, err)
   413  	}
   414  
   415  	_, err = ta.Accessor.DeleteUser(insert.Name)
   416  	if err != nil {
   417  		t.Errorf("Error occured during deletion of ID: %s, error: %s", insert.Name, err)
   418  	}
   419  
   420  	_, err = ta.Accessor.GetUser(insert.Name, nil)
   421  	if err == nil {
   422  		t.Error("Should have errored, and not returned any results")
   423  	}
   424  }
   425  
   426  func testUpdateUser(ta TestAccessor, t *testing.T) {
   427  	t.Log("TestUpdateUser")
   428  	ta.Truncate()
   429  
   430  	insert := cadbuser.Info{
   431  		Name:           "testId",
   432  		Pass:           "123456",
   433  		Type:           "client",
   434  		Attributes:     []api.Attribute{},
   435  		MaxEnrollments: 1,
   436  	}
   437  
   438  	err := ta.Accessor.InsertUser(&insert)
   439  	if err != nil {
   440  		t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err)
   441  	}
   442  
   443  	insert.Pass = "654321"
   444  
   445  	err = ta.Accessor.UpdateUser(nil, true)
   446  	if err == nil {
   447  		t.Error("Passing in nil should have resulted in an error")
   448  	}
   449  
   450  	err = ta.Accessor.UpdateUser(&insert, true)
   451  	if err != nil {
   452  		t.Errorf("Error occured during update query of ID: %s, error: %s", insert.Name, err)
   453  	}
   454  
   455  	user, err := ta.Accessor.GetUser(insert.Name, nil)
   456  	if err != nil {
   457  		t.Errorf("Error occured during querying of ID: %s, error: %s", insert.Name, err)
   458  	}
   459  
   460  	err = user.Login(insert.Pass, -1)
   461  	if err != nil {
   462  		t.Error("Failed to login in user: ", err)
   463  	}
   464  
   465  }
   466  
   467  func testInsertAndGetAffiliation(ta TestAccessor, t *testing.T) {
   468  	ta.Truncate()
   469  
   470  	err := ta.Accessor.InsertAffiliation("Bank1", "Banks", 0)
   471  	if err != nil {
   472  		t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank1", err)
   473  	}
   474  
   475  	group, err := ta.Accessor.GetAffiliation("Bank1")
   476  	if err != nil {
   477  		t.Errorf("Error occured during querying of name: %s, error: %s", "Bank1", err)
   478  	}
   479  
   480  	if group.GetName() != "Bank1" {
   481  		t.Error("Failed to query")
   482  	}
   483  
   484  }
   485  
   486  func testDeleteAffiliation(ta TestAccessor, t *testing.T) {
   487  	ta.Truncate()
   488  
   489  	err := ta.Accessor.InsertAffiliation("Banks.Bank2", "Banks", 0)
   490  	if err != nil {
   491  		t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank2", err)
   492  	}
   493  
   494  	_, err = ta.Accessor.DeleteAffiliation("Banks.Bank2", true, true, true)
   495  	if err != nil {
   496  		t.Errorf("Error occured during deletion of group: %s, error: %s", "Bank2", err)
   497  	}
   498  
   499  	_, err = ta.Accessor.GetAffiliation("Banks.Bank2")
   500  	if err == nil {
   501  		t.Error("Should have errored, and not returned any results")
   502  	}
   503  }
   504  
   505  func TestDBErrorMessages(t *testing.T) {
   506  	var err error
   507  
   508  	cleanTestSlateSQ(t)
   509  	defer cleanTestSlateSQ(t)
   510  
   511  	if _, err = os.Stat(dbPath); err != nil {
   512  		if os.IsNotExist(err) {
   513  			os.MkdirAll(dbPath, 0755)
   514  		}
   515  	} else {
   516  		err = os.RemoveAll(dbPath)
   517  		if err != nil {
   518  			t.Errorf("RemoveAll failed: %s", err)
   519  		}
   520  		os.MkdirAll(dbPath, 0755)
   521  	}
   522  
   523  	dataSource := dbPath + "/fabric-ca.db"
   524  	sqlitedb, err := getSqliteDb(dataSource)
   525  	if err != nil {
   526  		t.Error("Failed to open connection to DB")
   527  	}
   528  	accessor := NewDBAccessor(sqlitedb)
   529  
   530  	ta := TestAccessor{
   531  		Accessor: accessor,
   532  		DB:       sqlitedb,
   533  	}
   534  
   535  	expectedErr := "Failed to get %s"
   536  	_, err = ta.Accessor.GetAffiliation("hyperledger")
   537  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   538  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "affiliation"))
   539  	}
   540  
   541  	_, err = ta.Accessor.GetUser("testuser", []string{})
   542  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   543  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "User"))
   544  	}
   545  
   546  	newCertDBAcc := NewCertDBAccessor(sqlitedb, 0)
   547  	_, err = newCertDBAcc.GetCertificateWithID("serial", "aki")
   548  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   549  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "Certificate"))
   550  	}
   551  }
   552  
   553  func getSqliteDb(datasource string) (*db.DB, error) {
   554  	sqliteDB := sqlite.NewDB(datasource, "", nil)
   555  	err := sqliteDB.Connect()
   556  	if err != nil {
   557  		return nil, err
   558  	}
   559  	testdb, err := sqliteDB.Create()
   560  	if err != nil {
   561  		return nil, err
   562  	}
   563  	return testdb, nil
   564  }