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 }