Skip to content

Commit

Permalink
BE-777 Fix an issue of authentication (#140)
Browse files Browse the repository at this point in the history
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 <atsushin@fast.au.fujitsu.com>
  • Loading branch information
nekia authored Jul 14, 2020
1 parent 39ad972 commit d99a66d
Show file tree
Hide file tree
Showing 17 changed files with 286 additions and 99 deletions.
54 changes: 40 additions & 14 deletions README-CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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"
Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion app/passport/local-login.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion app/platform/fabric/FabricClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 2 additions & 8 deletions app/platform/fabric/Proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
"client": {
"tlsEnable": true,
"adminCredential": {
"id": "exploreradmin",
"id": "exploreradmin2",
"password": "exploreradminpw"
},
"enableAuthentication": false,
"enableAuthentication": true,
"organization": "org1",
"connection": {
"timeout": {
Expand Down Expand Up @@ -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": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"password": "exploreradminpw",
"affiliation": "org1.department1"
},
"enableAuthentication": false,
"enableAuthentication": true,
"organization": "org1",
"connection": {
"timeout": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"affiliation": "org2.department1"
},
"organization": "org2",
"enableAuthentication": false,
"enableAuthentication": true,
"connection": {
"timeout": {
"peer": {
Expand Down
84 changes: 72 additions & 12 deletions app/platform/fabric/e2e-test/specs/apitest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const (
waitSyncInterval = 7
)

func basicCheck() {
func basicCheck(loginId string) {

It("get network list", func() {

Expand All @@ -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() {
Expand Down Expand Up @@ -169,15 +180,15 @@ 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))

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)
Expand All @@ -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())
})

Expand All @@ -211,15 +222,36 @@ 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))

time.Sleep(waitSyncInterval * time.Second)
})

basicCheck()
basicCheck("exploreradmin2")

Describe("Bugfix check:", func() {

Expand Down Expand Up @@ -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())
})

Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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())
})

Expand Down
Loading

0 comments on commit d99a66d

Please sign in to comment.