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