github.com/49746628/fabric-ca-gm@v2.0.0-alpha.0.20200822143404-8a07eefa7452+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/internal/pkg/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  	// create user
   291  	insert := cadbuser.Info{
   292  		Name: "testTypesClient",
   293  		Pass: "123456",
   294  		Type: "client",
   295  		Attributes: []api.Attribute{
   296  			api.Attribute{
   297  				Name:  "hf.Registrar.Roles",
   298  				Value: "peer,client,orderer,user",
   299  			},
   300  			api.Attribute{
   301  				Name:  "hf.Revoker",
   302  				Value: "false",
   303  			},
   304  			api.Attribute{
   305  				Name:  "hf.Registrar.Attributes",
   306  				Value: "*",
   307  			},
   308  			api.Attribute{
   309  				Name:  "xyz",
   310  				Value: "xyz",
   311  			},
   312  		},
   313  	}
   314  	// insert user
   315  	err := ta.Accessor.InsertUser(&insert)
   316  	if err != nil {
   317  		t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err)
   318  	}
   319  	// test get the user
   320  	rows, err := ta.Accessor.GetFilteredUsers("", "client,orderer")
   321  	if err != nil {
   322  		t.Errorf("Failed to get users by affiliation: %s, and type: %s, error: %s", "", "client,orderer", err)
   323  	}
   324  
   325  	typesClientSuccessFlag := false
   326  	for rows.Next() {
   327  		var id cadbuser.Record
   328  		err := rows.StructScan(&id)
   329  		if err != nil {
   330  			t.Errorf("Failed to get read row! error: %s", err)
   331  		}
   332  		// get the target user
   333  		if id.Name == "testTypesClient" && id.Type == "client" {
   334  			typesClientSuccessFlag = true
   335  		}
   336  	}
   337  	// not success
   338  	if !typesClientSuccessFlag {
   339  		t.Errorf("Test InsertAndGetFilteredUsers Failed!")
   340  	}
   341  
   342  	// test type=* and affiliation is not nil
   343  	// insert affiliation
   344  	err = ta.Accessor.InsertAffiliation("Bank1", "Banks", 0)
   345  	if err != nil {
   346  		t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank1", err)
   347  	}
   348  	// change user info
   349  	insert.Name = "testTypesStar"
   350  	insert.Type = "*"
   351  	insert.Affiliation = "Bank1"
   352  	// insert user
   353  	err = ta.Accessor.InsertUser(&insert)
   354  	if err != nil {
   355  		t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err)
   356  	}
   357  	// test get the user
   358  	rows, err = ta.Accessor.GetFilteredUsers("Bank1", "*")
   359  	if err != nil {
   360  		t.Errorf("Failed to get users by affiliation: %s, and type: %s, error: %s", "Bank1", "*", err)
   361  	}
   362  	// use the success flag to tag success
   363  	affiliationsTypeStarSuccessFlag := false
   364  	for rows.Next() {
   365  		var id cadbuser.Record
   366  		err := rows.StructScan(&id)
   367  		if err != nil {
   368  			t.Errorf("Failed to get read row! error: %s", err)
   369  		}
   370  		// get the target user
   371  		if id.Affiliation == "Bank1" && id.Name == "testTypesStar" {
   372  			affiliationsTypeStarSuccessFlag = true
   373  		}
   374  	}
   375  	// not success
   376  	if !affiliationsTypeStarSuccessFlag {
   377  		t.Errorf("Test InsertAndGetFilteredUsers Failed!")
   378  	}
   379  
   380  	// test get all user
   381  	affiliationsTypeStarSuccessFlag = false
   382  	typesClientSuccessFlag = false
   383  	// test get all users
   384  	rows, err = ta.Accessor.GetFilteredUsers("", "*")
   385  	if err != nil {
   386  		t.Errorf("Failed to get users by affiliation: %s, and type: %s, error: %s", "", "*", err)
   387  	}
   388  	for rows.Next() {
   389  		var id cadbuser.Record
   390  		err := rows.StructScan(&id)
   391  		if err != nil {
   392  			t.Errorf("Failed to get read row! error: %s", err)
   393  		}
   394  		// get the target user
   395  		if id.Affiliation == "Bank1" && id.Name == "testTypesStar" {
   396  			affiliationsTypeStarSuccessFlag = true
   397  		}
   398  		if id.Name == "testTypesClient" && id.Type == "client" {
   399  			typesClientSuccessFlag = true
   400  		}
   401  	}
   402  	// not success
   403  	if !(affiliationsTypeStarSuccessFlag && typesClientSuccessFlag) {
   404  		t.Errorf("Test InsertAndGetFilteredUsers Failed!")
   405  	}
   406  }
   407  
   408  func testModifyAttribute(ta TestAccessor, t *testing.T) {
   409  
   410  	user, err := ta.Accessor.GetUser("testId", nil)
   411  	assert.NoError(t, err, "Failed to get user")
   412  
   413  	err = user.ModifyAttributes([]api.Attribute{
   414  		api.Attribute{
   415  			Name:  "hf.Registrar.Roles",
   416  			Value: "peer",
   417  		},
   418  		api.Attribute{
   419  			Name:  "hf.Revoker",
   420  			Value: "",
   421  		},
   422  		api.Attribute{
   423  			Name:  "xyz",
   424  			Value: "",
   425  		},
   426  		api.Attribute{
   427  			Name:  "hf.IntermediateCA",
   428  			Value: "true",
   429  		},
   430  	})
   431  	assert.NoError(t, err, "Failed to modify user's attributes")
   432  
   433  	user, err = ta.Accessor.GetUser("testId", nil)
   434  	assert.NoError(t, err, "Failed to get user")
   435  
   436  	_, err = user.GetAttribute("hf.Revoker")
   437  	assert.Error(t, err, "Should have returned an error, attribute should have been deleted")
   438  
   439  	// Removes last attribute in the slice, should have correctly removed it
   440  	_, err = user.GetAttribute("xyz")
   441  	assert.Error(t, err, "Should have returned an error, attribute should have been deleted")
   442  
   443  	attr, err := user.GetAttribute("hf.IntermediateCA")
   444  	assert.NoError(t, err, "Failed to add attribute")
   445  	assert.Equal(t, "true", attr.Value, "Incorrect value for attribute 'hf.IntermediateCA")
   446  
   447  	attr, err = user.GetAttribute("hf.Registrar.Roles")
   448  	assert.NoError(t, err, "Failed to get attribute")
   449  	assert.Equal(t, "peer", attr.Value, "Incorrect value for attribute 'hf.Registrar.Roles")
   450  
   451  	// Test to make sure that any existing attributes that were not modified continue to exist in there original state
   452  	attr, err = user.GetAttribute("hf.Registrar.Attributes")
   453  	assert.NoError(t, err, "Failed to get attribute")
   454  	assert.Equal(t, "*", attr.Value)
   455  }
   456  
   457  func testDeleteUser(ta TestAccessor, t *testing.T) {
   458  	t.Log("TestDeleteUser")
   459  	ta.Truncate()
   460  
   461  	insert := cadbuser.Info{
   462  		Name:       "testId",
   463  		Pass:       "123456",
   464  		Type:       "client",
   465  		Attributes: []api.Attribute{},
   466  	}
   467  
   468  	err := ta.Accessor.InsertUser(&insert)
   469  	if err != nil {
   470  		t.Errorf("Error occured during insert query of id: %s, error: %s", insert.Name, err)
   471  	}
   472  
   473  	_, err = ta.Accessor.DeleteUser(insert.Name)
   474  	if err != nil {
   475  		t.Errorf("Error occured during deletion of ID: %s, error: %s", insert.Name, err)
   476  	}
   477  
   478  	_, err = ta.Accessor.GetUser(insert.Name, nil)
   479  	if err == nil {
   480  		t.Error("Should have errored, and not returned any results")
   481  	}
   482  }
   483  
   484  func testUpdateUser(ta TestAccessor, t *testing.T) {
   485  	t.Log("TestUpdateUser")
   486  	ta.Truncate()
   487  
   488  	insert := cadbuser.Info{
   489  		Name:           "testId",
   490  		Pass:           "123456",
   491  		Type:           "client",
   492  		Attributes:     []api.Attribute{},
   493  		MaxEnrollments: 1,
   494  	}
   495  
   496  	err := ta.Accessor.InsertUser(&insert)
   497  	if err != nil {
   498  		t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err)
   499  	}
   500  
   501  	insert.Pass = "654321"
   502  
   503  	err = ta.Accessor.UpdateUser(nil, true)
   504  	if err == nil {
   505  		t.Error("Passing in nil should have resulted in an error")
   506  	}
   507  
   508  	err = ta.Accessor.UpdateUser(&insert, true)
   509  	if err != nil {
   510  		t.Errorf("Error occured during update query of ID: %s, error: %s", insert.Name, err)
   511  	}
   512  
   513  	user, err := ta.Accessor.GetUser(insert.Name, nil)
   514  	if err != nil {
   515  		t.Errorf("Error occured during querying of ID: %s, error: %s", insert.Name, err)
   516  	}
   517  
   518  	err = user.Login(insert.Pass, -1)
   519  	if err != nil {
   520  		t.Error("Failed to login in user: ", err)
   521  	}
   522  
   523  }
   524  
   525  func testInsertAndGetAffiliation(ta TestAccessor, t *testing.T) {
   526  	ta.Truncate()
   527  
   528  	err := ta.Accessor.InsertAffiliation("Bank1", "Banks", 0)
   529  	if err != nil {
   530  		t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank1", err)
   531  	}
   532  
   533  	group, err := ta.Accessor.GetAffiliation("Bank1")
   534  	if err != nil {
   535  		t.Errorf("Error occured during querying of name: %s, error: %s", "Bank1", err)
   536  	}
   537  
   538  	if group.GetName() != "Bank1" {
   539  		t.Error("Failed to query")
   540  	}
   541  
   542  }
   543  
   544  func testDeleteAffiliation(ta TestAccessor, t *testing.T) {
   545  	ta.Truncate()
   546  
   547  	err := ta.Accessor.InsertAffiliation("Banks.Bank2", "Banks", 0)
   548  	if err != nil {
   549  		t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank2", err)
   550  	}
   551  
   552  	_, err = ta.Accessor.DeleteAffiliation("Banks.Bank2", true, true, true)
   553  	if err != nil {
   554  		t.Errorf("Error occured during deletion of group: %s, error: %s", "Bank2", err)
   555  	}
   556  
   557  	_, err = ta.Accessor.GetAffiliation("Banks.Bank2")
   558  	if err == nil {
   559  		t.Error("Should have errored, and not returned any results")
   560  	}
   561  }
   562  
   563  func TestDBErrorMessages(t *testing.T) {
   564  	var err error
   565  
   566  	cleanTestSlateSQ(t)
   567  	defer cleanTestSlateSQ(t)
   568  
   569  	if _, err = os.Stat(dbPath); err != nil {
   570  		if os.IsNotExist(err) {
   571  			os.MkdirAll(dbPath, 0755)
   572  		}
   573  	} else {
   574  		err = os.RemoveAll(dbPath)
   575  		if err != nil {
   576  			t.Errorf("RemoveAll failed: %s", err)
   577  		}
   578  		os.MkdirAll(dbPath, 0755)
   579  	}
   580  
   581  	dataSource := dbPath + "/fabric-ca.db"
   582  	sqlitedb, err := getSqliteDb(dataSource)
   583  	if err != nil {
   584  		t.Error("Failed to open connection to DB")
   585  	}
   586  	accessor := NewDBAccessor(sqlitedb)
   587  
   588  	ta := TestAccessor{
   589  		Accessor: accessor,
   590  		DB:       sqlitedb,
   591  	}
   592  
   593  	expectedErr := "Failed to get %s"
   594  	_, err = ta.Accessor.GetAffiliation("hyperledger")
   595  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   596  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "affiliation"))
   597  	}
   598  
   599  	_, err = ta.Accessor.GetUser("testuser", []string{})
   600  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   601  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "User"))
   602  	}
   603  
   604  	newCertDBAcc := NewCertDBAccessor(sqlitedb, 0)
   605  	_, err = newCertDBAcc.GetCertificateWithID("serial", "aki")
   606  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   607  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "Certificate"))
   608  	}
   609  }
   610  
   611  func getSqliteDb(datasource string) (*db.DB, error) {
   612  	sqliteDB := sqlite.NewDB(datasource, "", nil)
   613  	err := sqliteDB.Connect()
   614  	if err != nil {
   615  		return nil, err
   616  	}
   617  	testdb, err := sqliteDB.Create()
   618  	if err != nil {
   619  		return nil, err
   620  	}
   621  	return testdb, nil
   622  }