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