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