github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/cmd/fabric-ca-client/main_test.go (about)

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