github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/peer/pkg_test.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package peer_test
    18  
    19  import (
    20  	"crypto/tls"
    21  	"crypto/x509"
    22  	"errors"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"path/filepath"
    26  	"testing"
    27  	"time"
    28  
    29  	"google.golang.org/grpc/credentials"
    30  
    31  	"golang.org/x/net/context"
    32  	"google.golang.org/grpc"
    33  
    34  	"github.com/golang/protobuf/proto"
    35  	configtxtest "github.com/hyperledger/fabric/common/configtx/test"
    36  	"github.com/hyperledger/fabric/core/comm"
    37  	testpb "github.com/hyperledger/fabric/core/comm/testdata/grpc"
    38  	"github.com/hyperledger/fabric/core/peer"
    39  	"github.com/hyperledger/fabric/msp"
    40  	cb "github.com/hyperledger/fabric/protos/common"
    41  	mspproto "github.com/hyperledger/fabric/protos/msp"
    42  	"github.com/spf13/viper"
    43  	"github.com/stretchr/testify/assert"
    44  )
    45  
    46  // default timeout for grpc connections
    47  var timeout = time.Second * 1
    48  
    49  // test server to be registered with the GRPCServer
    50  type testServiceServer struct{}
    51  
    52  func (tss *testServiceServer) EmptyCall(context.Context, *testpb.Empty) (*testpb.Empty, error) {
    53  	return new(testpb.Empty), nil
    54  }
    55  
    56  // createCertPool creates an x509.CertPool from an array of PEM-encoded certificates
    57  func createCertPool(rootCAs [][]byte) (*x509.CertPool, error) {
    58  
    59  	certPool := x509.NewCertPool()
    60  	for _, rootCA := range rootCAs {
    61  		if !certPool.AppendCertsFromPEM(rootCA) {
    62  			return nil, errors.New("Failed to load root certificates")
    63  		}
    64  	}
    65  	return certPool, nil
    66  }
    67  
    68  // helper function to invoke the EmptyCall againt the test service
    69  func invokeEmptyCall(address string, dialOptions []grpc.DialOption) (*testpb.Empty, error) {
    70  
    71  	//add DialOptions
    72  	dialOptions = append(dialOptions, grpc.WithBlock())
    73  	dialOptions = append(dialOptions, grpc.WithTimeout(timeout))
    74  	//create GRPC client conn
    75  	clientConn, err := grpc.Dial(address, dialOptions...)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	defer clientConn.Close()
    80  
    81  	//create GRPC client
    82  	client := testpb.NewTestServiceClient(clientConn)
    83  
    84  	ctx := context.Background()
    85  	ctx, cancel := context.WithTimeout(ctx, timeout)
    86  	defer cancel()
    87  
    88  	//invoke service
    89  	empty, err := client.EmptyCall(ctx, new(testpb.Empty))
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	return empty, nil
    95  }
    96  
    97  // helper function to build an MSPConfig given root certs
    98  func createMSPConfig(rootCerts [][]byte, mspID string) (*mspproto.MSPConfig, error) {
    99  	fmspconf := &mspproto.FabricMSPConfig{
   100  		RootCerts: rootCerts,
   101  		Name:      mspID}
   102  
   103  	fmpsjs, err := proto.Marshal(fmspconf)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	mspconf := &mspproto.MSPConfig{Config: fmpsjs, Type: int32(msp.FABRIC)}
   108  	return mspconf, nil
   109  }
   110  
   111  func createConfigBlock(chainID string, appMSPConf, ordererMSPConf *mspproto.MSPConfig,
   112  	appOrgID, ordererOrgID string) (*cb.Block, error) {
   113  	block, err := configtxtest.MakeGenesisBlockFromMSPs(chainID, appMSPConf, ordererMSPConf, appOrgID, ordererOrgID)
   114  	return block, err
   115  }
   116  
   117  func TestCreatePeerServer(t *testing.T) {
   118  	// load test certs from testdata
   119  	org1CA, err := ioutil.ReadFile(filepath.Join("testdata", "Org1-cert.pem"))
   120  	org1Server1Key, err := ioutil.ReadFile(filepath.Join("testdata", "Org1-server1-key.pem"))
   121  	org1Server1Cert, err := ioutil.ReadFile(filepath.Join("testdata", "Org1-server1-cert.pem"))
   122  	org1Server2Key, err := ioutil.ReadFile(filepath.Join("testdata", "Org1-server2-key.pem"))
   123  	org1Server2Cert, err := ioutil.ReadFile(filepath.Join("testdata", "Org1-server2-cert.pem"))
   124  	org2CA, err := ioutil.ReadFile(filepath.Join("testdata", "Org2-cert.pem"))
   125  	org2Server1Key, err := ioutil.ReadFile(filepath.Join("testdata", "Org2-server1-key.pem"))
   126  	org2Server1Cert, err := ioutil.ReadFile(filepath.Join("testdata", "Org2-server1-cert.pem"))
   127  	org3CA, err := ioutil.ReadFile(filepath.Join("testdata", "Org3-cert.pem"))
   128  
   129  	if err != nil {
   130  		t.Fatalf("Failed to load test certificates: %v", err)
   131  	}
   132  
   133  	// create test MSPConfigs
   134  	org1MSPConf, err := createMSPConfig([][]byte{org1CA}, "Org1MSP")
   135  	org2MSPConf, err := createMSPConfig([][]byte{org2CA}, "Org2MSP")
   136  	org3MSPConf, err := createMSPConfig([][]byte{org3CA}, "Org3MSP")
   137  	if err != nil {
   138  		t.Fatalf("Failed to create MSPConfigs (%s)", err)
   139  	}
   140  
   141  	// create test channel create blocks
   142  	channel1Block, err := createConfigBlock("channel1", org1MSPConf, org3MSPConf, "Org1MSP", "Org3MSP")
   143  	channel2Block, err := createConfigBlock("channel2", org2MSPConf, org3MSPConf, "Org2MSP", "Org3MSP")
   144  
   145  	createChannel := func(cid string, block *cb.Block) {
   146  		viper.Set("peer.tls.enabled", true)
   147  		viper.Set("peer.tls.cert.file", filepath.Join("testdata", "Org1-server1-cert.pem"))
   148  		viper.Set("peer.tls.key.file", filepath.Join("testdata", "Org1-server1-key.pem"))
   149  		viper.Set("peer.tls.rootcert.file", filepath.Join("testdata", "Org1-cert.pem"))
   150  		err := peer.CreateChainFromBlock(block)
   151  		if err != nil {
   152  			t.Fatalf("Failed to create config block (%s)", err)
   153  		}
   154  		t.Logf("Channel %s MSPIDs: (%s)", cid, peer.GetMSPIDs(cid))
   155  		appCAs, orgCAs := comm.GetCASupport().GetClientRootCAs()
   156  		t.Logf("appCAs after update for channel %s: %d", cid, len(appCAs))
   157  		t.Logf("orgCAs after update for channel %s: %d", cid, len(orgCAs))
   158  	}
   159  
   160  	org1CertPool, err := createCertPool([][]byte{org1CA})
   161  	org2CertPool, err := createCertPool([][]byte{org2CA})
   162  
   163  	if err != nil {
   164  		t.Fatalf("Failed to load root certificates into pool: %v", err)
   165  	}
   166  
   167  	org1Creds := credentials.NewClientTLSFromCert(org1CertPool, "")
   168  	org2Creds := credentials.NewClientTLSFromCert(org2CertPool, "")
   169  
   170  	// use server cert as client cert
   171  	org1ClientCert, err := tls.X509KeyPair(org1Server2Cert, org1Server2Key)
   172  	if err != nil {
   173  		t.Fatalf("Failed to load client certificate: %v", err)
   174  	}
   175  	org1Org1Creds := credentials.NewTLS(&tls.Config{
   176  		Certificates: []tls.Certificate{org1ClientCert},
   177  		RootCAs:      org1CertPool,
   178  	})
   179  	org2ClientCert, err := tls.X509KeyPair(org2Server1Cert, org2Server1Key)
   180  	if err != nil {
   181  		t.Fatalf("Failed to load client certificate: %v", err)
   182  	}
   183  	org1Org2Creds := credentials.NewTLS(&tls.Config{
   184  		Certificates: []tls.Certificate{org2ClientCert},
   185  		RootCAs:      org1CertPool,
   186  	})
   187  
   188  	// basic function tests
   189  	var tests = []struct {
   190  		name          string
   191  		listenAddress string
   192  		secureConfig  comm.SecureServerConfig
   193  		expectError   bool
   194  		createChannel func()
   195  		goodOptions   []grpc.DialOption
   196  		badOptions    []grpc.DialOption
   197  	}{
   198  
   199  		{
   200  			name:          "NoTLS",
   201  			listenAddress: fmt.Sprintf("localhost:%d", 4050),
   202  			secureConfig: comm.SecureServerConfig{
   203  				UseTLS: false,
   204  			},
   205  			expectError:   false,
   206  			createChannel: func() {},
   207  			goodOptions:   []grpc.DialOption{grpc.WithInsecure()},
   208  			badOptions:    []grpc.DialOption{grpc.WithTransportCredentials(org1Creds)},
   209  		},
   210  		{
   211  			name:          "ServerTLSOrg1",
   212  			listenAddress: fmt.Sprintf("localhost:%d", 4051),
   213  			secureConfig: comm.SecureServerConfig{
   214  				UseTLS:            true,
   215  				ServerCertificate: org1Server1Cert,
   216  				ServerKey:         org1Server1Key,
   217  				ServerRootCAs:     [][]byte{org1CA},
   218  			},
   219  			expectError:   false,
   220  			createChannel: func() {},
   221  			goodOptions:   []grpc.DialOption{grpc.WithTransportCredentials(org1Creds)},
   222  			badOptions:    []grpc.DialOption{grpc.WithTransportCredentials(org2Creds)},
   223  		},
   224  		{
   225  			name:          "MutualTLSOrg1Org1",
   226  			listenAddress: fmt.Sprintf("localhost:%d", 4052),
   227  			secureConfig: comm.SecureServerConfig{
   228  				UseTLS:            true,
   229  				ServerCertificate: org1Server1Cert,
   230  				ServerKey:         org1Server1Key,
   231  				ServerRootCAs:     [][]byte{org1CA},
   232  				RequireClientCert: true,
   233  			},
   234  			expectError:   false,
   235  			createChannel: func() { createChannel("channel1", channel1Block) },
   236  			goodOptions:   []grpc.DialOption{grpc.WithTransportCredentials(org1Org1Creds)},
   237  			badOptions:    []grpc.DialOption{grpc.WithTransportCredentials(org1Org2Creds)},
   238  		},
   239  		{
   240  			name:          "MutualTLSOrg1Org2",
   241  			listenAddress: fmt.Sprintf("localhost:%d", 4053),
   242  			secureConfig: comm.SecureServerConfig{
   243  				UseTLS:            true,
   244  				ServerCertificate: org1Server1Cert,
   245  				ServerKey:         org1Server1Key,
   246  				ServerRootCAs:     [][]byte{org1CA},
   247  				RequireClientCert: true,
   248  			},
   249  			expectError:   false,
   250  			createChannel: func() { createChannel("channel2", channel2Block) },
   251  			goodOptions:   []grpc.DialOption{grpc.WithTransportCredentials(org1Org2Creds)},
   252  			badOptions:    []grpc.DialOption{grpc.WithTransportCredentials(org1Creds)},
   253  		},
   254  	}
   255  
   256  	for _, test := range tests {
   257  		test := test
   258  		t.Run(test.name, func(t *testing.T) {
   259  			t.Logf("Running test %s ...", test.name)
   260  			_, err := peer.CreatePeerServer(test.listenAddress, test.secureConfig)
   261  			// check to see whether to not we expect an error
   262  			// we don't check the exact error because the comm package covers these cases
   263  			if test.expectError {
   264  				assert.Error(t, err, "CreatePeerServer should have returned an error")
   265  			} else {
   266  				assert.NoError(t, err, "CreatePeerServer should not have returned an error")
   267  				// get the server from peer
   268  				server := peer.GetPeerServer()
   269  				assert.NotNil(t, server, "GetPeerServer should not return a nil value")
   270  				// register a GRPC test service
   271  				testpb.RegisterTestServiceServer(server.Server(), &testServiceServer{})
   272  				go server.Start()
   273  				defer server.Stop()
   274  
   275  				// invoke the EmptyCall service with bad options
   276  				_, err = invokeEmptyCall(test.listenAddress, test.badOptions)
   277  				assert.Error(t, err, "Expected error using bad dial options")
   278  				// creating channel should update the trusted client roots
   279  				test.createChannel()
   280  				// invoke the EmptyCall service with good options
   281  				_, err = invokeEmptyCall(test.listenAddress, test.goodOptions)
   282  				assert.NoError(t, err, "Failed to invoke the EmptyCall service")
   283  
   284  			}
   285  		})
   286  	}
   287  }