/* Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package acl_test import ( "testing" "github.com/hyperledger/fabric/common/channelconfig" "github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/discovery/support/acl" "github.com/hyperledger/fabric/discovery/support/mocks" gmocks "github.com/hyperledger/fabric/internal/peer/gossip/mocks" "github.com/hyperledger/fabric/protoutil" "github.com/pkg/errors" "github.com/stretchr/testify/require" ) func TestGetChannelConfigFunc(t *testing.T) { r := &mocks.Resources{} f := func(cid string) channelconfig.Resources { return r } require.Equal(t, r, acl.ChannelConfigGetterFunc(f).GetChannelConfig("mychannel")) } func TestConfigSequenceEmptyChannelName(t *testing.T) { // If the channel name is empty, there is no config sequence, // and we return 0 sup := acl.NewDiscoverySupport(nil, nil, nil) require.Equal(t, uint64(0), sup.ConfigSequence("")) } func TestConfigSequence(t *testing.T) { tests := []struct { name string resourcesFound bool validatorFound bool sequence uint64 shouldPanic bool }{ { name: "resources not found", shouldPanic: true, }, { name: "validator not found", resourcesFound: true, shouldPanic: true, }, { name: "both resources and validator are found", resourcesFound: true, validatorFound: true, sequence: 100, }, } for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { chConfig := &mocks.ChannelConfigGetter{} r := &mocks.Resources{} v := &mocks.ConfigtxValidator{} if test.resourcesFound { chConfig.GetChannelConfigReturns(r) } if test.validatorFound { r.ConfigtxValidatorReturns(v) } v.SequenceReturns(test.sequence) sup := acl.NewDiscoverySupport(&mocks.Verifier{}, &mocks.Evaluator{}, chConfig) if test.shouldPanic { require.Panics(t, func() { sup.ConfigSequence("mychannel") }) return } require.Equal(t, test.sequence, sup.ConfigSequence("mychannel")) }) } } func TestEligibleForService(t *testing.T) { v := &mocks.Verifier{} e := &mocks.Evaluator{} v.VerifyByChannelReturnsOnCall(0, errors.New("verification failed")) v.VerifyByChannelReturnsOnCall(1, nil) e.EvaluateSignedDataReturnsOnCall(0, errors.New("verification failed for local msp")) e.EvaluateSignedDataReturnsOnCall(1, nil) chConfig := &mocks.ChannelConfigGetter{} sup := acl.NewDiscoverySupport(v, e, chConfig) err := sup.EligibleForService("mychannel", protoutil.SignedData{}) require.Equal(t, "verification failed", err.Error()) err = sup.EligibleForService("mychannel", protoutil.SignedData{}) require.NoError(t, err) err = sup.EligibleForService("", protoutil.SignedData{}) require.Equal(t, "verification failed for local msp", err.Error()) err = sup.EligibleForService("", protoutil.SignedData{}) require.NoError(t, err) } func TestSatisfiesPrincipal(t *testing.T) { var ( chConfig = &mocks.ChannelConfigGetter{} resources = &mocks.Resources{} mgr = &mocks.MSPManager{} idThatDoesNotSatisfyPrincipal = &mocks.Identity{} idThatSatisfiesPrincipal = &mocks.Identity{} ) tests := []struct { testDescription string before func() expectedErr string }{ { testDescription: "Channel does not exist", before: func() { chConfig.GetChannelConfigReturns(nil) }, expectedErr: "channel mychannel doesn't exist", }, { testDescription: "MSP manager not available", before: func() { chConfig.GetChannelConfigReturns(resources) resources.MSPManagerReturns(nil) }, expectedErr: "could not find MSP manager for channel mychannel", }, { testDescription: "Identity cannot be deserialized", before: func() { resources.MSPManagerReturns(mgr) mgr.DeserializeIdentityReturns(nil, errors.New("not a valid identity")) }, expectedErr: "failed deserializing identity: not a valid identity", }, { testDescription: "Identity does not satisfy principal", before: func() { idThatDoesNotSatisfyPrincipal.SatisfiesPrincipalReturns(errors.New("does not satisfy principal")) mgr.DeserializeIdentityReturns(idThatDoesNotSatisfyPrincipal, nil) }, expectedErr: "does not satisfy principal", }, { testDescription: "All is fine, identity is eligible", before: func() { idThatSatisfiesPrincipal.SatisfiesPrincipalReturns(nil) mgr.DeserializeIdentityReturns(idThatSatisfiesPrincipal, nil) }, expectedErr: "", }, } sup := acl.NewDiscoverySupport(&mocks.Verifier{}, &mocks.Evaluator{}, chConfig) for _, test := range tests { test := test t.Run(test.testDescription, func(t *testing.T) { test.before() err := sup.SatisfiesPrincipal("mychannel", nil, nil) if test.expectedErr != "" { require.Equal(t, test.expectedErr, err.Error()) } else { require.NoError(t, err) } }) } } func TestChannelVerifier(t *testing.T) { polMgr := &gmocks.ChannelPolicyManagerGetterWithManager{ Managers: map[string]policies.Manager{ "mychannel": &gmocks.ChannelPolicyManager{ Policy: &gmocks.Policy{ Deserializer: &gmocks.IdentityDeserializer{ Identity: []byte("Bob"), Msg: []byte("msg"), }, }, }, }, } verifier := &acl.ChannelVerifier{ Policy: "some policy string", ChannelPolicyManagerGetter: polMgr, } t.Run("Valid channel, identity, signature", func(t *testing.T) { err := verifier.VerifyByChannel("mychannel", &protoutil.SignedData{ Data: []byte("msg"), Identity: []byte("Bob"), Signature: []byte("msg"), }) require.NoError(t, err) }) t.Run("Invalid channel", func(t *testing.T) { err := verifier.VerifyByChannel("notmychannel", &protoutil.SignedData{ Data: []byte("msg"), Identity: []byte("Bob"), Signature: []byte("msg"), }) require.Error(t, err) require.Contains(t, err.Error(), "policy manager for channel notmychannel doesn't exist") }) t.Run("Writers policy cannot be retrieved", func(t *testing.T) { polMgr.Managers["mychannel"].(*gmocks.ChannelPolicyManager).Policy = nil err := verifier.VerifyByChannel("mychannel", &protoutil.SignedData{ Data: []byte("msg"), Identity: []byte("Bob"), Signature: []byte("msg"), }) require.Error(t, err) require.Contains(t, err.Error(), "failed obtaining channel application writers policy") }) }