github.com/defanghe/fabric@v2.1.1+incompatible/core/aclmgmt/resourceprovider.go (about)

     1  /*
     2  Copyright IBM Corp. 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/hyperledger/fabric-protos-go/common"
    13  	pb "github.com/hyperledger/fabric-protos-go/peer"
    14  	"github.com/hyperledger/fabric/common/channelconfig"
    15  	"github.com/hyperledger/fabric/protoutil"
    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  	return policy.EvaluateSignedData(sd)
    68  }
    69  
    70  //------ resourcePolicyProvider ----------
    71  
    72  //aclmgmtPolicyProvider is the interface implemented by resource based ACL.
    73  type aclmgmtPolicyProvider interface {
    74  	//GetPolicyName returns policy name given resource name
    75  	GetPolicyName(resName string) string
    76  
    77  	//CheckACL backs ACLProvider interface
    78  	CheckACL(polName string, idinfo interface{}) error
    79  }
    80  
    81  //aclmgmtPolicyProviderImpl holds the bytes from state of the ledger
    82  type aclmgmtPolicyProviderImpl struct {
    83  	pEvaluator policyEvaluator
    84  }
    85  
    86  //GetPolicyName returns the policy name given the resource string
    87  func (rp *aclmgmtPolicyProviderImpl) GetPolicyName(resName string) string {
    88  	return rp.pEvaluator.PolicyRefForAPI(resName)
    89  }
    90  
    91  //CheckACL implements AClProvider's CheckACL interface so it can be registered
    92  //as a provider with aclmgmt
    93  func (rp *aclmgmtPolicyProviderImpl) CheckACL(polName string, idinfo interface{}) error {
    94  	aclLogger.Debugf("acl check(%s)", polName)
    95  
    96  	//we will implement other identifiers. In the end we just need a SignedData
    97  	var sd []*protoutil.SignedData
    98  	switch idinfo := idinfo.(type) {
    99  	case *pb.SignedProposal:
   100  		signedProp := idinfo
   101  		proposal, err := protoutil.UnmarshalProposal(signedProp.ProposalBytes)
   102  		if err != nil {
   103  			return fmt.Errorf("Failing extracting proposal during check policy with policy [%s]: [%s]", polName, err)
   104  		}
   105  
   106  		header, err := protoutil.UnmarshalHeader(proposal.Header)
   107  		if err != nil {
   108  			return fmt.Errorf("Failing extracting header during check policy [%s]: [%s]", polName, err)
   109  		}
   110  
   111  		shdr, err := protoutil.UnmarshalSignatureHeader(header.SignatureHeader)
   112  		if err != nil {
   113  			return fmt.Errorf("Invalid Proposal's SignatureHeader during check policy [%s]: [%s]", polName, err)
   114  		}
   115  
   116  		sd = []*protoutil.SignedData{{
   117  			Data:      signedProp.ProposalBytes,
   118  			Identity:  shdr.Creator,
   119  			Signature: signedProp.Signature,
   120  		}}
   121  
   122  	case *common.Envelope:
   123  		var err error
   124  		sd, err = protoutil.EnvelopeAsSignedData(idinfo)
   125  		if err != nil {
   126  			return err
   127  		}
   128  
   129  	default:
   130  		return InvalidIdInfo(polName)
   131  	}
   132  
   133  	err := rp.pEvaluator.Evaluate(polName, sd)
   134  	if err != nil {
   135  		return fmt.Errorf("failed evaluating policy on signed data during check policy [%s]: [%s]", polName, err)
   136  	}
   137  
   138  	return nil
   139  }
   140  
   141  //-------- resource provider - entry point API used by aclmgmtimpl for doing resource based ACL ----------
   142  
   143  //resource getter gets channelconfig.Resources given channel ID
   144  type ResourceGetter func(channelID string) channelconfig.Resources
   145  
   146  //resource provider that uses the resource configuration information to provide ACL support
   147  type resourceProvider struct {
   148  	//resource getter
   149  	resGetter ResourceGetter
   150  
   151  	//default provider to be used for undefined resources
   152  	defaultProvider defaultACLProvider
   153  }
   154  
   155  //create a new resourceProvider
   156  func newResourceProvider(rg ResourceGetter, defprov defaultACLProvider) *resourceProvider {
   157  	return &resourceProvider{rg, defprov}
   158  }
   159  
   160  func (rp *resourceProvider) enforceDefaultBehavior(resName string, channelID string, idinfo interface{}) bool {
   161  	// we currently enforce using p types if defined.  In future we will allow p types
   162  	// to be overridden through peer configuration
   163  	return rp.defaultProvider.IsPtypePolicy(resName)
   164  }
   165  
   166  //CheckACL implements the ACL
   167  func (rp *resourceProvider) CheckACL(resName string, channelID string, idinfo interface{}) error {
   168  	if !rp.enforceDefaultBehavior(resName, channelID, idinfo) {
   169  		resCfg := rp.resGetter(channelID)
   170  
   171  		if resCfg != nil {
   172  			pp := &aclmgmtPolicyProviderImpl{&policyEvaluatorImpl{resCfg}}
   173  			policyName := pp.GetPolicyName(resName)
   174  			if policyName != "" {
   175  				aclLogger.Debugf("acl policy %s found in config for resource %s", policyName, resName)
   176  				return pp.CheckACL(policyName, idinfo)
   177  			}
   178  			aclLogger.Debugf("acl policy not found in config for resource %s", resName)
   179  		}
   180  	}
   181  
   182  	return rp.defaultProvider.CheckACL(resName, channelID, idinfo)
   183  }