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