github.com/yimialmonte/fabric@v2.1.1+incompatible/discovery/endorsement/collection_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package endorsement
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"testing"
    13  
    14  	"github.com/hyperledger/fabric-protos-go/common"
    15  	"github.com/hyperledger/fabric-protos-go/discovery"
    16  	"github.com/hyperledger/fabric-protos-go/msp"
    17  	"github.com/hyperledger/fabric-protos-go/peer"
    18  	"github.com/hyperledger/fabric/common/policies"
    19  	"github.com/hyperledger/fabric/gossip/api"
    20  	gcommon "github.com/hyperledger/fabric/gossip/common"
    21  	disc "github.com/hyperledger/fabric/gossip/discovery"
    22  	"github.com/hyperledger/fabric/protoutil"
    23  	"github.com/stretchr/testify/assert"
    24  )
    25  
    26  func TestPrincipalsFromCollectionConfig(t *testing.T) {
    27  	t.Run("Empty config", func(t *testing.T) {
    28  		res, err := principalsFromCollectionConfig(nil)
    29  		assert.NoError(t, err)
    30  		assert.Empty(t, res)
    31  	})
    32  
    33  	t.Run("Not empty config", func(t *testing.T) {
    34  		org1AndOrg2 := []*msp.MSPPrincipal{orgPrincipal("Org1MSP"), orgPrincipal("Org2MSP")}
    35  		org3AndOrg4 := []*msp.MSPPrincipal{orgPrincipal("Org3MSP"), orgPrincipal("Org4MSP")}
    36  		col2principals := map[string][]*msp.MSPPrincipal{
    37  			"foo": org1AndOrg2,
    38  			"bar": org3AndOrg4,
    39  		}
    40  		config := buildCollectionConfig(col2principals)
    41  		res, err := principalsFromCollectionConfig(config)
    42  		assert.NoError(t, err)
    43  		assertEqualPrincipalSets(t, policies.PrincipalSet(org1AndOrg2), res["foo"])
    44  		assertEqualPrincipalSets(t, policies.PrincipalSet(org3AndOrg4), res["bar"])
    45  		assert.Empty(t, res["baz"])
    46  	})
    47  }
    48  
    49  func TestNewCollectionFilterInvalidInput(t *testing.T) {
    50  	t.Run("Invalid collection type", func(t *testing.T) {
    51  		collections := &peer.CollectionConfigPackage{}
    52  		collections.Config = []*peer.CollectionConfig{
    53  			{
    54  				Payload: nil,
    55  			},
    56  		}
    57  		filter, err := principalsFromCollectionConfig(collections)
    58  		assert.Nil(t, filter)
    59  		assert.Contains(t, err.Error(), "expected a static collection")
    60  	})
    61  
    62  	t.Run("Invalid membership policy", func(t *testing.T) {
    63  		collections := &peer.CollectionConfigPackage{}
    64  		collections.Config = []*peer.CollectionConfig{
    65  			{
    66  				Payload: &peer.CollectionConfig_StaticCollectionConfig{
    67  					StaticCollectionConfig: &peer.StaticCollectionConfig{
    68  						Name: "foo",
    69  					},
    70  				},
    71  			},
    72  		}
    73  		filter, err := principalsFromCollectionConfig(collections)
    74  		assert.Nil(t, filter)
    75  		assert.Contains(t, err.Error(), "MemberOrgsPolicy of foo is nil")
    76  	})
    77  
    78  	t.Run("Missing policy", func(t *testing.T) {
    79  		collections := &peer.CollectionConfigPackage{}
    80  		collections.Config = []*peer.CollectionConfig{
    81  			{
    82  				Payload: &peer.CollectionConfig_StaticCollectionConfig{
    83  					StaticCollectionConfig: &peer.StaticCollectionConfig{
    84  						Name:             "foo",
    85  						MemberOrgsPolicy: &peer.CollectionPolicyConfig{},
    86  					},
    87  				},
    88  			},
    89  		}
    90  		filter, err := principalsFromCollectionConfig(collections)
    91  		assert.Nil(t, filter)
    92  		assert.Contains(t, err.Error(), "policy of foo is nil")
    93  	})
    94  }
    95  
    96  func TestToIdentityFilter(t *testing.T) {
    97  	col2principals := make(principalSetsByCollectionName)
    98  	col2principals["foo"] = []*msp.MSPPrincipal{orgPrincipal("Org1MSP"), orgPrincipal("Org2MSP")}
    99  
   100  	t.Run("collection doesn't exist in mapping", func(t *testing.T) {
   101  		filter, err := col2principals.toIdentityFilter("mychannel", &principalEvaluatorMock{}, &discovery.ChaincodeCall{
   102  			Name:            "mycc",
   103  			CollectionNames: []string{"bar"},
   104  		})
   105  		assert.Nil(t, filter)
   106  		assert.Equal(t, "collection bar doesn't exist in collection config for chaincode mycc", err.Error())
   107  	})
   108  
   109  	t.Run("collection exists in mapping", func(t *testing.T) {
   110  		filter, err := col2principals.toIdentityFilter("mychannel", &principalEvaluatorMock{}, &discovery.ChaincodeCall{
   111  			Name:            "mycc",
   112  			CollectionNames: []string{"foo"},
   113  		})
   114  		assert.NoError(t, err)
   115  		identity := protoutil.MarshalOrPanic(&msp.SerializedIdentity{
   116  			Mspid: "Org2MSP",
   117  		})
   118  		assert.True(t, filter(identity))
   119  		identity = protoutil.MarshalOrPanic(&msp.SerializedIdentity{
   120  			Mspid: "Org3MSP",
   121  		})
   122  		assert.False(t, filter(identity))
   123  	})
   124  }
   125  
   126  func TestCombine(t *testing.T) {
   127  	filter1 := identityFilter(func(identity api.PeerIdentityType) bool {
   128  		return bytes.Equal([]byte("p1"), identity) || bytes.Equal([]byte("p2"), identity)
   129  	})
   130  
   131  	filter2 := identityFilter(func(identity api.PeerIdentityType) bool {
   132  		return bytes.Equal([]byte("p2"), identity) || bytes.Equal([]byte("p3"), identity)
   133  	})
   134  
   135  	filter := identityFilters{filter1, filter2}.combine()
   136  	assert.False(t, filter(api.PeerIdentityType("p1")))
   137  	assert.True(t, filter(api.PeerIdentityType("p2")))
   138  	assert.False(t, filter(api.PeerIdentityType("p3")))
   139  	assert.False(t, filter(api.PeerIdentityType("p4")))
   140  }
   141  
   142  func TestToMemberFilter(t *testing.T) {
   143  	unauthorizedIdentity := api.PeerIdentityType("unauthorizedIdentity")
   144  	authorizedIdentity := api.PeerIdentityType("authorizedIdentity")
   145  	notPresentIdentity := api.PeerIdentityType("api.PeerIdentityInfo")
   146  
   147  	filter := identityFilter(func(identity api.PeerIdentityType) bool {
   148  		return bytes.Equal(authorizedIdentity, identity)
   149  	})
   150  	identityInfoByID := map[string]api.PeerIdentityInfo{
   151  		"authorizedIdentity":   {PKIId: gcommon.PKIidType(authorizedIdentity), Identity: authorizedIdentity},
   152  		"unauthorizedIdentity": {PKIId: gcommon.PKIidType(unauthorizedIdentity), Identity: unauthorizedIdentity},
   153  	}
   154  	memberFilter := filter.toMemberFilter(identityInfoByID)
   155  
   156  	t.Run("Member is authorized", func(t *testing.T) {
   157  		authorized := memberFilter(disc.NetworkMember{
   158  			PKIid: gcommon.PKIidType(authorizedIdentity),
   159  		})
   160  		assert.True(t, authorized)
   161  	})
   162  
   163  	t.Run("Member is unauthorized", func(t *testing.T) {
   164  		authorized := memberFilter(disc.NetworkMember{
   165  			PKIid: gcommon.PKIidType(unauthorizedIdentity),
   166  		})
   167  		assert.False(t, authorized)
   168  	})
   169  
   170  	t.Run("Member is not found in mapping", func(t *testing.T) {
   171  		authorized := memberFilter(disc.NetworkMember{
   172  			PKIid: gcommon.PKIidType(notPresentIdentity),
   173  		})
   174  		assert.False(t, authorized)
   175  	})
   176  
   177  }
   178  
   179  func TestIsIdentityAuthorizedByPrincipalSet(t *testing.T) {
   180  	principals := []*msp.MSPPrincipal{orgPrincipal("Org1MSP"), orgPrincipal("Org2MSP")}
   181  	t.Run("Authorized", func(t *testing.T) {
   182  		identity := protoutil.MarshalOrPanic(&msp.SerializedIdentity{
   183  			Mspid: "Org1MSP",
   184  		})
   185  		authorized := isIdentityAuthorizedByPrincipalSet("mychannel", &principalEvaluatorMock{}, principals, identity)
   186  		assert.True(t, authorized)
   187  	})
   188  
   189  	t.Run("Unauthorized", func(t *testing.T) {
   190  		identity := protoutil.MarshalOrPanic(&msp.SerializedIdentity{
   191  			Mspid: "Org3MSP",
   192  		})
   193  		authorized := isIdentityAuthorizedByPrincipalSet("mychannel", &principalEvaluatorMock{}, principals, identity)
   194  		assert.False(t, authorized)
   195  	})
   196  }
   197  
   198  func TestFilterForPrincipalSets(t *testing.T) {
   199  	org1AndOrg2 := []*msp.MSPPrincipal{orgPrincipal("Org1MSP"), orgPrincipal("Org2MSP")}
   200  	org2AndOrg3 := []*msp.MSPPrincipal{orgPrincipal("Org2MSP"), orgPrincipal("Org3MSP")}
   201  	org3AndOrg4 := []*msp.MSPPrincipal{orgPrincipal("Org3MSP"), orgPrincipal("Org4MSP")}
   202  
   203  	identity := protoutil.MarshalOrPanic(&msp.SerializedIdentity{
   204  		Mspid: "Org2MSP",
   205  	})
   206  
   207  	t.Run("Identity is authorized by all principals", func(t *testing.T) {
   208  		filter := filterForPrincipalSets("mychannel", &principalEvaluatorMock{}, policies.PrincipalSets{org1AndOrg2, org2AndOrg3})
   209  		assert.True(t, filter(identity))
   210  	})
   211  
   212  	t.Run("Identity is not authorized by all principals", func(t *testing.T) {
   213  		filter := filterForPrincipalSets("mychannel", &principalEvaluatorMock{}, policies.PrincipalSets{org1AndOrg2, org3AndOrg4})
   214  		assert.False(t, filter(identity))
   215  	})
   216  }
   217  
   218  func buildCollectionConfig(col2principals map[string][]*msp.MSPPrincipal) *peer.CollectionConfigPackage {
   219  	collections := &peer.CollectionConfigPackage{}
   220  	for col, principals := range col2principals {
   221  		collections.Config = append(collections.Config, &peer.CollectionConfig{
   222  			Payload: &peer.CollectionConfig_StaticCollectionConfig{
   223  				StaticCollectionConfig: &peer.StaticCollectionConfig{
   224  					Name: col,
   225  					MemberOrgsPolicy: &peer.CollectionPolicyConfig{
   226  						Payload: &peer.CollectionPolicyConfig_SignaturePolicy{
   227  							SignaturePolicy: &common.SignaturePolicyEnvelope{
   228  								Identities: principals,
   229  							},
   230  						},
   231  					},
   232  				},
   233  			},
   234  		})
   235  	}
   236  
   237  	return collections
   238  }
   239  
   240  func orgPrincipal(mspID string) *msp.MSPPrincipal {
   241  	return &msp.MSPPrincipal{
   242  		PrincipalClassification: msp.MSPPrincipal_ROLE,
   243  		Principal: protoutil.MarshalOrPanic(&msp.MSPRole{
   244  			MspIdentifier: mspID,
   245  			Role:          msp.MSPRole_PEER,
   246  		}),
   247  	}
   248  }
   249  
   250  func assertEqualPrincipalSets(t *testing.T, ps1, ps2 policies.PrincipalSet) {
   251  	ps1s := fmt.Sprintf("%v", ps1)
   252  	ps2s := fmt.Sprintf("%v", ps2)
   253  	assert.Equal(t, ps1s, ps2s)
   254  }