Skip to content

Commit

Permalink
[FABG-889] add CreateConfigSignatureFromReader method
Browse files Browse the repository at this point in the history
Purpose of this commit is to add method to sign a config
which is passed as io.Reader, not file path.

 - Added CreateConfigSignatureFromReader method
 - Added CreateConfigSignatureDataFromReader method
 - Made deprecated CreateConfigSignature, CreateConfigSignatureData
 - Fixed tests, old methods replaced

Signed-off-by: kopaygorodsky <vlad.kopaygorodsky@gmail.com>
Change-Id: I7eaea1e2835b7e0ef5fcf8b529f6076d1f34c454
  • Loading branch information
kopaygorodsky committed Aug 8, 2019
1 parent 5679961 commit bf5e77c
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 36 deletions.
64 changes: 41 additions & 23 deletions pkg/client/resmgmt/resmgmt.go
Expand Up @@ -999,24 +999,6 @@ func (rc *Client) getConfigSignatures(req SaveChannelRequest, chConfig []byte) (
return rc.createCfgSigFromIDs(chConfig, signers...)
}

func readChConfigData(channelConfigPath string) ([]byte, error) {
if channelConfigPath == "" {
return nil, errors.New("must provide a channel config path")
}

configReader, err := os.Open(channelConfigPath) // nolint
if err != nil {
return nil, errors.Wrapf(err, "opening channel config file failed")
}
defer loggedClose(configReader)

chConfig, err := extractChConfigData(configReader)
if err != nil {
return nil, errors.WithMessage(err, "extracting channel config from channel config reader of channelConfigPath failed")
}
return chConfig, nil
}

func extractChConfigData(channelConfigReader io.Reader) ([]byte, error) {
if channelConfigReader == nil {
return nil, errors.New("must provide a non empty channel config file")
Expand All @@ -1036,10 +1018,27 @@ func extractChConfigData(channelConfigReader io.Reader) ([]byte, error) {

// CreateConfigSignature creates a signature for the given client, custom signers and chConfig from channelConfigPath argument
// return ConfigSignature will be signed internally by the SDK. It can be passed to WithConfigSignatures() option
// Deprecated: this method is deprecated in order to use CreateConfigSignatureFromReader
func (rc *Client) CreateConfigSignature(signer msp.SigningIdentity, channelConfigPath string) (*common.ConfigSignature, error) {
chConfig, err := readChConfigData(channelConfigPath)
if channelConfigPath == "" {
return nil, errors.New("must provide a channel config path")
}

configReader, err := os.Open(channelConfigPath) //nolint
if err != nil {
return nil, err
return nil, errors.Wrapf(err, "opening channel config file failed")
}
defer loggedClose(configReader)

return rc.CreateConfigSignatureFromReader(signer, configReader)
}

// CreateConfigSignatureFromReader creates a signature for the given client, custom signers and chConfig from io.Reader argument
// return ConfigSignature will be signed internally by the SDK. It can be passed to WithConfigSignatures() option
func (rc *Client) CreateConfigSignatureFromReader(signer msp.SigningIdentity, channelConfig io.Reader) (*common.ConfigSignature, error) {
chConfig, err := extractChConfigData(channelConfig)
if err != nil {
return nil, errors.WithMessage(err, "extracting channel config failed")
}

sigs, err := rc.createCfgSigFromIDs(chConfig, signer)
Expand All @@ -1055,17 +1054,36 @@ func (rc *Client) CreateConfigSignature(signer msp.SigningIdentity, channelConfi
}

// CreateConfigSignatureData will prepare a SignatureHeader and the full signing []byte (signingBytes) to be used for signing a Channel Config
// Deprecated: this method is deprecated in order to use CreateConfigSignatureDataFromReader
func (rc *Client) CreateConfigSignatureData(signer msp.SigningIdentity, channelConfigPath string) (signatureHeaderData resource.ConfigSignatureData, e error) {
if channelConfigPath == "" {
e = errors.New("must provide a channel config path")
return
}

configReader, err := os.Open(channelConfigPath) //nolint
if err != nil {
e = errors.Wrapf(err, "opening channel config file failed")
return
}
defer loggedClose(configReader)

return rc.CreateConfigSignatureDataFromReader(signer, configReader)
}

// CreateConfigSignatureDataFromReader will prepare a SignatureHeader and the full signing []byte (signingBytes) to be used for signing a Channel Config
// Once SigningBytes have been signed externally (signing signatureHeaderData.SigningBytes using an external tool like OpenSSL), do the following:
// 1. create a common.ConfigSignature{} instance
// 2. assign its SignatureHeader field with the returned field 'signatureHeaderData.signatureHeader'
// 3. assign its Signature field with the generated signature of 'signatureHeaderData.signingBytes' from the external tool
// Then use WithConfigSignatures() option to pass this new instance for channel updates
func (rc *Client) CreateConfigSignatureData(signer msp.SigningIdentity, channelConfigPath string) (signatureHeaderData resource.ConfigSignatureData, e error) {
chConfig, err := readChConfigData(channelConfigPath)
func (rc *Client) CreateConfigSignatureDataFromReader(signer msp.SigningIdentity, channelConfig io.Reader) (signatureHeaderData resource.ConfigSignatureData, e error) {
chConfig, err := extractChConfigData(channelConfig)
if err != nil {
e = err
e = errors.WithMessage(err, "extracting channel config failed")
return
}

sigCtx := contextImpl.Client{
SigningIdentity: signer,
Providers: rc.ctx,
Expand Down
51 changes: 40 additions & 11 deletions pkg/client/resmgmt/resmgmt_test.go
Expand Up @@ -8,7 +8,9 @@ package resmgmt

import (
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
Expand Down Expand Up @@ -1237,6 +1239,8 @@ func TestSaveChannelWithSignatureOpt(t *testing.T) {

ctx := setupTestContext("test", "Org1MSP")
channelConfigPath := filepath.Join(metadata.GetProjectPath(), metadata.ChannelConfigPath, channelConfigFile)
configReader, err := getConfigReader(channelConfigPath)
assert.NoError(t, err, "Failed to create reader for the config %s", channelConfigPath)

mockConfig := &fcmocks.MockConfig{}
grpcOpts := make(map[string]interface{})
Expand All @@ -1260,7 +1264,7 @@ func TestSaveChannelWithSignatureOpt(t *testing.T) {
req := SaveChannelRequest{ChannelID: "mychannel", ChannelConfig: r1}

// get a valid signature for user "test" and mspID "Org1MSP"
signature, err := cc.CreateConfigSignature(ctx.SigningIdentity, channelConfigPath)
signature, err := cc.CreateConfigSignatureFromReader(ctx.SigningIdentity, configReader)
assert.NoError(t, err, "Failed to get channel config signature")

opts := WithConfigSignatures(signature)
Expand All @@ -1272,16 +1276,16 @@ func TestSaveChannelWithSignatureOpt(t *testing.T) {
user2Msp1 := mspmocks.NewMockSigningIdentity("user2", "Org1MSP")
user1Msp2 := mspmocks.NewMockSigningIdentity("user1", "Org2MSP")
user2Msp2 := mspmocks.NewMockSigningIdentity("user2", "Org2MSP")
signature, err = cc.CreateConfigSignature(user1Msp1, channelConfigPath)
signature, err = cc.CreateConfigSignatureFromReader(user1Msp1, configReader)
assert.NoError(t, err, "Failed to get channel config signature")
signatures := []*common.ConfigSignature{signature}
signature, err = cc.CreateConfigSignature(user2Msp1, channelConfigPath)
signature, err = cc.CreateConfigSignatureFromReader(user2Msp1, configReader)
assert.NoError(t, err, "Failed to get channel config signature")
signatures = append(signatures, signature)
signature, err = cc.CreateConfigSignature(user1Msp2, channelConfigPath)
signature, err = cc.CreateConfigSignatureFromReader(user1Msp2, configReader)
assert.NoError(t, err, "Failed to get channel config signature")
signatures = append(signatures, signature)
signature, err = cc.CreateConfigSignature(user2Msp2, channelConfigPath)
signature, err = cc.CreateConfigSignatureFromReader(user2Msp2, configReader)
assert.NoError(t, err, "Failed to get channel config signature")
signatures = append(signatures, signature)

Expand Down Expand Up @@ -1396,18 +1400,38 @@ func importSignature(t *testing.T, dir, prefix string) (RequestOption, *os.File)
return opt, file
}

func getConfigReader(configPath string) (io.Reader, error) {
fileConfigReader, err := os.Open(configPath)
if err != nil {
return nil, errors.Wrapf(err, "opening channel config file failed")
}

defer fileConfigReader.Close()

config, err := ioutil.ReadAll(fileConfigReader)

if err != nil {
return nil, errors.WithStack(err)
}

return bytes.NewReader(config), nil
}

func createOrgIDsAndExportSignatures(t *testing.T, fabCtx *fcmocks.MockContext, cc *Client, org, dir string) {
user1Msp1 := mspmocks.NewMockSigningIdentity("user1", org)
user2Msp1 := mspmocks.NewMockSigningIdentity("user2", org)
channelConfigPath := filepath.Join(metadata.GetProjectPath(), metadata.ChannelConfigPath, channelConfigFile)

sig, err := cc.CreateConfigSignature(fabCtx.SigningIdentity, channelConfigPath)
configReader, err := getConfigReader(channelConfigPath)
assert.NoError(t, err, "Failed to create reader for the config %s", channelConfigPath)

sig, err := cc.CreateConfigSignatureFromReader(fabCtx.SigningIdentity, configReader)
assert.NoError(t, err, "Failed to create config signature for default user of %s", org)
exportCfgSignature(t, sig, dir, fmt.Sprintf("signature1_%s", org))
sig, err = cc.CreateConfigSignature(user1Msp1, channelConfigPath)
sig, err = cc.CreateConfigSignatureFromReader(user1Msp1, configReader)
assert.NoError(t, err, "Failed to create config signature for user1 of %s", org)
exportCfgSignature(t, sig, dir, fmt.Sprintf("signature2_%s", org))
sig, err = cc.CreateConfigSignature(user2Msp1, channelConfigPath)
sig, err = cc.CreateConfigSignatureFromReader(user2Msp1, configReader)
assert.NoError(t, err, "Failed to create config signature for user2 of %s", org)
exportCfgSignature(t, sig, dir, fmt.Sprintf("signature3_%s", org))
}
Expand Down Expand Up @@ -1435,8 +1459,10 @@ func TestMarshalUnMarshalCfgSignatures(t *testing.T) {
ctx := setupTestContext("test", "Org1MSP")
cc := setupResMgmtClient(t, ctx)
channelConfigPath := filepath.Join(metadata.GetProjectPath(), metadata.ChannelConfigPath, channelConfigFile)
configReader, err := getConfigReader(channelConfigPath)
assert.NoError(t, err, "Failed to create reader for the config %s", channelConfigPath)

sig, err := cc.CreateConfigSignature(ctx.SigningIdentity, channelConfigPath)
sig, err := cc.CreateConfigSignatureFromReader(ctx.SigningIdentity, configReader)
assert.NoError(t, err, "failed to create Msp1 ConfigSignature")
mSig, err := MarshalConfigSignature(sig)
assert.NoError(t, err, "failed to marshal Msp1 ConfigSignature")
Expand Down Expand Up @@ -1465,7 +1491,7 @@ func TestMarshalUnMarshalCfgSignatures(t *testing.T) {
assert.EqualValues(t, b.SignatureHeader, sig.SignatureHeader, "Marshaled signature did not match the one build from the unmarshaled copy")

// test prep call for external signature signing
cfd, e := cc.CreateConfigSignatureData(ctx.SigningIdentity, channelConfigPath)
cfd, e := cc.CreateConfigSignatureDataFromReader(ctx.SigningIdentity, configReader)
assert.NoError(t, e, "getting config info for external signing failed")
assert.NotEmpty(t, cfd.SignatureHeader, "getting signing header is not supposed to be empty")
assert.NotEmpty(t, cfd.SigningBytes, "getting signing bytes is not supposed to be empty")
Expand Down Expand Up @@ -1530,7 +1556,10 @@ func TestGetConfigSignaturesFromIdentities(t *testing.T) {
cc := setupResMgmtClient(t, ctx)
channelConfigPath := filepath.Join(metadata.GetProjectPath(), metadata.ChannelConfigPath, channelConfigFile)

signature, err := cc.CreateConfigSignature(ctx.SigningIdentity, channelConfigPath)
configReader, err := getConfigReader(channelConfigPath)
assert.NoError(t, err, "Failed to create reader for the config %s", channelConfigPath)

signature, err := cc.CreateConfigSignatureFromReader(ctx.SigningIdentity, configReader)
assert.NoError(t, err, "CreateSignaturesFromCfgPath failed")
//t.Logf("Signature: %s", signature)
assert.NotNil(t, signature, "signatures must not be empty")
Expand Down
19 changes: 17 additions & 2 deletions test/integration/e2e/orgs/multi_orgs_ch_update_signatures_test.go
Expand Up @@ -231,7 +231,14 @@ func createSignatureFromSDK(t *testing.T, dsCtx *dsClientCtx, chConfigPath strin
usr, err := mspClient.GetSigningIdentity(user)
require.NoError(t, err, "error creating a new SigningIdentity for %s", dsCtx.org)

signature, err := dsCtx.rsCl.CreateConfigSignature(usr, chConfigPath)
chConfigReader, err := os.Open(chConfigPath)
require.NoError(t, err, "failed to create reader for the config %s", chConfigPath)
defer func() {
err = chConfigReader.Close()
require.NoError(t, err, "failed to close chConfig file %s", chConfigPath)
}()

signature, err := dsCtx.rsCl.CreateConfigSignatureFromReader(usr, chConfigReader)
require.NoError(t, err, "error creating a new ConfigSignature for %s", org1)

return signature
Expand Down Expand Up @@ -407,7 +414,15 @@ func generateChConfigData(t *testing.T, dsCtx *dsClientCtx, chConfigPath, user,
u, err := mspClient.GetSigningIdentity(user)
require.NoError(t, err, "error creating a new SigningIdentity for %s", dsCtx.org)

d, err := dsCtx.rsCl.CreateConfigSignatureData(u, chConfigPath)
chConfigReader, err := os.Open(chConfigPath)
assert.NoError(t, err, "Failed to create reader for the config %s", chConfigPath)

defer func() {
err = chConfigReader.Close()
require.NoError(t, err, "Failed to close chConfig file")
}()

d, err := dsCtx.rsCl.CreateConfigSignatureDataFromReader(u, chConfigReader)
require.NoError(t, err, "Failed to fetch Channel config data for signing")

chCfgName := getBaseChCfgFileName(chConfigPath)
Expand Down
1 change: 1 addition & 0 deletions test/performance/go.mod
Expand Up @@ -11,6 +11,7 @@ replace github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/
require (
github.com/golang/protobuf v1.2.0
github.com/hyperledger/fabric-sdk-go v0.0.0-00010101000000-000000000000
github.com/hyperledger/fabric-sdk-go/test/integration v0.0.0-20190805170536-5679961428c2 // indirect
github.com/hyperledger/fabric-sdk-go/third_party/github.com/hyperledger/fabric v0.0.0-20190524192706-bfae339c63bf
github.com/pkg/errors v0.8.1
github.com/stretchr/testify v1.3.0
Expand Down
2 changes: 2 additions & 0 deletions test/performance/go.sum
Expand Up @@ -38,6 +38,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hyperledger/fabric-lib-go v1.0.0 h1:UL1w7c9LvHZUSkIvHTDGklxFv2kTeva1QI2emOVc324=
github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc=
github.com/hyperledger/fabric-sdk-go/test/integration v0.0.0-20190805170536-5679961428c2 h1:QIiOb5fuX0dWODo4fA9yriRXfr+FQzbRN98Y7Mq+Jfs=
github.com/hyperledger/fabric-sdk-go/test/integration v0.0.0-20190805170536-5679961428c2/go.mod h1:B7IeeRQ6Gk7zQ+DJ0OVZ3XrnnHvzvAwWGwNlVhW3DLE=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
Expand Down

0 comments on commit bf5e77c

Please sign in to comment.