github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/core/peer/pkg_test.go (about)

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