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