github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/core/policy/policy.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package policy 18 19 import ( 20 "fmt" 21 22 "errors" 23 24 "github.com/hyperledger/fabric/common/policies" 25 "github.com/hyperledger/fabric/msp" 26 "github.com/hyperledger/fabric/msp/mgmt" 27 "github.com/hyperledger/fabric/protos/common" 28 pb "github.com/hyperledger/fabric/protos/peer" 29 "github.com/hyperledger/fabric/protos/utils" 30 ) 31 32 // PolicyChecker offers methods to check a signed proposal against a specific policy 33 // defined in a channel or not. 34 type PolicyChecker interface { 35 // CheckPolicy checks that the passed signed proposal is valid with the respect to 36 // passed policy on the passed channel. 37 // If no channel is passed, CheckPolicyNoChannel is invoked directly. 38 CheckPolicy(channelID, policyName string, signedProp *pb.SignedProposal) error 39 40 // CheckPolicyBySignedData checks that the passed signed data is valid with the respect to 41 // passed policy on the passed channel. 42 // If no channel is passed, the method will fail. 43 CheckPolicyBySignedData(channelID, policyName string, sd []*common.SignedData) error 44 45 // CheckPolicyNoChannel checks that the passed signed proposal is valid with the respect to 46 // passed policy on the local MSP. 47 CheckPolicyNoChannel(policyName string, signedProp *pb.SignedProposal) error 48 } 49 50 type policyChecker struct { 51 channelPolicyManagerGetter policies.ChannelPolicyManagerGetter 52 localMSP msp.IdentityDeserializer 53 principalGetter mgmt.MSPPrincipalGetter 54 } 55 56 // NewPolicyChecker creates a new instance of PolicyChecker 57 func NewPolicyChecker(channelPolicyManagerGetter policies.ChannelPolicyManagerGetter, localMSP msp.IdentityDeserializer, principalGetter mgmt.MSPPrincipalGetter) PolicyChecker { 58 return &policyChecker{channelPolicyManagerGetter, localMSP, principalGetter} 59 } 60 61 // CheckPolicy checks that the passed signed proposal is valid with the respect to 62 // passed policy on the passed channel. 63 func (p *policyChecker) CheckPolicy(channelID, policyName string, signedProp *pb.SignedProposal) error { 64 if channelID == "" { 65 return p.CheckPolicyNoChannel(policyName, signedProp) 66 } 67 68 if policyName == "" { 69 return fmt.Errorf("Invalid policy name during check policy on channel [%s]. Name must be different from nil.", channelID) 70 } 71 72 if signedProp == nil { 73 return fmt.Errorf("Invalid signed proposal during check policy on channel [%s] with policy [%s]", channelID, policyName) 74 } 75 76 // Get Policy 77 policyManager, _ := p.channelPolicyManagerGetter.Manager(channelID) 78 if policyManager == nil { 79 return fmt.Errorf("Failed to get policy manager for channel [%s]", channelID) 80 } 81 82 // Prepare SignedData 83 proposal, err := utils.GetProposal(signedProp.ProposalBytes) 84 if err != nil { 85 return fmt.Errorf("Failing extracting proposal during check policy on channel [%s] with policy [%s]: [%s]", channelID, policyName, err) 86 } 87 88 header, err := utils.GetHeader(proposal.Header) 89 if err != nil { 90 return fmt.Errorf("Failing extracting header during check policy on channel [%s] with policy [%s]: [%s]", channelID, policyName, err) 91 } 92 93 shdr, err := utils.GetSignatureHeader(header.SignatureHeader) 94 if err != nil { 95 return fmt.Errorf("Invalid Proposal's SignatureHeader during check policy on channel [%s] with policy [%s]: [%s]", channelID, policyName, err) 96 } 97 98 sd := []*common.SignedData{&common.SignedData{ 99 Data: signedProp.ProposalBytes, 100 Identity: shdr.Creator, 101 Signature: signedProp.Signature, 102 }} 103 104 return p.CheckPolicyBySignedData(channelID, policyName, sd) 105 } 106 107 // CheckPolicyNoChannel checks that the passed signed proposal is valid with the respect to 108 // passed policy on the local MSP. 109 func (p *policyChecker) CheckPolicyNoChannel(policyName string, signedProp *pb.SignedProposal) error { 110 if policyName == "" { 111 return errors.New("Invalid policy name during channelless check policy. Name must be different from nil.") 112 } 113 114 if signedProp == nil { 115 return fmt.Errorf("Invalid signed proposal during channelless check policy with policy [%s]", policyName) 116 } 117 118 proposal, err := utils.GetProposal(signedProp.ProposalBytes) 119 if err != nil { 120 return fmt.Errorf("Failing extracting proposal during channelless check policy with policy [%s]: [%s]", policyName, err) 121 } 122 123 header, err := utils.GetHeader(proposal.Header) 124 if err != nil { 125 return fmt.Errorf("Failing extracting header during channelless check policy with policy [%s]: [%s]", policyName, err) 126 } 127 128 shdr, err := utils.GetSignatureHeader(header.SignatureHeader) 129 if err != nil { 130 return fmt.Errorf("Invalid Proposal's SignatureHeader during channelless check policy with policy [%s]: [%s]", policyName, err) 131 } 132 133 // Deserialize proposal's creator with the local MSP 134 id, err := p.localMSP.DeserializeIdentity(shdr.Creator) 135 if err != nil { 136 return fmt.Errorf("Failed deserializing proposal creator during channelless check policy with policy [%s]: [%s]", policyName, err) 137 } 138 139 // Load MSPPrincipal for policy 140 principal, err := p.principalGetter.Get(policyName) 141 if err != nil { 142 return fmt.Errorf("Failed getting local MSP principal during channelless check policy with policy [%s]: [%s]", policyName, err) 143 } 144 145 // Verify that proposal's creator satisfies the principal 146 err = id.SatisfiesPrincipal(principal) 147 if err != nil { 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 []*common.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.Evaluate(sd) 181 if err != nil { 182 return fmt.Errorf("Failed evaluating policy on signed data during check policy on channel [%s] with policy [%s]: [%s]", channelID, policyName, err) 183 } 184 185 return nil 186 } 187 188 var pcFactory PolicyCheckerFactory 189 190 // PolicyCheckerFactory defines a factory interface so 191 // that the actual implementation can be injected 192 type PolicyCheckerFactory interface { 193 NewPolicyChecker() PolicyChecker 194 } 195 196 // RegisterPolicyCheckerFactory is to be called once to set 197 // the factory that will be used to obtain instances of PolicyChecker 198 func RegisterPolicyCheckerFactory(f PolicyCheckerFactory) { 199 pcFactory = f 200 } 201 202 // GetPolicyChecker returns instances of PolicyChecker; 203 // the actual implementation is controlled by the factory that 204 // is registered via RegisterPolicyCheckerFactory 205 func GetPolicyChecker() PolicyChecker { 206 if pcFactory == nil { 207 panic("The factory must be set first via RegisterPolicyCheckerFactory") 208 } 209 return pcFactory.NewPolicyChecker() 210 }