Skip to content

Commit 22d2d5c

Browse files
author
Jason Yellick
committed
[FAB-2322] Allow mod_policy to be relative
https://jira.hyperledger.org/browse/FAB-2322 With the notion of hierarchical policies, the configuration mod_policy needs to be able to refer to policies in the current group (relatively) or policies relative to the channel root configuration (absolute). This CR modifies the policy lookup to ask the relative policy manager unless the policy begins with a "/" in which case the policy is retrieved from the root policy manager. Change-Id: Id14e327a5c37c4c1848521abd691aa857a12039d Signed-off-by: Jason Yellick <[email protected]>
1 parent a971b0f commit 22d2d5c

File tree

3 files changed

+121
-7
lines changed

3 files changed

+121
-7
lines changed

common/configtx/update.go

+20-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package configtx
1818

1919
import (
2020
"fmt"
21+
"strings"
2122

2223
"github.com/hyperledger/fabric/common/policies"
2324
cb "github.com/hyperledger/fabric/protos/common"
@@ -94,12 +95,15 @@ func (cm *configManager) authorizeUpdate(configUpdateEnv *cb.ConfigUpdateEnvelop
9495

9596
// Get the modification policy for this config item if one was previously specified
9697
// or accept it if it is new, as the group policy will be evaluated for its inclusion
97-
var policy policies.Policy
9898
if ok {
99-
policy, _ = cm.PolicyManager().GetPolicy(oldValue.modPolicy())
99+
policy, ok := cm.policyForItem(oldValue)
100+
if !ok {
101+
return nil, fmt.Errorf("Unexpected missing policy %s for item %s", oldValue.modPolicy(), key)
102+
}
103+
100104
// Ensure the policy is satisfied
101105
if err = policy.Evaluate(signedData); err != nil {
102-
return nil, err
106+
return nil, fmt.Errorf("Policy for %s not satisfied: %s", key, err)
103107
}
104108
}
105109

@@ -118,6 +122,19 @@ func (cm *configManager) authorizeUpdate(configUpdateEnv *cb.ConfigUpdateEnvelop
118122
return cm.computeUpdateResult(configMap), nil
119123
}
120124

125+
func (cm *configManager) policyForItem(item comparable) (policies.Policy, bool) {
126+
if strings.HasPrefix(item.modPolicy(), PathSeparator) {
127+
return cm.PolicyManager().GetPolicy(item.modPolicy()[1:])
128+
}
129+
130+
// path is always at least of length 1
131+
manager, ok := cm.PolicyManager().Manager(item.path[1:])
132+
if !ok {
133+
return nil, ok
134+
}
135+
return manager.GetPolicy(item.modPolicy())
136+
}
137+
121138
// computeUpdateResult takes a configMap generated by an update and produces a new configMap overlaying it onto the old config
122139
func (cm *configManager) computeUpdateResult(updatedConfig map[string]comparable) map[string]comparable {
123140
newConfigMap := make(map[string]comparable)

common/configtx/update_test.go

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package configtx
18+
19+
import (
20+
"fmt"
21+
"testing"
22+
23+
mockconfigtx "github.com/hyperledger/fabric/common/mocks/configtx"
24+
mockpolicies "github.com/hyperledger/fabric/common/mocks/policies"
25+
cb "github.com/hyperledger/fabric/protos/common"
26+
27+
"github.com/stretchr/testify/assert"
28+
)
29+
30+
func TestPolicyForItem(t *testing.T) {
31+
// Policies are set to different error values to differentiate them in equal assertion
32+
rootPolicy := &mockpolicies.Policy{Err: fmt.Errorf("rootPolicy")}
33+
fooPolicy := &mockpolicies.Policy{Err: fmt.Errorf("fooPolicy")}
34+
35+
cm := &configManager{
36+
Resources: &mockconfigtx.Resources{
37+
PolicyManagerVal: &mockpolicies.Manager{
38+
BasePathVal: "root",
39+
Policy: rootPolicy,
40+
SubManagersMap: map[string]*mockpolicies.Manager{
41+
"foo": &mockpolicies.Manager{
42+
Policy: fooPolicy,
43+
BasePathVal: "foo",
44+
},
45+
},
46+
},
47+
},
48+
}
49+
50+
policy, ok := cm.policyForItem(comparable{
51+
path: []string{"root"},
52+
ConfigValue: &cb.ConfigValue{
53+
ModPolicy: "rootPolicy",
54+
},
55+
})
56+
assert.True(t, ok)
57+
assert.Equal(t, policy, rootPolicy, "Should have found relative policy off the root manager")
58+
59+
policy, ok = cm.policyForItem(comparable{
60+
path: []string{"root", "wrong"},
61+
ConfigValue: &cb.ConfigValue{
62+
ModPolicy: "rootPolicy",
63+
},
64+
})
65+
assert.False(t, ok, "Should not have found rootPolicy off a non-existant manager")
66+
67+
policy, ok = cm.policyForItem(comparable{
68+
path: []string{"root", "foo"},
69+
ConfigValue: &cb.ConfigValue{
70+
ModPolicy: "foo",
71+
},
72+
})
73+
assert.True(t, ok)
74+
assert.Equal(t, policy, fooPolicy, "Should not have found relative foo policy the foo manager")
75+
76+
policy, ok = cm.policyForItem(comparable{
77+
path: []string{"root", "foo"},
78+
ConfigValue: &cb.ConfigValue{
79+
ModPolicy: "/rootPolicy",
80+
},
81+
})
82+
assert.True(t, ok)
83+
assert.Equal(t, policy, rootPolicy, "Should not have found absolute root policy from the foo path position")
84+
}

common/mocks/policies/policies.go

+17-4
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,20 @@ type Manager struct {
4343

4444
// PolicyMap is returned is used to look up Policies in
4545
PolicyMap map[string]*Policy
46+
47+
// SubManagers is used for the return value of Manager and SubManagers
48+
SubManagersMap map[string]*Manager
4649
}
4750

48-
// Managers panics
51+
// Managers returns the values of SubManagers
4952
func (m *Manager) SubManagers() []policies.Manager {
50-
panic("Unimplimented")
53+
result := make([]policies.Manager, len(m.SubManagersMap))
54+
i := 0
55+
for _, manager := range m.SubManagersMap {
56+
result[i] = manager
57+
i++
58+
}
59+
return result
5160
}
5261

5362
// PolicyNames panics
@@ -60,9 +69,13 @@ func (m *Manager) BasePath() string {
6069
return m.BasePathVal
6170
}
6271

63-
// Manager always returns itself
72+
// Manager returns the Manager from SubManagers for the last component of the path
6473
func (m *Manager) Manager(path []string) (policies.Manager, bool) {
65-
return m, true
74+
if len(path) == 0 {
75+
return m, true
76+
}
77+
manager, ok := m.SubManagersMap[path[len(path)-1]]
78+
return manager, ok
6679
}
6780

6881
// GetPolicy returns the value of Manager.Policy and whether it was nil or not

0 commit comments

Comments
 (0)