github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/peer/pkg_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package peer_test
     8  
     9  import (
    10  	"context"
    11  	"crypto/tls"
    12  	"crypto/x509"
    13  	"errors"
    14  	"net"
    15  	"testing"
    16  	"time"
    17  
    18  	configtxtest "github.com/hechain20/hechain/common/configtx/test"
    19  	"github.com/hechain20/hechain/common/crypto/tlsgen"
    20  	"github.com/hechain20/hechain/core/ledger/mock"
    21  	"github.com/hechain20/hechain/core/peer"
    22  	"github.com/hechain20/hechain/internal/pkg/comm"
    23  	"github.com/hechain20/hechain/internal/pkg/comm/testpb"
    24  	"github.com/hechain20/hechain/internal/pkg/txflags"
    25  	"github.com/hechain20/hechain/msp"
    26  	"github.com/hechain20/hechain/protoutil"
    27  	cb "github.com/hyperledger/fabric-protos-go/common"
    28  	mspproto "github.com/hyperledger/fabric-protos-go/msp"
    29  	pb "github.com/hyperledger/fabric-protos-go/peer"
    30  	"github.com/stretchr/testify/require"
    31  	"google.golang.org/grpc"
    32  	"google.golang.org/grpc/credentials"
    33  )
    34  
    35  // test server to be registered with the GRPCServer
    36  type testServiceServer struct{}
    37  
    38  func (tss *testServiceServer) EmptyCall(context.Context, *testpb.Empty) (*testpb.Empty, error) {
    39  	return new(testpb.Empty), nil
    40  }
    41  
    42  // createCertPool creates an x509.CertPool from an array of PEM-encoded certificates
    43  func createCertPool(rootCAs [][]byte) (*x509.CertPool, error) {
    44  	certPool := x509.NewCertPool()
    45  	for _, rootCA := range rootCAs {
    46  		if !certPool.AppendCertsFromPEM(rootCA) {
    47  			return nil, errors.New("Failed to load root certificates")
    48  		}
    49  	}
    50  	return certPool, nil
    51  }
    52  
    53  // helper function to invoke the EmptyCall againt the test service
    54  func invokeEmptyCall(address string, dialOptions []grpc.DialOption) (*testpb.Empty, error) {
    55  	// add DialOptions
    56  	dialOptions = append(dialOptions, grpc.WithBlock())
    57  	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    58  	defer cancel()
    59  
    60  	// create GRPC client conn
    61  	clientConn, err := grpc.DialContext(ctx, address, dialOptions...)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	defer clientConn.Close()
    66  
    67  	// create GRPC client
    68  	client := testpb.NewTestServiceClient(clientConn)
    69  
    70  	// invoke service
    71  	empty, err := client.EmptyCall(context.Background(), new(testpb.Empty))
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	return empty, nil
    77  }
    78  
    79  // helper function to build an MSPConfig given root certs
    80  func createMSPConfig(mspID string, rootCerts, tlsRootCerts, tlsIntermediateCerts [][]byte) (*mspproto.MSPConfig, error) {
    81  	fmspconf := &mspproto.FabricMSPConfig{
    82  		RootCerts:            rootCerts,
    83  		TlsRootCerts:         tlsRootCerts,
    84  		TlsIntermediateCerts: tlsIntermediateCerts,
    85  		Name:                 mspID,
    86  		FabricNodeOus: &mspproto.FabricNodeOUs{
    87  			Enable: true,
    88  			ClientOuIdentifier: &mspproto.FabricOUIdentifier{
    89  				OrganizationalUnitIdentifier: "client",
    90  			},
    91  			PeerOuIdentifier: &mspproto.FabricOUIdentifier{
    92  				OrganizationalUnitIdentifier: "peer",
    93  			},
    94  			AdminOuIdentifier: &mspproto.FabricOUIdentifier{
    95  				OrganizationalUnitIdentifier: "admin",
    96  			},
    97  		},
    98  	}
    99  
   100  	return &mspproto.MSPConfig{
   101  		Config: protoutil.MarshalOrPanic(fmspconf),
   102  		Type:   int32(msp.FABRIC),
   103  	}, nil
   104  }
   105  
   106  func createConfigBlock(channelID string, appMSPConf, ordererMSPConf *mspproto.MSPConfig,
   107  	appOrgID, ordererOrgID string) (*cb.Block, error) {
   108  	block, err := configtxtest.MakeGenesisBlockFromMSPs(channelID, appMSPConf, ordererMSPConf, appOrgID, ordererOrgID)
   109  	if block == nil || err != nil {
   110  		return block, err
   111  	}
   112  
   113  	txsFilter := txflags.NewWithValues(len(block.Data.Data), pb.TxValidationCode_VALID)
   114  	block.Metadata.Metadata[cb.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
   115  
   116  	return block, nil
   117  }
   118  
   119  func TestUpdateRootsFromConfigBlock(t *testing.T) {
   120  	org1CA, err := tlsgen.NewCA()
   121  	require.NoError(t, err)
   122  	org1Server1KeyPair, err := org1CA.NewServerCertKeyPair("localhost", "127.0.0.1", "::1")
   123  	require.NoError(t, err)
   124  
   125  	org2CA, err := tlsgen.NewCA()
   126  	require.NoError(t, err)
   127  	org2Server1KeyPair, err := org2CA.NewServerCertKeyPair("localhost", "127.0.0.1", "::1")
   128  	require.NoError(t, err)
   129  
   130  	org2IntermediateCA, err := org2CA.NewIntermediateCA()
   131  	require.NoError(t, err)
   132  	org2IntermediateServer1KeyPair, err := org2IntermediateCA.NewServerCertKeyPair("localhost", "127.0.0.1", "::1")
   133  	require.NoError(t, err)
   134  
   135  	ordererOrgCA, err := tlsgen.NewCA()
   136  	require.NoError(t, err)
   137  	ordererOrgServer1KeyPair, err := ordererOrgCA.NewServerCertKeyPair("localhost", "127.0.0.1", "::1")
   138  	require.NoError(t, err)
   139  
   140  	// create test MSPConfigs
   141  	org1MSPConf, err := createMSPConfig("Org1MSP", [][]byte{org2CA.CertBytes()}, [][]byte{org1CA.CertBytes()}, [][]byte{})
   142  	require.NoError(t, err)
   143  	org2MSPConf, err := createMSPConfig("Org2MSP", [][]byte{org1CA.CertBytes()}, [][]byte{org2CA.CertBytes()}, [][]byte{})
   144  	require.NoError(t, err)
   145  	org2IntermediateMSPConf, err := createMSPConfig("Org2IntermediateMSP", [][]byte{org1CA.CertBytes()}, [][]byte{org2CA.CertBytes()}, [][]byte{org2IntermediateCA.CertBytes()})
   146  	require.NoError(t, err)
   147  	ordererOrgMSPConf, err := createMSPConfig("OrdererOrgMSP", [][]byte{org1CA.CertBytes()}, [][]byte{ordererOrgCA.CertBytes()}, [][]byte{})
   148  	require.NoError(t, err)
   149  
   150  	// create test channel create blocks
   151  	channel1Block, err := createConfigBlock("channel1", org1MSPConf, ordererOrgMSPConf, "Org1MSP", "OrdererOrgMSP")
   152  	require.NoError(t, err)
   153  	channel2Block, err := createConfigBlock("channel2", org2MSPConf, ordererOrgMSPConf, "Org2MSP", "OrdererOrgMSP")
   154  	require.NoError(t, err)
   155  	channel3Block, err := createConfigBlock("channel3", org2IntermediateMSPConf, ordererOrgMSPConf, "Org2IntermediateMSP", "OrdererOrgMSP")
   156  	require.NoError(t, err)
   157  
   158  	serverConfig := comm.ServerConfig{
   159  		SecOpts: comm.SecureOptions{
   160  			UseTLS:            true,
   161  			Certificate:       org1Server1KeyPair.Cert,
   162  			Key:               org1Server1KeyPair.Key,
   163  			ServerRootCAs:     [][]byte{org1CA.CertBytes()},
   164  			RequireClientCert: true,
   165  		},
   166  	}
   167  
   168  	peerInstance, cleanup := peer.NewTestPeer(t)
   169  	defer cleanup()
   170  	peerInstance.CredentialSupport = comm.NewCredentialSupport()
   171  
   172  	createChannel := func(t *testing.T, cid string, block *cb.Block) {
   173  		err = peerInstance.CreateChannel(cid, block, &mock.DeployedChaincodeInfoProvider{}, nil, nil)
   174  		require.NoError(t, err, "failed to create channel from block")
   175  		t.Logf("Channel %s MSPIDs: (%s)", cid, peerInstance.GetMSPIDs(cid))
   176  	}
   177  
   178  	org1CertPool, err := createCertPool([][]byte{org1CA.CertBytes()})
   179  	require.NoError(t, err)
   180  
   181  	// use server cert as client cert
   182  	org1ClientCert, err := tls.X509KeyPair(org1Server1KeyPair.Cert, org1Server1KeyPair.Key)
   183  	require.NoError(t, err)
   184  
   185  	org1Creds := credentials.NewTLS(&tls.Config{
   186  		Certificates: []tls.Certificate{org1ClientCert},
   187  		RootCAs:      org1CertPool,
   188  	})
   189  
   190  	org2ClientCert, err := tls.X509KeyPair(org2Server1KeyPair.Cert, org2Server1KeyPair.Key)
   191  	require.NoError(t, err)
   192  	org2Creds := credentials.NewTLS(&tls.Config{
   193  		Certificates: []tls.Certificate{org2ClientCert},
   194  		RootCAs:      org1CertPool,
   195  	})
   196  
   197  	org2IntermediateClientCert, err := tls.X509KeyPair(org2IntermediateServer1KeyPair.Cert, org2IntermediateServer1KeyPair.Key)
   198  	require.NoError(t, err)
   199  	org2IntermediateCreds := credentials.NewTLS(&tls.Config{
   200  		Certificates: []tls.Certificate{org2IntermediateClientCert},
   201  		RootCAs:      org1CertPool,
   202  	})
   203  
   204  	ordererOrgClientCert, err := tls.X509KeyPair(ordererOrgServer1KeyPair.Cert, ordererOrgServer1KeyPair.Key)
   205  	require.NoError(t, err)
   206  
   207  	ordererOrgCreds := credentials.NewTLS(&tls.Config{
   208  		Certificates: []tls.Certificate{ordererOrgClientCert},
   209  		RootCAs:      org1CertPool,
   210  	})
   211  
   212  	// basic function tests
   213  	tests := []struct {
   214  		name          string
   215  		serverConfig  comm.ServerConfig
   216  		createChannel func(*testing.T)
   217  		goodOptions   []grpc.DialOption
   218  		badOptions    []grpc.DialOption
   219  		numAppCAs     int
   220  		numOrdererCAs int
   221  	}{
   222  		{
   223  			name:          "MutualTLSOrg1Org1",
   224  			serverConfig:  serverConfig,
   225  			createChannel: func(t *testing.T) { createChannel(t, "channel1", channel1Block) },
   226  			goodOptions:   []grpc.DialOption{grpc.WithTransportCredentials(org1Creds)},
   227  			badOptions:    []grpc.DialOption{grpc.WithTransportCredentials(ordererOrgCreds)},
   228  			numAppCAs:     3, // each channel also has a DEFAULT MSP
   229  			numOrdererCAs: 1,
   230  		},
   231  		{
   232  			name:          "MutualTLSOrg1Org2",
   233  			serverConfig:  serverConfig,
   234  			createChannel: func(t *testing.T) { createChannel(t, "channel2", channel2Block) },
   235  			goodOptions: []grpc.DialOption{
   236  				grpc.WithTransportCredentials(org2Creds),
   237  			},
   238  			badOptions: []grpc.DialOption{
   239  				grpc.WithTransportCredentials(ordererOrgCreds),
   240  			},
   241  			numAppCAs:     6,
   242  			numOrdererCAs: 2,
   243  		},
   244  		{
   245  			name:          "MutualTLSOrg1Org2Intermediate",
   246  			serverConfig:  serverConfig,
   247  			createChannel: func(t *testing.T) { createChannel(t, "channel3", channel3Block) },
   248  			goodOptions: []grpc.DialOption{
   249  				grpc.WithTransportCredentials(org2IntermediateCreds),
   250  			},
   251  			badOptions: []grpc.DialOption{
   252  				grpc.WithTransportCredentials(ordererOrgCreds),
   253  			},
   254  			numAppCAs:     10,
   255  			numOrdererCAs: 3,
   256  		},
   257  	}
   258  
   259  	for _, test := range tests {
   260  		test := test
   261  		t.Run(test.name, func(t *testing.T) {
   262  			server, err := comm.NewGRPCServer("localhost:0", test.serverConfig)
   263  			require.NoError(t, err, "failed to create gRPC server")
   264  			require.NotNil(t, server)
   265  
   266  			peerInstance.SetServer(server)
   267  			peerInstance.ServerConfig = test.serverConfig
   268  
   269  			// register a GRPC test service
   270  			testpb.RegisterTestServiceServer(server.Server(), &testServiceServer{})
   271  			go server.Start()
   272  			defer server.Stop()
   273  
   274  			// extract dynamic listen port
   275  			_, port, err := net.SplitHostPort(server.Listener().Addr().String())
   276  			require.NoError(t, err, "unable to extract listener port")
   277  			testAddress := "localhost:" + port
   278  
   279  			// invoke the EmptyCall service with good options but should fail
   280  			// until channel is created and root CAs are updated
   281  			_, err = invokeEmptyCall(testAddress, test.goodOptions)
   282  			require.Error(t, err, "Expected error invoking the EmptyCall service ")
   283  
   284  			// creating channel should update the trusted client roots
   285  			test.createChannel(t)
   286  
   287  			// invoke the EmptyCall service with good options
   288  			_, err = invokeEmptyCall(testAddress, test.goodOptions)
   289  			require.NoError(t, err, "Failed to invoke the EmptyCall service")
   290  
   291  			// invoke the EmptyCall service with bad options
   292  			_, err = invokeEmptyCall(testAddress, test.badOptions)
   293  			require.Error(t, err, "Expected error using bad dial options")
   294  		})
   295  	}
   296  }