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

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package aclmgmt
     8  
     9  import (
    10  	"fmt"
    11  
    12  	"github.com/hechain20/hechain/common/channelconfig"
    13  	"github.com/hechain20/hechain/protoutil"
    14  	"github.com/hyperledger/fabric-protos-go/common"
    15  	pb "github.com/hyperledger/fabric-protos-go/peer"
    16  )
    17  
    18  //--------- errors ---------
    19  
    20  // PolicyNotFound cache for resource
    21  type PolicyNotFound string
    22  
    23  func (e PolicyNotFound) Error() string {
    24  	return fmt.Sprintf("policy %s not found", string(e))
    25  }
    26  
    27  // InvalidIdInfo
    28  type InvalidIdInfo string
    29  
    30  func (e InvalidIdInfo) Error() string {
    31  	return fmt.Sprintf("Invalid id for policy [%s]", string(e))
    32  }
    33  
    34  //---------- policyEvaluator ------
    35  
    36  // policyEvalutor interface provides the interfaces for policy evaluation
    37  type policyEvaluator interface {
    38  	PolicyRefForAPI(resName string) string
    39  	Evaluate(polName string, id []*protoutil.SignedData) error
    40  }
    41  
    42  // policyEvaluatorImpl implements policyEvaluator
    43  type policyEvaluatorImpl struct {
    44  	bundle channelconfig.Resources
    45  }
    46  
    47  func (pe *policyEvaluatorImpl) PolicyRefForAPI(resName string) string {
    48  	app, exists := pe.bundle.ApplicationConfig()
    49  	if !exists {
    50  		return ""
    51  	}
    52  
    53  	pm := app.APIPolicyMapper()
    54  	if pm == nil {
    55  		return ""
    56  	}
    57  
    58  	return pm.PolicyRefForAPI(resName)
    59  }
    60  
    61  func (pe *policyEvaluatorImpl) Evaluate(polName string, sd []*protoutil.SignedData) error {
    62  	policy, ok := pe.bundle.PolicyManager().GetPolicy(polName)
    63  	if !ok {
    64  		return PolicyNotFound(polName)
    65  	}
    66  
    67  	err := policy.EvaluateSignedData(sd)
    68  	if err != nil {
    69  		aclLogger.Warnw("EvaluateSignedData policy check failed", "error", err, "policyName", polName, policy, "policy", "signingIdentities", protoutil.LogMessageForSerializedIdentities(sd))
    70  	}
    71  	return err
    72  }
    73  
    74  //------ resourcePolicyProvider ----------
    75  
    76  // aclmgmtPolicyProvider is the interface implemented by resource based ACL.
    77  type aclmgmtPolicyProvider interface {
    78  	// GetPolicyName returns policy name given resource name
    79  	GetPolicyName(resName string) string
    80  
    81  	// CheckACL backs ACLProvider interface
    82  	CheckACL(polName string, idinfo interface{}) error
    83  }
    84  
    85  // aclmgmtPolicyProviderImpl holds the bytes from state of the ledger
    86  type aclmgmtPolicyProviderImpl struct {
    87  	pEvaluator policyEvaluator
    88  }
    89  
    90  // GetPolicyName returns the policy name given the resource string
    91  func (rp *aclmgmtPolicyProviderImpl) GetPolicyName(resName string) string {
    92  	return rp.pEvaluator.PolicyRefForAPI(resName)
    93  }
    94  
    95  // CheckACL implements AClProvider's CheckACL interface so it can be registered
    96  // as a provider with aclmgmt
    97  func (rp *aclmgmtPolicyProviderImpl) CheckACL(polName string, idinfo interface{}) error {
    98  	aclLogger.Debugf("acl check(%s)", polName)
    99  
   100  	// we will implement other identifiers. In the end we just need a SignedData
   101  	var sd []*protoutil.SignedData
   102  	switch idinfo := idinfo.(type) {
   103  	case *pb.SignedProposal:
   104  		signedProp := idinfo
   105  		proposal, err := protoutil.UnmarshalProposal(signedProp.ProposalBytes)
   106  		if err != nil {
   107  			return fmt.Errorf("Failing extracting proposal during check policy with policy [%s]: [%s]", polName, err)
   108  		}
   109  
   110  		header, err := protoutil.UnmarshalHeader(proposal.Header)
   111  		if err != nil {
   112  			return fmt.Errorf("Failing extracting header during check policy [%s]: [%s]", polName, err)
   113  		}
   114  
   115  		shdr, err := protoutil.UnmarshalSignatureHeader(header.SignatureHeader)
   116  		if err != nil {
   117  			return fmt.Errorf("Invalid Proposal's SignatureHeader during check policy [%s]: [%s]", polName, err)
   118  		}
   119  
   120  		sd = []*protoutil.SignedData{{
   121  			Data:      signedProp.ProposalBytes,
   122  			Identity:  shdr.Creator,
   123  			Signature: signedProp.Signature,
   124  		}}
   125  
   126  	case *common.Envelope:
   127  		var err error
   128  		sd, err = protoutil.EnvelopeAsSignedData(idinfo)
   129  		if err != nil {
   130  			return err
   131  		}
   132  
   133  	case *protoutil.SignedData:
   134  		sd = []*protoutil.SignedData{idinfo}
   135  
   136  	default:
   137  		return InvalidIdInfo(polName)
   138  	}
   139  
   140  	err := rp.pEvaluator.Evaluate(polName, sd)
   141  	if err != nil {
   142  		return fmt.Errorf("failed evaluating policy on signed data during check policy [%s]: [%s]", polName, err)
   143  	}
   144  
   145  	return nil
   146  }
   147  
   148  //-------- resource provider - entry point API used by aclmgmtimpl for doing resource based ACL ----------
   149  
   150  // resource getter gets channelconfig.Resources given channel ID
   151  type ResourceGetter func(channelID string) channelconfig.Resources
   152  
   153  // resource provider that uses the resource configuration information to provide ACL support
   154  type resourceProvider struct {
   155  	// resource getter
   156  	resGetter ResourceGetter
   157  
   158  	// default provider to be used for undefined resources
   159  	defaultProvider defaultACLProvider
   160  }
   161  
   162  // create a new resourceProvider
   163  func newResourceProvider(rg ResourceGetter, defprov defaultACLProvider) *resourceProvider {
   164  	return &resourceProvider{rg, defprov}
   165  }
   166  
   167  func (rp *resourceProvider) enforceDefaultBehavior(resName string, channelID string, idinfo interface{}) bool {
   168  	// we currently enforce using p types if defined.  In future we will allow p types
   169  	// to be overridden through peer configuration
   170  	return rp.defaultProvider.IsPtypePolicy(resName)
   171  }
   172  
   173  // CheckACL implements the ACL
   174  func (rp *resourceProvider) CheckACL(resName string, channelID string, idinfo interface{}) error {
   175  	if !rp.enforceDefaultBehavior(resName, channelID, idinfo) {
   176  		resCfg := rp.resGetter(channelID)
   177  
   178  		if resCfg != nil {
   179  			pp := &aclmgmtPolicyProviderImpl{&policyEvaluatorImpl{resCfg}}
   180  			policyName := pp.GetPolicyName(resName)
   181  			if policyName != "" {
   182  				aclLogger.Debugf("acl policy %s found in config for resource %s", policyName, resName)
   183  				return pp.CheckACL(policyName, idinfo)
   184  			}
   185  			aclLogger.Debugf("acl policy not found in config for resource %s", resName)
   186  		}
   187  	}
   188  
   189  	return rp.defaultProvider.CheckACL(resName, channelID, idinfo)
   190  }
   191  
   192  // CheckACLNoChannel implements the ACLProvider interface function
   193  func (rp *resourceProvider) CheckACLNoChannel(resName string, idinfo interface{}) error {
   194  	if !rp.enforceDefaultBehavior(resName, "", idinfo) {
   195  		return fmt.Errorf("cannot override peer type policy for channeless ACL check")
   196  	}
   197  
   198  	return rp.defaultProvider.CheckACLNoChannel(resName, idinfo)
   199  }