forked from ThienLK1/fabric-v2.2
-
Notifications
You must be signed in to change notification settings - Fork 1
/
policy.go
395 lines (324 loc) · 13.1 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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package policies
import (
"fmt"
"strings"
"github.com/golang/protobuf/proto"
cb "github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric-protos-go/msp"
"github.com/hyperledger/fabric/common/flogging"
mspi "github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric/protoutil"
"github.com/pkg/errors"
"go.uber.org/zap/zapcore"
)
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"
// ChannelOrdererAdmins is the label for the channel's orderer admin policy
ChannelOrdererAdmins = PathSeparator + ChannelPrefix + PathSeparator + OrdererPrefix + PathSeparator + "Admins"
// ChannelOrdererWriters is the label for the channel's orderer writers policy
ChannelOrdererWriters = PathSeparator + ChannelPrefix + PathSeparator + OrdererPrefix + PathSeparator + "Writers"
// ChannelOrdererReaders is the label for the channel's orderer readers policy
ChannelOrdererReaders = PathSeparator + ChannelPrefix + PathSeparator + OrdererPrefix + PathSeparator + "Readers"
)
var logger = flogging.MustGetLogger("policies")
// PrincipalSet is a collection of MSPPrincipals
type PrincipalSet []*msp.MSPPrincipal
// PrincipalSets aggregates PrincipalSets
type PrincipalSets []PrincipalSet
// ContainingOnly returns PrincipalSets that contain only principals of the given predicate
func (psSets PrincipalSets) ContainingOnly(f func(*msp.MSPPrincipal) bool) PrincipalSets {
var res PrincipalSets
for _, set := range psSets {
if !set.ContainingOnly(f) {
continue
}
res = append(res, set)
}
return res
}
// ContainingOnly returns whether the given PrincipalSet contains only Principals
// that satisfy the given predicate
func (ps PrincipalSet) ContainingOnly(f func(*msp.MSPPrincipal) bool) bool {
for _, principal := range ps {
if !f(principal) {
return false
}
}
return true
}
// UniqueSet returns a histogram that is induced by the PrincipalSet
func (ps PrincipalSet) UniqueSet() map[*msp.MSPPrincipal]int {
// Create a histogram that holds the MSPPrincipals and counts them
histogram := make(map[struct {
cls int32
principal string
}]int)
// Now, populate the histogram
for _, principal := range ps {
key := struct {
cls int32
principal string
}{
cls: int32(principal.PrincipalClassification),
principal: string(principal.Principal),
}
histogram[key]++
}
// Finally, convert to a histogram of MSPPrincipal pointers
res := make(map[*msp.MSPPrincipal]int)
for principal, count := range histogram {
res[&msp.MSPPrincipal{
PrincipalClassification: msp.MSPPrincipal_Classification(principal.cls),
Principal: []byte(principal.principal),
}] = count
}
return res
}
// Converter represents a policy
// which may be translated into a SignaturePolicyEnvelope
type Converter interface {
Convert() (*cb.SignaturePolicyEnvelope, error)
}
// Policy is used to determine if a signature is valid
type Policy interface {
// EvaluateSignedData takes a set of SignedData and evaluates whether
// 1) the signatures are valid over the related message
// 2) the signing identities satisfy the policy
EvaluateSignedData(signatureSet []*protoutil.SignedData) error
// EvaluateIdentities takes an array of identities and evaluates whether
// they satisfy the policy
EvaluateIdentities(identities []mspi.Identity) error
}
// InquireablePolicy is a Policy that one can inquire
type InquireablePolicy interface {
// SatisfiedBy returns a slice of PrincipalSets that each of them
// satisfies the policy.
SatisfiedBy() []PrincipalSet
}
// 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 with the specified channel.
Manager(channelID string) Manager
}
// PolicyManagerGetterFunc is a function adapater for ChannelPolicyManagerGetter.
type PolicyManagerGetterFunc func(channelID string) Manager
func (p PolicyManagerGetterFunc) Manager(channelID string) Manager { return p(channelID) }
// 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) EvaluateSignedData(signedData []*protoutil.SignedData) error {
return errors.Errorf("no such policy: '%s'", rp)
}
func (rp rejectPolicy) EvaluateIdentities(identities []mspi.Identity) error {
return errors.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) EvaluateSignedData(signatureSet []*protoutil.SignedData) error {
if logger.IsEnabledFor(zapcore.DebugLevel) {
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.EvaluateSignedData(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
}
func (pl *PolicyLogger) EvaluateIdentities(identities []mspi.Identity) error {
if logger.IsEnabledFor(zapcore.DebugLevel) {
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.EvaluateIdentities(identities)
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
}
func (pl *PolicyLogger) Convert() (*cb.SignaturePolicyEnvelope, error) {
logger.Debugf("== Converting %T Policy %s ==", pl.Policy, pl.policyName)
convertiblePolicy, ok := pl.Policy.(Converter)
if !ok {
logger.Errorf("policy (name='%s',type='%T') is not convertible to SignaturePolicyEnvelope", pl.policyName, pl.Policy)
return nil, errors.Errorf("policy (name='%s',type='%T') is not convertible to SignaturePolicyEnvelope", pl.policyName, pl.Policy)
}
cp, err := convertiblePolicy.Convert()
if err != nil {
logger.Errorf("== Error Converting %T Policy %s, err %s", pl.Policy, pl.policyName, err.Error())
} else {
logger.Debugf("== Done Converting %T Policy %s", pl.Policy, pl.policyName)
}
return cp, 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) {
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 {
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
}
// SignatureSetToValidIdentities takes a slice of pointers to signed data,
// checks the validity of the signature and of the signer and returns a
// slice of associated identities. The returned identities are deduplicated.
func SignatureSetToValidIdentities(signedData []*protoutil.SignedData, identityDeserializer mspi.IdentityDeserializer) []mspi.Identity {
idMap := map[string]struct{}{}
identities := make([]mspi.Identity, 0, len(signedData))
for i, sd := range signedData {
identity, err := identityDeserializer.DeserializeIdentity(sd.Identity)
if err != nil {
logger.Warningf("principal deserialization failure (%s) for identity %x", err, sd.Identity)
continue
}
key := identity.GetIdentifier().Mspid + identity.GetIdentifier().Id
// We check if this identity has already appeared before doing a signature check, to ensure that
// someone cannot force us to waste time checking the same signature thousands of times
if _, ok := idMap[key]; ok {
logger.Warningf("De-duplicating identity [%s] at index %d in signature set", key, i)
continue
}
err = identity.Verify(sd.Data, sd.Signature)
if err != nil {
logger.Warningf("signature for identity %d is invalid: %s", i, err)
continue
}
logger.Debugf("signature for identity %d validated", i)
idMap[key] = struct{}{}
identities = append(identities, identity)
}
return identities
}