Skip to content

Commit

Permalink
[FAB-6567] Move ACL resources deeper in tree
Browse files Browse the repository at this point in the history
The ACL work preliminarily put all of the policy references and polici
at the root level of the config tree.  Because the peer resources tree
is now intended to support more than ACLs, keeping these at the root
level does not make sense.  Instead, these need to be moved down into
the tree.

This CR moves the old resource policy references from

 /Resources

to

 /Resources/APIs

It also creates

 /Resources/PeerPolicies

as a global location to declare policies which may be referenced both
for API ACL purposes, as well as later by other parts of the resources
tree.

Change-Id: I5c8eeba0472f480ac88ddbf02a0a1a3d90092463
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Oct 12, 2017
1 parent 20b5503 commit 33e3fb6
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 89 deletions.
51 changes: 51 additions & 0 deletions common/resourcesconfig/apis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
Copyright IBM Corp. 2017 All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package resourcesconfig

import (
cb "github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"

"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
)

// apisGroup represents the ConfigGroup names APIs off the resources group
type apisGroup struct {
apiPolicyRefs map[string]string
}

func (ag *apisGroup) PolicyRefForAPI(apiName string) string {
return ag.apiPolicyRefs[apiName]
}

func newAPIsGroup(group *cb.ConfigGroup) (*apisGroup, error) {
if len(group.Groups) > 0 {
return nil, errors.New("apis group does not support sub-groups")
}

apiPolicyRefs := make(map[string]string)

for key, value := range group.Values {
api := &pb.Resource{}
if err := proto.Unmarshal(value.Value, api); err != nil {
return nil, err
}

// If the policy is fully qualified, ie to /Channel/Application/Readers leave it alone
// otherwise, make it fully qualified referring to /Resources/APIs/policyName
if '/' != api.PolicyRef[0] {
apiPolicyRefs[key] = "/" + RootGroupKey + "/" + APIsGroupKey + "/" + api.PolicyRef
} else {
apiPolicyRefs[key] = api.PolicyRef
}
}

return &apisGroup{
apiPolicyRefs: apiPolicyRefs,
}, nil
}
10 changes: 5 additions & 5 deletions common/resourcesconfig/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ var logger = flogging.MustGetLogger("common/config/resource")

// PolicyMapper is an interface for
type PolicyMapper interface {
// PolicyRefForResource takes the name of a resource, and returns the policy name for a resource
// or the empty string is the resource is not found
PolicyRefForResource(resourceName string) string
// PolicyRefForAPI takes the name of an API, and returns the policy name
// or the empty string if the API is not found
PolicyRefForAPI(apiName string) string
}

type Bundle struct {
Expand Down Expand Up @@ -107,6 +107,6 @@ func (b *Bundle) PolicyManager() policies.Manager {
return b.pm
}

func (b *Bundle) ResourcePolicyMapper() PolicyMapper {
return b.rg
func (b *Bundle) APIPolicyMapper() PolicyMapper {
return b.rg.apisGroup
}
48 changes: 27 additions & 21 deletions common/resourcesconfig/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,32 @@ func TestBundleGreenPath(t *testing.T) {
env, err := utils.CreateSignedEnvelope(cb.HeaderType_CONFIG, "foo", nil, &cb.ConfigEnvelope{
Config: &cb.Config{
ChannelGroup: &cb.ConfigGroup{
Values: map[string]*cb.ConfigValue{
"Foo": &cb.ConfigValue{
Value: utils.MarshalOrPanic(&pb.Resource{
PolicyRef: "foo",
}),
},
"Bar": &cb.ConfigValue{
Value: utils.MarshalOrPanic(&pb.Resource{
PolicyRef: "/Channel/foo",
}),
},
},
Policies: map[string]*cb.ConfigPolicy{
"foo": dummyPolicy,
"bar": dummyPolicy,
},
Groups: map[string]*cb.ConfigGroup{
"subGroup": &cb.ConfigGroup{
APIsGroupKey: &cb.ConfigGroup{
Values: map[string]*cb.ConfigValue{
"Foo": &cb.ConfigValue{
Value: utils.MarshalOrPanic(&pb.Resource{
PolicyRef: "foo",
}),
},
"Bar": &cb.ConfigValue{
Value: utils.MarshalOrPanic(&pb.Resource{
PolicyRef: "/Channel/foo",
}),
},
},
},
PeerPoliciesGroupKey: &cb.ConfigGroup{
Policies: map[string]*cb.ConfigPolicy{
"other": dummyPolicy,
"foo": dummyPolicy,
"bar": dummyPolicy,
},
Groups: map[string]*cb.ConfigGroup{
"subGroup": &cb.ConfigGroup{
Policies: map[string]*cb.ConfigPolicy{
"other": dummyPolicy,
},
},
},
},
},
Expand All @@ -64,8 +70,8 @@ func TestBundleGreenPath(t *testing.T) {
b, err := New(env, nil, nil)
assert.NoError(t, err)
assert.NotNil(t, b)
assert.Equal(t, "/Resources/foo", b.ResourcePolicyMapper().PolicyRefForResource("Foo"))
assert.Equal(t, "/Channel/foo", b.ResourcePolicyMapper().PolicyRefForResource("Bar"))
assert.Equal(t, "/Resources/APIs/foo", b.APIPolicyMapper().PolicyRefForAPI("Foo"))
assert.Equal(t, "/Channel/foo", b.APIPolicyMapper().PolicyRefForAPI("Bar"))

t.Run("Code coverage nits", func(t *testing.T) {
assert.Equal(t, b.RootGroupKey(), RootGroupKey)
Expand All @@ -79,7 +85,7 @@ func TestBundleBadSubGroup(t *testing.T) {
Config: &cb.Config{
ChannelGroup: &cb.ConfigGroup{
Groups: map[string]*cb.ConfigGroup{
"subGroup": &cb.ConfigGroup{
PeerPoliciesGroupKey: &cb.ConfigGroup{
Values: map[string]*cb.ConfigValue{
"Foo": &cb.ConfigValue{
Value: utils.MarshalOrPanic(&pb.Resource{
Expand Down
32 changes: 32 additions & 0 deletions common/resourcesconfig/peerpolicies.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Copyright IBM Corp. 2017 All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package resourcesconfig

import (
cb "github.com/hyperledger/fabric/protos/common"

"github.com/pkg/errors"
)

// peerPoliciesGroup is a free-form group, which supports only policies
type peerPoliciesGroup struct{}

func newPeerPoliciesGroup(group *cb.ConfigGroup) (*peerPoliciesGroup, error) {
return &peerPoliciesGroup{}, verifyNoMoreValues(group)
}

func verifyNoMoreValues(subGroup *cb.ConfigGroup) error {
if len(subGroup.Values) > 0 {
return errors.Errorf("sub-groups not allowed to have values")
}
for _, subGroup := range subGroup.Groups {
if err := verifyNoMoreValues(subGroup); err != nil {
return err
}
}
return nil
}
71 changes: 29 additions & 42 deletions common/resourcesconfig/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,60 +7,47 @@ SPDX-License-Identifier: Apache-2.0
package resourcesconfig

import (
"fmt"

cb "github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"

"github.com/golang/protobuf/proto"
"github.com/pkg/errors"
)

// ResourceGroup represents the ConfigGroup at the base of the resource configuration
type resourceGroup struct {
resourcePolicyRefs map[string]string
}
const (
PeerPoliciesGroupKey = "PeerPolicies"
APIsGroupKey = "APIs"
)

func (rg *resourceGroup) PolicyRefForResource(resourceName string) string {
return rg.resourcePolicyRefs[resourceName]
// resourceGroup represents the ConfigGroup at the base of the resource configuration.
type resourceGroup struct {
apisGroup *apisGroup
peerPoliciesGroup *peerPoliciesGroup
}

func newResourceGroup(root *cb.ConfigGroup) (*resourceGroup, error) {
resourcePolicyRefs := make(map[string]string)

for key, value := range root.Values {
resource := &pb.Resource{}
if err := proto.Unmarshal(value.Value, resource); err != nil {
return nil, err
}

// If the policy is fully qualified, ie to /Channel/Application/Readers leave it alone
// otherwise, make it fully qualified referring to /Resources/policyName
if '/' != resource.PolicyRef[0] {
resourcePolicyRefs[key] = "/" + RootGroupKey + "/" + resource.PolicyRef
} else {
resourcePolicyRefs[key] = resource.PolicyRef
}
if len(root.Values) > 0 {
return nil, errors.New("/Resources group does not support any values")
}

for _, subGroup := range root.Groups {
if err := verifyNoMoreValues(subGroup); err != nil {
return nil, err
}
// initialize the elements with empty implementations, override if actually set
rg := &resourceGroup{
apisGroup: &apisGroup{},
peerPoliciesGroup: &peerPoliciesGroup{},
}

return &resourceGroup{
resourcePolicyRefs: resourcePolicyRefs,
}, nil
}

func verifyNoMoreValues(subGroup *cb.ConfigGroup) error {
if len(subGroup.Values) > 0 {
return fmt.Errorf("sub-groups not allowed to have values")
}
for _, subGroup := range subGroup.Groups {
if err := verifyNoMoreValues(subGroup); err != nil {
return err
for subGroupName, subGroup := range root.Groups {
var err error
switch subGroupName {
case APIsGroupKey:
rg.apisGroup, err = newAPIsGroup(subGroup)
case PeerPoliciesGroupKey:
rg.peerPoliciesGroup, err = newPeerPoliciesGroup(subGroup)
default:
err = errors.New("unknown sub-group")
}
if err != nil {
return nil, errors.Wrapf(err, "error processing group %s", subGroupName)
}
}
return nil

return rg, nil
}
34 changes: 19 additions & 15 deletions core/scc/rscc/rscc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,22 +91,26 @@ func createConfig() []byte {
b := utils.MarshalOrPanic(&common.Config{
Type: int32(common.ConfigType_RESOURCE),
ChannelGroup: &common.ConfigGroup{
// All of the default seed data values would inside this ConfigGroup
Values: map[string]*common.ConfigValue{
"res": &common.ConfigValue{
Value: utils.MarshalOrPanic(&pb.Resource{
PolicyRef: "respol",
}),
ModPolicy: "resmodpol",
},
},
Policies: map[string]*common.ConfigPolicy{
"respol": &common.ConfigPolicy{
Policy: &common.Policy{
Type: int32(common.Policy_SIGNATURE),
Value: utils.MarshalOrPanic(cauthdsl.AcceptAllPolicy),
Groups: map[string]*common.ConfigGroup{
"APIs": &common.ConfigGroup{
// All of the default seed data values would inside this ConfigGroup
Values: map[string]*common.ConfigValue{
"res": &common.ConfigValue{
Value: utils.MarshalOrPanic(&pb.Resource{
PolicyRef: "respol",
}),
ModPolicy: "resmodpol",
},
},
Policies: map[string]*common.ConfigPolicy{
"respol": &common.ConfigPolicy{
Policy: &common.Policy{
Type: int32(common.Policy_SIGNATURE),
Value: utils.MarshalOrPanic(cauthdsl.AcceptAllPolicy),
},
ModPolicy: "Example",
},
},
ModPolicy: "Example",
},
},
ModPolicy: "adminpol",
Expand Down
10 changes: 5 additions & 5 deletions core/scc/rscc/rsccpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (e InvalidIdInfo) Error() string {

//policyEvalutor interface provides the interfaces for policy evaluation
type policyEvaluator interface {
PolicyRefForResource(resName string) string
PolicyRefForAPI(resName string) string
Evaluate(polName string, id []*common.SignedData) error
}

Expand All @@ -44,13 +44,13 @@ type policyEvaluatorImpl struct {
bundle *resourcesconfig.Bundle
}

func (pe *policyEvaluatorImpl) PolicyRefForResource(resName string) string {
pm := pe.bundle.ResourcePolicyMapper()
func (pe *policyEvaluatorImpl) PolicyRefForAPI(resName string) string {
pm := pe.bundle.APIPolicyMapper()
if pm == nil {
return ""
}

return pm.PolicyRefForResource(resName)
return pm.PolicyRefForAPI(resName)
}

func (pe *policyEvaluatorImpl) Evaluate(polName string, sd []*common.SignedData) error {
Expand Down Expand Up @@ -80,7 +80,7 @@ type rsccPolicyProviderImpl struct {

//GetPolicyName returns the policy name given the resource string
func (rp *rsccPolicyProviderImpl) GetPolicyName(resName string) string {
return rp.pEvaluator.PolicyRefForResource(resName)
return rp.pEvaluator.PolicyRefForAPI(resName)
}

func newRsccPolicyProvider(channel string, pEvaluator policyEvaluator) rsccPolicyProvider {
Expand Down
2 changes: 1 addition & 1 deletion core/scc/rscc/rsccpolicy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type mockPolicyEvaluatorImpl struct {
peval map[string]error
}

func (pe *mockPolicyEvaluatorImpl) PolicyRefForResource(resName string) string {
func (pe *mockPolicyEvaluatorImpl) PolicyRefForAPI(resName string) string {
return pe.pmap[resName]
}

Expand Down

0 comments on commit 33e3fb6

Please sign in to comment.