226 lines
6.4 KiB
Go
226 lines
6.4 KiB
Go
/*
|
|
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")
|
|
})
|
|
}
|