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