278 lines
6.9 KiB
Go
278 lines
6.9 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package configtx
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/hyperledger/fabric-config/configtx/internal/policydsl"
|
|
cb "github.com/hyperledger/fabric-protos-go/common"
|
|
mb "github.com/hyperledger/fabric-protos-go/msp"
|
|
)
|
|
|
|
// getPolicies returns a map of Policy from given map of ConfigPolicy in organization config group.
|
|
func getPolicies(policies map[string]*cb.ConfigPolicy) (map[string]Policy, error) {
|
|
p := map[string]Policy{}
|
|
|
|
for name, policy := range policies {
|
|
switch cb.Policy_PolicyType(policy.Policy.Type) {
|
|
case cb.Policy_IMPLICIT_META:
|
|
imp := &cb.ImplicitMetaPolicy{}
|
|
err := proto.Unmarshal(policy.Policy.Value, imp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rule, err := implicitMetaToString(imp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
p[name] = Policy{
|
|
Type: ImplicitMetaPolicyType,
|
|
Rule: rule,
|
|
ModPolicy: policy.GetModPolicy(),
|
|
}
|
|
case cb.Policy_SIGNATURE:
|
|
sp := &cb.SignaturePolicyEnvelope{}
|
|
err := proto.Unmarshal(policy.Policy.Value, sp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rule, err := signatureMetaToString(sp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
p[name] = Policy{
|
|
Type: SignaturePolicyType,
|
|
Rule: rule,
|
|
ModPolicy: policy.GetModPolicy(),
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("unknown policy type: %v", policy.Policy.Type)
|
|
}
|
|
}
|
|
|
|
return p, nil
|
|
}
|
|
|
|
// implicitMetaToString converts a *cb.ImplicitMetaPolicy to a string representation.
|
|
func implicitMetaToString(imp *cb.ImplicitMetaPolicy) (string, error) {
|
|
var args string
|
|
|
|
switch imp.Rule {
|
|
case cb.ImplicitMetaPolicy_ANY:
|
|
args += cb.ImplicitMetaPolicy_ANY.String()
|
|
case cb.ImplicitMetaPolicy_ALL:
|
|
args += cb.ImplicitMetaPolicy_ALL.String()
|
|
case cb.ImplicitMetaPolicy_MAJORITY:
|
|
args += cb.ImplicitMetaPolicy_MAJORITY.String()
|
|
default:
|
|
return "", fmt.Errorf("unknown implicit meta policy rule type %v", imp.Rule)
|
|
}
|
|
|
|
args = args + " " + imp.SubPolicy
|
|
|
|
return args, nil
|
|
}
|
|
|
|
// signatureMetaToString converts a *cb.SignaturePolicyEnvelope to a string representation.
|
|
func signatureMetaToString(sig *cb.SignaturePolicyEnvelope) (string, error) {
|
|
var roles []string
|
|
|
|
for _, id := range sig.Identities {
|
|
role, err := mspPrincipalToString(id)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
roles = append(roles, role)
|
|
}
|
|
|
|
return signaturePolicyToString(sig.Rule, roles)
|
|
}
|
|
|
|
// mspPrincipalToString converts a *mb.MSPPrincipal to a string representation.
|
|
func mspPrincipalToString(principal *mb.MSPPrincipal) (string, error) {
|
|
switch principal.PrincipalClassification {
|
|
case mb.MSPPrincipal_ROLE:
|
|
var res strings.Builder
|
|
|
|
role := &mb.MSPRole{}
|
|
|
|
err := proto.Unmarshal(principal.Principal, role)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
res.WriteString("'")
|
|
res.WriteString(role.MspIdentifier)
|
|
res.WriteString(".")
|
|
res.WriteString(strings.ToLower(role.Role.String()))
|
|
res.WriteString("'")
|
|
|
|
return res.String(), nil
|
|
// TODO: currently fabric only support string to principle convertion for
|
|
// type ROLE. Implement MSPPrinciple to String for types ORGANIZATION_UNIT,
|
|
// IDENTITY, ANONYMITY, and GOMBINED once we have support from fabric.
|
|
case mb.MSPPrincipal_ORGANIZATION_UNIT:
|
|
return "", nil
|
|
case mb.MSPPrincipal_IDENTITY:
|
|
return "", nil
|
|
case mb.MSPPrincipal_ANONYMITY:
|
|
return "", nil
|
|
case mb.MSPPrincipal_COMBINED:
|
|
return "", nil
|
|
default:
|
|
return "", fmt.Errorf("unknown MSP principal classiciation %v", principal.PrincipalClassification)
|
|
}
|
|
}
|
|
|
|
// signaturePolicyToString recursively converts a *cb.SignaturePolicy to a
|
|
// string representation.
|
|
func signaturePolicyToString(sig *cb.SignaturePolicy, IDs []string) (string, error) {
|
|
switch sig.Type.(type) {
|
|
case *cb.SignaturePolicy_NOutOf_:
|
|
nOutOf := sig.GetNOutOf()
|
|
|
|
var policies []string
|
|
|
|
var res strings.Builder
|
|
|
|
// get gate values
|
|
gate := policydsl.GateOutOf
|
|
if nOutOf.N == 1 {
|
|
gate = policydsl.GateOr
|
|
}
|
|
|
|
if nOutOf.N == int32(len(nOutOf.Rules)) {
|
|
gate = policydsl.GateAnd
|
|
}
|
|
|
|
if gate == policydsl.GateOutOf {
|
|
policies = append(policies, strconv.Itoa(int(nOutOf.N)))
|
|
}
|
|
|
|
// get subpolicies recursively
|
|
for _, rule := range nOutOf.Rules {
|
|
subPolicy, err := signaturePolicyToString(rule, IDs)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
policies = append(policies, subPolicy)
|
|
}
|
|
|
|
res.WriteString(strings.ToUpper(gate))
|
|
res.WriteString("(")
|
|
res.WriteString(strings.Join(policies, ", "))
|
|
res.WriteString(")")
|
|
|
|
return res.String(), nil
|
|
case *cb.SignaturePolicy_SignedBy:
|
|
return IDs[sig.GetSignedBy()], nil
|
|
default:
|
|
return "", fmt.Errorf("unknown signature policy type %v", sig.Type)
|
|
}
|
|
}
|
|
|
|
func setPolicies(cg *cb.ConfigGroup, policyMap map[string]Policy) error {
|
|
if policyMap == nil {
|
|
return errors.New("no policies defined")
|
|
}
|
|
|
|
if _, ok := policyMap[AdminsPolicyKey]; !ok {
|
|
return errors.New("no Admins policy defined")
|
|
}
|
|
|
|
if _, ok := policyMap[ReadersPolicyKey]; !ok {
|
|
return errors.New("no Readers policy defined")
|
|
}
|
|
|
|
if _, ok := policyMap[WritersPolicyKey]; !ok {
|
|
return errors.New("no Writers policy defined")
|
|
}
|
|
|
|
cg.Policies = make(map[string]*cb.ConfigPolicy)
|
|
for policyName, policy := range policyMap {
|
|
err := setPolicy(cg, policyName, policy)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func setPolicy(cg *cb.ConfigGroup, policyName string, policy Policy) error {
|
|
if cg.Policies == nil {
|
|
cg.Policies = make(map[string]*cb.ConfigPolicy)
|
|
}
|
|
|
|
switch policy.Type {
|
|
case ImplicitMetaPolicyType:
|
|
imp, err := implicitMetaFromString(policy.Rule)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid implicit meta policy rule: '%s': %v", policy.Rule, err)
|
|
}
|
|
|
|
implicitMetaPolicy, err := proto.Marshal(imp)
|
|
if err != nil {
|
|
return fmt.Errorf("marshaling implicit meta policy: %v", err)
|
|
}
|
|
|
|
if policy.ModPolicy == "" {
|
|
policy.ModPolicy = AdminsPolicyKey
|
|
}
|
|
|
|
cg.Policies[policyName] = &cb.ConfigPolicy{
|
|
ModPolicy: policy.ModPolicy,
|
|
Policy: &cb.Policy{
|
|
Type: int32(cb.Policy_IMPLICIT_META),
|
|
Value: implicitMetaPolicy,
|
|
},
|
|
}
|
|
case SignaturePolicyType:
|
|
sp, err := policydsl.FromString(policy.Rule)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid signature policy rule: '%s': %v", policy.Rule, err)
|
|
}
|
|
|
|
signaturePolicy, err := proto.Marshal(sp)
|
|
if err != nil {
|
|
return fmt.Errorf("marshaling signature policy: %v", err)
|
|
}
|
|
|
|
if policy.ModPolicy == "" {
|
|
policy.ModPolicy = AdminsPolicyKey
|
|
}
|
|
|
|
cg.Policies[policyName] = &cb.ConfigPolicy{
|
|
ModPolicy: policy.ModPolicy,
|
|
Policy: &cb.Policy{
|
|
Type: int32(cb.Policy_SIGNATURE),
|
|
Value: signaturePolicy,
|
|
},
|
|
}
|
|
default:
|
|
return fmt.Errorf("unknown policy type: %s", policy.Type)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// removePolicy removes an existing policy from an group key organization.
|
|
func removePolicy(configGroup *cb.ConfigGroup, policyName string, policies map[string]Policy) {
|
|
delete(configGroup.Policies, policyName)
|
|
}
|