Commit 0ee18c2b authored by Jason Yellick's avatar Jason Yellick
Browse files

FAB-10314 Hide ACLs behind capability



The ACLs function affects how channel config is parsed, and as such, it
must be deterministic across versions.  Channel config parsing should
not allow the presence of ACLs until the corresponding capability has
been enabled.

Change-Id: Ie55a69b620d48198bc485cde820b5f03d6dd6c2d
Signed-off-by: default avatarJason Yellick <jyellick@us.ibm.com>
parent c37715b5
......@@ -35,11 +35,10 @@ const (
// ApplicationProvider provides capabilities information for application level config.
type ApplicationProvider struct {
*registry
v11 bool
v12 bool
v11PvtDataExperimental bool
v11ResourcesTreeExperimental bool
v12LifecycleExperimental bool
v11 bool
v12 bool
v11PvtDataExperimental bool
v12LifecycleExperimental bool
}
// NewApplicationProvider creates a application capabilities provider.
......@@ -49,7 +48,6 @@ func NewApplicationProvider(capabilities map[string]*cb.Capability) *Application
_, ap.v11 = capabilities[ApplicationV1_1]
_, ap.v12 = capabilities[ApplicationV1_2]
_, ap.v11PvtDataExperimental = capabilities[ApplicationPvtDataExperimental]
_, ap.v11ResourcesTreeExperimental = capabilities[ApplicationResourcesTreeExperimental]
_, ap.v12LifecycleExperimental = capabilities[ApplicationChaincodeLifecycleExperimental]
return ap
}
......@@ -59,9 +57,9 @@ func (ap *ApplicationProvider) Type() string {
return applicationTypeName
}
// ResourcesTree returns whether the experimental resources tree transaction processing should be enabled.
func (ap *ApplicationProvider) ResourcesTree() bool {
return ap.v11ResourcesTreeExperimental
// ACLs returns whether ACLs may be specified in the channel application config
func (ap *ApplicationProvider) ACLs() bool {
return ap.v12
}
// ForbidDuplicateTXIdInBlock specifies whether two transactions with the same TXId are permitted
......
......@@ -52,6 +52,13 @@ func TestApplicationPvtDataExperimental(t *testing.T) {
}
func TestApplicationACLs(t *testing.T) {
ap := NewApplicationProvider(map[string]*cb.Capability{
ApplicationV1_2: {},
})
assert.True(t, ap.ACLs())
}
func TestApplicationCollectionUpgrade(t *testing.T) {
op := NewApplicationProvider(map[string]*cb.Capability{
ApplicationV1_2: {},
......
......@@ -123,8 +123,8 @@ type ApplicationCapabilities interface {
// in the same block or whether we mark the second one as TxValidationCode_DUPLICATE_TXID
ForbidDuplicateTXIdInBlock() bool
// ResourcesTree returns true if the peer should process the experimental resources transactions
ResourcesTree() bool
// ACLs returns true is ACLs may be specified in the Application portion of the config tree
ACLs() bool
// PrivateChannelData returns true if support for private channel data (a.k.a. collections) is enabled.
// In v1.1, the private channel data is experimental and has to be enabled explicitly.
......
......@@ -45,6 +45,12 @@ func NewApplicationConfig(appGroup *cb.ConfigGroup, mspConfig *MSPConfigHandler)
return nil, errors.Wrap(err, "failed to deserialize values")
}
if !ac.Capabilities().ACLs() {
if _, ok := appGroup.Values[ACLsKey]; ok {
return nil, errors.New("ACLs may not be specified without the required capability")
}
}
var err error
for orgName, orgGroup := range appGroup.Groups {
ac.applicationOrgs[orgName], err = NewApplicationOrgConfig(orgName, orgGroup, mspConfig)
......
......@@ -9,6 +9,12 @@ package channelconfig
import (
"testing"
"github.com/hyperledger/fabric/common/capabilities"
cb "github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/utils"
"github.com/golang/protobuf/proto"
. "github.com/onsi/gomega"
logging "github.com/op/go-logging"
)
......@@ -19,3 +25,36 @@ func init() {
func TestApplicationInterface(t *testing.T) {
_ = Application((*ApplicationConfig)(nil))
}
func TestACL(t *testing.T) {
g := NewGomegaWithT(t)
cgt := &cb.ConfigGroup{
Values: map[string]*cb.ConfigValue{
ACLsKey: {
Value: utils.MarshalOrPanic(
ACLValues(map[string]string{}).Value(),
),
},
CapabilitiesKey: {
Value: utils.MarshalOrPanic(
CapabilitiesValue(map[string]bool{
capabilities.ApplicationV1_2: true,
}).Value(),
),
},
},
}
t.Run("Success", func(t *testing.T) {
cg := proto.Clone(cgt).(*cb.ConfigGroup)
_, err := NewApplicationConfig(proto.Clone(cg).(*cb.ConfigGroup), nil)
g.Expect(err).NotTo(HaveOccurred())
})
t.Run("MissingCapability", func(t *testing.T) {
cg := proto.Clone(cgt).(*cb.ConfigGroup)
delete(cg.Values, CapabilitiesKey)
_, err := NewApplicationConfig(cg, nil)
g.Expect(err).To(MatchError("ACLs may not be specified without the required capability"))
})
}
......@@ -38,7 +38,7 @@ func (m *MockApplication) APIPolicyMapper() channelconfig.PolicyMapper {
type MockApplicationCapabilities struct {
SupportedRv error
ForbidDuplicateTXIdInBlockRv bool
ResourcesTreeRv bool
ACLsRv bool
PrivateChannelDataRv bool
CollectionUpgradeRv bool
V1_1ValidationRv bool
......@@ -55,8 +55,8 @@ func (mac *MockApplicationCapabilities) ForbidDuplicateTXIdInBlock() bool {
return mac.ForbidDuplicateTXIdInBlockRv
}
func (mac *MockApplicationCapabilities) ResourcesTree() bool {
return mac.ResourcesTreeRv
func (mac *MockApplicationCapabilities) ACLs() bool {
return mac.ACLsRv
}
func (mac *MockApplicationCapabilities) PrivateChannelData() bool {
......
......@@ -14,8 +14,8 @@ type Capabilities struct {
mock.Mock
}
// CollectionUpgrade provides a mock function with given fields:
func (_m *Capabilities) CollectionUpgrade() bool {
// ACLs provides a mock function with given fields:
func (_m *Capabilities) ACLs() bool {
ret := _m.Called()
var r0 bool
......@@ -28,8 +28,8 @@ func (_m *Capabilities) CollectionUpgrade() bool {
return r0
}
// ForbidDuplicateTXIdInBlock provides a mock function with given fields:
func (_m *Capabilities) ForbidDuplicateTXIdInBlock() bool {
// CollectionUpgrade provides a mock function with given fields:
func (_m *Capabilities) CollectionUpgrade() bool {
ret := _m.Called()
var r0 bool
......@@ -42,8 +42,8 @@ func (_m *Capabilities) ForbidDuplicateTXIdInBlock() bool {
return r0
}
// KeyLevelEndorsement provides a mock function with given fields:
func (_m *Capabilities) KeyLevelEndorsement() bool {
// ForbidDuplicateTXIdInBlock provides a mock function with given fields:
func (_m *Capabilities) ForbidDuplicateTXIdInBlock() bool {
ret := _m.Called()
var r0 bool
......@@ -56,8 +56,8 @@ func (_m *Capabilities) KeyLevelEndorsement() bool {
return r0
}
// MetadataLifecycle provides a mock function with given fields:
func (_m *Capabilities) MetadataLifecycle() bool {
// KeyLevelEndorsement provides a mock function with given fields:
func (_m *Capabilities) KeyLevelEndorsement() bool {
ret := _m.Called()
var r0 bool
......@@ -70,8 +70,8 @@ func (_m *Capabilities) MetadataLifecycle() bool {
return r0
}
// PrivateChannelData provides a mock function with given fields:
func (_m *Capabilities) PrivateChannelData() bool {
// MetadataLifecycle provides a mock function with given fields:
func (_m *Capabilities) MetadataLifecycle() bool {
ret := _m.Called()
var r0 bool
......@@ -84,8 +84,8 @@ func (_m *Capabilities) PrivateChannelData() bool {
return r0
}
// ResourcesTree provides a mock function with given fields:
func (_m *Capabilities) ResourcesTree() bool {
// PrivateChannelData provides a mock function with given fields:
func (_m *Capabilities) PrivateChannelData() bool {
ret := _m.Called()
var r0 bool
......
......@@ -19,8 +19,8 @@ type Capabilities interface {
// in the same block or whether we mark the second one as TxValidationCode_DUPLICATE_TXID
ForbidDuplicateTXIdInBlock() bool
// ResourcesTree returns true if the peer should process the experimental resources transactions
ResourcesTree() bool
// ACLs returns true if the peer supports ACLs in the channel config
ACLs() bool
// PrivateChannelData returns true if support for private channel data (a.k.a. collections) is enabled.
PrivateChannelData() bool
......
......@@ -14,8 +14,8 @@ type Capabilities struct {
mock.Mock
}
// CollectionUpgrade provides a mock function with given fields:
func (_m *Capabilities) CollectionUpgrade() bool {
// ACLs provides a mock function with given fields:
func (_m *Capabilities) ACLs() bool {
ret := _m.Called()
var r0 bool
......@@ -28,8 +28,8 @@ func (_m *Capabilities) CollectionUpgrade() bool {
return r0
}
// ForbidDuplicateTXIdInBlock provides a mock function with given fields:
func (_m *Capabilities) ForbidDuplicateTXIdInBlock() bool {
// CollectionUpgrade provides a mock function with given fields:
func (_m *Capabilities) CollectionUpgrade() bool {
ret := _m.Called()
var r0 bool
......@@ -42,8 +42,8 @@ func (_m *Capabilities) ForbidDuplicateTXIdInBlock() bool {
return r0
}
// KeyLevelEndorsement provides a mock function with given fields:
func (_m *Capabilities) KeyLevelEndorsement() bool {
// ForbidDuplicateTXIdInBlock provides a mock function with given fields:
func (_m *Capabilities) ForbidDuplicateTXIdInBlock() bool {
ret := _m.Called()
var r0 bool
......@@ -56,8 +56,8 @@ func (_m *Capabilities) KeyLevelEndorsement() bool {
return r0
}
// MetadataLifecycle provides a mock function with given fields:
func (_m *Capabilities) MetadataLifecycle() bool {
// KeyLevelEndorsement provides a mock function with given fields:
func (_m *Capabilities) KeyLevelEndorsement() bool {
ret := _m.Called()
var r0 bool
......@@ -70,8 +70,8 @@ func (_m *Capabilities) MetadataLifecycle() bool {
return r0
}
// PrivateChannelData provides a mock function with given fields:
func (_m *Capabilities) PrivateChannelData() bool {
// MetadataLifecycle provides a mock function with given fields:
func (_m *Capabilities) MetadataLifecycle() bool {
ret := _m.Called()
var r0 bool
......@@ -84,8 +84,8 @@ func (_m *Capabilities) PrivateChannelData() bool {
return r0
}
// ResourcesTree provides a mock function with given fields:
func (_m *Capabilities) ResourcesTree() bool {
// PrivateChannelData provides a mock function with given fields:
func (_m *Capabilities) PrivateChannelData() bool {
ret := _m.Called()
var r0 bool
......
......@@ -62,7 +62,7 @@ func TestConfigTxCreateLedger(t *testing.T) {
assert.Equal(t, proto.CompactTextString(chanConf), proto.CompactTextString(retrievedchanConf))
}
func TestConfigTxUpdateResConfig(t *testing.T) {
func TestConfigTxUpdateChanConfig(t *testing.T) {
helper := &testHelper{t: t}
cleanup := setupPeerFS(t)
defer cleanup()
......@@ -125,8 +125,7 @@ func (h *testHelper) sampleChannelConfig(sequence uint64, enableV11Capability bo
profile.Orderer.Capabilities = make(map[string]bool)
profile.Orderer.Capabilities[capabilities.ApplicationV1_1] = true
profile.Application.Capabilities = make(map[string]bool)
profile.Application.Capabilities[capabilities.ApplicationV1_1] = true
profile.Application.Capabilities[capabilities.ApplicationResourcesTreeExperimental] = true
profile.Application.Capabilities[capabilities.ApplicationV1_2] = true
}
channelGroup, _ := encoder.NewChannelGroup(profile)
return &common.Config{
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment