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