gitee.com/zhaochuninhefei/fabric-ca-gm@v0.0.2/cmd/fabric-ca-client/command/main_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package command
     8  
     9  import (
    10  	"bufio"
    11  	"bytes"
    12  	"encoding/hex"
    13  	"encoding/pem"
    14  	"errors"
    15  	"fmt"
    16  	"io"
    17  	"io/ioutil"
    18  	"math/big"
    19  	"os"
    20  	"path"
    21  	"path/filepath"
    22  	"reflect"
    23  	"strconv"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"gitee.com/zhaochuninhefei/cfssl-gm/csr"
    29  	"gitee.com/zhaochuninhefei/fabric-ca-gm/internal/pkg/api"
    30  	"gitee.com/zhaochuninhefei/fabric-ca-gm/internal/pkg/util"
    31  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib"
    32  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/attr"
    33  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/attrmgr"
    34  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/metadata"
    35  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/db"
    36  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/db/sqlite"
    37  	cadbuser "gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/user"
    38  	"gitee.com/zhaochuninhefei/gmgo/x509"
    39  	log "gitee.com/zhaochuninhefei/zcgolog/zclog"
    40  	"github.com/stretchr/testify/assert"
    41  )
    42  
    43  const (
    44  	testdataDir          = "homeDir"
    45  	myhost               = "hostname"
    46  	certfile             = "ec.pem"
    47  	keyfile              = "ec-key.pem"
    48  	tlsCertFile          = "tls_server-cert.pem"
    49  	tlsKeyFile           = "tls_server-key.pem"
    50  	rootCert             = "root.pem"
    51  	tlsClientCertFile    = "tls_client-cert.pem"
    52  	tlsClientCertExpired = "expiredcert.pem"
    53  	tlsClientKeyFile     = "tls_client-key.pem"
    54  	tdDir                = "../../../testdata"
    55  	dbName               = "fabric-ca-server.db"
    56  	serverPort           = 7090
    57  	rootCertEnvVar       = "FABRIC_CA_CLIENT_TLS_CERTFILES"
    58  	clientKeyEnvVar      = "FABRIC_CA_CLIENT_TLS_CLIENT_KEYFILE"
    59  	clientCertEnvVar     = "FABRIC_CA_CLIENT_TLS_CLIENT_CERTFILE"
    60  	moptionDir           = "moption-test"
    61  	clientCMD            = "fabric-ca-client"
    62  	crlExpiry            = time.Hour * 240 // 10 days
    63  )
    64  
    65  const jsonConfig = `{
    66    "URL": "http://localhost:8888",
    67    "tls": {
    68      "enabled": false,
    69      "certfiles": null,
    70      "client": {
    71        "certfile": null,
    72        "keyfile": null
    73      }
    74    },
    75    "csr": {
    76      "cn": "admin",
    77      "names": [
    78        {
    79          "C": "CN",
    80          "ST": "Anhui",
    81          "L": "Hefei",
    82          "O": "gcsoft",
    83          "OU": "gcbaas"
    84        }
    85      ],
    86      "hosts": [
    87        "charente"
    88      ],
    89      "ca": {
    90        "pathlen": null,
    91        "pathlenzero": null,
    92        "expiry": null
    93      }
    94    },
    95    "id": {
    96      "name": null,
    97      "type": null,
    98      "group": null,
    99      "attributes": [
   100        {
   101          "name": null,
   102          "value": null
   103        }
   104      ]
   105    },
   106    "enrollment": {
   107      "hosts": null,
   108      "profile": null,
   109      "label": null
   110    }
   111  }`
   112  
   113  var (
   114  	defYaml      string
   115  	fabricCADB   = path.Join(tdDir, dbName)
   116  	srv          *lib.Server
   117  	serverURL    = fmt.Sprintf("http://localhost:%d", serverPort)
   118  	enrollURL    = fmt.Sprintf("http://admin:adminpw@localhost:%d", serverPort)
   119  	enrollURL1   = fmt.Sprintf("http://admin2:adminpw2@localhost:%d", serverPort)
   120  	tlsServerURL = fmt.Sprintf("https://localhost:%d", serverPort)
   121  	tlsEnrollURL = fmt.Sprintf("https://admin:adminpw@localhost:%d", serverPort)
   122  	testYaml     = path.Join(tdDir, "test.yaml")
   123  )
   124  
   125  type TestData struct {
   126  	input []string // input
   127  }
   128  
   129  func TestMain(m *testing.M) {
   130  	metadata.Version = "1.1.0"
   131  	os.Exit(m.Run())
   132  }
   133  
   134  func TestNoArguments(t *testing.T) {
   135  	err := RunMain([]string{cmdName})
   136  	if err == nil {
   137  		assert.Error(t, errors.New("Should have resulted in an error as no arguments provided"))
   138  	}
   139  }
   140  func TestExtraArguments(t *testing.T) {
   141  	errCases := []TestData{
   142  		{[]string{cmdName, "enroll", "extraArg", "extraArg2"}},
   143  		{[]string{cmdName, "reenroll", "extraArg", "extraArg2"}},
   144  		{[]string{cmdName, "register", "extraArg", "extraArg2"}},
   145  		{[]string{cmdName, "revoke", "extraArg", "extraArg2"}},
   146  		{[]string{cmdName, "getcacert", "extraArg", "extraArg2"}},
   147  	}
   148  
   149  	for _, e := range errCases {
   150  		extraArgErrorTest(&e, t)
   151  	}
   152  }
   153  
   154  // TestCreateDefaultConfigFile test to make sure default config file gets generated correctly
   155  func TestCreateDefaultConfigFile(t *testing.T) {
   156  	defYaml = util.GetDefaultConfigFile("fabric-ca-client")
   157  	os.Remove(defYaml)
   158  
   159  	err := RunMain([]string{cmdName, "enroll", "-u", enrollURL, "-m", myhost})
   160  	if err == nil {
   161  		t.Errorf("No server running, should have failed")
   162  	}
   163  
   164  	fileBytes, err := ioutil.ReadFile(defYaml)
   165  	if err != nil {
   166  		t.Error(err)
   167  	}
   168  
   169  	configFile := string(fileBytes)
   170  
   171  	if !strings.Contains(configFile, "localhost:7090") {
   172  		t.Error("Failed to update default config file with url")
   173  	}
   174  
   175  	if !strings.Contains(configFile, myhost) {
   176  		t.Error("Failed to update default config file with host name")
   177  	}
   178  
   179  	os.Remove(defYaml)
   180  }
   181  
   182  func TestClientCommandsNoTLS(t *testing.T) {
   183  	os.Remove(fabricCADB)
   184  
   185  	srv = lib.TestGetServer(serverPort, testdataDir, "", -1, t)
   186  	srv.HomeDir = tdDir
   187  	srv.Config.Debug = true
   188  
   189  	err := srv.RegisterBootstrapUser("admin", "adminpw", "")
   190  	if err != nil {
   191  		t.Errorf("Failed to register bootstrap user: %s", err)
   192  	}
   193  
   194  	err = srv.RegisterBootstrapUser("admin2", "adminpw2", "hyperledger")
   195  	if err != nil {
   196  		t.Errorf("Failed to register bootstrap user: %s", err)
   197  	}
   198  
   199  	err = srv.RegisterBootstrapUser("admin3", "adminpw3", "company1")
   200  	if err != nil {
   201  		t.Errorf("Failed to register bootstrap user: %s", err)
   202  	}
   203  
   204  	aff := make(map[string]interface{})
   205  	aff["hyperledger"] = []string{"org1", "org2", "org3"}
   206  	aff["company1"] = []string{"dept1"}
   207  	aff["company2"] = []string{}
   208  
   209  	srv.CA.Config.Affiliations = aff
   210  
   211  	err = srv.Start()
   212  	if err != nil {
   213  		t.Errorf("Server start failed: %s", err)
   214  	}
   215  	defer srv.Stop()
   216  
   217  	testConfigFileTypes(t)
   218  	testGetCACert(t)
   219  	testEnroll(t)
   220  	testProfiling(t)
   221  	testRegisterConfigFile(t)
   222  	testRegisterEnvVar(t)
   223  	testRegisterCommandLine(t, srv)
   224  	testRevoke(t)
   225  	testBogus(t)
   226  	testAffiliation(t)
   227  }
   228  
   229  func TestEnroll(t *testing.T) {
   230  	t.Log("Testing Enroll")
   231  	adminHome := filepath.Join(tdDir, "enrolladminhome")
   232  
   233  	// Remove admin home directory if it exists
   234  	err := os.RemoveAll(adminHome)
   235  	if err != nil {
   236  		t.Fatalf("Failed to remove directory %s: %s", adminHome, err)
   237  	}
   238  
   239  	// Remove admin home directory that this test is going to create before
   240  	// exiting the test case
   241  	defer os.RemoveAll(adminHome)
   242  
   243  	srv := setupEnrollTest(t)
   244  
   245  	// Cleanup before exiting the test case
   246  	defer stopAndCleanupServer(t, srv)
   247  
   248  	// Enroll with -u parameter. Value of the -u parameter is used as server URL
   249  	err = RunMain([]string{cmdName, "enroll", "-d", "-u", enrollURL, "-H", adminHome})
   250  	if err != nil {
   251  		t.Errorf("client enroll -u failed: %s", err)
   252  	}
   253  
   254  	// Enroll without -u parameter, should fail as the server URL is picked
   255  	// from the configuration file but userid and password are not part of the
   256  	// URL
   257  	err = RunMain([]string{cmdName, "enroll", "-d", "-H", adminHome})
   258  	if err == nil {
   259  		t.Errorf("No username/password provided, should have errored")
   260  	}
   261  
   262  	// Remove admin home
   263  	err = os.RemoveAll(adminHome)
   264  	if err != nil {
   265  		t.Fatalf("Failed to remove directory %s: %s", adminHome, err)
   266  	}
   267  
   268  	// Enroll without -u parameter but with FABRIC_CA_CLIENT_URL env variable
   269  	// Default client configuration file will be generated. Value of the
   270  	// FABRIC_CA_CLIENT_URL env variable is used as server URL
   271  	os.Setenv("FABRIC_CA_CLIENT_URL", enrollURL1)
   272  	defer os.Unsetenv("FABRIC_CA_CLIENT_URL")
   273  	err = RunMain([]string{cmdName, "enroll", "-d", "-H", adminHome})
   274  	if err != nil {
   275  		t.Errorf("client enroll with FABRIC_CA_CLIENT_URL env variable failed: %s", err)
   276  	}
   277  
   278  	// Enroll without -u parameter but with FABRIC_CA_CLIENT_URL env variable
   279  	// Existing client configuration file will be used. Value of the
   280  	// FABRIC_CA_CLIENT_URL env variable is used as server URL
   281  	err = RunMain([]string{cmdName, "enroll", "-d", "-H", adminHome})
   282  	if err != nil {
   283  		t.Errorf("client enroll with FABRIC_CA_CLIENT_URL env variable failed: %s", err)
   284  	}
   285  }
   286  
   287  // Tests expiration of enrollment certificate is not after the expiration
   288  // of the CA certificate that issued the enrollment certificate.
   289  func TestEnrollmentCertExpiry(t *testing.T) {
   290  	certExpiryTestDir := "certexpirytest"
   291  	os.RemoveAll(certExpiryTestDir)
   292  	defer os.RemoveAll(certExpiryTestDir)
   293  
   294  	exprStr := "720h"
   295  	srv := startServerWithCustomExpiry(path.Join(certExpiryTestDir, "rootServer"), serverPort, exprStr, t)
   296  	defer srv.Stop()
   297  
   298  	adminHome := filepath.Join(tdDir, "certexpadminhome")
   299  	err := os.RemoveAll(adminHome)
   300  	if err != nil {
   301  		t.Fatalf("Failed to remove directory %s: %s", adminHome, err)
   302  	}
   303  	defer os.RemoveAll(adminHome)
   304  
   305  	// Enroll admin identity
   306  	err = RunMain([]string{cmdName, "enroll", "-d", "-u", enrollURL, "-H", adminHome})
   307  	if err != nil {
   308  		t.Errorf("Enrollment of admin failed: %s", err)
   309  	}
   310  
   311  	certfile := filepath.Join(adminHome, "msp/signcerts/cert.pem")
   312  	cacertFile := filepath.Join(adminHome, "msp/cacerts/localhost-"+strconv.Itoa(serverPort)+".pem")
   313  
   314  	certbytes, err := ioutil.ReadFile(certfile)
   315  	assert.NoError(t, err, "Failed to read the cert from the file %s", certfile)
   316  	cert, err := lib.BytesToX509Cert(certbytes)
   317  	assert.NoError(t, err, "Failed to convert bytes to certificate")
   318  
   319  	certbytes, err = ioutil.ReadFile(cacertFile)
   320  	assert.NoError(t, err, "Failed to read the cert from the file %s", cacertFile)
   321  	cacert, err := lib.BytesToX509Cert(certbytes)
   322  	assert.NoError(t, err, "Failed to convert bytes to certificate")
   323  
   324  	y, m, d := cacert.NotAfter.Date()
   325  	dur, _ := time.ParseDuration(exprStr)
   326  	y1, m1, d1 := time.Now().UTC().Add(dur).Date()
   327  	assert.Equal(t, y1, y, "CA cert's expiration year is not as expected")
   328  	assert.Equal(t, m1, m, "CA cert's expiration month is not as expected")
   329  	assert.Equal(t, d1, d, "CA cert's expiration day is not as expected")
   330  
   331  	assert.False(t, cert.NotAfter.After(cacert.NotAfter),
   332  		"Enrollment certificate expires after CA cert")
   333  }
   334  
   335  // Test cases for gencrl command
   336  func TestGenCRL(t *testing.T) {
   337  	t.Log("Testing GenCRL")
   338  	adminHome := filepath.Join(tdDir, "gencrladminhome")
   339  
   340  	// Remove admin home directory if it exists
   341  	err := os.RemoveAll(adminHome)
   342  	if err != nil {
   343  		t.Fatalf("Failed to remove directory %s: %s", adminHome, err)
   344  	}
   345  
   346  	// Remove admin home directory that this test is going to create before
   347  	// exiting the test case
   348  	defer os.RemoveAll(adminHome)
   349  
   350  	// Set up for the test case
   351  	srv := setupGenCRLTest(t, adminHome)
   352  
   353  	// Cleanup before exiting the test case
   354  	defer stopAndCleanupServer(t, srv)
   355  
   356  	// Error case 1: gencrl command should fail when called without enrollment info
   357  	tmpHome := filepath.Join(os.TempDir(), "gencrlhome")
   358  	defer os.RemoveAll(tmpHome)
   359  	prvHome := os.Getenv(homeEnvVar)
   360  	defer os.Setenv(homeEnvVar, prvHome)
   361  
   362  	os.Setenv(homeEnvVar, tmpHome)
   363  	err = RunMain([]string{cmdName, "gencrl"})
   364  	assert.Error(t, err, "gencrl should have failed when called without enrollment information")
   365  
   366  	os.Setenv(homeEnvVar, adminHome)
   367  
   368  	// Register, enroll and revoke two users using admin identity
   369  	client := &lib.Client{
   370  		Config:  &lib.ClientConfig{URL: fmt.Sprintf("http://localhost:%d", serverPort)},
   371  		HomeDir: adminHome,
   372  	}
   373  	admin, err := client.LoadMyIdentity()
   374  	if err != nil {
   375  		t.Fatalf("Failed to load admin identity: %s", err)
   376  	}
   377  
   378  	var revokedCertSerials []*big.Int
   379  
   380  	// Success cases
   381  	// success case 1: there are no revoked certs
   382  	err = RunMain([]string{cmdName, "gencrl"})
   383  	assert.NoError(t, err, "gencrl failed")
   384  	checkCRL(t, admin.GetClient(), revokedCertSerials)
   385  
   386  	revokedCertSerials = registerAndRevokeUsers(t, admin, 2)
   387  
   388  	// success case 2: gencrl invoked without any arguments
   389  	err = RunMain([]string{cmdName, "gencrl"})
   390  	assert.NoError(t, err, "gencrl failed")
   391  	checkCRL(t, admin.GetClient(), revokedCertSerials)
   392  
   393  	// success case 3: gencrl invoked with --revokedafter argument but not --revokedbefore
   394  	pastTime := time.Now().UTC().Add(time.Hour * -1).Format(time.RFC3339)
   395  	err = RunMain([]string{cmdName, "gencrl", "--revokedafter", pastTime})
   396  	assert.NoError(t, err, "gencrl failed")
   397  	checkCRL(t, admin.GetClient(), revokedCertSerials)
   398  
   399  	// success case 4: gencrl invoked with --revokedbefore argument but not --revokedafter
   400  	futureTime := time.Now().UTC().Add(time.Hour * 1).Format(time.RFC3339)
   401  	err = RunMain([]string{cmdName, "gencrl", "--revokedbefore", futureTime})
   402  	assert.NoError(t, err, "gencrl failed")
   403  	checkCRL(t, admin.GetClient(), revokedCertSerials)
   404  
   405  	// success case 5: gencrl invoked with --expirebefore, --revokedbefore and --revokedafter args
   406  	expTime := time.Now().UTC().Add(time.Hour * 3).Format(time.RFC3339)
   407  	err = RunMain([]string{cmdName, "gencrl", "--revokedafter", pastTime,
   408  		"--revokedbefore", futureTime, "--expirebefore", expTime})
   409  	assert.NoError(t, err, "gencrl failed")
   410  	checkCRL(t, admin.GetClient(), revokedCertSerials)
   411  
   412  	// success case 6: gencrl invoked with --expireafter, --revokedbefore and --revokedafter args
   413  	err = RunMain([]string{cmdName, "gencrl", "--expireafter", time.Now().UTC().Format(time.RFC3339),
   414  		"--revokedafter", pastTime, "--revokedbefore", futureTime})
   415  	assert.NoError(t, err, "gencrl failed")
   416  	checkCRL(t, admin.GetClient(), revokedCertSerials)
   417  
   418  	// success case 6: gencrl invoked with all args
   419  	err = RunMain([]string{cmdName, "gencrl", "--expireafter", time.Now().UTC().Format(time.RFC3339),
   420  		"--expirebefore", time.Now().Add(time.Hour * 24 * 365 * 2).UTC().Format(time.RFC3339),
   421  		"--revokedafter", pastTime, "--revokedbefore", futureTime})
   422  	assert.NoError(t, err, "gencrl failed")
   423  	checkCRL(t, admin.GetClient(), revokedCertSerials)
   424  
   425  	// Error cases
   426  	// Error case 2: should fail when invoked with invalid --revokedafter arg
   427  	err = RunMain([]string{cmdName, "gencrl", "--revokedafter", "foo"})
   428  	assert.Error(t, err, "gencrl should have failed when --revokedafter value is not a timestamp")
   429  
   430  	// Error case 3: should fail when invoked with invalid --revokedafter arg
   431  	err = RunMain([]string{cmdName, "gencrl", "--revokedafter", "Mon Jan 2 15:04:05 -0700 MST 2006"})
   432  	assert.Error(t, err, "gencrl should have failed when --revokedafter value is not in RFC339 format")
   433  
   434  	// Error case 4: should fail when invoked with invalid --revokedbefore arg
   435  	err = RunMain([]string{cmdName, "gencrl", "--revokedbefore", "bar"})
   436  	assert.Error(t, err, "gencrl should have failed when --revokedbefore value is not a timestamp")
   437  
   438  	// Error case 5: should fail when invoked with invalid --revokedbefore arg
   439  	err = RunMain([]string{cmdName, "gencrl", "--revokedbefore", "Sat Mar 7 11:06:39 PST 2015"})
   440  	assert.Error(t, err, "gencrl should have failed when --revokedbefore value is not in RFC339 format")
   441  
   442  	// Error case 6: should fail when invoked with revokeafter value is greater (comes after) than revokedbefore
   443  	err = RunMain([]string{cmdName, "gencrl", "--revokedafter", "2017-09-13T16:39:57-08:00",
   444  		"--revokedbefore", "2017-09-13T15:39:57-08:00"})
   445  	assert.Error(t, err, "gencrl should have failed when --revokedafter value is greater than --revokedbefore")
   446  
   447  	// Error case 7: should fail when invoked with invalid --expireafter arg
   448  	err = RunMain([]string{cmdName, "gencrl", "--expireafter", "foo"})
   449  	assert.Error(t, err, "gencrl should have failed when --expireafter value is not a timestamp")
   450  
   451  	// Error case 8: should fail when invoked with invalid --expireafter arg
   452  	err = RunMain([]string{cmdName, "gencrl", "--expireafter", "Mon Jan 2 15:04:05 -0700 MST 2006"})
   453  	assert.Error(t, err, "gencrl should have failed when --expireafter value is not in RFC339 format")
   454  
   455  	// Error case 9: should fail when invoked with invalid --expirebefore arg
   456  	err = RunMain([]string{cmdName, "gencrl", "--expirebefore", "bar"})
   457  	assert.Error(t, err, "gencrl should have failed when --expirebefore value is not a timestamp")
   458  
   459  	// Error case 10: should fail when invoked with invalid --expirebefore arg
   460  	err = RunMain([]string{cmdName, "gencrl", "--expirebefore", "Sat Mar 7 11:06:39 PST 2015"})
   461  	assert.Error(t, err, "gencrl should have failed when --expirebefore value is not in RFC339 format")
   462  
   463  	// Error case 11: should fail when invoked with expireafter value is greater (comes after) than expirebefore
   464  	err = RunMain([]string{cmdName, "gencrl", "--expireafter", "2017-09-13T16:39:57-08:00",
   465  		"--expirebefore", "2017-09-13T15:39:57-08:00"})
   466  	assert.Error(t, err, "gencrl should have failed when --expireafter value is greater than --expirebefore")
   467  }
   468  
   469  // Test role based access control
   470  func TestRBAC(t *testing.T) {
   471  	// Variable initialization
   472  	curDir, err := os.Getwd()
   473  	if err != nil {
   474  		t.Fatalf("Failed to get current working directory: %s", err)
   475  	}
   476  	testDir := path.Join(curDir, "testDir")
   477  	testUser := "testUser"
   478  	testPass := "testUserpw"
   479  	adminUserHome := path.Join(testDir, "adminUser")
   480  	adminUserConfig := path.Join(adminUserHome, "config.yaml")
   481  	testUserHome := path.Join(testDir, "testUser")
   482  	testUserConfig := path.Join(testUserHome, "config.yaml")
   483  
   484  	// Start with a clean test dir
   485  	os.RemoveAll(testDir)
   486  	defer os.RemoveAll(testDir)
   487  
   488  	// Start the server
   489  	server := startServer(testDir, 7054, "", t)
   490  	defer server.Stop()
   491  
   492  	// Negative test case to try to enroll with an badly formatted attribute request
   493  	err = RunMain([]string{
   494  		cmdName, "enroll",
   495  		"--enrollment.attrs", "foo,bar:zoo",
   496  		"-c", adminUserConfig,
   497  		"-u", "http://admin:adminpw@localhost:7054"})
   498  	if err == nil {
   499  		t.Error("enrollment with badly formatted attribute requests should fail")
   500  	}
   501  
   502  	// Enroll the admin
   503  	err = RunMain([]string{
   504  		cmdName, "enroll",
   505  		"-c", adminUserConfig,
   506  		"-u", "http://admin:adminpw@localhost:7054"})
   507  	if err != nil {
   508  		t.Fatalf("client enroll -u failed: %s", err)
   509  	}
   510  
   511  	// Negative test to add attribute with invalid flag (foo)
   512  	err = RunMain([]string{
   513  		cmdName, "register", "-d",
   514  		"-c", adminUserConfig,
   515  		"--id.name", testUser,
   516  		"--id.secret", testPass,
   517  		"--id.type", "user",
   518  		"--id.affiliation", "org1",
   519  		"--id.attrs", "admin=true:foo"})
   520  	if err == nil {
   521  		t.Error("client register should have failed because of invalid attribute flag")
   522  	}
   523  
   524  	// Register test user with an attribute to be inserted in ecert by default
   525  	err = RunMain([]string{
   526  		cmdName, "register", "-d",
   527  		"-c", adminUserConfig,
   528  		"--id.name", testUser,
   529  		"--id.secret", testPass,
   530  		"--id.type", "user",
   531  		"--id.affiliation", "org1",
   532  		"--id.attrs", "admin=true:ecert,foo=bar"})
   533  	if err != nil {
   534  		t.Errorf("client register failed: %s", err)
   535  	}
   536  
   537  	// Enroll the test user with no attribute requests and make sure the
   538  	// resulting ecert has the default attributes and no extra
   539  	err = RunMain([]string{
   540  		cmdName, "enroll", "-d",
   541  		"-c", testUserConfig,
   542  		"-u", fmt.Sprintf("http://%s:%s@localhost:7054", testUser, testPass)})
   543  	if err != nil {
   544  		t.Fatalf("client enroll of test user failed: %s", err)
   545  	}
   546  	checkAttrsInCert(t, testUserHome, "admin", "true", "foo")
   547  
   548  	// Enroll the test user with attribute requests and make sure the
   549  	// resulting ecert has the requested attributes only
   550  	err = RunMain([]string{
   551  		cmdName, "enroll", "-d",
   552  		"--enrollment.attrs", "foo,unknown:opt",
   553  		"-c", testUserConfig,
   554  		"-u", fmt.Sprintf("http://%s:%s@localhost:7054", testUser, testPass)})
   555  	if err != nil {
   556  		t.Fatalf("client enroll of test user failed: %s", err)
   557  	}
   558  	checkAttrsInCert(t, testUserHome, "foo", "bar", "admin")
   559  
   560  	// Negative test case to request an attribute that the identity doesn't have
   561  	err = RunMain([]string{
   562  		cmdName, "enroll", "-d",
   563  		"--enrollment.attrs", "unknown",
   564  		"-c", testUserConfig,
   565  		"-u", fmt.Sprintf("http://%s:%s@localhost:7054", testUser, testPass)})
   566  	if err == nil {
   567  		t.Error("enrollment request with unknown required attribute should fail")
   568  	}
   569  
   570  	// Stop the server
   571  	err = server.Stop()
   572  	if err != nil {
   573  		t.Errorf("Server stop failed: %s", err)
   574  	}
   575  }
   576  
   577  func TestIdentityCmd(t *testing.T) {
   578  	idWithNoAttrs := lib.CAConfigIdentity{
   579  		Name:           "userWithNoAttrs",
   580  		Pass:           "userWithNoAttrs",
   581  		Affiliation:    "org1",
   582  		MaxEnrollments: 10,
   583  		Type:           "client",
   584  	}
   585  	server := setupIdentityCmdTest(t, idWithNoAttrs)
   586  	defer stopAndCleanupServer(t, server)
   587  
   588  	err := RunMain([]string{cmdName, "enroll", "-u", enrollURL})
   589  	util.FatalError(t, err, "Failed to enroll user")
   590  
   591  	err = RunMain([]string{cmdName, "register", "--id.name", "test user"})
   592  	util.FatalError(t, err, "Failed to register user")
   593  
   594  	result, err := captureOutput(RunMain, []string{
   595  		cmdName, "identity", "list"})
   596  	assert.NoError(t, err, "Failed to get all ids")
   597  	assert.Contains(t, result, "admin")
   598  	assert.Contains(t, result, "test user")
   599  
   600  	result, err = captureOutput(RunMain, []string{
   601  		cmdName, "identity", "list", "--id", "test user"})
   602  	assert.NoError(t, err, "Failed to get id 'test user'")
   603  	assert.Contains(t, result, "test user")
   604  
   605  	err = RunMain([]string{
   606  		cmdName, "identity", "add"})
   607  	if assert.Error(t, err, "Should have failed, no arguments provided") {
   608  		assert.Contains(t, err.Error(), "Identity name is required")
   609  	}
   610  
   611  	err = RunMain([]string{
   612  		cmdName, "identity", "modify"})
   613  	if assert.Error(t, err, "Should have failed, no arguments provided") {
   614  		assert.Contains(t, err.Error(), "Identity name is required")
   615  	}
   616  
   617  	err = RunMain([]string{
   618  		cmdName, "identity", "remove"})
   619  	if assert.Error(t, err, "Should have failed, no arguments provided") {
   620  		assert.Contains(t, err.Error(), "Identity name is required")
   621  	}
   622  
   623  	err = RunMain([]string{
   624  		cmdName, "identity", "add", "user1", "badinput"})
   625  	if assert.Error(t, err, "Should have failed, too many arguments") {
   626  		assert.Contains(t, err.Error(), "Unknown argument")
   627  	}
   628  
   629  	err = RunMain([]string{
   630  		cmdName, "identity", "modify", "user1", "badinput"})
   631  	if assert.Error(t, err, "Should have failed, too many arguments") {
   632  		assert.Contains(t, err.Error(), "Unknown argument")
   633  	}
   634  
   635  	err = RunMain([]string{
   636  		cmdName, "identity", "remove", "user1", "badinput"})
   637  	if assert.Error(t, err, "Should have failed, too many arguments") {
   638  		assert.Contains(t, err.Error(), "Unknown argument")
   639  	}
   640  
   641  	err = RunMain([]string{
   642  		cmdName, "identity", "add", "testuser", "--json", `{"type": "peer"}`, "--type", "peer"})
   643  	if assert.Error(t, err, "Should have failed") {
   644  		assert.Contains(t, err.Error(), "Can't use 'json' flag in conjunction with other flags")
   645  	}
   646  
   647  	err = RunMain([]string{
   648  		cmdName, "identity", "add", "testuser", "--json", `{"type": "peer"}`, "--attrs", "hf.Revoker=true"})
   649  	if assert.Error(t, err, "Should have failed") {
   650  		assert.Contains(t, err.Error(), "Can't use 'json' flag in conjunction with other flags")
   651  	}
   652  
   653  	err = RunMain([]string{
   654  		cmdName, "identity", "modify", "testuser", "--json", `{"type": "peer"}`, "--type", "peer"})
   655  	if assert.Error(t, err, "Should have failed") {
   656  		assert.Contains(t, err.Error(), "Can't use 'json' flag in conjunction with other flags")
   657  	}
   658  
   659  	err = RunMain([]string{
   660  		cmdName, "identity", "modify", "testuser", "--json", `{"type": "peer"}`, "--affiliation", "org1"})
   661  	if assert.Error(t, err, "Should have failed") {
   662  		assert.Contains(t, err.Error(), "Can't use 'json' flag in conjunction with other flags")
   663  	}
   664  
   665  	// Add user using JSON
   666  	err = RunMain([]string{
   667  		cmdName, "identity", "add", "-d", "testuser1", "--json", `{"secret": "user1pw", "type": "user", "affiliation": "org1", "max_enrollments": 1, "attrs": [{"name": "hf.Revoker", "value": "false"},{"name": "hf.IntermediateCA", "value": "false"}]}`})
   668  	assert.NoError(t, err, "Failed to add user 'testuser1'")
   669  
   670  	err = RunMain([]string{
   671  		cmdName, "identity", "add", "testuser1", "--json", `{"secret": "user1pw", "type": "user", "affiliation": "org1", "max_enrollments": 1, "attrs": [{"name:": "hf.Revoker", "value": "false"}]}`})
   672  	assert.Error(t, err, "Should have failed to add same user twice")
   673  
   674  	// Check that the secret got correctly configured
   675  	err = RunMain([]string{
   676  		cmdName, "enroll", "-u", "http://testuser1:user1pw@localhost:7090", "-d"})
   677  	assert.NoError(t, err, "Failed to enroll user 'testuser2'")
   678  
   679  	// Enroll admin back to use it credentials for next commands
   680  	err = RunMain([]string{cmdName, "enroll", "-u", enrollURL})
   681  	util.FatalError(t, err, "Failed to enroll user")
   682  
   683  	// Add user using flags
   684  	err = RunMain([]string{
   685  		cmdName, "identity", "add", "testuser2", "--secret", "user2pw", "--type", "client", "--affiliation", ".", "--maxenrollments", "45", "--attrs", "hf.Revoker=true"})
   686  	assert.NoError(t, err, "Failed to add user 'testuser2'")
   687  
   688  	server.CA.Config.Registry.MaxEnrollments = 50
   689  	// Test default max enrollment values for adding identity default to using CA's max enrollment value
   690  	err = RunMain([]string{
   691  		cmdName, "identity", "add", "testuser3"})
   692  	assert.NoError(t, err, "Failed to add user 'testuser3'")
   693  
   694  	// Check that the secret got correctly configured
   695  	err = RunMain([]string{
   696  		cmdName, "enroll", "-u", "http://testuser2:user2pw@localhost:7090", "-d"})
   697  	assert.NoError(t, err, "Failed to enroll user 'testuser2'")
   698  
   699  	// Enroll admin back to use it credentials for next commands
   700  	err = RunMain([]string{cmdName, "enroll", "-u", enrollURL})
   701  	util.FatalError(t, err, "Failed to enroll user")
   702  
   703  	// modify user secret using flags
   704  	err = RunMain([]string{
   705  		cmdName, "identity", "modify", "testuser2", "--secret", "user2pw2"})
   706  	assert.NoError(t, err, "Failed to add user 'testuser2'")
   707  
   708  	// Modify user's secret, check if no other user attributes were modified
   709  	userBforeModify, err := getUser(idWithNoAttrs.Name, server)
   710  	if err != nil {
   711  		t.Fatalf("Failed to read '%s' from the database", idWithNoAttrs.Name)
   712  	}
   713  
   714  	// modify user with no attrs
   715  	err = RunMain([]string{
   716  		cmdName, "identity", "modify", idWithNoAttrs.Name, "--secret", "user2pw2"})
   717  	assert.NoError(t, err, "Failed to modify user "+idWithNoAttrs.Name)
   718  
   719  	userAfterModify, err := getUser(idWithNoAttrs.Name, server)
   720  	if err != nil {
   721  		t.Fatalf("Failed to read '%s' from the database", idWithNoAttrs.Name)
   722  	}
   723  	assert.Equal(t, userBforeModify.GetType(), userAfterModify.GetType(),
   724  		"User type must be same after user secret was modified")
   725  	assert.Equal(t, cadbuser.GetAffiliation(userBforeModify),
   726  		cadbuser.GetAffiliation(userAfterModify),
   727  		"User affiliation must be same after user secret was modified")
   728  	assert.Equal(t, userBforeModify.GetMaxEnrollments(), userAfterModify.GetMaxEnrollments(),
   729  		"User max enrollments must be same after user secret was modified")
   730  
   731  	origAttrs, err := userBforeModify.GetAttributes(nil)
   732  	if err != nil {
   733  		t.Fatalf("Failed to get attributes of the user '%s'", idWithNoAttrs.Name)
   734  	}
   735  	modAttrs, err := userAfterModify.GetAttributes(nil)
   736  	if err != nil {
   737  		t.Fatalf("Failed to get attributes of the modified user '%s'", idWithNoAttrs.Name)
   738  	}
   739  	assert.Equal(t, len(origAttrs), len(modAttrs),
   740  		"User attributes must be same after user secret was modified")
   741  
   742  	// Check that the secret got correctly configured
   743  	err = RunMain([]string{
   744  		cmdName, "enroll", "-u", "http://testuser2:user2pw2@localhost:7090", "-d"})
   745  	assert.NoError(t, err, "Failed to enroll user 'testuser2'")
   746  
   747  	// Enroll admin back to use it credentials for next commands
   748  	err = RunMain([]string{cmdName, "enroll", "-u", enrollURL})
   749  	util.FatalError(t, err, "Failed to enroll user")
   750  
   751  	registry := server.CA.DBAccessor()
   752  	user, err := registry.GetUser("testuser1", nil)
   753  	util.FatalError(t, err, "Failed to get user 'testuser1'")
   754  
   755  	_, err = user.GetAttribute("hf.IntermediateCA")
   756  	assert.NoError(t, err, "Failed to get attribute")
   757  
   758  	_, err = registry.GetUser("testuser2", nil)
   759  	assert.NoError(t, err, "Failed to get user 'testuser2'")
   760  
   761  	// Modify value for hf.Revoker, add hf.Registrar.Roles, and delete hf.IntermediateCA attribute
   762  	err = RunMain([]string{
   763  		cmdName, "identity", "modify", "testuser1", "--type", "peer", "--affiliation", ".", "--attrs", "hf.Revoker=true,hf.Registrar.Roles=peer,hf.IntermediateCA="})
   764  	assert.NoError(t, err, "Failed to modify user 'testuser1'")
   765  
   766  	user, err = registry.GetUser("testuser1", nil)
   767  	util.FatalError(t, err, "Failed to get user 'testuser1'")
   768  
   769  	if user.GetType() != "peer" {
   770  		t.Error("Failed to correctly modify user 'testuser1'")
   771  	}
   772  	affPath := cadbuser.GetAffiliation(user)
   773  	if affPath != "" {
   774  		t.Error("Failed to correctly modify user 'testuser1'")
   775  	}
   776  	attrs, err := user.GetAttributes(nil)
   777  	assert.NoError(t, err, "Failed to get user attributes")
   778  	attrMap := getAttrsMap(attrs)
   779  
   780  	val := attrMap["hf.Revoker"]
   781  	assert.Equal(t, "true", val.Value, "Failed to correctly modify attributes for user 'testuser1'")
   782  
   783  	val = attrMap["hf.Registrar.Roles"]
   784  	assert.Equal(t, "peer", val.Value, "Failed to correctly modify attributes for user 'testuser1'")
   785  
   786  	_, found := attrMap["hf.IntermediateCA"]
   787  	assert.False(t, found, "Failed to delete attribute 'hf.IntermediateCA'")
   788  
   789  	err = RunMain([]string{
   790  		cmdName, "identity", "remove", "testuser1"})
   791  	assert.Error(t, err, "Should have failed, identity removal not allowed on server")
   792  
   793  	user, err = registry.GetUser("testuser3", nil)
   794  	util.FatalError(t, err, "Failed to get user 'testuser1'")
   795  	assert.Equal(t, 50, user.GetMaxEnrollments())
   796  
   797  	server.CA.Config.Cfg.Identities.AllowRemove = true
   798  
   799  	err = RunMain([]string{
   800  		cmdName, "identity", "remove", "testuser1"})
   801  	assert.NoError(t, err, "Failed to remove user")
   802  }
   803  
   804  func TestAffiliationCmd(t *testing.T) {
   805  	var err error
   806  
   807  	// Start with a clean test dir
   808  	os.RemoveAll("affiliation")
   809  	defer os.RemoveAll("affiliation")
   810  
   811  	// Start the server
   812  	server := startServer("affiliation", 7090, "", t)
   813  	defer server.Stop()
   814  
   815  	err = RunMain([]string{cmdName, "enroll", "-u", enrollURL})
   816  	util.FatalError(t, err, "Failed to enroll user")
   817  
   818  	result, err := captureOutput(RunMain, []string{cmdName, "affiliation", "list"})
   819  	assert.NoError(t, err, "Failed to return all affiliations")
   820  	assert.Equal(t, "affiliation: org1\n", result)
   821  
   822  	err = RunMain([]string{cmdName, "affiliation", "list", "--affiliation", "org2"})
   823  	assert.Error(t, err, "Should failed to get the requested affiliation, affiliation does not exist")
   824  
   825  	err = RunMain([]string{
   826  		cmdName, "affiliation", "add"})
   827  	if assert.Error(t, err, "Should have failed, no arguments provided") {
   828  		assert.Contains(t, err.Error(), "affiliation name is required")
   829  	}
   830  
   831  	err = RunMain([]string{
   832  		cmdName, "affiliation", "modify"})
   833  	if assert.Error(t, err, "Should have failed, no arguments provided") {
   834  		assert.Contains(t, err.Error(), "affiliation name is required")
   835  	}
   836  
   837  	err = RunMain([]string{
   838  		cmdName, "affiliation", "remove"})
   839  	if assert.Error(t, err, "Should have failed, no arguments provided") {
   840  		assert.Contains(t, err.Error(), "affiliation name is required")
   841  	}
   842  
   843  	err = RunMain([]string{
   844  		cmdName, "affiliation", "add", "org3", "badinput"})
   845  	if assert.Error(t, err, "Should have failed, too many arguments") {
   846  		assert.Contains(t, err.Error(), "Unknown argument")
   847  	}
   848  
   849  	err = RunMain([]string{
   850  		cmdName, "affiliation", "modify", "org3", "badinput"})
   851  	if assert.Error(t, err, "Should have failed, too many arguments") {
   852  		assert.Contains(t, err.Error(), "Unknown argument")
   853  	}
   854  
   855  	err = RunMain([]string{
   856  		cmdName, "affiliation", "remove", "org3", "badinput"})
   857  	if assert.Error(t, err, "Should have failed, too many arguments") {
   858  		assert.Contains(t, err.Error(), "Unknown argument")
   859  	}
   860  
   861  	err = RunMain([]string{
   862  		cmdName, "affiliation", "add", "org3"})
   863  	assert.NoError(t, err, "Caller with root affiliation failed to add affiliation 'org3'")
   864  
   865  	err = RunMain([]string{
   866  		cmdName, "affiliation", "add", "org4.dept1.team", "--force"})
   867  	assert.NoError(t, err, "Caller with root affiliation failed to add affiliation 'org4.dept1.team2'")
   868  
   869  	server.CA.Config.Cfg.Affiliations.AllowRemove = true
   870  
   871  	registry := server.CA.DBAccessor()
   872  
   873  	err = RunMain([]string{
   874  		cmdName, "affiliation", "remove", "org3"})
   875  	assert.NoError(t, err, "Failed to remove affiliation")
   876  
   877  	_, err = registry.GetAffiliation("org3")
   878  	assert.Error(t, err, "Failed to remove 'org3' successfully")
   879  
   880  	err = RunMain([]string{
   881  		cmdName, "affiliation", "modify", "org1", "--name", "org3"})
   882  	assert.NoError(t, err, "Failed to rename affiliation from 'org2' to 'org3'")
   883  
   884  	_, err = registry.GetAffiliation("org3")
   885  	assert.NoError(t, err, "Failed to rename 'org1' to 'org3' successfully")
   886  
   887  	err = RunMain([]string{
   888  		cmdName, "affiliation", "remove", "org4"})
   889  	assert.Error(t, err, "Should have failed, no force argument provided and affiliation being deleted had sub-affiliations")
   890  
   891  	// if previous test failed, don't bother with the next one
   892  	if err != nil {
   893  		err = RunMain([]string{
   894  			cmdName, "affiliation", "remove", "org4", "--force"})
   895  		assert.NoError(t, err, "Failed to remove affiliation with force argument")
   896  	}
   897  }
   898  
   899  // Verify the certificate has attribute 'name' with a value of 'val'
   900  // and does not have the 'missing' attribute.
   901  func checkAttrsInCert(t *testing.T, home, name, val, missing string) {
   902  
   903  	// Load the user's ecert
   904  	cert, err := util.GetX509CertificateFromPEMFile(path.Join(home, "msp", "signcerts", "cert.pem"))
   905  	if err != nil {
   906  		t.Fatalf("Failed to load test user's cert: %s", err)
   907  	}
   908  
   909  	// sm2Cert := sw.ParseX509Certificate2Sm2(cert)
   910  	// Get the attributes from the cert
   911  	attrs, err := attrmgr.New().GetAttributesFromCert(cert)
   912  	if err != nil {
   913  		t.Fatalf("Failed to get attributes from certificate: %s", err)
   914  	}
   915  
   916  	// Make sure the attribute is in the cert
   917  	v, ok, err := attrs.Value(name)
   918  	if err != nil {
   919  		t.Fatalf("Failed to get '%s' attribute from cert: %s", name, err)
   920  	}
   921  	if !ok {
   922  		t.Fatalf("The '%s' attribute was not found in the cert", name)
   923  	}
   924  
   925  	// Make sure the value of the attribute is as expected
   926  	if v != val {
   927  		t.Fatalf("The value of the '%s' attribute is '%s' rather than '%s'", name, v, val)
   928  	}
   929  
   930  	// Make sure the missing attribute was NOT found
   931  	_, ok, err = attrs.Value(missing)
   932  	if err != nil {
   933  		t.Fatalf("Failed to get '%s' attribute from cert: %s", missing, err)
   934  	}
   935  	if ok {
   936  		t.Fatalf("The '%s' attribute was found in the cert but should not be", missing)
   937  	}
   938  }
   939  
   940  func testConfigFileTypes(t *testing.T) {
   941  	t.Log("Testing config file types")
   942  
   943  	// Viper supports file types:
   944  	//    yaml, yml, json, hcl, toml, props, prop, properties, so
   945  	// any other file type will result in an error. However, not all
   946  	// these file types are suitable to represent fabric-ca
   947  	// client/server config properties -- for example, props/prop/properties
   948  	// file type
   949  	err := RunMain([]string{cmdName, "enroll", "-u", enrollURL,
   950  		"-c", "config/client-config.txt"})
   951  	if err == nil {
   952  		t.Errorf("Enroll command invoked with -c config/client-config.txt should have failed: %v",
   953  			err.Error())
   954  	}
   955  
   956  	err = RunMain([]string{cmdName, "enroll", "-u", enrollURL,
   957  		"-c", "config/client-config.mf"})
   958  	if err == nil {
   959  		t.Errorf("Enroll command invoked with -c config/client-config.mf should have failed: %v",
   960  			err.Error())
   961  	}
   962  
   963  	fName := os.TempDir() + "/client-config.json"
   964  	f, err := os.Create(fName)
   965  	if err != nil {
   966  		t.Fatalf("Unable to create json config file: %v", err.Error())
   967  	}
   968  	w := bufio.NewWriter(f)
   969  	nb, err := w.WriteString(jsonConfig)
   970  	if err != nil {
   971  		t.Fatalf("Unable to write to json config file: %v", err.Error())
   972  	}
   973  	t.Logf("Wrote %d bytes to %s", nb, fName)
   974  	w.Flush()
   975  
   976  	err = RunMain([]string{cmdName, "enroll", "-u", enrollURL,
   977  		"-c", fName})
   978  	if err != nil {
   979  		t.Errorf("Enroll command invoked with -c %s failed: %v",
   980  			fName, err.Error())
   981  	}
   982  	os.RemoveAll("./config")
   983  }
   984  
   985  // TestGetCACert tests fabric-ca-client getcacert
   986  func testGetCACert(t *testing.T) {
   987  	t.Log("Testing getcacert command")
   988  	defYaml = util.GetDefaultConfigFile("fabric-ca-client")
   989  	os.Remove(defYaml) // Clean up any left over config file
   990  	os.RemoveAll("msp")
   991  	err := RunMain([]string{cmdName, "getcacert", "-d", "-u", serverURL})
   992  	assert.NoError(t, err, "getcacert should not have failed")
   993  	assert.True(t, util.FileExists(path.Dir(defYaml)+"/msp/IssuerPublicKey"), "IssuerPublicKey file should exist after getcacert call")
   994  
   995  	err = RunMain([]string{cmdName, "getcacert", "-d", "-u", "http://localhost:9999"})
   996  	if err == nil {
   997  		t.Error("getcacert with bogus URL should have failed but did not")
   998  	}
   999  
  1000  	err = RunMain([]string{cmdName, "getcacert", "-d"})
  1001  	if err == nil {
  1002  		t.Error("getcacert with no URL should have failed but did not")
  1003  	}
  1004  
  1005  	err = RunMain([]string{cmdName, "getcacert", "Z"})
  1006  	if err == nil {
  1007  		t.Error("getcacert called with bogus argument, should have failed")
  1008  	}
  1009  	os.RemoveAll("cacerts")
  1010  	os.RemoveAll("msp")
  1011  	os.Remove(defYaml)
  1012  }
  1013  
  1014  // TestEnroll tests fabric-ca-client enroll
  1015  func testEnroll(t *testing.T) {
  1016  	t.Log("Testing Enroll command")
  1017  	defYaml = util.GetDefaultConfigFile("fabric-ca-client")
  1018  
  1019  	os.Remove(defYaml) // Clean up any left over config file
  1020  
  1021  	// Negative test case, enroll command without username/password
  1022  	err := RunMain([]string{cmdName, "enroll", "-d"})
  1023  	if err == nil {
  1024  		t.Errorf("No username/password provided, should have errored")
  1025  	}
  1026  
  1027  	err = RunMain([]string{cmdName, "enroll", "-d", "-u", enrollURL, "-M", filepath.Join(filepath.Dir(defYaml), "msp"), "--csr.keyrequest.algo", "badalgo"})
  1028  	assert.Error(t, err, "Incorrect key algo value, should fail")
  1029  
  1030  	err = RunMain([]string{cmdName, "enroll", "-d", "-u", enrollURL, "-M", filepath.Join(filepath.Dir(defYaml), "msp"), "--csr.keyrequest.algo", "ecdsa", "--csr.keyrequest.size", "1234"})
  1031  	assert.Error(t, err, "Incorrect key size value, should fail")
  1032  
  1033  	err = RunMain([]string{cmdName, "enroll", "-u", enrollURL, "-M", filepath.Join(filepath.Dir(defYaml), "msp"), "--csr.keyrequest.algo", "ecdsa", "--csr.keyrequest.size", "256"})
  1034  	if err != nil {
  1035  		t.Errorf("client enroll -u failed: %s", err)
  1036  	}
  1037  
  1038  	testReenroll(t)
  1039  
  1040  	err = RunMain([]string{cmdName, "enroll", "-u", "http://admin2:adminpw2@localhost:7091"})
  1041  	if err == nil {
  1042  		t.Error("Should have failed, client config file should have incorrect port (7091) for server")
  1043  	}
  1044  
  1045  	err = RunMain([]string{cmdName, "enroll", "Z"})
  1046  	if err == nil {
  1047  		t.Error("enroll called with bogus argument, should have failed")
  1048  	}
  1049  	os.Remove(defYaml)
  1050  }
  1051  
  1052  // TestGencsr tests fabric-ca-client gencsr
  1053  func TestGencsr(t *testing.T) {
  1054  	t.Log("Testing gencsr CMD")
  1055  	defYaml = util.GetDefaultConfigFile("fabric-ca-client")
  1056  
  1057  	os.Remove(defYaml) // Clean up any left over config file
  1058  
  1059  	mspDir := filepath.Join(filepath.Dir(defYaml), "msp")
  1060  
  1061  	os.RemoveAll(mspDir)
  1062  
  1063  	defer os.Remove(defYaml)
  1064  
  1065  	err := RunMain([]string{cmdName, "gencsr", "--csr.cn", "identity", "--csr.names", "C=CA,O=Org1,OU=OU1", "-M", mspDir})
  1066  	if err != nil {
  1067  		t.Errorf("client gencsr failed: %s", err)
  1068  	}
  1069  
  1070  	signcerts := path.Join(mspDir, "signcerts")
  1071  	assertFilesInDir(signcerts, 1, t)
  1072  
  1073  	files, err := ioutil.ReadDir(signcerts)
  1074  	if err != nil {
  1075  		t.Fatalf("Failed to get number of files in directory '%s': %s", signcerts, err)
  1076  	}
  1077  
  1078  	if files[0].Name() != "identity.csr" {
  1079  		t.Fatalf("Failed to find identity.csr in '%s': %s", signcerts, err)
  1080  	}
  1081  
  1082  	err = RunMain([]string{cmdName, "gencsr", "--csr.cn", "identity", "--csr.names", "C=CA,O=Org1,FOO=BAR", "-M", mspDir})
  1083  	if err == nil {
  1084  		t.Error("Should have failed: Invalid CSR name")
  1085  	}
  1086  
  1087  	err = RunMain([]string{cmdName, "gencsr", "--csr.cn", "identity", "--csr.names", "C:CA,O=Org1,OU=OU2", "-M", mspDir})
  1088  	if err == nil {
  1089  		t.Error("Should have failed: No '=' for name/value pair")
  1090  	}
  1091  
  1092  	err = RunMain([]string{cmdName, "gencsr", "-c", defYaml, "--csr.names", "C=CA,O=Org1,OU=OU1", "-M", mspDir})
  1093  	if err == nil {
  1094  		t.Error("Should have failed: CSR CN not specified.")
  1095  	}
  1096  }
  1097  
  1098  func TestDifferentKeySizeAlgos(t *testing.T) {
  1099  	config := `csr:
  1100    cn: <<CN>>
  1101    names:
  1102      - C: CN
  1103        ST: "Anhui"
  1104        L: "Hefei"
  1105        O: gcsoft
  1106        OU: gcbaas
  1107    keyrequest:
  1108      algo: <<ALGO>>
  1109      size: <<SIZE>>
  1110    hosts:
  1111     - hostname
  1112  `
  1113  	writeConfig := func(cn, algo string, size int, dir string) error {
  1114  		cfg := strings.Replace(config, "<<CN>>", cn, 1)
  1115  		cfg = strings.Replace(cfg, "<<ALGO>>", algo, 1)
  1116  		cfg = strings.Replace(cfg, "<<SIZE>>", strconv.Itoa(size), 1)
  1117  		err := os.MkdirAll(dir, 0755)
  1118  		if err != nil {
  1119  			return err
  1120  		}
  1121  		fileName := filepath.Join(dir, "fabric-ca-client-config.yaml")
  1122  		err = ioutil.WriteFile(fileName, []byte(cfg), os.ModePerm)
  1123  		return err
  1124  	}
  1125  
  1126  	testdata := []struct {
  1127  		algo                  string
  1128  		size                  int
  1129  		errorExpected         bool
  1130  		expectedSignatureAlgo x509.SignatureAlgorithm
  1131  	}{
  1132  		{"ecdsa", 256, false, x509.ECDSAWithSHA256},
  1133  		{"ecdsa", 384, false, x509.ECDSAWithSHA384},
  1134  		{"ecdsa", 521, true, x509.ECDSAWithSHA512},
  1135  		{"rsa", 2048, false, x509.SHA256WithRSA},
  1136  		{"rsa", 3072, false, x509.SHA384WithRSA},
  1137  		{"rsa", 4096, false, x509.SHA512WithRSA},
  1138  	}
  1139  
  1140  	homeDir := filepath.Join(tdDir, "genCSRDiffKeyReqs")
  1141  	err := os.RemoveAll(homeDir)
  1142  	if err != nil {
  1143  		t.Fatalf("Failed to remove directory %s: %s", homeDir, err)
  1144  	}
  1145  
  1146  	// Remove home directory that this test is going to create before
  1147  	// exiting the test case
  1148  	defer os.RemoveAll(homeDir)
  1149  
  1150  	for _, data := range testdata {
  1151  		cn := "TestGenCSRWithDifferentKeyRequests" + data.algo + strconv.Itoa(data.size)
  1152  		err := writeConfig(cn, data.algo, data.size, homeDir)
  1153  		if err != nil {
  1154  			t.Fatalf("Failed to write client config file in the %s directory: %s", homeDir, err)
  1155  		}
  1156  
  1157  		err = RunMain([]string{cmdName, "gencsr", "-H", homeDir})
  1158  		if !data.errorExpected {
  1159  			assert.NoError(t, err, "GenCSR called with %s algorithm and %d key size should not have failed", data.algo, data.size)
  1160  			csrFileName := cn + ".csr"
  1161  			csrBytes, rerr := ioutil.ReadFile(filepath.Join(homeDir, "msp/signcerts", csrFileName))
  1162  			assert.NoError(t, rerr, "Failed to read the generated CSR from the file %s:", csrFileName)
  1163  
  1164  			block, _ := pem.Decode(csrBytes)
  1165  			if block == nil || block.Type != "CERTIFICATE REQUEST" {
  1166  				t.Errorf("Block type read from the CSR file %s is not of type certificate request", csrFileName)
  1167  			}
  1168  			certReq, perr := x509.ParseCertificateRequest(block.Bytes)
  1169  			assert.NoError(t, perr, "Failed to parse generated CSR")
  1170  			assert.Equal(t, data.expectedSignatureAlgo, certReq.SignatureAlgorithm, "Not expected signature algorithm in the CSR")
  1171  		} else {
  1172  			if assert.Errorf(t, err, "GenCSR called with %s algorithm and %d key size should have failed", data.algo, data.size) {
  1173  				assert.Contains(t, err.Error(), "Unsupported", "Not expected error message")
  1174  			}
  1175  		}
  1176  	}
  1177  
  1178  	// Test enroll with ecdsa algorithm and 384 key size
  1179  	srv := setupGenCSRTest(t, homeDir)
  1180  	defer stopAndCleanupServer(t, srv)
  1181  
  1182  	// Enroll admin
  1183  	err = RunMain([]string{cmdName, "enroll", "-H", homeDir, "-u", "http://admin:adminpw@localhost:7090"})
  1184  	if err != nil {
  1185  		t.Fatalf("Failed to enroll admin: %s", err)
  1186  	}
  1187  	certBytes, rerr1 := ioutil.ReadFile(filepath.Join(homeDir, "msp/signcerts/cert.pem"))
  1188  	if rerr1 != nil {
  1189  		t.Fatalf("Failed to read the enrollment certificate: %s", err)
  1190  	}
  1191  
  1192  	block, _ := pem.Decode(certBytes)
  1193  	if block == nil || block.Type != "CERTIFICATE" {
  1194  		t.Errorf("Block type read from the cert file is not of type certificate")
  1195  	}
  1196  	cert, perr1 := x509.ParseCertificate(block.Bytes)
  1197  	assert.NoError(t, perr1, "Failed to parse enrollment certificate")
  1198  	assert.Equal(t, x509.ECDSAWithSHA384, cert.SignatureAlgorithm, "Not expected signature algorithm in the ecert")
  1199  }
  1200  
  1201  // TestMOption tests to make sure that the key is stored in the correct
  1202  // directory when the "-M" option is used.
  1203  // This also ensures the intermediatecerts directory structure is populated
  1204  // since we enroll with an intermediate CA.
  1205  func TestMOption(t *testing.T) {
  1206  	os.RemoveAll(moptionDir)
  1207  	defer os.RemoveAll(moptionDir)
  1208  	rootCAPort := 7173
  1209  	rootServer := startServer(path.Join(moptionDir, "rootServer"), rootCAPort, "", t)
  1210  	if rootServer == nil {
  1211  		return
  1212  	}
  1213  	defer rootServer.Stop()
  1214  	rootCAURL := fmt.Sprintf("http://admin:adminpw@localhost:%d", rootCAPort)
  1215  	intCAPort := 7174
  1216  	intServer := startServer(path.Join(moptionDir, "intServer"), intCAPort, rootCAURL, t)
  1217  	if intServer == nil {
  1218  		return
  1219  	}
  1220  	defer intServer.Stop()
  1221  	homedir := path.Join(moptionDir, "client")
  1222  	mspdir := "msp2" // relative to homedir
  1223  	err := RunMain([]string{
  1224  		cmdName, "enroll",
  1225  		"-u", fmt.Sprintf("http://admin:adminpw@localhost:%d", intCAPort),
  1226  		"-c", path.Join(homedir, "config.yaml"),
  1227  		"-M", mspdir, "-d"})
  1228  	if err != nil {
  1229  		t.Fatalf("client enroll -u failed: %s", err)
  1230  	}
  1231  	assertFilesInDir(path.Join(homedir, mspdir, "keystore"), 1, t)
  1232  	assertFilesInDir(path.Join(homedir, mspdir, "cacerts"), 1, t)
  1233  	assertFilesInDir(path.Join(homedir, mspdir, "intermediatecerts"), 1, t)
  1234  	validCertsInDir(path.Join(homedir, mspdir, "cacerts"), path.Join(homedir, mspdir, "intermediatecerts"), t)
  1235  	_, err = ioutil.ReadDir(path.Join(homedir, mspdir, "tlscacerts"))
  1236  	assert.Error(t, err, "The MSP folder 'tlscacerts' should not exist")
  1237  	_, err = ioutil.ReadDir(path.Join(homedir, mspdir, "tlsintermediatecerts"))
  1238  	assert.Error(t, err, "The MSP folder 'tlsintermediatecerts' should not exist")
  1239  
  1240  	homedir = path.Join(moptionDir, "client")
  1241  	mspdir = "msp3" // relative to homedir
  1242  	err = RunMain([]string{
  1243  		cmdName, "enroll",
  1244  		"-u", fmt.Sprintf("http://admin:adminpw@localhost:%d", intCAPort),
  1245  		"-c", path.Join(homedir, "config.yaml"),
  1246  		"-M", mspdir, "--enrollment.profile", "tls", "-d"})
  1247  	if err != nil {
  1248  		t.Fatalf("client enroll -u failed: %s", err)
  1249  	}
  1250  	assertFilesInDir(path.Join(homedir, mspdir, "keystore"), 1, t)
  1251  	assertFilesInDir(path.Join(homedir, mspdir, "tlscacerts"), 1, t)
  1252  	assertFilesInDir(path.Join(homedir, mspdir, "tlsintermediatecerts"), 1, t)
  1253  	validCertsInDir(path.Join(homedir, mspdir, "tlscacerts"), path.Join(homedir, mspdir, "tlsintermediatecerts"), t)
  1254  	assertFilesInDir(path.Join(homedir, mspdir, "cacerts"), 0, t)
  1255  	_, err = ioutil.ReadDir(path.Join(homedir, mspdir, "intermediatecerts"))
  1256  	assert.Error(t, err, "The MSP folder 'intermediatecerts' should not exist")
  1257  
  1258  	// Test case: msp and home are in different paths
  1259  	// Enroll the bootstrap user and then register another user. Since msp
  1260  	// and home are in two different directory paths, registration should
  1261  	// not fail if -M option is not specified
  1262  	mspdir = os.TempDir() + "/msp-abs-test"
  1263  	homedir = os.TempDir() + "/msp-abs-test-home"
  1264  	defer os.RemoveAll(mspdir)
  1265  	defer os.RemoveAll(homedir)
  1266  	err = RunMain([]string{
  1267  		cmdName, "enroll",
  1268  		"-u", fmt.Sprintf("http://admin:adminpw@localhost:%d", intCAPort),
  1269  		"-H", homedir,
  1270  		"-M", mspdir, "-d"})
  1271  	if err != nil {
  1272  		t.Fatalf("client enroll -u failed: %s", err)
  1273  	}
  1274  	err = RunMain([]string{cmdName, "register", "-d", "--id.name", "testRegisterForMoption",
  1275  		"--id.affiliation", "org1", "--id.type", "user", "-H", homedir})
  1276  	assert.NoError(t, err, "Register command should not fail even though -M option is not specified")
  1277  }
  1278  
  1279  // Checks to see if root and intermediate certificates are correctly getting stored in their respective directories
  1280  func validCertsInDir(rootCertDir, interCertsDir string, t *testing.T) {
  1281  	files, err := ioutil.ReadDir(rootCertDir)
  1282  	if err != nil {
  1283  		t.Fatalf("failed to read root cert dir: %s", err)
  1284  	}
  1285  	file := files[0].Name()
  1286  	rootCertPath := filepath.Join(rootCertDir, file)
  1287  	rootcert, err := util.GetX509CertificateFromPEMFile(rootCertPath)
  1288  	assert.NoError(t, err, "Failed to read cert file")
  1289  
  1290  	if !reflect.DeepEqual(rootcert.Subject, rootcert.Issuer) {
  1291  		t.Errorf("Not a valid root certificate '%s' stored in the '%s' directory", rootCertPath, filepath.Base(rootCertDir))
  1292  	}
  1293  
  1294  	interCertPath := filepath.Join(interCertsDir, file)
  1295  	intercert, err := util.GetX509CertificateFromPEMFile(interCertPath)
  1296  	assert.NoError(t, err, "Failed to read intermediate cert file")
  1297  
  1298  	if reflect.DeepEqual(intercert.Issuer, rootcert.Subject) && reflect.DeepEqual(intercert.Subject, intercert.Issuer) {
  1299  		t.Errorf("Not a valid intermediate certificate '%s' stored in '%s' directory", interCertPath, filepath.Base(interCertsDir))
  1300  	}
  1301  }
  1302  
  1303  // TestThreeCAHierarchy runs testThreeCAHierarchy test with and without
  1304  // setting the environment variable CA_CHAIN_PARENT_FIRST
  1305  func TestThreeCAHierarchy(t *testing.T) {
  1306  	parentFirstEnvVal := os.Getenv(lib.CAChainParentFirstEnvVar)
  1307  	os.Unsetenv(lib.CAChainParentFirstEnvVar)
  1308  	defer os.Setenv(lib.CAChainParentFirstEnvVar, parentFirstEnvVal)
  1309  	testThreeCAHierarchy(t)
  1310  
  1311  	os.Setenv(lib.CAChainParentFirstEnvVar, "true")
  1312  	testThreeCAHierarchy(t)
  1313  }
  1314  
  1315  // testThreeCAHierarchy tests three CA hierarchy (root CA -- intermediate CA -- Issuing CA)
  1316  // The client enrolls a user with the Issuing CA and checks if the there is one root CA cert
  1317  // in the 'cacerts' folder of client msp and two intermediate CA certs in the pem file in
  1318  // the 'intermediatecerts' folder.
  1319  func testThreeCAHierarchy(t *testing.T) {
  1320  	validateCACerts := func(rootCertDir, interCertsDir string) {
  1321  		files, err := ioutil.ReadDir(rootCertDir)
  1322  		assert.NoError(t, err, "failed to read %", rootCertDir)
  1323  		file := files[0].Name()
  1324  		rootCertPath := filepath.Join(rootCertDir, file)
  1325  		rootcaCertBytes, err := util.ReadFile(rootCertPath)
  1326  		assert.NoError(t, err, "Failed to read root CA certificate file %s", rootCertPath)
  1327  		rootcerts, err := util.GetX509CertificatesFromPEM(rootcaCertBytes)
  1328  		assert.NoError(t, err, "Failed to retrieve root certificate from root CA certificate file")
  1329  		assert.Equal(t, 1, len(rootcerts), "There should be only one root CA certificate")
  1330  		assert.True(t, reflect.DeepEqual(rootcerts[0].Subject, rootcerts[0].Issuer),
  1331  			"Not a valid root certificate '%s' stored in the '%s' directory",
  1332  			rootCertPath, filepath.Base(rootCertDir))
  1333  
  1334  		interCertPath := filepath.Join(interCertsDir, file)
  1335  		intcaCertBytes, err := util.ReadFile(interCertPath)
  1336  		assert.NoError(t, err, "Failed to read intermediate CA certificates file %s", interCertPath)
  1337  		intcerts, err := util.GetX509CertificatesFromPEM(intcaCertBytes)
  1338  		assert.NoError(t, err, "Failed to retrieve certs from intermediate CA certificates file")
  1339  		assert.Equal(t, 2, len(intcerts), "There should be 2 intermediate CA certificates")
  1340  		if os.Getenv(lib.CAChainParentFirstEnvVar) != "" {
  1341  			// Assert that first int CA cert's issuer must be root CA's subject
  1342  			assert.True(t, bytes.Equal(intcerts[0].RawIssuer, rootcerts[0].RawSubject), "Intermediate CA's issuer should be root CA's subject")
  1343  
  1344  			// Assert that second int CA cert's issuer must be first int CA's subject
  1345  			assert.True(t, bytes.Equal(intcerts[1].RawIssuer, intcerts[0].RawSubject), "Issuing CA's issuer should be intermediate CA's subject")
  1346  
  1347  			// Assert that first int CA's cert expires before or on root CA cert's expiry
  1348  			assert.False(t, intcerts[0].NotAfter.After(rootcerts[0].NotAfter), "Intermediate CA certificate expires after root CA's certificate")
  1349  
  1350  			// Assert that second int CA's cert expires before or on first int CA cert's expiry
  1351  			assert.False(t, intcerts[1].NotAfter.After(intcerts[0].NotAfter), "Issuing CA certificate expires after intermediate CA's certificate")
  1352  		} else {
  1353  			// Assert that first int CA cert's issuer must be second int CA's subject
  1354  			assert.True(t, bytes.Equal(intcerts[0].RawIssuer, intcerts[1].RawSubject), "Issuing CA's issuer should be intermediate CA's subject")
  1355  			// Assert that second int CA cert's issuer must be root CA's subject
  1356  			assert.True(t, bytes.Equal(intcerts[1].RawIssuer, rootcerts[0].RawSubject), "Intermediate CA's issuer should be root CA's subject")
  1357  
  1358  			// Assert that first int CA's cert expires before or on second int CA cert's expiry
  1359  			assert.False(t, intcerts[0].NotAfter.After(intcerts[1].NotAfter), "Issuing CA certificate expires after intermediate CA's certificate")
  1360  			// Assert that second int CA's cert expires before or on root CA cert's expiry
  1361  			assert.False(t, intcerts[1].NotAfter.After(rootcerts[0].NotAfter), "Intermediate CA certificate expires after root CA's certificate")
  1362  		}
  1363  	}
  1364  
  1365  	multiIntCATestDir := "multi-intca-test"
  1366  	os.RemoveAll(multiIntCATestDir)
  1367  	defer os.RemoveAll(multiIntCATestDir)
  1368  
  1369  	// Create and start the Root CA server
  1370  	rootCAPort := 7173
  1371  	// Set root server cert expiry to 30 days and start the server
  1372  	rootServer := startServerWithCustomExpiry(path.Join(multiIntCATestDir, "rootServer"), rootCAPort, "720h", t)
  1373  	defer rootServer.Stop()
  1374  
  1375  	// Create and start the Intermediate CA server
  1376  	rootCAURL := fmt.Sprintf("http://admin:adminpw@localhost:%d", rootCAPort)
  1377  	intCAPort := 7174
  1378  	intServer := startServer(path.Join(multiIntCATestDir, "intServer"), intCAPort, rootCAURL, t)
  1379  	defer intServer.Stop()
  1380  
  1381  	// Stop the Intermediate CA server to register identity of the Issuing CA
  1382  	err := intServer.Stop()
  1383  	if err != nil {
  1384  		t.Fatal("Failed to stop intermediate CA server after registering identity for the Issuing CA server")
  1385  	}
  1386  
  1387  	// Register an identity for Issuing CA with the Intermediate CA, this identity will be used by the Issuing
  1388  	// CA to get it's CA certificate
  1389  	intCA1Admin := "int-ca1-admin"
  1390  	err = intServer.RegisterBootstrapUser(intCA1Admin, "adminpw", "")
  1391  	if err != nil {
  1392  		t.Fatal("Failed to register identity for the Issuing CA server")
  1393  	}
  1394  
  1395  	// Restart the Intermediate CA server
  1396  	err = intServer.Start()
  1397  	if err != nil {
  1398  		t.Fatal("Failed to start intermediate CA server after registering identity for the Issuing CA server")
  1399  	}
  1400  
  1401  	// Create and start the Issuing CA server
  1402  	intCAURL := fmt.Sprintf("http://%s:adminpw@localhost:%d", intCA1Admin, intCAPort)
  1403  	intCA1Port := 7175
  1404  	intServer1 := startServer(path.Join(multiIntCATestDir, "intServer1"), intCA1Port, intCAURL, t)
  1405  	defer intServer1.Stop()
  1406  
  1407  	// Enroll bootstrap admin of the Issuing CA
  1408  	homedir := path.Join(multiIntCATestDir, "client")
  1409  	mspdir := "msp" // relative to homedir
  1410  	err = RunMain([]string{
  1411  		cmdName, "enroll",
  1412  		"-u", fmt.Sprintf("http://admin:adminpw@localhost:%d", intCA1Port),
  1413  		"-c", path.Join(homedir, "config.yaml"),
  1414  		"-M", mspdir, "-d"})
  1415  	if err != nil {
  1416  		t.Fatalf("Client enroll -u failed: %s", err)
  1417  	}
  1418  
  1419  	assertFilesInDir(path.Join(homedir, mspdir, "keystore"), 1, t)
  1420  	assertFilesInDir(path.Join(homedir, mspdir, "cacerts"), 1, t)
  1421  	assertFilesInDir(path.Join(homedir, mspdir, "intermediatecerts"), 1, t)
  1422  	validateCACerts(path.Join(homedir, mspdir, "cacerts"), path.Join(homedir, mspdir, "intermediatecerts"))
  1423  }
  1424  
  1425  // TestReenroll tests fabric-ca-client reenroll
  1426  func testReenroll(t *testing.T) {
  1427  	t.Log("Testing Reenroll command")
  1428  	defYaml = util.GetDefaultConfigFile("fabric-ca-client")
  1429  
  1430  	err := RunMain([]string{cmdName, "reenroll", "-u", serverURL, "--csr.hosts", "host1,host2"})
  1431  	if err != nil {
  1432  		t.Errorf("client reenroll --url -f failed: %s", err)
  1433  	}
  1434  
  1435  	err = util.CheckHostsInCert(
  1436  		filepath.Join(filepath.Dir(defYaml), "msp", "signcerts", "cert.pem"),
  1437  		"host1",
  1438  		"host2",
  1439  	)
  1440  	if err != nil {
  1441  		t.Error(err)
  1442  	}
  1443  
  1444  	err = RunMain([]string{cmdName, "reenroll", "-u", serverURL,
  1445  		"--enrollment.hosts", "host1,host2", "Z"})
  1446  	if err == nil {
  1447  		t.Error("reenroll called with bogus argument, should have failed")
  1448  	}
  1449  	os.Remove(defYaml)
  1450  }
  1451  
  1452  // testRegisterConfigFile tests fabric-ca-client register using the config file
  1453  func testRegisterConfigFile(t *testing.T) {
  1454  	t.Log("Testing Register command using config file")
  1455  
  1456  	err := RunMain([]string{cmdName, "enroll", "-d", "-c",
  1457  		"../../../testdata/fabric-ca-client-config.yaml", "-u", enrollURL1})
  1458  	if err != nil {
  1459  		t.Errorf("client enroll -u failed: %s", err)
  1460  	}
  1461  
  1462  	err = RunMain([]string{cmdName, "register", "-d", "-c",
  1463  		"../../../testdata/fabric-ca-client-config.yaml"})
  1464  	if err != nil {
  1465  		t.Errorf("client register failed using config file: %s", err)
  1466  	}
  1467  }
  1468  
  1469  // testRegisterEnvVar tests fabric-ca-client register using environment variables
  1470  func testRegisterEnvVar(t *testing.T) {
  1471  	t.Log("Testing Register command using env variables")
  1472  
  1473  	os.Setenv("FABRIC_CA_CLIENT_HOME", tdDir)
  1474  	os.Setenv("FABRIC_CA_CLIENT_ID_NAME", "testRegister2")
  1475  	os.Setenv("FABRIC_CA_CLIENT_ID_AFFILIATION", "hyperledger.org2")
  1476  	os.Setenv("FABRIC_CA_CLIENT_ID_TYPE", "client")
  1477  	defer func() {
  1478  		os.Unsetenv("FABRIC_CA_CLIENT_HOME")
  1479  		os.Unsetenv("FABRIC_CA_CLIENT_ID_NAME")
  1480  		os.Unsetenv("FABRIC_CA_CLIENT_ID_AFFILIATION")
  1481  		os.Unsetenv("FABRIC_CA_CLIENT_ID_TYPE")
  1482  	}()
  1483  
  1484  	err := RunMain([]string{cmdName, "register"})
  1485  	if err != nil {
  1486  		t.Errorf("client register failed using environment variables: %s", err)
  1487  	}
  1488  }
  1489  
  1490  // testRegisterCommandLine tests fabric-ca-client register using command line input
  1491  func testRegisterCommandLine(t *testing.T, srv *lib.Server) {
  1492  	t.Log("Testing Register using command line options")
  1493  	os.Setenv("FABRIC_CA_CLIENT_HOME", tdDir)
  1494  	defer os.Unsetenv("FABRIC_CA_CLIENT_HOME")
  1495  
  1496  	fooName := "foo"
  1497  	fooVal := "a=b"
  1498  	roleName := "hf.Registrar.Roles"
  1499  	roleVal := "peer,user"
  1500  	attributes := fmt.Sprintf("%s=%s,bar=c,\"%s=%s\"", fooName, fooVal, roleName, roleVal)
  1501  
  1502  	err := RunMain([]string{cmdName, "register", "-d", "--id.name", "testRegister3",
  1503  		"--id.affiliation", "hyperledger.org1", "--id.type", "client", "--id.attrs",
  1504  		attributes})
  1505  	if err != nil {
  1506  		t.Errorf("client register failed: %s", err)
  1507  	}
  1508  
  1509  	sqliteDB, err := getSqliteDb(srv.CA.Config.DB.Datasource)
  1510  	assert.NoError(t, err)
  1511  
  1512  	db := lib.NewDBAccessor(sqliteDB)
  1513  	user, err := db.GetUser("testRegister3", nil)
  1514  	assert.NoError(t, err)
  1515  
  1516  	allAttrs, _ := user.GetAttributes(nil)
  1517  	val := attr.GetAttrValue(allAttrs, fooName)
  1518  	if val != fooVal {
  1519  		t.Errorf("Incorrect value returned for attribute '%s', expected '%s' got '%s'", fooName, fooVal, val)
  1520  	}
  1521  	val = attr.GetAttrValue(allAttrs, roleName)
  1522  	if val != roleVal {
  1523  		t.Errorf("Incorrect value returned for attribute '%s', expected '%s' got '%s'", roleName, roleVal, val)
  1524  	}
  1525  
  1526  	err = RunMain([]string{cmdName, "register", "-d", "--id.name", "testRegister4",
  1527  		"--id.secret", "testRegister4", "--id.affiliation", "hyperledger.org2", "--id.type", "user"})
  1528  	if err != nil {
  1529  		t.Errorf("client register failed: %s", err)
  1530  	}
  1531  
  1532  	// Register an identity without identity type parameter (--id.type). It should succeed.
  1533  	// The identity type is set to default type "client"
  1534  	userName := "testRegister5"
  1535  	err = RunMain([]string{cmdName, "register", "-d", "--id.name", userName,
  1536  		"--id.secret", "testRegister5", "--id.affiliation", "hyperledger.org1"})
  1537  	assert.NoError(t, err, "Failed to register identity "+userName)
  1538  	user, err = db.GetUser(userName, nil)
  1539  	assert.NoError(t, err)
  1540  	assert.Equal(t, "client", user.GetType(), "Identity type for '%s' should have been 'user'", userName)
  1541  
  1542  	// Register an identity with a space in its name
  1543  	userName = "Test Register5"
  1544  	err = RunMain([]string{cmdName, "register", "-d", "--id.name", userName,
  1545  		"--id.affiliation", "hyperledger.org1"})
  1546  	assert.NoError(t, err, "Failed to register identity "+userName)
  1547  	user, err = db.GetUser(userName, nil)
  1548  	assert.NoError(t, err)
  1549  	assert.Equal(t, "client", user.GetType(), "Identity type for '%s' should have been 'user'", userName)
  1550  
  1551  	// Register an identity with no max enrollment specified should pick up CA's make enrollment
  1552  	srv.CA.Config.Registry.MaxEnrollments = 200
  1553  
  1554  	userName = "Test Register6"
  1555  	err = RunMain([]string{cmdName, "register", "-d", "--id.name", userName,
  1556  		"--id.affiliation", "hyperledger.org1"})
  1557  	assert.NoError(t, err, "Failed to register identity "+userName)
  1558  	user, err = db.GetUser(userName, nil)
  1559  	assert.NoError(t, err)
  1560  	assert.Equal(t, "client", user.GetType(), "Identity type for '%s' should have been 'user'", userName)
  1561  	assert.Equal(t, 200, user.GetMaxEnrollments())
  1562  
  1563  	os.Remove(defYaml) // Delete default config file
  1564  
  1565  	err = RunMain([]string{cmdName, "register", "-u", "http://localhost:7091"})
  1566  	if err == nil {
  1567  		t.Error("Should have failed, client config file should have incorrect port (7091) for server")
  1568  	}
  1569  
  1570  	err = RunMain([]string{cmdName, "register", "-u", serverURL, "Y"})
  1571  	if err == nil {
  1572  		t.Error("register called with bogus argument, should have failed")
  1573  	}
  1574  }
  1575  
  1576  // TestRevoke tests fabric-ca-client revoke
  1577  func testRevoke(t *testing.T) {
  1578  	t.Log("Testing Revoke command")
  1579  	clientHome := tdDir
  1580  	os.Setenv("FABRIC_CA_CLIENT_HOME", clientHome)
  1581  	defer os.Unsetenv("FABRIC_CA_CLIENT_HOME")
  1582  
  1583  	err := RunMain([]string{cmdName, "revoke"})
  1584  	if err == nil {
  1585  		t.Errorf("No enrollment ID or serial/aki provided, should have failed")
  1586  	}
  1587  
  1588  	serial, aki, err := getSerialAKIByID("admin")
  1589  	if err != nil {
  1590  		t.Error(err)
  1591  	}
  1592  
  1593  	// Revoker's affiliation: hyperledger
  1594  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL,
  1595  		"--revoke.name", "nonexistinguser"})
  1596  	if err == nil {
  1597  		t.Errorf("Non existing user being revoked, should have failed")
  1598  	}
  1599  
  1600  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL,
  1601  		"--revoke.serial", serial})
  1602  	if err == nil {
  1603  		t.Errorf("Only serial specified, should have failed")
  1604  	}
  1605  
  1606  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL,
  1607  		"--revoke.aki", aki})
  1608  	if err == nil {
  1609  		t.Errorf("Only aki specified, should have failed")
  1610  	}
  1611  
  1612  	// revoker's affiliation: hyperledger, revoking affiliation: ""
  1613  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL,
  1614  		"--revoke.serial", serial, "--revoke.aki", aki})
  1615  	if err == nil {
  1616  		t.Error("Should have failed, admin2 cannot revoke root affiliation")
  1617  	}
  1618  
  1619  	// When serial, aki and enrollment id are specified in a revoke request,
  1620  	// fabric ca server returns an error if the serial and aki do not belong
  1621  	// to the enrollment ID.
  1622  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL,
  1623  		"--revoke.name", "blah", "--revoke.serial", serial, "--revoke.aki", aki})
  1624  	if err == nil {
  1625  		t.Errorf("The Serial and AKI are not associated with the enrollment ID: %s", err)
  1626  	}
  1627  
  1628  	// Enroll testRegister4
  1629  	testRegister4Home := filepath.Join(os.TempDir(), "testregister4Home")
  1630  	defer os.RemoveAll(testRegister4Home)
  1631  	err = RunMain([]string{cmdName, "enroll", "-u",
  1632  		fmt.Sprintf("http://testRegister4:testRegister4@localhost:%d", serverPort)})
  1633  	if err != nil {
  1634  		t.Fatalf("Failed to enroll testRegister4 user: %s", err)
  1635  	}
  1636  
  1637  	// testRegister2's affiliation: hyperledger.org2, hyperledger.org2
  1638  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL, "--revoke.name",
  1639  		"testRegister2", "--revoke.serial", "", "--revoke.aki", ""})
  1640  	if err == nil {
  1641  		t.Errorf("Revoker has different type than the identity being revoked, should have failed")
  1642  	}
  1643  
  1644  	// Enroll admin with root affiliation and test revoking with root
  1645  	err = RunMain([]string{cmdName, "enroll", "-u", enrollURL})
  1646  	if err != nil {
  1647  		t.Fatalf("client enroll -u failed: %s", err)
  1648  	}
  1649  
  1650  	// testRegister4's affiliation: company2, revoker's affiliation: "" (root)
  1651  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL, "--revoke.name",
  1652  		"testRegister4", "--revoke.serial", "", "--revoke.aki", "", "--gencrl"})
  1653  	if err != nil {
  1654  		t.Errorf("User with root affiliation failed to revoke, error: %s", err)
  1655  	}
  1656  
  1657  	crlFile := filepath.Join(clientHome, "msp/crls/crl.pem")
  1658  	_, err = os.Stat(crlFile)
  1659  	assert.NoError(t, err, "CRL should be created when revoke is called with --gencrl parameter")
  1660  
  1661  	// Remove the CRL file created by revoke command
  1662  	err = os.Remove(crlFile)
  1663  	if err != nil {
  1664  		t.Fatalf("Failed to delete the CRL file '%s': %s", crlFile, err)
  1665  	}
  1666  
  1667  	// Enroll testRegister5, so the next revoke command will revoke atleast one
  1668  	// ecert
  1669  	testRegister5Home := filepath.Join(os.TempDir(), "testregister5Home")
  1670  	defer os.RemoveAll(testRegister5Home)
  1671  	err = RunMain([]string{cmdName, "enroll", "-u",
  1672  		fmt.Sprintf("http://testRegister5:testRegister5@localhost:%d", serverPort), "-H", testRegister5Home})
  1673  	if err != nil {
  1674  		t.Fatalf("Failed to enroll testRegister5 user: %s", err)
  1675  	}
  1676  
  1677  	testRegister5Serial, testRegister5AKI, err := getSerialAKIByID("testRegister5")
  1678  	if err != nil {
  1679  		t.Fatalf("Failed to get serial and aki of the enrollment certificate of the user 'testRegister5': %s", err)
  1680  	}
  1681  
  1682  	// Revoke testRegister5 without --gencrl option, so it does not create a CRL
  1683  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL, "--revoke.name",
  1684  		"testRegister5", "--revoke.serial", "", "--revoke.aki", ""})
  1685  	if err != nil {
  1686  		t.Errorf("Failed to revoke testRegister5, error: %s", err)
  1687  	}
  1688  	_, err = os.Stat(filepath.Join(clientHome, "msp/crls/crl.pem"))
  1689  	assert.Error(t, err, "CRL should not be created when revoke is called without --gencrl parameter")
  1690  
  1691  	// Revoke testRegister5 certificate that was revoked by the above revoke command, we expect
  1692  	// an error in this case
  1693  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL,
  1694  		"--revoke.serial", testRegister5Serial, "--revoke.aki", testRegister5AKI})
  1695  	if err == nil {
  1696  		t.Error("Revoke of testRegister5's certificate should have failed as it was already revoked")
  1697  	}
  1698  
  1699  	err = RunMain([]string{cmdName, "enroll", "-d", "-u", "http://admin3:adminpw3@localhost:7090"})
  1700  	if err != nil {
  1701  		t.Errorf("client enroll -u failed: %s", err)
  1702  	}
  1703  
  1704  	// Revoked user's affiliation: hyperledger.org3
  1705  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL, "--revoke.name",
  1706  		"testRegister3", "--revoke.serial", "", "--revoke.aki", ""})
  1707  	if err == nil {
  1708  		t.Error("Should have failed, admin3 does not have authority revoke")
  1709  	}
  1710  
  1711  	// testRegister4's affiliation: company2, revoker's affiliation: company1
  1712  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL, "--revoke.name",
  1713  		"testRegister4"})
  1714  	if err == nil {
  1715  		t.Error("Should have failed have different affiliation path")
  1716  	}
  1717  
  1718  	os.Remove(defYaml) // Delete default config file
  1719  
  1720  	err = RunMain([]string{cmdName, "revoke", "-u", "http://localhost:7091"})
  1721  	if err == nil {
  1722  		t.Error("Should have failed, client config file should have incorrect port (7091) for server")
  1723  	}
  1724  	err = RunMain([]string{cmdName, "revoke", "-u", serverURL, "U"})
  1725  	if err == nil {
  1726  		t.Error("revoke called with bogus argument, should have failed")
  1727  	}
  1728  
  1729  	os.RemoveAll(filepath.Dir(defYaml))
  1730  }
  1731  
  1732  // Test that affiliations get correctly set when registering a user with affiliation specified
  1733  func testAffiliation(t *testing.T) {
  1734  	var err error
  1735  
  1736  	// admin2 has affiliation of 'hyperledger'
  1737  	err = RunMain([]string{cmdName, "enroll", "-d", "-u", enrollURL1})
  1738  	if err != nil {
  1739  		t.Errorf("client enroll -u failed: %s", err)
  1740  	}
  1741  
  1742  	// Registering with affiliation of "", should result in error. Registrar does not have absolute root affiliation
  1743  	err = RunMain([]string{cmdName, "register", "-d", "--id.name", "testRegister5", "--id.type", "client", "--id.affiliation", "."})
  1744  	if err == nil {
  1745  		t.Error("Registering with affiliation of '', should result in error. Registrar does not have absolute root affiliation")
  1746  	}
  1747  
  1748  	// admin has affiliation of ""
  1749  	err = RunMain([]string{cmdName, "enroll", "-d", "-u", enrollURL})
  1750  	if err != nil {
  1751  		t.Errorf("client enroll -u failed: %s", err)
  1752  	}
  1753  
  1754  	// Registering with affiliation of "hyperledger", valid scenario
  1755  	err = RunMain([]string{cmdName, "register", "-d", "--id.name", "testRegister6", "--id.type", "client", "--id.affiliation", "hyperledger"})
  1756  	if err != nil {
  1757  		t.Errorf("client register failed: %s", err)
  1758  	}
  1759  
  1760  	sqliteDB, err := getSqliteDb(srv.CA.Config.DB.Datasource)
  1761  	assert.NoError(t, err)
  1762  
  1763  	db := lib.NewDBAccessor(sqliteDB)
  1764  	user, err := db.GetUser("testRegister6", nil)
  1765  	assert.NoError(t, err)
  1766  
  1767  	userAff := cadbuser.GetAffiliation(user)
  1768  	if userAff != "hyperledger" {
  1769  		t.Errorf("Incorrectly set affiliation for user being registered when no affiliation was specified, expected 'hyperledger' got %s", userAff)
  1770  	}
  1771  
  1772  	os.RemoveAll(filepath.Dir(defYaml))
  1773  }
  1774  
  1775  // testProfiling tests enablement of fabric CA client heap/cpu profiling
  1776  func testProfiling(t *testing.T) {
  1777  	t.Log("Testing profiling")
  1778  	var testCases = []struct {
  1779  		pEnvVal       string
  1780  		input         []string
  1781  		mProfExpected bool
  1782  		cProfExpected bool
  1783  	}{
  1784  		{"heap", []string{cmdName, "getcacert", "-u", serverURL}, true, false},
  1785  		{"cpu", []string{cmdName, "getcacert", "-u", serverURL}, false, true},
  1786  		{"", []string{cmdName, "getcacert", "-u", serverURL}, false, false},
  1787  		{"foo", []string{cmdName, "getcacert", "-u", serverURL}, false, false},
  1788  	}
  1789  	wd, err := os.Getwd()
  1790  	if err != nil {
  1791  		wd = os.Getenv("HOME")
  1792  	}
  1793  	mfile := wd + "/mem.pprof"
  1794  	cfile := wd + "/cpu.pprof"
  1795  	for _, testCase := range testCases {
  1796  		os.Setenv(fabricCAClientProfileMode, testCase.pEnvVal)
  1797  		_ = RunMain(testCase.input)
  1798  		_, err := os.Stat(mfile)
  1799  		_, err1 := os.Stat(cfile)
  1800  		if testCase.cProfExpected && err1 != nil {
  1801  			t.Errorf("%s is found. It should not be created when cpu profiling is NOT enabled: %s", cfile, err1)
  1802  		}
  1803  		if !testCase.cProfExpected && err1 == nil {
  1804  			t.Errorf("%s is not found. It should be created when cpu profiling is enabled", cfile)
  1805  		}
  1806  		if testCase.mProfExpected && err != nil {
  1807  			t.Errorf("%s is found. It should not be created when memory profiling is NOT enabled: %s", mfile, err)
  1808  		}
  1809  		if !testCase.mProfExpected && err == nil {
  1810  			t.Errorf("%s is not found. It should be created when memory profiling is enabled", mfile)
  1811  		}
  1812  		os.Remove(mfile)
  1813  		os.Remove(cfile)
  1814  		os.Remove(defYaml)
  1815  	}
  1816  	os.Unsetenv(fabricCAClientProfileMode)
  1817  }
  1818  
  1819  // TestBogus tests a negative test case
  1820  func testBogus(t *testing.T) {
  1821  	err := RunMain([]string{cmdName, "bogus"})
  1822  	if err == nil {
  1823  		t.Errorf("client bogus passed but should have failed")
  1824  	}
  1825  }
  1826  
  1827  func TestGetCACert(t *testing.T) {
  1828  	srv = getServer()
  1829  	srv.Config.Debug = true
  1830  
  1831  	// Configure TLS settings on server
  1832  	srv.HomeDir = tdDir
  1833  	srv.Config.TLS.Enabled = true
  1834  	srv.Config.TLS.CertFile = tlsCertFile
  1835  	srv.Config.TLS.KeyFile = tlsKeyFile
  1836  
  1837  	err := srv.Start()
  1838  	if err != nil {
  1839  		t.Errorf("Server start failed: %s", err)
  1840  	}
  1841  
  1842  	// Test getcacert command using environment variables to set root TLS cert
  1843  	err = testGetCACertEnvVar(t)
  1844  	assert.NoError(t, err, "Failed to get CA cert using environment variables")
  1845  
  1846  	// Change client authentication type on server
  1847  	srv.Config.TLS.ClientAuth.Type = "RequireAndVerifyClientCert"
  1848  
  1849  	// Test getcacert command using configuration files to read in client TLS cert and key
  1850  	err = testGetCACertConfigFile(t)
  1851  	assert.NoError(t, err, "Failed to get CA cert using client configuration file")
  1852  
  1853  	err = srv.Stop()
  1854  	if err != nil {
  1855  		t.Errorf("Server stop failed: %s", err)
  1856  	}
  1857  }
  1858  
  1859  func TestClientCommandsUsingConfigFile(t *testing.T) {
  1860  	os.Remove(fabricCADB)
  1861  
  1862  	srv = lib.TestGetServer(serverPort, testdataDir, "", -1, t)
  1863  	srv.Config.Debug = true
  1864  
  1865  	err := srv.RegisterBootstrapUser("admin", "adminpw", "org1")
  1866  	if err != nil {
  1867  		t.Errorf("Failed to register bootstrap user: %s", err)
  1868  	}
  1869  
  1870  	srv.HomeDir = tdDir
  1871  	srv.Config.TLS.Enabled = true
  1872  	srv.Config.TLS.CertFile = tlsCertFile
  1873  	srv.Config.TLS.KeyFile = tlsKeyFile
  1874  
  1875  	err = srv.Start()
  1876  	if err != nil {
  1877  		t.Errorf("Server start failed: %s", err)
  1878  	}
  1879  
  1880  	err = RunMain([]string{cmdName, "enroll", "-c",
  1881  		filepath.Join(tdDir, "fabric-ca-client-config.yaml"), "-u",
  1882  		tlsEnrollURL, "-d"})
  1883  	if err != nil {
  1884  		t.Errorf("client enroll -c -u failed: %s", err)
  1885  	}
  1886  
  1887  	err = srv.Stop()
  1888  	if err != nil {
  1889  		t.Errorf("Server stop failed: %s", err)
  1890  	}
  1891  }
  1892  
  1893  func TestClientCommandsTLSEnvVar(t *testing.T) {
  1894  	os.Remove(fabricCADB)
  1895  
  1896  	srv = lib.TestGetServer(serverPort, testdataDir, "", -1, t)
  1897  	srv.Config.Debug = true
  1898  
  1899  	err := srv.RegisterBootstrapUser("admin2", "adminpw2", "org1")
  1900  	if err != nil {
  1901  		t.Errorf("Failed to register bootstrap user: %s", err)
  1902  	}
  1903  
  1904  	srv.HomeDir = tdDir
  1905  	srv.Config.TLS.Enabled = true
  1906  	srv.Config.TLS.CertFile = tlsCertFile
  1907  	srv.Config.TLS.KeyFile = tlsKeyFile
  1908  
  1909  	err = srv.Start()
  1910  	if err != nil {
  1911  		t.Errorf("Server start failed: %s", err)
  1912  	}
  1913  
  1914  	os.Setenv(rootCertEnvVar, rootCert)
  1915  	os.Setenv(clientKeyEnvVar, tlsClientKeyFile)
  1916  	os.Setenv(clientCertEnvVar, tlsClientCertFile)
  1917  
  1918  	err = RunMain([]string{cmdName, "enroll", "-d", "-c", testYaml,
  1919  		"-u", tlsEnrollURL, "-d"})
  1920  	if err != nil {
  1921  		t.Errorf("client enroll -c -u failed: %s", err)
  1922  	}
  1923  
  1924  	err = srv.Stop()
  1925  	if err != nil {
  1926  		t.Errorf("Server stop failed: %s", err)
  1927  	}
  1928  
  1929  	os.Unsetenv(rootCertEnvVar)
  1930  	os.Unsetenv(clientKeyEnvVar)
  1931  	os.Unsetenv(clientCertEnvVar)
  1932  }
  1933  
  1934  func TestClientCommandsTLS(t *testing.T) {
  1935  	os.Remove(fabricCADB)
  1936  
  1937  	srv = lib.TestGetServer(serverPort, testdataDir, "", -1, t)
  1938  	srv.Config.Debug = true
  1939  
  1940  	err := srv.RegisterBootstrapUser("admin2", "adminpw2", "org1")
  1941  	if err != nil {
  1942  		t.Errorf("Failed to register bootstrap user: %s", err)
  1943  	}
  1944  
  1945  	srv.HomeDir = tdDir
  1946  	srv.Config.TLS.Enabled = true
  1947  	srv.Config.TLS.CertFile = tlsCertFile
  1948  	srv.Config.TLS.KeyFile = tlsKeyFile
  1949  
  1950  	err = srv.Start()
  1951  	if err != nil {
  1952  		t.Errorf("Server start failed: %s", err)
  1953  	}
  1954  
  1955  	err = RunMain([]string{cmdName, "enroll", "-c", testYaml, "--tls.certfiles",
  1956  		rootCert, "--tls.client.keyfile", tlsClientKeyFile, "--tls.client.certfile",
  1957  		tlsClientCertFile, "-u", tlsEnrollURL, "-d"})
  1958  	if err != nil {
  1959  		t.Errorf("client enroll -c -u failed: %s", err)
  1960  	}
  1961  
  1962  	err = RunMain([]string{cmdName, "enroll", "-c", testYaml, "--tls.certfiles",
  1963  		rootCert, "--tls.client.keyfile", tlsClientKeyFile, "--tls.client.certfile",
  1964  		tlsClientCertExpired, "-u", tlsEnrollURL, "-d"})
  1965  	if err == nil {
  1966  		t.Errorf("Expired certificate used for TLS connection, should have failed")
  1967  	}
  1968  
  1969  	err = srv.Stop()
  1970  	if err != nil {
  1971  		t.Errorf("Server stop failed: %s", err)
  1972  	}
  1973  	os.Remove(testYaml)
  1974  }
  1975  
  1976  func TestMultiCA(t *testing.T) {
  1977  	cleanMultiCADir()
  1978  
  1979  	srv = lib.TestGetServer(serverPort, testdataDir, "", -1, t)
  1980  	srv.HomeDir = tdDir
  1981  	srv.Config.CAfiles = []string{"ca/rootca/ca1/fabric-ca-server-config.yaml",
  1982  		"ca/rootca/ca2/fabric-ca-server-config.yaml"}
  1983  	srv.CA.Config.CSR.Hosts = []string{"hostname"}
  1984  	t.Logf("Server configuration: %+v\n", srv.Config)
  1985  
  1986  	err := srv.RegisterBootstrapUser("admin", "adminpw", "")
  1987  	if err != nil {
  1988  		t.Errorf("Failed to register bootstrap user: %s", err)
  1989  	}
  1990  
  1991  	srv.BlockingStart = false
  1992  	err = srv.Start()
  1993  	if err != nil {
  1994  		t.Fatal("Failed to start server:", err)
  1995  	}
  1996  
  1997  	// Test going to default CA if no caname provided in client request
  1998  	err = RunMain([]string{cmdName, "enroll", "-c", testYaml, "-u", enrollURL, "-d"})
  1999  	if err != nil {
  2000  		t.Errorf("client enroll -c -u failed: %s", err)
  2001  	}
  2002  
  2003  	enrURL := fmt.Sprintf("http://adminca1:adminca1pw@localhost:%d", serverPort)
  2004  	err = RunMain([]string{cmdName, "enroll", "-c", testYaml, "-u", enrURL, "-d",
  2005  		"--caname", "rootca1"})
  2006  	if err != nil {
  2007  		t.Errorf("client enroll -c -u --caname failed: %s", err)
  2008  	}
  2009  
  2010  	err = RunMain([]string{cmdName, "reenroll", "-c", testYaml, "-d", "--caname",
  2011  		"rootca1"})
  2012  	if err != nil {
  2013  		t.Errorf("client reenroll -c --caname failed: %s", err)
  2014  	}
  2015  
  2016  	err = RunMain([]string{cmdName, "register", "-c", testYaml, "-d", "--id.name",
  2017  		"testuser", "--id.type", "user", "--id.affiliation", "org2", "--caname", "rootca1"})
  2018  	if err != nil {
  2019  		t.Errorf("client register failed: %s", err)
  2020  	}
  2021  
  2022  	err = RunMain([]string{cmdName, "revoke", "-c", testYaml, "-d",
  2023  		"--revoke.name", "adminca1", "--caname", "rootca1"})
  2024  	if err != nil {
  2025  		t.Errorf("client revoke failed: %s", err)
  2026  	}
  2027  
  2028  	err = RunMain([]string{cmdName, "getcacert", "-u", serverURL, "-c", testYaml, "-d",
  2029  		"--caname", "rootca1"})
  2030  	if err != nil {
  2031  		t.Errorf("client getcacert failed: %s", err)
  2032  	}
  2033  
  2034  	err = RunMain([]string{cmdName, "enroll", "-c", testYaml, "-u",
  2035  		enrollURL, "-d", "--caname", "rootca2"})
  2036  	if err != nil {
  2037  		t.Errorf("client enroll failed: %s", err)
  2038  	}
  2039  
  2040  	err = RunMain([]string{cmdName, "enroll", "-c", testYaml, "-u",
  2041  		enrURL, "-d", "--caname", "rootca3"})
  2042  	if err == nil {
  2043  		t.Errorf("Should have failed, rootca3 does not exist on server")
  2044  	}
  2045  
  2046  	err = srv.Stop()
  2047  	if err != nil {
  2048  		t.Errorf("Server stop failed: %s", err)
  2049  	}
  2050  }
  2051  
  2052  func TestMSPDirectoryCreation(t *testing.T) {
  2053  	os.RemoveAll("mspConfigTest")
  2054  	defer os.RemoveAll("mspConfigTest")
  2055  	srv := lib.TestGetServer(serverPort, "mspConfigTest", "", -1, t)
  2056  
  2057  	err := srv.Start()
  2058  	if err != nil {
  2059  		t.Fatal("Failed to start server:", err)
  2060  	}
  2061  
  2062  	if util.FileExists("msp") {
  2063  		t.Errorf("MSP directory should not exist at the local directory")
  2064  	}
  2065  
  2066  	err = srv.Stop()
  2067  	if err != nil {
  2068  		t.Errorf("Server stop failed: %s", err)
  2069  	}
  2070  }
  2071  
  2072  func TestHomeDirectory(t *testing.T) {
  2073  	configFilePath := util.GetDefaultConfigFile(clientCMD)
  2074  	defaultClientConfigDir, defaultClientConfigFile := filepath.Split(configFilePath)
  2075  
  2076  	dir := filepath.Join(tdDir, "testhome")
  2077  	os.RemoveAll(dir)
  2078  	defer os.RemoveAll(dir)
  2079  
  2080  	RunMain([]string{cmdName, "enroll", "-u", enrollURL, "-c", ""})
  2081  	if !util.FileExists(configFilePath) {
  2082  		t.Errorf("Failed to correctly created the default config (fabric-ca-client-config) in the default home directory")
  2083  	}
  2084  
  2085  	os.RemoveAll(defaultClientConfigDir) // Remove default directory before testing another default case
  2086  
  2087  	RunMain([]string{cmdName, "enroll", "-u", enrollURL, "-H", ""})
  2088  	if !util.FileExists(configFilePath) {
  2089  		t.Errorf("Failed to correctly created the default config (fabric-ca-client-config) in the default home directory")
  2090  	}
  2091  
  2092  	os.RemoveAll(defaultClientConfigDir) // Remove default directory before testing another default case
  2093  
  2094  	RunMain([]string{cmdName, "enroll", "-u", enrollURL})
  2095  	if !util.FileExists(configFilePath) {
  2096  		t.Errorf("Failed to correctly created the default config (fabric-ca-client-config) in the default home directory")
  2097  	}
  2098  
  2099  	RunMain([]string{cmdName, "enroll", "-u", enrollURL, "-H", filepath.Join(tdDir, "testhome/testclientcmd")})
  2100  	if !util.FileExists(filepath.Join(tdDir, "testhome/testclientcmd", defaultClientConfigFile)) {
  2101  		t.Errorf("Failed to correctly created the default config (fabric-ca-client-config.yaml) in the '../../../testdata/testhome/testclientcmd' directory")
  2102  	}
  2103  
  2104  	RunMain([]string{cmdName, "enroll", "-u", enrollURL, "-d", "-c", filepath.Join(tdDir, "testhome/testclientcmd2/testconfig2.yaml")})
  2105  	if !util.FileExists(filepath.Join(tdDir, "testhome/testclientcmd2/testconfig2.yaml")) {
  2106  		t.Errorf("Failed to correctly created the config (testconfig2.yaml) in the '../../../testdata/testhome/testclientcmd2' directory")
  2107  	}
  2108  
  2109  	RunMain([]string{cmdName, "enroll", "-u", enrollURL, "-d", "-H", filepath.Join(tdDir, "testclientcmd3"), "-c", filepath.Join(tdDir, "testhome/testclientcmd3/testconfig3.yaml")})
  2110  	if !util.FileExists(filepath.Join(tdDir, "testhome/testclientcmd3/testconfig3.yaml")) {
  2111  		t.Errorf("Failed to correctly created the config (testconfig3.yaml) in the '../../../testdata/testhome/testclientcmd3' directory")
  2112  	}
  2113  
  2114  }
  2115  
  2116  func TestDebugSetting(t *testing.T) {
  2117  	os.RemoveAll(testdataDir)
  2118  	defer os.RemoveAll(testdataDir)
  2119  
  2120  	srv = lib.TestGetServer(serverPort, testdataDir, "", -1, t)
  2121  	err := srv.Start()
  2122  	util.FatalError(t, err, "Failed to start server")
  2123  	defer srv.Stop()
  2124  
  2125  	err = RunMain([]string{cmdName, "enroll", "-u", enrollURL})
  2126  	util.FatalError(t, err, "Failed to enroll user")
  2127  
  2128  	err = RunMain([]string{cmdName, "affiliation", "list"})
  2129  	assert.NoError(t, err, "Failed to return all affiliations")
  2130  	assert.Equal(t, 2, log.Level) // Default level for listing affiliations is warning (2)
  2131  
  2132  	err = RunMain([]string{cmdName, "affiliation", "list", "-d"})
  2133  	assert.NoError(t, err, "Failed to return all affiliations")
  2134  	assert.Equal(t, 0, log.Level) // With '-d' flag log level should be debug (0)
  2135  
  2136  	err = RunMain([]string{cmdName, "identity", "list"})
  2137  	assert.NoError(t, err, "Failed to return all affiliations")
  2138  	assert.Equal(t, 2, log.Level) // Default level for listing identities is warning (2)
  2139  
  2140  	err = RunMain([]string{cmdName, "identity", "list", "-d"})
  2141  	assert.NoError(t, err, "Failed to return all affiliations")
  2142  	assert.Equal(t, 0, log.Level) // With '-d' flag log level should be debug (0)
  2143  }
  2144  
  2145  func TestClientLogLevelCLI(t *testing.T) {
  2146  	// Not passing in -u flag, don't need for the enroll to complete successfully to
  2147  	// verify that the log level is correctly getting set
  2148  	RunMain([]string{cmdName, "enroll", "--loglevel", "info"})
  2149  	assert.Equal(t, log.Level, log.LOG_LEVEL_INFO)
  2150  
  2151  	RunMain([]string{cmdName, "enroll", "--loglevel", "debug"})
  2152  	assert.Equal(t, log.Level, log.LOG_LEVEL_DEBUG)
  2153  
  2154  	RunMain([]string{cmdName, "enroll", "--loglevel", "warning"})
  2155  	assert.Equal(t, log.Level, log.LOG_LEVEL_WARNING)
  2156  
  2157  	RunMain([]string{cmdName, "enroll", "--loglevel", "fatal"})
  2158  	assert.Equal(t, log.Level, log.LOG_LEVEL_FATAL)
  2159  
  2160  	RunMain([]string{cmdName, "enroll", "--loglevel", "panic"})
  2161  	assert.Equal(t, log.Level, log.LOG_LEVEL_PANIC)
  2162  }
  2163  
  2164  func TestClientLogLevelEnvVar(t *testing.T) {
  2165  	// Not passing in -u flag, don't need for the enroll to complete successfully to
  2166  	// verify that the log level is correctly getting set
  2167  	os.Setenv("FABRIC_CA_CLIENT_LOGLEVEL", "info")
  2168  	RunMain([]string{cmdName, "enroll"})
  2169  	assert.Equal(t, log.Level, log.LOG_LEVEL_INFO)
  2170  
  2171  	os.Setenv("FABRIC_CA_CLIENT_LOGLEVEL", "debug")
  2172  	RunMain([]string{cmdName, "enroll"})
  2173  	assert.Equal(t, log.Level, log.LOG_LEVEL_DEBUG)
  2174  
  2175  	os.Setenv("FABRIC_CA_CLIENT_LOGLEVEL", "warning")
  2176  	RunMain([]string{cmdName, "enroll"})
  2177  	assert.Equal(t, log.Level, log.LOG_LEVEL_WARNING)
  2178  
  2179  	os.Setenv("FABRIC_CA_CLIENT_LOGLEVEL", "fatal")
  2180  	RunMain([]string{cmdName, "enroll"})
  2181  	assert.Equal(t, log.Level, log.LOG_LEVEL_FATAL)
  2182  
  2183  	os.Setenv("FABRIC_CA_CLIENT_LOGLEVEL", "panic")
  2184  	RunMain([]string{cmdName, "enroll"})
  2185  	assert.Equal(t, log.Level, log.LOG_LEVEL_PANIC)
  2186  }
  2187  
  2188  func TestCleanUp(t *testing.T) {
  2189  	os.Remove(filepath.Join(tdDir, "ca-cert.pem"))
  2190  	os.Remove(filepath.Join(tdDir, "ca-key.pem"))
  2191  	os.Remove(filepath.Join(tdDir, "IssuerPublicKey"))
  2192  	os.Remove(filepath.Join(tdDir, "IssuerSecretKey"))
  2193  	os.Remove(filepath.Join(tdDir, "IssuerRevocationPublicKey"))
  2194  	os.Remove(testYaml)
  2195  	os.Remove(fabricCADB)
  2196  	os.RemoveAll(moptionDir)
  2197  	cleanMultiCADir()
  2198  }
  2199  
  2200  func cleanMultiCADir() {
  2201  	caFolder := filepath.Join(tdDir, "ca/rootca")
  2202  	nestedFolders := []string{"ca1", "ca2"}
  2203  	removeFiles := []string{"msp", "ca-cert.pem",
  2204  		"fabric-ca-server.db", "fabric-ca2-server.db", "ca-chain.pem", "IssuerPublicKey", "IssuerSecretKey", "IssuerRevocationPublicKey"}
  2205  
  2206  	for _, nestedFolder := range nestedFolders {
  2207  		path := filepath.Join(caFolder, nestedFolder)
  2208  		for _, file := range removeFiles {
  2209  			os.RemoveAll(filepath.Join(path, file))
  2210  		}
  2211  		os.RemoveAll(filepath.Join(path, "msp"))
  2212  	}
  2213  }
  2214  
  2215  func TestRegisterWithoutEnroll(t *testing.T) {
  2216  	err := RunMain([]string{cmdName, "register", "-c", testYaml})
  2217  	if err == nil {
  2218  		t.Errorf("Should have failed, as no enrollment information should exist. Enroll commands needs to be the first command to be executed")
  2219  	}
  2220  }
  2221  
  2222  func testGetCACertEnvVar(t *testing.T) error {
  2223  	t.Log("testGetCACertEnvVar - Entered")
  2224  	os.Setenv(rootCertEnvVar, filepath.Join(tdDir, "root.pem"))
  2225  	defer os.Unsetenv(rootCertEnvVar)
  2226  
  2227  	defer os.RemoveAll("msp")
  2228  	err := RunMain([]string{cmdName, "getcacert", "-d", "-c", "fakeConfig.yaml", "-u", tlsServerURL,
  2229  		"--tls.client.certfile", "", "--tls.client.keyfile", "", "--caname", ""})
  2230  	if err != nil {
  2231  		return fmt.Errorf("getcainfo failed: %s", err)
  2232  	}
  2233  
  2234  	return nil
  2235  }
  2236  
  2237  func testGetCACertConfigFile(t *testing.T) error {
  2238  	t.Log("testGetCACertConfigFile - Entered")
  2239  	configFile := filepath.Join(tdDir, "fabric-ca-client-config.yaml")
  2240  
  2241  	err := RunMain([]string{cmdName, "getcacert", "-d", "-c", configFile, "-u", tlsServerURL, "--tls.certfiles", rootCert})
  2242  	if err != nil {
  2243  		return fmt.Errorf("getcainfo failed: %s", err)
  2244  	}
  2245  
  2246  	return nil
  2247  }
  2248  
  2249  func TestVersion(t *testing.T) {
  2250  	err := RunMain([]string{cmdName, "version"})
  2251  	if err != nil {
  2252  		t.Error("Failed to get fabric-ca-client version: ", err)
  2253  	}
  2254  }
  2255  
  2256  func captureOutput(f func(args []string) error, args []string) (string, error) {
  2257  	old := os.Stdout
  2258  	r, w, err := os.Pipe()
  2259  	if err != nil {
  2260  		panic(err)
  2261  	}
  2262  	os.Stdout = w
  2263  	err = f(args)
  2264  	if err != nil {
  2265  		return "", err
  2266  	}
  2267  	w.Close()
  2268  	os.Stdout = old
  2269  	var buf bytes.Buffer
  2270  	io.Copy(&buf, r)
  2271  	return buf.String(), nil
  2272  }
  2273  
  2274  func getServer() *lib.Server {
  2275  	return &lib.Server{
  2276  		HomeDir: ".",
  2277  		Config:  getServerConfig(),
  2278  		CA: lib.CA{
  2279  			Config: getCAConfig(),
  2280  		},
  2281  	}
  2282  }
  2283  
  2284  func getServerConfig() *lib.ServerConfig {
  2285  	return &lib.ServerConfig{
  2286  		Debug: true,
  2287  		Port:  serverPort,
  2288  	}
  2289  }
  2290  
  2291  func getCAConfig() *lib.CAConfig {
  2292  	affiliations := map[string]interface{}{
  2293  		"org1": nil,
  2294  	}
  2295  
  2296  	return &lib.CAConfig{
  2297  		CA: lib.CAInfo{
  2298  			Keyfile:  keyfile,
  2299  			Certfile: certfile,
  2300  		},
  2301  		Affiliations: affiliations,
  2302  		CSR: api.CSRInfo{
  2303  			CN: "TestCN",
  2304  		},
  2305  	}
  2306  }
  2307  
  2308  func setupIdentityCmdTest(t *testing.T, id lib.CAConfigIdentity) *lib.Server {
  2309  	srvHome := filepath.Join(tdDir, "identityCmdTestHome")
  2310  	err := os.RemoveAll(srvHome)
  2311  	if err != nil {
  2312  		t.Fatalf("Failed to remove home directory %s: %s", srvHome, err)
  2313  	}
  2314  	affiliations := map[string]interface{}{"org1": nil}
  2315  	srv := &lib.Server{
  2316  		HomeDir: srvHome,
  2317  		Config: &lib.ServerConfig{
  2318  			Debug: true,
  2319  			Port:  serverPort,
  2320  		},
  2321  		CA: lib.CA{
  2322  			Config: &lib.CAConfig{
  2323  				Affiliations: affiliations,
  2324  				Registry: lib.CAConfigRegistry{
  2325  					MaxEnrollments: -1,
  2326  				},
  2327  			},
  2328  		},
  2329  	}
  2330  	srv.CA.Config.Registry.Identities = append(srv.CA.Config.Registry.Identities, id)
  2331  
  2332  	err = srv.RegisterBootstrapUser("admin", "adminpw", "")
  2333  	if err != nil {
  2334  		t.Fatalf("Failed to register bootstrap user: %s", err)
  2335  	}
  2336  	err = srv.Start()
  2337  	if err != nil {
  2338  		t.Fatalf("Failed to start server: %s", err)
  2339  	}
  2340  	return srv
  2341  }
  2342  
  2343  func getUser(id string, server *lib.Server) (cadbuser.User, error) {
  2344  	testdb, err := getSqliteDb(server.CA.Config.DB.Datasource)
  2345  	if err != nil {
  2346  		return nil, err
  2347  	}
  2348  	db := lib.NewDBAccessor(testdb)
  2349  	return db.GetUser(id, nil)
  2350  }
  2351  
  2352  func getSerialAKIByID(id string) (serial, aki string, err error) {
  2353  	testdb, err := getSqliteDb(srv.CA.Config.DB.Datasource)
  2354  	if err != nil {
  2355  		return "", "", err
  2356  	}
  2357  	acc := lib.NewCertDBAccessor(testdb, 0)
  2358  
  2359  	certs, err := acc.GetCertificatesByID(id)
  2360  	if err != nil {
  2361  		return "", "", err
  2362  	}
  2363  
  2364  	block, _ := pem.Decode([]byte(certs[0].PEM))
  2365  	if block == nil {
  2366  		return "", "", errors.New("Failed to PEM decode certificate")
  2367  	}
  2368  	x509Cert, err := x509.ParseCertificate(block.Bytes)
  2369  	if err != nil {
  2370  		return "", "", fmt.Errorf("Error from x509.ParseCertificate: %s", err)
  2371  	}
  2372  
  2373  	serial = util.GetSerialAsHex(x509Cert.SerialNumber)
  2374  	aki = hex.EncodeToString(x509Cert.AuthorityKeyId)
  2375  
  2376  	return
  2377  }
  2378  
  2379  func getSqliteDb(datasource string) (*db.DB, error) {
  2380  	sqliteDB := sqlite.NewDB(datasource, "", nil)
  2381  	err := sqliteDB.Connect()
  2382  	if err != nil {
  2383  		return nil, err
  2384  	}
  2385  	testdb, err := sqliteDB.Create()
  2386  	if err != nil {
  2387  		return nil, err
  2388  	}
  2389  	return testdb, nil
  2390  }
  2391  
  2392  func setupEnrollTest(t *testing.T) *lib.Server {
  2393  	srvHome := filepath.Join(tdDir, "enrollsrvhome")
  2394  	err := os.RemoveAll(srvHome)
  2395  	if err != nil {
  2396  		t.Fatalf("Failed to remove home directory %s: %s", srvHome, err)
  2397  	}
  2398  	srv = lib.TestGetServer(serverPort, srvHome, "", -1, t)
  2399  	srv.Config.Debug = true
  2400  
  2401  	err = srv.RegisterBootstrapUser("admin", "adminpw", "")
  2402  	if err != nil {
  2403  		t.Errorf("Failed to register bootstrap user: %s", err)
  2404  	}
  2405  
  2406  	err = srv.RegisterBootstrapUser("admin2", "adminpw2", "hyperledger")
  2407  	if err != nil {
  2408  		t.Errorf("Failed to register bootstrap user: %s", err)
  2409  	}
  2410  
  2411  	aff := make(map[string]interface{})
  2412  	aff["hyperledger"] = []string{"org1", "org2", "org3"}
  2413  	aff["company1"] = []string{"dept1"}
  2414  	aff["company2"] = []string{}
  2415  
  2416  	srv.CA.Config.Affiliations = aff
  2417  
  2418  	err = srv.Start()
  2419  	if err != nil {
  2420  		t.Errorf("Server start failed: %s", err)
  2421  	}
  2422  	return srv
  2423  }
  2424  
  2425  func setupGenCRLTest(t *testing.T, adminHome string) *lib.Server {
  2426  	srvHome := filepath.Join(tdDir, "gencrlsrvhom")
  2427  	err := os.RemoveAll(srvHome)
  2428  	if err != nil {
  2429  		t.Fatalf("Failed to remove home directory %s: %s", srvHome, err)
  2430  	}
  2431  
  2432  	srv := lib.TestGetServer(serverPort, srvHome, "", -1, t)
  2433  	srv.Config.Debug = true
  2434  	srv.CA.Config.CRL.Expiry = crlExpiry
  2435  	d, _ := time.ParseDuration("2h")
  2436  	srv.CA.Config.Signing.Default.Expiry = d
  2437  
  2438  	adminName := "admin"
  2439  	adminPass := "adminpw"
  2440  	err = srv.RegisterBootstrapUser(adminName, adminPass, "")
  2441  	if err != nil {
  2442  		t.Fatalf("Failed to register bootstrap user: %s", err)
  2443  	}
  2444  
  2445  	err = srv.Start()
  2446  	if err != nil {
  2447  		t.Fatalf("Server start failed: %s", err)
  2448  	}
  2449  
  2450  	err = RunMain([]string{cmdName, "enroll", "-u", enrollURL, "-H", adminHome})
  2451  	if err != nil {
  2452  		t.Fatalf("Failed to enroll admin: %s", err)
  2453  	}
  2454  	return srv
  2455  }
  2456  
  2457  func stopAndCleanupServer(t *testing.T, srv *lib.Server) {
  2458  	if srv != nil {
  2459  		defer os.RemoveAll(srv.HomeDir)
  2460  		err := srv.Stop()
  2461  		if err != nil {
  2462  			t.Errorf("Server stop failed: %s", err)
  2463  		}
  2464  	}
  2465  }
  2466  
  2467  // Checks if the generated CRL is in PEM format and contains expected
  2468  // revoked certificates
  2469  func checkCRL(t *testing.T, client *lib.Client, revokedSerials []*big.Int) {
  2470  	crlfile := filepath.Join(client.Config.MSPDir, "crls/crl.pem")
  2471  	crl, err := ioutil.ReadFile(crlfile)
  2472  	assert.NoError(t, err, "Failed to read the CRL from the file %s", crlfile)
  2473  	blk, _ := pem.Decode(crl)
  2474  	assert.Equal(t, blk.Type, "X509 CRL", "The %s is not a pem encoded CRL")
  2475  
  2476  	revokedList, err := x509.ParseCRL(crl)
  2477  	assert.False(t, revokedList.HasExpired(time.Now().UTC().Add(crlExpiry-time.Hour)), "Next Update value is not set to expected value (240h)")
  2478  	assert.True(t, revokedList.HasExpired(time.Now().UTC().Add(crlExpiry+time.Hour)), "Next Update value is not set to expected value (240h)")
  2479  	assert.NoError(t, err, "Failed to parse the CRL")
  2480  	assert.Equal(t, len(revokedSerials), len(revokedList.TBSCertList.RevokedCertificates),
  2481  		"CRL contains unexpected number of revoked certificates")
  2482  	t.Logf("Revoked certs from the CRL: %v", revokedList.TBSCertList.RevokedCertificates)
  2483  	for _, revokedCert := range revokedList.TBSCertList.RevokedCertificates {
  2484  		serial := util.GetSerialAsHex(revokedCert.SerialNumber)
  2485  		found := false
  2486  		for _, revokedSerial := range revokedSerials {
  2487  			if revokedCert.SerialNumber.Cmp(revokedSerial) == 0 {
  2488  				found = true
  2489  				break
  2490  			}
  2491  		}
  2492  		assert.True(t, found, "Certificate %s is not one of revoked certificates", serial)
  2493  	}
  2494  }
  2495  
  2496  // Registers, enrolls and revokes specified number of users. This is
  2497  // a utility function used by the gencrl test cases
  2498  func registerAndRevokeUsers(t *testing.T, admin *lib.Identity, num int) []*big.Int {
  2499  	var serials []*big.Int
  2500  	for i := 0; i < num; i++ {
  2501  		userName := "gencrluser" + strconv.Itoa(i)
  2502  		// Register a user
  2503  		regRes, err := admin.Register(&api.RegistrationRequest{
  2504  			Name:        userName,
  2505  			Type:        "user",
  2506  			Affiliation: "org2",
  2507  		})
  2508  		if err != nil {
  2509  			t.Fatalf("Failed to register the identity '%s': %s", userName, err)
  2510  		}
  2511  
  2512  		// Enroll the user
  2513  		enrollResp, err := admin.GetClient().Enroll(&api.EnrollmentRequest{
  2514  			Name:   userName,
  2515  			Secret: regRes.Secret,
  2516  			CSR:    &api.CSRInfo{Hosts: []string{"localhost"}},
  2517  		})
  2518  		if err != nil {
  2519  			t.Fatalf("Failed to enroll the identity '%s': %s", userName, err)
  2520  		}
  2521  
  2522  		x509Cred := enrollResp.Identity.GetECert()
  2523  		if x509Cred == nil || x509Cred.GetX509Cert() == nil {
  2524  			t.Fatalf("Failed to get enrollment certificate for the user %s", userName)
  2525  		}
  2526  		cert := x509Cred.GetX509Cert()
  2527  		revokeReq := &api.RevocationRequest{}
  2528  		if i%2 == 0 {
  2529  			revokeReq.Name = userName
  2530  		} else {
  2531  			revokeReq.Serial = util.GetSerialAsHex(cert.SerialNumber)
  2532  			revokeReq.AKI = hex.EncodeToString(cert.AuthorityKeyId)
  2533  			// Reenroll the user, this should create a new certificate, so this
  2534  			// user will have two valid certificates, but we will revoke one
  2535  			// of her certificate only
  2536  			_, err := enrollResp.Identity.Reenroll(&api.ReenrollmentRequest{})
  2537  			if err != nil {
  2538  				t.Fatalf("Reenrollment of user %s failed: %s", userName, err)
  2539  			}
  2540  		}
  2541  
  2542  		// Revoke the user cert
  2543  		_, err = admin.Revoke(revokeReq)
  2544  		if err != nil {
  2545  			t.Fatalf("Failed to revoke the identity '%s': %s", userName, err)
  2546  		}
  2547  
  2548  		serials = append(serials, cert.SerialNumber)
  2549  	}
  2550  	t.Logf("Revoked certificates: %v", serials)
  2551  	return serials
  2552  }
  2553  
  2554  func setupGenCSRTest(t *testing.T, adminHome string) *lib.Server {
  2555  	srvHome := filepath.Join(tdDir, "gencsrsrvhome")
  2556  	err := os.RemoveAll(srvHome)
  2557  	if err != nil {
  2558  		t.Fatalf("Failed to remove home directory %s: %s", srvHome, err)
  2559  	}
  2560  
  2561  	srv := lib.TestGetServer(serverPort, srvHome, "", -1, t)
  2562  	srv.Config.Debug = true
  2563  	srv.CA.Config.CSR.KeyRequest = &api.KeyRequest{Algo: "ecdsa", Size: 384}
  2564  
  2565  	adminName := "admin"
  2566  	adminPass := "adminpw"
  2567  	err = srv.RegisterBootstrapUser(adminName, adminPass, "")
  2568  	if err != nil {
  2569  		t.Fatalf("Failed to register bootstrap user: %s", err)
  2570  	}
  2571  
  2572  	err = srv.Start()
  2573  	if err != nil {
  2574  		t.Fatalf("Server start failed: %s", err)
  2575  	}
  2576  
  2577  	err = RunMain([]string{cmdName, "enroll", "-u", enrollURL, "-H", adminHome})
  2578  	if err != nil {
  2579  		t.Fatalf("Failed to enroll admin: %s", err)
  2580  	}
  2581  	return srv
  2582  }
  2583  
  2584  func extraArgErrorTest(in *TestData, t *testing.T) {
  2585  	err := RunMain(in.input)
  2586  	if err == nil {
  2587  		assert.Error(t, errors.New("Should have resulted in an error as extra arguments provided"))
  2588  	}
  2589  	if err != nil {
  2590  		assert.Contains(t, err.Error(), "Unrecognized arguments found",
  2591  			"Failed for other reason besides unrecognized argument")
  2592  	}
  2593  }
  2594  
  2595  // Make sure there is exactly one file in a directory
  2596  func assertFilesInDir(dir string, numFiles int, t *testing.T) {
  2597  	files, err := ioutil.ReadDir(dir)
  2598  	if err != nil {
  2599  		t.Fatalf("Failed to get number of files in directory '%s': %s", dir, err)
  2600  	}
  2601  	count := len(files)
  2602  	if count != numFiles {
  2603  		t.Fatalf("Expecting %d file in %s but found %d", numFiles, dir, count)
  2604  	}
  2605  }
  2606  
  2607  func startServer(home string, port int, parentURL string, t *testing.T) *lib.Server {
  2608  	affiliations := map[string]interface{}{"org1": nil}
  2609  	srv := &lib.Server{
  2610  		HomeDir: home,
  2611  		Config: &lib.ServerConfig{
  2612  			Debug: true,
  2613  			Port:  port,
  2614  		},
  2615  		CA: lib.CA{
  2616  			Config: &lib.CAConfig{
  2617  				Affiliations: affiliations,
  2618  				Registry: lib.CAConfigRegistry{
  2619  					MaxEnrollments: -1,
  2620  				},
  2621  			},
  2622  		},
  2623  	}
  2624  	if parentURL != "" {
  2625  		srv.CA.Config.Intermediate.ParentServer.URL = parentURL
  2626  	}
  2627  	err := srv.RegisterBootstrapUser("admin", "adminpw", "")
  2628  	if err != nil {
  2629  		t.Fatalf("Failed to register bootstrap user: %s", err)
  2630  	}
  2631  	err = srv.Start()
  2632  	if err != nil {
  2633  		t.Fatalf("Failed to start server: %s", err)
  2634  	}
  2635  	return srv
  2636  }
  2637  
  2638  func getAttrsMap(attrs []api.Attribute) map[string]api.Attribute {
  2639  	attrMap := make(map[string]api.Attribute)
  2640  	for _, attr := range attrs {
  2641  		attrMap[attr.Name] = api.Attribute{
  2642  			Name:  attr.Name,
  2643  			Value: attr.Value,
  2644  			ECert: attr.ECert,
  2645  		}
  2646  	}
  2647  	return attrMap
  2648  }
  2649  
  2650  func startServerWithCustomExpiry(home string, port int, certExpiry string, t *testing.T) *lib.Server {
  2651  	affiliations := map[string]interface{}{"org1": nil}
  2652  	srv := &lib.Server{
  2653  		HomeDir: home,
  2654  		Config: &lib.ServerConfig{
  2655  			Debug: true,
  2656  			Port:  port,
  2657  		},
  2658  		CA: lib.CA{
  2659  			Config: &lib.CAConfig{
  2660  				Affiliations: affiliations,
  2661  				Registry: lib.CAConfigRegistry{
  2662  					MaxEnrollments: -1,
  2663  				},
  2664  				CSR: api.CSRInfo{
  2665  					CA: &csr.CAConfig{
  2666  						Expiry: certExpiry,
  2667  					},
  2668  				},
  2669  			},
  2670  		},
  2671  	}
  2672  	err := srv.RegisterBootstrapUser("admin", "adminpw", "")
  2673  	if err != nil {
  2674  		t.Fatalf("Failed to register bootstrap user: %s", err)
  2675  	}
  2676  	err = srv.Start()
  2677  	if err != nil {
  2678  		t.Fatalf("Failed to start server: %s", err)
  2679  	}
  2680  	return srv
  2681  }