github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/policy/policy.go (about)

     1  /*
     2  Copyright hechain. 2017 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package policy
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  
    13  	"github.com/hechain20/hechain/common/flogging"
    14  	"github.com/hechain20/hechain/common/policies"
    15  	"github.com/hechain20/hechain/msp"
    16  	"github.com/hechain20/hechain/protoutil"
    17  	pb "github.com/hyperledger/fabric-protos-go/peer"
    18  )
    19  
    20  var logger = flogging.MustGetLogger("policy")
    21  
    22  // PolicyChecker offers methods to check a signed proposal against a specific policy
    23  // defined in a channel or not.
    24  type PolicyChecker interface {
    25  	// CheckPolicy checks that the passed signed proposal is valid with the respect to
    26  	// passed policy on the passed channel.
    27  	// If no channel is passed, CheckPolicyNoChannel is invoked directly.
    28  	CheckPolicy(channelID, policyName string, signedProp *pb.SignedProposal) error
    29  
    30  	// CheckPolicyBySignedData checks that the passed signed data is valid with the respect to
    31  	// passed policy on the passed channel.
    32  	// If no channel is passed, the method will fail.
    33  	CheckPolicyBySignedData(channelID, policyName string, sd []*protoutil.SignedData) error
    34  
    35  	// CheckPolicyNoChannel checks that the passed signed proposal is valid with the respect to
    36  	// passed policy on the local MSP.
    37  	CheckPolicyNoChannel(policyName string, signedProp *pb.SignedProposal) error
    38  
    39  	// CheckPolicyNoChannelBySignedData checks that the passed signed data is valid with the respect to
    40  	// passed policy on the local MSP.
    41  	CheckPolicyNoChannelBySignedData(policyName string, signedData []*protoutil.SignedData) error
    42  }
    43  
    44  type policyChecker struct {
    45  	channelPolicyManagerGetter policies.ChannelPolicyManagerGetter
    46  	localMSP                   msp.IdentityDeserializer
    47  	principalGetter            MSPPrincipalGetter
    48  }
    49  
    50  // NewPolicyChecker creates a new instance of PolicyChecker
    51  func NewPolicyChecker(channelPolicyManagerGetter policies.ChannelPolicyManagerGetter, localMSP msp.MSP) PolicyChecker {
    52  	return &policyChecker{
    53  		channelPolicyManagerGetter: channelPolicyManagerGetter,
    54  		localMSP:                   localMSP,
    55  		principalGetter:            &localMSPPrincipalGetter{localMSP: localMSP},
    56  	}
    57  }
    58  
    59  // CheckPolicy checks that the passed signed proposal is valid with the respect to
    60  // passed policy on the passed channel.
    61  func (p *policyChecker) CheckPolicy(channelID, policyName string, signedProp *pb.SignedProposal) error {
    62  	if channelID == "" {
    63  		return p.CheckPolicyNoChannel(policyName, signedProp)
    64  	}
    65  
    66  	if policyName == "" {
    67  		return fmt.Errorf("Invalid policy name during check policy on channel [%s]. Name must be different from nil.", channelID)
    68  	}
    69  
    70  	if signedProp == nil {
    71  		return fmt.Errorf("Invalid signed proposal during check policy on channel [%s] with policy [%s]", channelID, policyName)
    72  	}
    73  
    74  	// Get Policy
    75  	policyManager := p.channelPolicyManagerGetter.Manager(channelID)
    76  	if policyManager == nil {
    77  		return fmt.Errorf("Failed to get policy manager for channel [%s]", channelID)
    78  	}
    79  
    80  	// Prepare SignedData
    81  	proposal, err := protoutil.UnmarshalProposal(signedProp.ProposalBytes)
    82  	if err != nil {
    83  		return fmt.Errorf("Failing extracting proposal during check policy on channel [%s] with policy [%s]: [%s]", channelID, policyName, err)
    84  	}
    85  
    86  	header, err := protoutil.UnmarshalHeader(proposal.Header)
    87  	if err != nil {
    88  		return fmt.Errorf("Failing extracting header during check policy on channel [%s] with policy [%s]: [%s]", channelID, policyName, err)
    89  	}
    90  
    91  	shdr, err := protoutil.UnmarshalSignatureHeader(header.SignatureHeader)
    92  	if err != nil {
    93  		return fmt.Errorf("Invalid Proposal's SignatureHeader during check policy on channel [%s] with policy [%s]: [%s]", channelID, policyName, err)
    94  	}
    95  
    96  	sd := []*protoutil.SignedData{{
    97  		Data:      signedProp.ProposalBytes,
    98  		Identity:  shdr.Creator,
    99  		Signature: signedProp.Signature,
   100  	}}
   101  
   102  	return p.CheckPolicyBySignedData(channelID, policyName, sd)
   103  }
   104  
   105  // CheckPolicyNoChannel checks that the passed signed proposal is valid with the respect to
   106  // passed policy on the local MSP.
   107  func (p *policyChecker) CheckPolicyNoChannel(policyName string, signedProp *pb.SignedProposal) error {
   108  	if policyName == "" {
   109  		return errors.New("Invalid policy name during channelless check policy. Name must be different from nil.")
   110  	}
   111  
   112  	if signedProp == nil {
   113  		return fmt.Errorf("Invalid signed proposal during channelless check policy with policy [%s]", policyName)
   114  	}
   115  
   116  	proposal, err := protoutil.UnmarshalProposal(signedProp.ProposalBytes)
   117  	if err != nil {
   118  		return fmt.Errorf("Failing extracting proposal during channelless check policy with policy [%s]: [%s]", policyName, err)
   119  	}
   120  
   121  	header, err := protoutil.UnmarshalHeader(proposal.Header)
   122  	if err != nil {
   123  		return fmt.Errorf("Failing extracting header during channelless check policy with policy [%s]: [%s]", policyName, err)
   124  	}
   125  
   126  	shdr, err := protoutil.UnmarshalSignatureHeader(header.SignatureHeader)
   127  	if err != nil {
   128  		return fmt.Errorf("Invalid Proposal's SignatureHeader during channelless check policy with policy [%s]: [%s]", policyName, err)
   129  	}
   130  
   131  	// Deserialize proposal's creator with the local MSP
   132  	id, err := p.localMSP.DeserializeIdentity(shdr.Creator)
   133  	if err != nil {
   134  		logger.Warnw("Failed deserializing proposal creator during channelless check policy", "error", err, "policyName", policyName, "identity", protoutil.LogMessageForSerializedIdentity(shdr.Creator))
   135  		return fmt.Errorf("Failed deserializing proposal creator during channelless check policy with policy [%s]: [%s]", policyName, err)
   136  	}
   137  
   138  	// Load MSPPrincipal for policy
   139  	principal, err := p.principalGetter.Get(policyName)
   140  	if err != nil {
   141  		return fmt.Errorf("Failed getting local MSP principal during channelless check policy with policy [%s]: [%s]", policyName, err)
   142  	}
   143  
   144  	// Verify that proposal's creator satisfies the principal
   145  	err = id.SatisfiesPrincipal(principal)
   146  	if err != nil {
   147  		logger.Warnw("Failed verifying that proposal's creator satisfies local MSP principal during channelless check policy", "error", err, "policyName", policyName, "requiredPrincipal", principal, "signingIdentity", protoutil.LogMessageForSerializedIdentity(shdr.Creator))
   148  		return fmt.Errorf("Failed verifying that proposal's creator satisfies local MSP principal during channelless check policy with policy [%s]: [%s]", policyName, err)
   149  	}
   150  
   151  	// Verify the signature
   152  	return id.Verify(signedProp.ProposalBytes, signedProp.Signature)
   153  }
   154  
   155  // CheckPolicyBySignedData checks that the passed signed data is valid with the respect to
   156  // passed policy on the passed channel.
   157  func (p *policyChecker) CheckPolicyBySignedData(channelID, policyName string, sd []*protoutil.SignedData) error {
   158  	if channelID == "" {
   159  		return errors.New("Invalid channel ID name during check policy on signed data. Name must be different from nil.")
   160  	}
   161  
   162  	if policyName == "" {
   163  		return fmt.Errorf("Invalid policy name during check policy on signed data on channel [%s]. Name must be different from nil.", channelID)
   164  	}
   165  
   166  	if sd == nil {
   167  		return fmt.Errorf("Invalid signed data during check policy on channel [%s] with policy [%s]", channelID, policyName)
   168  	}
   169  
   170  	// Get Policy
   171  	policyManager := p.channelPolicyManagerGetter.Manager(channelID)
   172  	if policyManager == nil {
   173  		return fmt.Errorf("Failed to get policy manager for channel [%s]", channelID)
   174  	}
   175  
   176  	// Recall that get policy always returns a policy object
   177  	policy, _ := policyManager.GetPolicy(policyName)
   178  
   179  	// Evaluate the policy
   180  	err := policy.EvaluateSignedData(sd)
   181  	if err != nil {
   182  		logger.Warnw("Failed evaluating policy on signed data", "error", err, "policyName", policyName, "identities", protoutil.LogMessageForSerializedIdentities(sd))
   183  		return fmt.Errorf("Failed evaluating policy on signed data during check policy on channel [%s] with policy [%s]: [%s]", channelID, policyName, err)
   184  	}
   185  
   186  	return nil
   187  }
   188  
   189  // CheckPolicyNoChannelBySignedData checks that the passed signed data are valid with the respect to
   190  // passed policy on the local MSP.
   191  func (p *policyChecker) CheckPolicyNoChannelBySignedData(policyName string, signedData []*protoutil.SignedData) error {
   192  	if policyName == "" {
   193  		return errors.New("invalid policy name during channelless check policy. Name must be different from nil.")
   194  	}
   195  
   196  	if len(signedData) == 0 {
   197  		return fmt.Errorf("no signed data during channelless check policy with policy [%s]", policyName)
   198  	}
   199  
   200  	for _, data := range signedData {
   201  		// Deserialize identity with the local MSP
   202  		id, err := p.localMSP.DeserializeIdentity(data.Identity)
   203  		if err != nil {
   204  			logger.Warnw("Failed deserializing signed data identity during channelless check policy", "error", err, "policyName", policyName, "identity", protoutil.LogMessageForSerializedIdentity(data.Identity))
   205  			return fmt.Errorf("failed deserializing signed data identity during channelless check policy with policy [%s]: [%s]", policyName, err)
   206  		}
   207  
   208  		// Load MSPPrincipal for policy
   209  		principal, err := p.principalGetter.Get(policyName)
   210  		if err != nil {
   211  			return fmt.Errorf("failed getting local MSP principal during channelless check policy with policy [%s]: [%s]", policyName, err)
   212  		}
   213  
   214  		// Verify that proposal's creator satisfies the principal
   215  		err = id.SatisfiesPrincipal(principal)
   216  		if err != nil {
   217  			logger.Warnw("failed verifying that the signed data identity satisfies local MSP principal during channelless check policy", "error", err, "policyName", policyName, "requiredPrincipal", principal, "identity", protoutil.LogMessageForSerializedIdentity(data.Identity))
   218  			return fmt.Errorf("failed verifying that the signed data identity satisfies local MSP principal during channelless check policy with policy [%s]: [%s]", policyName, err)
   219  		}
   220  
   221  		// Verify the signature
   222  		if err = id.Verify(data.Data, data.Signature); err != nil {
   223  			return err
   224  		}
   225  	}
   226  
   227  	return nil
   228  }