github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/lib/dasqlite_test.go (about)

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