From b8c714fd4cc0878602c006da59b554a7d520839e Mon Sep 17 00:00:00 2001 From: Atsushi Neki Date: Tue, 14 Jul 2020 17:24:29 +1000 Subject: [PATCH] BE-777 Fix an issue of authentication Even if enable authentication, user can login by using any invalid credential. Added some error handlings and e2e-test scenarios for user authentication. Signed-off-by: Atsushi Neki --- README-CONFIG.md | 54 ++++++++---- app/passport/local-login.js | 2 +- app/platform/fabric/FabricClient.js | 1 - app/platform/fabric/Proxy.js | 10 +-- .../configs/config_single-disable-auth.json | 9 ++ .../org1-network-disable-auth.json | 60 +++++++++++++ .../connection-profile/org1-network-pem.json | 10 +-- .../connection-profile/org1-network.json | 2 +- .../connection-profile/org2-network.json | 2 +- .../fabric/e2e-test/specs/apitest_test.go | 84 ++++++++++++++++--- .../fabric/e2e-test/specs/runexplorer.sh | 62 ++++++++------ .../fabric/e2e-test/specs/stopexplorer.sh | 16 +++- app/platform/fabric/gateway/FabricGateway.js | 17 ++-- app/platform/fabric/models/User.js | 4 +- app/platform/fabric/service/UserService.js | 47 ++++++++--- app/rest/authroutes.js | 3 +- start.sh | 2 - 17 files changed, 286 insertions(+), 99 deletions(-) create mode 100644 app/platform/fabric/e2e-test/configs/config_single-disable-auth.json create mode 100644 app/platform/fabric/e2e-test/configs/connection-profile/org1-network-disable-auth.json diff --git a/README-CONFIG.md b/README-CONFIG.md index 5c6b32570..00606e4af 100644 --- a/README-CONFIG.md +++ b/README-CONFIG.md @@ -42,6 +42,45 @@ This document will describe about the detail of each configuration: * `expiresIn`: expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms). Eg: `60`, `"2 days"`, `"10h"`, `"7d"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`"120"` is equal to `"120ms"`). +* Modify the connection profile (e.g. `app/platform/fabric/connection-profile/first-network.json`) to configure authorization of login user. + + ```json + "client": { + "adminCredential": { + "id": "exploreradmin", + "password": "exploreradminpw" + }, + "enableAuthentication": true, + ``` + * `adminCredential.id` is the the admin user to login Explorer. Currently Explorer only supports single user mode (can't add more users. We're working on it) + * `adminCredential.password` is the password for the admin user to login Explorer. + * `enableAuthentication` is a flag to enable authentication using a login page, setting to false will skip authentication. + * Even if disable user authentication, you still need to get `adminCredential.id` specified, because it's used to get access to the wallet. + +## Disable Explorer login authentication + +* If you want to disable login authentication, set `false` to `enableAuthentication` in the connection profile + ```json + "client": { + "enableAuthentication": false + } + ``` + +## Enable TLS + +* If your fabric network enables TLS, then set `true` to `client.tlsEnable` in the connection profile (e.g. `app/platform/fabric/connection-profile/first-network.json`). + And you also need to specify peer URL with `grpcs://`. If your fabrice network disables TLS, use `grpc://` instead. + + ```json + "client": { + "tlsEnable": true, + ``` + ```json + "peers": { + "peer0.org1.example.com": { + "url": "grpcs://localhost:7051", + ``` + ## Connection profile for Hyperledger Fabric network * Modify `app/platform/fabric/config.json` to define your fabric network connection profile: @@ -51,8 +90,7 @@ This document will describe about the detail of each configuration: "network-configs": { "first-network": { "name": "firstnetwork", - "profile": "./connection-profile/first-network.json", - "enableAuthentication": false + "profile": "./connection-profile/first-network.json" } }, "license": "Apache-2.0" @@ -76,18 +114,6 @@ This document will describe about the detail of each configuration: "pem": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMG ... utE5HtrGM\n-----END PRIVATE KEY-----\n" }, ``` - * `adminUser` is the the admin user of the network, in this case it's fabric CA or an identity user. - * `adminPassword` is the password for the admin user. - * `enableAuthentication` is a flag to enable authentication using a login page, setting to false will skip authentication. - -## Disable Explorer login authentication - -* If you want to disable login authentication, set `false` to `enableAuthentication` in the connection profile - ```json - "client": { - "enableAuthentication": false - } - ``` ## Using Fabric-CA diff --git a/app/passport/local-login.js b/app/passport/local-login.js index a632581bb..6e47c0535 100644 --- a/app/passport/local-login.js +++ b/app/passport/local-login.js @@ -39,7 +39,7 @@ const strategy = function(platform) { network: userInfo.network }; - if (userInfo && !userInfo.authenticated) { + if (!userInfo || !userInfo.authenticated) { const error = { name: 'IncorrectCredentialsError', message: userInfo.message diff --git a/app/platform/fabric/FabricClient.js b/app/platform/fabric/FabricClient.js index 2d39b757c..1e3e6cd8c 100644 --- a/app/platform/fabric/FabricClient.js +++ b/app/platform/fabric/FabricClient.js @@ -70,7 +70,6 @@ class FabricClient { // Getting channels from queryChannels let channels; try { - // logger.debug('this.defaultPeer ', this.defaultPeer); channels = await this.fabricGateway.queryChannels(); } catch (e) { logger.error(e); diff --git a/app/platform/fabric/Proxy.js b/app/platform/fabric/Proxy.js index 221046872..fef74112e 100644 --- a/app/platform/fabric/Proxy.js +++ b/app/platform/fabric/Proxy.js @@ -38,14 +38,8 @@ class Proxy { */ async authenticate(user) { const userService = new UserService(this.platform); - let response = await userService.authenticate(user); - if (!response) { - response = { - status: false, - message: `Failed authentication for user: ${user} ` - }; - } - logger.debug('login >> %s', response); + const response = await userService.authenticate(user); + logger.debug('result of authentication >> %j', response); return response; } diff --git a/app/platform/fabric/e2e-test/configs/config_single-disable-auth.json b/app/platform/fabric/e2e-test/configs/config_single-disable-auth.json new file mode 100644 index 000000000..2eac92ad8 --- /dev/null +++ b/app/platform/fabric/e2e-test/configs/config_single-disable-auth.json @@ -0,0 +1,9 @@ +{ + "network-configs": { + "org1-network": { + "name": "org1-network", + "profile": "./e2e-test/configs/connection-profile/org1-network-disable-auth.json" + } + }, + "license": "Apache-2.0" +} diff --git a/app/platform/fabric/e2e-test/configs/connection-profile/org1-network-disable-auth.json b/app/platform/fabric/e2e-test/configs/connection-profile/org1-network-disable-auth.json new file mode 100644 index 000000000..a29e0cdbe --- /dev/null +++ b/app/platform/fabric/e2e-test/configs/connection-profile/org1-network-disable-auth.json @@ -0,0 +1,60 @@ +{ + "name": "org1-network", + "version": "1.0.0", + "license": "Apache-2.0", + "client": { + "tlsEnable": true, + "adminCredential": { + "id": "exploreradmin3" + }, + "enableAuthentication": false, + "organization": "org1", + "connection": { + "timeout": { + "peer": { + "endorser": "300" + }, + "orderer": "300" + } + } + }, + "channels": { + "commonchannel": { + "peers": { + "peer0-org1": {} + }, + "connection": { + "timeout": { + "peer": { + "endorser": "6000", + "eventHub": "6000", + "eventReg": "6000" + } + } + } + } + }, + "organizations": { + "org1": { + "mspid": "Org1ExampleCom", + "adminPrivateKey": { + "path": "./app/platform/fabric/e2e-test/specs/crypto-config/peerOrganizations/org1/users/Admin@org1/msp/keystore/priv_sk" + }, + "peers": ["peer0-org1"], + "signedCert": { + "path": "./app/platform/fabric/e2e-test/specs/crypto-config/peerOrganizations/org1/users/Admin@org1/msp/signcerts/Admin@org1-cert.pem" + } + } + }, + "peers": { + "peer0-org1": { + "tlsCACerts": { + "path": "./app/platform/fabric/e2e-test/specs/crypto-config/peerOrganizations/org1/peers/peer0-org1.org1/tls/ca.crt" + }, + "url": "grpcs://localhost:31000", + "grpcOptions": { + "ssl-target-name-override": "peer0-org1" + } + } + } +} diff --git a/app/platform/fabric/e2e-test/configs/connection-profile/org1-network-pem.json b/app/platform/fabric/e2e-test/configs/connection-profile/org1-network-pem.json index ec1c0bc4d..d72ef06bd 100644 --- a/app/platform/fabric/e2e-test/configs/connection-profile/org1-network-pem.json +++ b/app/platform/fabric/e2e-test/configs/connection-profile/org1-network-pem.json @@ -5,10 +5,10 @@ "client": { "tlsEnable": true, "adminCredential": { - "id": "exploreradmin", + "id": "exploreradmin2", "password": "exploreradminpw" }, - "enableAuthentication": false, + "enableAuthentication": true, "organization": "org1", "connection": { "timeout": { @@ -39,18 +39,18 @@ "org1": { "mspid": "Org1ExampleCom", "adminPrivateKey": { - "pem": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgMwFI31oAw7BLotqD\nlt83zXPSFdcG9s68O8xjsmuEcDChRANCAAQeGSJN2yd9m1m0rRnXnO2/kjiZywRE\nIpjVDyBArAgoFwIAVgmkkps4NI3EMPMBXiTw8NTHjeEEkuovbohNAEal\n-----END PRIVATE KEY-----\n\n" + "pem": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgTOe+tIgG/TCjBruv\na5namOzeiEGhNxV+wYke2Ya7vXqhRANCAATux7xsRpKYrTJv18qJPfI8ypWrjcno\nzs9pF0UsrT2zKfaKPouGT3Tl58DujHvwXbM68FKQPiA86GA4AKrSMpZx\n-----END PRIVATE KEY-----\n\n" }, "peers": ["peer0-org1"], "signedCert": { - "pem": "-----BEGIN CERTIFICATE-----\nMIICBTCCAaugAwIBAgIQKSCQe3pGrCx15SgsHg6I+TAKBggqhkjOPQQDAjBbMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzENMAsGA1UEChMEb3JnMTEQMA4GA1UEAxMHY2Eub3JnMTAeFw0yMDA3\nMTAxNTIyMDBaFw0zMDA3MDgxNTIyMDBaMF8xCzAJBgNVBAYTAlVTMRMwEQYDVQQI\nEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMQ4wDAYDVQQLEwVh\nZG1pbjETMBEGA1UEAwwKQWRtaW5Ab3JnMTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABB4ZIk3bJ32bWbStGdec7b+SOJnLBEQimNUPIECsCCgXAgBWCaSSmzg0jcQw\n8wFeJPDw1MeN4QSS6i9uiE0ARqWjTTBLMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMB\nAf8EAjAAMCsGA1UdIwQkMCKAIJnau5jo0eUJwITnEe/wl2pg0gmtYvYsfYPKQy8t\nM/4ZMAoGCCqGSM49BAMCA0gAMEUCIQDiqNYuzalWflQQizqyjeZ0wynW395RZ9Ix\n7wVivlZNcQIgDWIDMnponNx8eSmv0f4ISJJtvsmTNFGSwpoGzpKWQ2s=\n-----END CERTIFICATE-----\n\n" + "pem": "-----BEGIN CERTIFICATE-----\nMIIB9DCCAZugAwIBAgIQOiMkd2Zh+BDeMU+pGOsfdzAKBggqhkjOPQQDAjBbMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzENMAsGA1UEChMEb3JnMTEQMA4GA1UEAxMHY2Eub3JnMTAeFw0yMDA3\nMTQwNjI3MDBaFw0zMDA3MTIwNjI3MDBaME8xCzAJBgNVBAYTAlVTMRMwEQYDVQQI\nEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQDDApB\nZG1pbkBvcmcxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7se8bEaSmK0yb9fK\niT3yPMqVq43J6M7PaRdFLK09syn2ij6Lhk905efA7ox78F2zOvBSkD4gPOhgOACq\n0jKWcaNNMEswDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQw\nIoAg0W6Kv0Z9DV5E+3sD6OErwjsJ882ogeeGzrB9jCBwZ74wCgYIKoZIzj0EAwID\nRwAwRAIgG6fqi1lB4sjcosYRbO2YxDYJ92jmvR6FqCqKOXtwSQQCIGnXgTzNGvof\np1DFPz5c3DKmgjQlok2MAlKn6z01JRBM\n-----END CERTIFICATE-----\n\n" } } }, "peers": { "peer0-org1": { "tlsCACerts": { - "pem": "-----BEGIN CERTIFICATE-----\nMIICJzCCAc2gAwIBAgIQTjoDncZ/NWffVrgB449RmTAKBggqhkjOPQQDAjBeMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzENMAsGA1UEChMEb3JnMTETMBEGA1UEAxMKdGxzY2Eub3JnMTAeFw0y\nMDA3MTAxNTIyMDBaFw0zMDA3MDgxNTIyMDBaMF4xCzAJBgNVBAYTAlVTMRMwEQYD\nVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQK\nEwRvcmcxMRMwEQYDVQQDEwp0bHNjYS5vcmcxMFkwEwYHKoZIzj0CAQYIKoZIzj0D\nAQcDQgAEXREuqNRHBPddBxwWT+01LZzkLjnFHhI0j+xpcGvLurqSpHwuh8XEe+nW\ncN2vzP6v16W6F2pjiYrqTwAvwrwUfqNtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1Ud\nJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1Ud\nDgQiBCCRDXS4hPlBUrW2wLu+fNy2PYfY1maQe1b6eLXjgoXclzAKBggqhkjOPQQD\nAgNIADBFAiEA3vNlfA2AKI9+lFHVKl9MD3+ZLN4M0K1HYlfx2BkuZToCIG7Nky+/\nPOT1iS3XCRPfZq4EAd4S2hQs5i7vuXB0b47o\n-----END CERTIFICATE-----\n\n" + "pem": "-----BEGIN CERTIFICATE-----\nMIICJjCCAc2gAwIBAgIQRckhJx+KJbD5liP6bky2SjAKBggqhkjOPQQDAjBeMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzENMAsGA1UEChMEb3JnMTETMBEGA1UEAxMKdGxzY2Eub3JnMTAeFw0y\nMDA3MTQwNjI3MDBaFw0zMDA3MTIwNjI3MDBaMF4xCzAJBgNVBAYTAlVTMRMwEQYD\nVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQK\nEwRvcmcxMRMwEQYDVQQDEwp0bHNjYS5vcmcxMFkwEwYHKoZIzj0CAQYIKoZIzj0D\nAQcDQgAEVzX85nYUlr/Kc8kWYcdr2L4ICp1GURWDgG0oZd9X6ATZUj2yghcTk6hh\nKvawyyfVuH95S3johA3WZzzRW537FaNtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1Ud\nJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1Ud\nDgQiBCDkk8d226n5IMJh9RwUaanA3lDDErXkSXT9uTUhA++3lDAKBggqhkjOPQQD\nAgNHADBEAiBx7YneCm31nYCo8kk7LD1gLbMeW//ItePlwLjYtowGcwIgPdjuHCOX\nH+U/87Z4PvNbNdoDi4a22Bg8BPIPRISxYjU=\n-----END CERTIFICATE-----\n\n" }, "url": "grpcs://localhost:31000", "grpcOptions": { diff --git a/app/platform/fabric/e2e-test/configs/connection-profile/org1-network.json b/app/platform/fabric/e2e-test/configs/connection-profile/org1-network.json index 07065f2ee..76ff80c6f 100644 --- a/app/platform/fabric/e2e-test/configs/connection-profile/org1-network.json +++ b/app/platform/fabric/e2e-test/configs/connection-profile/org1-network.json @@ -14,7 +14,7 @@ "password": "exploreradminpw", "affiliation": "org1.department1" }, - "enableAuthentication": false, + "enableAuthentication": true, "organization": "org1", "connection": { "timeout": { diff --git a/app/platform/fabric/e2e-test/configs/connection-profile/org2-network.json b/app/platform/fabric/e2e-test/configs/connection-profile/org2-network.json index 196b0d4de..8776b4d54 100644 --- a/app/platform/fabric/e2e-test/configs/connection-profile/org2-network.json +++ b/app/platform/fabric/e2e-test/configs/connection-profile/org2-network.json @@ -14,7 +14,7 @@ "affiliation": "org2.department1" }, "organization": "org2", - "enableAuthentication": false, + "enableAuthentication": true, "connection": { "timeout": { "peer": { diff --git a/app/platform/fabric/e2e-test/specs/apitest_test.go b/app/platform/fabric/e2e-test/specs/apitest_test.go index a2422ca4b..e0fbcb2ce 100644 --- a/app/platform/fabric/e2e-test/specs/apitest_test.go +++ b/app/platform/fabric/e2e-test/specs/apitest_test.go @@ -35,7 +35,7 @@ const ( waitSyncInterval = 7 ) -func basicCheck() { +func basicCheck(loginId string) { It("get network list", func() { @@ -52,12 +52,23 @@ func basicCheck() { It("login to org1-network", func() { - resp := restPost("/auth/login", map[string]interface{}{"user": "exploreradmin", "password": "exploreradminpw", "network": "org1-network"}, &LoginResponse{}) + resp := restPost("/auth/login", map[string]interface{}{"user": loginId, "password": "exploreradminpw", "network": "org1-network"}, &LoginResponse{}) result := resp.Result().(*LoginResponse) token = result.Token + Expect(resp.StatusCode()).Should(Equal(200)) + Expect(result.Success).Should(Equal(true)) Expect(result.User.Message).Should(Equal("logged in")) - Expect(result.User.Name).Should(Equal("exploreradmin")) + Expect(result.User.Name).Should(Equal(loginId)) + }) + + It("fail to login with invalid credential", func() { + + resp := restPost("/auth/login", map[string]interface{}{"user": loginId, "password": "invalid", "network": "org1-network"}, &LoginResponse{}) + result := resp.Result().(*LoginResponse) + + Expect(resp.StatusCode()).Should(Equal(400)) + Expect(result.Success).Should(Equal(false)) }) It("get channels", func() { @@ -169,7 +180,7 @@ var _ = Describe("REST API Test Suite - Single profile", func() { os.RemoveAll("./logs") os.Chdir(cwd) - cmd := exec.Command("./runexplorer.sh", "single") + cmd := exec.Command("bash", "./runexplorer.sh", "-m", "single") err := cmd.Start() Expect(err).NotTo(HaveOccurred()) Eventually(isExplorerReady, 60, 5).Should(Equal(true)) @@ -177,7 +188,7 @@ var _ = Describe("REST API Test Suite - Single profile", func() { time.Sleep(waitSyncInterval * time.Second) }) - basicCheck() + basicCheck("exploreradmin") XIt("register user", func() { resp := restPostWithToken("/api/register", map[string]interface{}{"user": "test", "password": "test", "affiliation": "department2", "role": "admin"}, &RegisterResp{}, token) @@ -201,7 +212,7 @@ var _ = Describe("REST API Test Suite - Single profile", func() { }) It("stop explorer", func() { - _, err := networkclient.ExecuteCommand("./stopexplorer.sh", []string{}, true) + _, err := networkclient.ExecuteCommand("bash", []string{"./stopexplorer.sh"}, true) Expect(err).NotTo(HaveOccurred()) }) @@ -211,7 +222,28 @@ var _ = Describe("REST API Test Suite - Single profile", func() { os.RemoveAll("./logs") os.Chdir(cwd) - cmd := exec.Command("./runexplorer.sh", "single-pem") + cmd := exec.Command("bash", "./runexplorer.sh", "-m", "single-pem") + err := cmd.Start() + Expect(err).NotTo(HaveOccurred()) + Eventually(isExplorerReady, 60, 5).Should(Equal(true)) + + time.Sleep(waitSyncInterval * time.Second) + }) + + basicCheck("exploreradmin2") + + It("stop explorer, but persist data and wallet", func() { + _, err := networkclient.ExecuteCommand("bash", []string{"./stopexplorer.sh", "-k"}, true) + Expect(err).NotTo(HaveOccurred()) + }) + + It("restart explorer", func() { + cwd, _ := os.Getwd() + os.Chdir(relativePahtToRoot) + os.RemoveAll("./logs") + os.Chdir(cwd) + + cmd := exec.Command("bash", "./runexplorer.sh", "-m", "single-pem", "-k") err := cmd.Start() Expect(err).NotTo(HaveOccurred()) Eventually(isExplorerReady, 60, 5).Should(Equal(true)) @@ -219,7 +251,7 @@ var _ = Describe("REST API Test Suite - Single profile", func() { time.Sleep(waitSyncInterval * time.Second) }) - basicCheck() + basicCheck("exploreradmin2") Describe("Bugfix check:", func() { @@ -277,7 +309,35 @@ var _ = Describe("REST API Test Suite - Single profile", func() { }) It("stop explorer", func() { - _, err := networkclient.ExecuteCommand("./stopexplorer.sh", []string{}, true) + _, err := networkclient.ExecuteCommand("bash", []string{"./stopexplorer.sh"}, true) + Expect(err).NotTo(HaveOccurred()) + }) + + It("launch explorer - disable authentication", func() { + cwd, _ := os.Getwd() + os.Chdir(relativePahtToRoot) + os.RemoveAll("./logs") + os.Chdir(cwd) + + cmd := exec.Command("bash", "./runexplorer.sh", "-m", "single-disable-auth") + err := cmd.Start() + Expect(err).NotTo(HaveOccurred()) + Eventually(isExplorerReady, 60, 5).Should(Equal(true)) + + time.Sleep(waitSyncInterval * time.Second) + }) + + It("succeed to login with invalid credential", func() { + + resp := restPost("/auth/login", map[string]interface{}{"user": "invalid", "password": "invalid", "network": "org1-network"}, &LoginResponse{}) + result := resp.Result().(*LoginResponse) + + Expect(resp.StatusCode()).Should(Equal(200)) + Expect(result.Success).Should(Equal(true)) + }) + + It("stop explorer", func() { + _, err := networkclient.ExecuteCommand("bash", []string{"./stopexplorer.sh"}, true) Expect(err).NotTo(HaveOccurred()) }) @@ -326,7 +386,7 @@ var _ = Describe("REST API Test Suite - Multiple profile", func() { inputSpecPath = "apitest-input-multiprofile.yml" By("0) Generating channel artifacts") - _, err := networkclient.ExecuteCommand("./genchannelartifacts.sh", []string{}, true) + _, err := networkclient.ExecuteCommand("bash", []string{"./genchannelartifacts.sh"}, true) Expect(err).NotTo(HaveOccurred()) By("1) Creating channel") @@ -369,7 +429,7 @@ var _ = Describe("REST API Test Suite - Multiple profile", func() { os.RemoveAll("./logs") os.Chdir(cwd) - cmd := exec.Command("./runexplorer.sh", "multi") + cmd := exec.Command("bash", "./runexplorer.sh", "-m", "multi") err := cmd.Start() Expect(err).NotTo(HaveOccurred()) Eventually(isExplorerReady, 60, 5).Should(Equal(true)) @@ -695,7 +755,7 @@ var _ = Describe("REST API Test Suite - Multiple profile", func() { // }) It("stop explorer", func() { - _, err := networkclient.ExecuteCommand("./stopexplorer.sh", []string{}, true) + _, err := networkclient.ExecuteCommand("bash", []string{"./stopexplorer.sh"}, true) Expect(err).NotTo(HaveOccurred()) }) diff --git a/app/platform/fabric/e2e-test/specs/runexplorer.sh b/app/platform/fabric/e2e-test/specs/runexplorer.sh index 3c96b64c1..856231f57 100755 --- a/app/platform/fabric/e2e-test/specs/runexplorer.sh +++ b/app/platform/fabric/e2e-test/specs/runexplorer.sh @@ -4,13 +4,21 @@ SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" ROOTPATH="$( cd "$(dirname "$0")/../../../../.." >/dev/null 2>&1 ; pwd -P )" -export NETWORK_MODE=$1 - -pushd ${ROOTPATH} -# At first, need to clean up logs as test app is monitoring logs/console to detect completion of explorer setup -rm -rf logs wallet -popd - +CLEANUP=1 + +while getopts "km:" opt; do + case "$opt" in + k) + echo "keep DB data and wallet" + CLEANUP=0 + ;; + m) + NETWORK_MODE=$OPTARG + export NETWORK_MODE=$NETWORK_MODE + echo "Network mode : ${NETWORK_MODE}" + ;; + esac +done echo $SCRIPTPATH echo $ROOTPATH @@ -50,25 +58,27 @@ popd pushd ${ROOTPATH} -./build_docker_image.sh -d -docker-compose -f ./app/platform/fabric/e2e-test/docker-compose.yaml down -v -docker-compose -f ./app/platform/fabric/e2e-test/docker-compose.yaml up -d explorerdb.mynetwork.com -echo "#### Starting DB container ..." - -rc=1 -starttime=$(date +%s) -while - [[ "$(($(date +%s) - starttime))" -lt "$TIMEOUT" ]] && [[ $rc -ne 0 ]]; -do - sleep $DELAY - set -x - docker logs explorerdb.mynetwork.com 2>/dev/null | grep -q "database system is ready to accept connections" - rc=$? - set +x -done -echo "#### Started DB container" - -rm -rf logs wallet +if [ $CLEANUP -eq 1 ]; then + ./build_docker_image.sh -d + docker-compose -f ./app/platform/fabric/e2e-test/docker-compose.yaml down -v + docker-compose -f ./app/platform/fabric/e2e-test/docker-compose.yaml up -d explorerdb.mynetwork.com + echo "#### Starting DB container ..." + + rc=1 + starttime=$(date +%s) + while + [[ "$(($(date +%s) - starttime))" -lt "$TIMEOUT" ]] && [[ $rc -ne 0 ]]; + do + sleep $DELAY + set -x + docker logs explorerdb.mynetwork.com 2>/dev/null | grep -q "database system is ready to accept connections" + rc=$? + set +x + done + echo "#### Started DB container" + + rm -rf logs wallet +fi # export LOG_LEVEL_CONSOLE=debug export EXPLORER_SYNC_BLOCKSYNCTIME_SEC=5 diff --git a/app/platform/fabric/e2e-test/specs/stopexplorer.sh b/app/platform/fabric/e2e-test/specs/stopexplorer.sh index eb60bf251..7992ea5c7 100755 --- a/app/platform/fabric/e2e-test/specs/stopexplorer.sh +++ b/app/platform/fabric/e2e-test/specs/stopexplorer.sh @@ -4,11 +4,23 @@ SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" ROOTPATH="$( cd "$(dirname "$0")/../../../../.." >/dev/null 2>&1 ; pwd -P )" +CLEANUP=1 + +while getopts "k" opt; do + case "$opt" in + k) + echo "keep DB data and wallet" + CLEANUP=0 + ;; + esac +done pushd ${ROOTPATH} ./stop.sh -docker-compose -f ./app/platform/fabric/e2e-test/docker-compose.yaml down -v -rm -rf wallet/ logs/ +if [ $CLEANUP -eq 1 ]; then + docker-compose -f ./app/platform/fabric/e2e-test/docker-compose.yaml down -v + rm -rf wallet/ logs/ +fi popd \ No newline at end of file diff --git a/app/platform/fabric/gateway/FabricGateway.js b/app/platform/fabric/gateway/FabricGateway.js index f31593210..c34394403 100644 --- a/app/platform/fabric/gateway/FabricGateway.js +++ b/app/platform/fabric/gateway/FabricGateway.js @@ -31,8 +31,6 @@ class FabricGateway { this.wallet = null; this.tlsEnable = false; this.defaultChannelName = null; - this.defaultPeer = null; - this.defaultPeerUrl = null; this.gateway = new Gateway(); this.fabricConfig = new FabricConfig(); this.fabricCaEnabled = false; @@ -55,18 +53,15 @@ class FabricGateway { this.FSWALLET = 'wallet/' + this.networkName; const explorerAdminId = this.fabricConfig.getAdminUser(); + if (!explorerAdminId) { + logger.error('Failed to get admin ID from configuration file'); + throw new ExplorerError(explorer_mess.error.ERROR_1010); + } + const info = `Loading configuration ${this.config}`; logger.debug(info.toUpperCase()); - const peers = this.fabricConfig.getPeers(); - this.defaultPeer = peers[0].name; - this.defaultPeerUrl = peers[0].url; - - logger.info('========== > defaultPeer ', this.defaultPeer); - /* eslint-disable */ - this.defaultChannelName = this.fabricConfig.getDefaultChannel(); - /* eslint-enable */ let identity; try { // Create a new file system based wallet for managing identities. @@ -174,7 +169,7 @@ class FabricGateway { mspId: this.fabricConfig.getMspId(), type: 'X.509' }; - logger.log('enrollUserIdentity: userName :', userName); + logger.info('enrollUserIdentity: userName :', userName); await this.wallet.put(userName, identity); return identity; } diff --git a/app/platform/fabric/models/User.js b/app/platform/fabric/models/User.js index e4b1822ca..ba9f7edba 100644 --- a/app/platform/fabric/models/User.js +++ b/app/platform/fabric/models/User.js @@ -4,7 +4,7 @@ const helper = require('../../../common/helper'); -const logger = helper.getLogger('FabricGateway'); +const logger = helper.getLogger('User'); /** * @@ -20,10 +20,10 @@ class User { constructor(user) { // Put the user request in user object this.userJson = {}; + logger.debug(`User : ${user.user}`); Object.keys(user).forEach(key => { const value = user[key]; this.userJson[key] = value; - logger.log('User.constructor ', key, '= ', value); }); } diff --git a/app/platform/fabric/service/UserService.js b/app/platform/fabric/service/UserService.js index 4b0fb5d9a..d1b4f509e 100644 --- a/app/platform/fabric/service/UserService.js +++ b/app/platform/fabric/service/UserService.js @@ -45,17 +45,40 @@ class UserService { let adminUser = null; let adminPassword = null; if (user.user && user.password && user.network) { - logger.log('user.network ', user.network); + logger.info('user.network ', user.network); const clientObj = this.platform.getNetworks().get(user.network); - // TODO, need review maybe there is a better way to get the client config enableAuthentication + if (!clientObj) { + const errMsg = `Faied to get client object for ${user.network}`; + logger.error(errMsg); + return { + authenticated: false, + user: user.user, + message: `Internal error: ${errMsg}`, + enableAuthentication: enableAuth, + network: user.network + }; + } + let client = clientObj.instance; - if (client.config && client.config.client) { - enableAuth = client.config.client.enableAuthentication; - if (typeof enableAuth !== 'undefined' && enableAuth !== null) { - logger.info(`Network: ${user.network} enableAuthentication ${enableAuth}`); - adminUser = client.config.client.adminUser; - adminPassword = client.config.client.adminPassword; + const fabricConfig = client.fabricGateway.fabricConfig; + enableAuth = fabricConfig.getEnableAuthentication(); + if (enableAuth) { + logger.info(`Network: ${user.network} enableAuthentication ${enableAuth}`); + adminUser = fabricConfig.getAdminUser(); + adminPassword = fabricConfig.getAdminPassword(); + + // Not authorized if credentials are incomplete in auth enabled mode + if (!adminUser || !adminPassword) { + const errMsg = `Faied authentication for ${user.network}`; + logger.error(errMsg); + return { + authenticated: false, + user: user.user, + message: `Internal error: ${errMsg}`, + enableAuthentication: enableAuth, + network: user.network + }; } } @@ -82,15 +105,17 @@ class UserService { authenticated: false, user: user.user, message: 'Invalid user name, or password', - enableAuthentication: enableAuth + enableAuthentication: enableAuth, + network: user.network }; } } else { return { authenticated: false, - message: 'Invalid request, found ', user: user.user, - enableAuthentication: enableAuth + message: 'Invalid request', + enableAuthentication: enableAuth, + network: user.network }; } } diff --git a/app/rest/authroutes.js b/app/rest/authroutes.js index 42e63aa65..e4f0112e5 100644 --- a/app/rest/authroutes.js +++ b/app/rest/authroutes.js @@ -54,8 +54,7 @@ const authroutes = async function(router, platform) { message: 'Could not process the form.' }); } - return res.json({ - status: 200, + return res.status(200).json({ success: true, message: 'You have successfully logged in!', token, diff --git a/start.sh b/start.sh index c0210f00e..68b12ee11 100755 --- a/start.sh +++ b/start.sh @@ -8,8 +8,6 @@ #Please visit ./logs/app to view the application logs and visit the ./logs/db to view the Database logs and visit the ./log/console for the console.log # Log rotating for every 7 days. -rm -rf /tmp/fabric-client-kvs_peerOrg* - echo "************************************************************************************" echo "**************************** Hyperledger Explorer **********************************" echo "************************************************************************************"