From bf5e77cb15bf123d8994d342f7d876f87bf6a9b3 Mon Sep 17 00:00:00 2001 From: kopaygorodsky Date: Wed, 7 Aug 2019 00:03:04 +0300 Subject: [PATCH] [FABG-889] add CreateConfigSignatureFromReader method 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 Change-Id: I7eaea1e2835b7e0ef5fcf8b529f6076d1f34c454 --- pkg/client/resmgmt/resmgmt.go | 64 ++++++++++++------- pkg/client/resmgmt/resmgmt_test.go | 51 +++++++++++---- .../multi_orgs_ch_update_signatures_test.go | 19 +++++- test/performance/go.mod | 1 + test/performance/go.sum | 2 + 5 files changed, 101 insertions(+), 36 deletions(-) diff --git a/pkg/client/resmgmt/resmgmt.go b/pkg/client/resmgmt/resmgmt.go index 814d39ca01..7463764069 100644 --- a/pkg/client/resmgmt/resmgmt.go +++ b/pkg/client/resmgmt/resmgmt.go @@ -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") @@ -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) @@ -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, diff --git a/pkg/client/resmgmt/resmgmt_test.go b/pkg/client/resmgmt/resmgmt_test.go index de2f0f8846..c0179a15a8 100644 --- a/pkg/client/resmgmt/resmgmt_test.go +++ b/pkg/client/resmgmt/resmgmt_test.go @@ -8,7 +8,9 @@ package resmgmt import ( "bufio" + "bytes" "fmt" + "io" "io/ioutil" "net/http" "os" @@ -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{}) @@ -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) @@ -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) @@ -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)) } @@ -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") @@ -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") @@ -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") diff --git a/test/integration/e2e/orgs/multi_orgs_ch_update_signatures_test.go b/test/integration/e2e/orgs/multi_orgs_ch_update_signatures_test.go index a831d31bf6..0ef4aba697 100644 --- a/test/integration/e2e/orgs/multi_orgs_ch_update_signatures_test.go +++ b/test/integration/e2e/orgs/multi_orgs_ch_update_signatures_test.go @@ -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 @@ -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) diff --git a/test/performance/go.mod b/test/performance/go.mod index 2b7e29769b..6aa6cc63c6 100644 --- a/test/performance/go.mod +++ b/test/performance/go.mod @@ -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 diff --git a/test/performance/go.sum b/test/performance/go.sum index cd62c42db6..9c6101f077 100644 --- a/test/performance/go.sum +++ b/test/performance/go.sum @@ -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=