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  }