forked from hyperledger/fabric
/
policy.go
232 lines (187 loc) · 7.38 KB
/
policy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package policies
import (
"fmt"
"strings"
"github.com/hyperledger/fabric/common/flogging"
cb "github.com/hyperledger/fabric/protos/common"
"github.com/golang/protobuf/proto"
logging "github.com/op/go-logging"
"github.com/pkg/errors"
)
const (
// Path separator is used to separate policy names in paths
PathSeparator = "/"
// ChannelPrefix is used in the path of standard channel policy managers
ChannelPrefix = "Channel"
// ApplicationPrefix is used in the path of standard application policy paths
ApplicationPrefix = "Application"
// OrdererPrefix is used in the path of standard orderer policy paths
OrdererPrefix = "Orderer"
// ChannelReaders is the label for the channel's readers policy (encompassing both orderer and application readers)
ChannelReaders = PathSeparator + ChannelPrefix + PathSeparator + "Readers"
// ChannelWriters is the label for the channel's writers policy (encompassing both orderer and application writers)
ChannelWriters = PathSeparator + ChannelPrefix + PathSeparator + "Writers"
// ChannelApplicationReaders is the label for the channel's application readers policy
ChannelApplicationReaders = PathSeparator + ChannelPrefix + PathSeparator + ApplicationPrefix + PathSeparator + "Readers"
// ChannelApplicationWriters is the label for the channel's application writers policy
ChannelApplicationWriters = PathSeparator + ChannelPrefix + PathSeparator + ApplicationPrefix + PathSeparator + "Writers"
// ChannelApplicationAdmins is the label for the channel's application admin policy
ChannelApplicationAdmins = PathSeparator + ChannelPrefix + PathSeparator + ApplicationPrefix + PathSeparator + "Admins"
// BlockValidation is the label for the policy which should validate the block signatures for the channel
BlockValidation = PathSeparator + ChannelPrefix + PathSeparator + OrdererPrefix + PathSeparator + "BlockValidation"
)
var logger = flogging.MustGetLogger("policies")
// Policy is used to determine if a signature is valid
type Policy interface {
// Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy
Evaluate(signatureSet []*cb.SignedData) error
}
// Manager is a read only subset of the policy ManagerImpl
type Manager interface {
// GetPolicy returns a policy and true if it was the policy requested, or false if it is the default policy
GetPolicy(id string) (Policy, bool)
// Manager returns the sub-policy manager for a given path and whether it exists
Manager(path []string) (Manager, bool)
}
// Provider provides the backing implementation of a policy
type Provider interface {
// NewPolicy creates a new policy based on the policy bytes
NewPolicy(data []byte) (Policy, proto.Message, error)
}
// ChannelPolicyManagerGetter is a support interface
// to get access to the policy manager of a given channel
type ChannelPolicyManagerGetter interface {
// Returns the policy manager associated to the passed channel
// and true if it was the manager requested, or false if it is the default manager
Manager(channelID string) (Manager, bool)
}
// ManagerImpl is an implementation of Manager and configtx.ConfigHandler
// In general, it should only be referenced as an Impl for the configtx.ConfigManager
type ManagerImpl struct {
path string // The group level path
policies map[string]Policy
managers map[string]*ManagerImpl
}
// NewManagerImpl creates a new ManagerImpl with the given CryptoHelper
func NewManagerImpl(path string, providers map[int32]Provider, root *cb.ConfigGroup) (*ManagerImpl, error) {
var err error
_, ok := providers[int32(cb.Policy_IMPLICIT_META)]
if ok {
logger.Panicf("ImplicitMetaPolicy type must be provider by the policy manager")
}
managers := make(map[string]*ManagerImpl)
for groupName, group := range root.Groups {
managers[groupName], err = NewManagerImpl(path+PathSeparator+groupName, providers, group)
if err != nil {
return nil, err
}
}
policies := make(map[string]Policy)
for policyName, configPolicy := range root.Policies {
policy := configPolicy.Policy
if policy == nil {
return nil, fmt.Errorf("policy %s at path %s was nil", policyName, path)
}
var cPolicy Policy
if policy.Type == int32(cb.Policy_IMPLICIT_META) {
imp, err := newImplicitMetaPolicy(policy.Value, managers)
if err != nil {
return nil, errors.Wrapf(err, "implicit policy %s at path %s did not compile", policyName, path)
}
cPolicy = imp
} else {
provider, ok := providers[int32(policy.Type)]
if !ok {
return nil, fmt.Errorf("policy %s at path %s has unknown policy type: %v", policyName, path, policy.Type)
}
var err error
cPolicy, _, err = provider.NewPolicy(policy.Value)
if err != nil {
return nil, errors.Wrapf(err, "policy %s at path %s did not compile", policyName, path)
}
}
policies[policyName] = cPolicy
logger.Debugf("Proposed new policy %s for %s", policyName, path)
}
for groupName, manager := range managers {
for policyName, policy := range manager.policies {
policies[groupName+PathSeparator+policyName] = policy
}
}
return &ManagerImpl{
path: path,
policies: policies,
managers: managers,
}, nil
}
type rejectPolicy string
func (rp rejectPolicy) Evaluate(signedData []*cb.SignedData) error {
return fmt.Errorf("No such policy: '%s'", rp)
}
// Manager returns the sub-policy manager for a given path and whether it exists
func (pm *ManagerImpl) Manager(path []string) (Manager, bool) {
logger.Debugf("Manager %s looking up path %v", pm.path, path)
for manager := range pm.managers {
logger.Debugf("Manager %s has managers %s", pm.path, manager)
}
if len(path) == 0 {
return pm, true
}
m, ok := pm.managers[path[0]]
if !ok {
return nil, false
}
return m.Manager(path[1:])
}
type policyLogger struct {
policy Policy
policyName string
}
func (pl *policyLogger) Evaluate(signatureSet []*cb.SignedData) error {
if logger.IsEnabledFor(logging.DEBUG) {
logger.Debugf("== Evaluating %T Policy %s ==", pl.policy, pl.policyName)
defer logger.Debugf("== Done Evaluating %T Policy %s", pl.policy, pl.policyName)
}
err := pl.policy.Evaluate(signatureSet)
if err != nil {
logger.Debugf("Signature set did not satisfy policy %s", pl.policyName)
} else {
logger.Debugf("Signature set satisfies policy %s", pl.policyName)
}
return err
}
// GetPolicy returns a policy and true if it was the policy requested, or false if it is the default reject policy
func (pm *ManagerImpl) GetPolicy(id string) (Policy, bool) {
if id == "" {
logger.Errorf("Returning dummy reject all policy because no policy ID supplied")
return rejectPolicy(id), false
}
var relpath string
if strings.HasPrefix(id, PathSeparator) {
if !strings.HasPrefix(id, PathSeparator+pm.path) {
if logger.IsEnabledFor(logging.DEBUG) {
logger.Debugf("Requested absolute policy %s from %s, returning rejectAll", id, pm.path)
}
return rejectPolicy(id), false
}
// strip off the leading slash, the path, and the trailing slash
relpath = id[1+len(pm.path)+1:]
} else {
relpath = id
}
policy, ok := pm.policies[relpath]
if !ok {
if logger.IsEnabledFor(logging.DEBUG) {
logger.Debugf("Returning dummy reject all policy because %s could not be found in %s/%s", id, pm.path, relpath)
}
return rejectPolicy(relpath), false
}
return &policyLogger{
policy: policy,
policyName: PathSeparator + pm.path + PathSeparator + relpath,
}, true
}