Skip to content

Commit edd0c07

Browse files
committed
[FAB-2103] Adding ACL enforcement for CC2CC
This change-set does the following: 1. It adds ACL checks to CC2CC invocation. The checks are the following: - If a system chaincode is invoked then the call is just authorized. This assumes that the system chaincodes perform their own access control. - If a normal chaincode is invoked then it is checked that the proposal's creator is a writer on the destination channel. This change-set comes in the context of: https://jira.hyperledger.org/browse/FAB-2103 Change-Id: I7d97fbcb7bc3016bdc235b28efab6c60f3da583c Signed-off-by: Angelo De Caro <[email protected]>
1 parent 0fd4f6f commit edd0c07

File tree

11 files changed

+202
-92
lines changed

11 files changed

+202
-92
lines changed

common/configtx/manager_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/hyperledger/fabric/common/configtx/api"
2424
mockconfigtx "github.com/hyperledger/fabric/common/mocks/configtx"
2525
mockpolicies "github.com/hyperledger/fabric/common/mocks/policies"
26+
"github.com/hyperledger/fabric/common/policies"
2627
cb "github.com/hyperledger/fabric/protos/common"
2728
"github.com/hyperledger/fabric/protos/utils"
2829

@@ -354,7 +355,7 @@ func TestUnchangedConfigViolatesPolicy(t *testing.T) {
354355
}
355356

356357
// Set the mock policy to error
357-
initializer.Resources.PolicyManagerVal.PolicyMap = make(map[string]*mockpolicies.Policy)
358+
initializer.Resources.PolicyManagerVal.PolicyMap = make(map[string]policies.Policy)
358359
initializer.Resources.PolicyManagerVal.PolicyMap["foo"] = &mockpolicies.Policy{Err: fmt.Errorf("err")}
359360

360361
newConfig := makeConfigUpdateEnvelope(

common/mocks/policies/policies.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type Manager struct {
4242
BasePathVal string
4343

4444
// PolicyMap is returned is used to look up Policies in
45-
PolicyMap map[string]*Policy
45+
PolicyMap map[string]policies.Policy
4646

4747
// SubManagers is used for the return value of Manager
4848
SubManagersMap map[string]*Manager

core/chaincode/concurrency_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func TestExecuteConcurrentInvokes(t *testing.T) {
9090
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: chaincodeID, Input: &pb.ChaincodeInput{Args: args}}
9191

9292
//start with a new background
93-
_, _, results[qnum], err = invoke(context.Background(), chainID, spec, nextBlockNumber)
93+
_, _, results[qnum], err = invoke(context.Background(), chainID, spec, nextBlockNumber, nil)
9494

9595
if err != nil {
9696
errs[qnum] = fmt.Errorf("Error executing <%s>: %s", chaincodeID.Name, err)

core/chaincode/exectransaction_test.go

+145-50
Large diffs are not rendered by default.

core/chaincode/handler.go

+26-1
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,16 @@ import (
2525

2626
"github.com/golang/protobuf/proto"
2727
commonledger "github.com/hyperledger/fabric/common/ledger"
28+
"github.com/hyperledger/fabric/common/policies"
2829
"github.com/hyperledger/fabric/common/util"
2930
"github.com/hyperledger/fabric/core/common/ccprovider"
3031
"github.com/hyperledger/fabric/core/common/sysccprovider"
3132
"github.com/hyperledger/fabric/core/container/ccintf"
3233
"github.com/hyperledger/fabric/core/ledger"
3334
"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
3435
"github.com/hyperledger/fabric/core/peer"
36+
"github.com/hyperledger/fabric/core/policy"
37+
"github.com/hyperledger/fabric/msp/mgmt"
3538
pb "github.com/hyperledger/fabric/protos/peer"
3639
"github.com/looplab/fsm"
3740
logging "github.com/op/go-logging"
@@ -85,6 +88,10 @@ type ccParts struct {
8588
suffix string //for now just the chain name
8689
}
8790

91+
func (p *ccParts) String() string {
92+
return p.suffix + "." + p.name + "#" + p.version
93+
}
94+
8895
// Handler responsbile for management of Peer's side of chaincode stream
8996
type Handler struct {
9097
sync.RWMutex
@@ -106,6 +113,8 @@ type Handler struct {
106113

107114
// used to do Send after making sure the state transition is complete
108115
nextState chan *nextStateInfo
116+
117+
policyChecker policy.PolicyChecker
109118
}
110119

111120
func shorttxid(txid string) string {
@@ -251,7 +260,17 @@ func (handler *Handler) checkACL(signedProp *pb.SignedProposal, proposal *pb.Pro
251260
// - an application chaincode (and we still need to determine
252261
// whether the invoker can invoke it)
253262

254-
return nil
263+
if sysccprovider.GetSystemChaincodeProvider().IsSysCC(calledCC.name) {
264+
// Allow this call
265+
return nil
266+
}
267+
268+
// A Nil signedProp will be rejected for non-system chaincodes
269+
if signedProp == nil {
270+
return fmt.Errorf("Signed Proposal must not be nil from caller [%s]", calledCC.String())
271+
}
272+
273+
return handler.policyChecker.CheckPolicy(calledCC.suffix, policies.ChannelApplicationWriters, signedProp)
255274
}
256275

257276
//THIS CAN BE REMOVED ONCE WE FULL SUPPORT (Invoke) CONFIDENTIALITY WITH CC-CALLING-CC
@@ -456,6 +475,12 @@ func newChaincodeSupportHandler(chaincodeSupport *ChaincodeSupport, peerChatStre
456475
},
457476
)
458477

478+
v.policyChecker = policy.NewPolicyChecker(
479+
peer.NewChannelPolicyManagerGetter(),
480+
mgmt.GetLocalMSP(),
481+
mgmt.NewLocalMSPPrincipalGetter(),
482+
)
483+
459484
return v
460485
}
461486

core/chaincode/systemchaincode_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func deploySampleSysCC(t *testing.T, ctxt context.Context, chainID string) error
105105

106106
spec := &pb.ChaincodeSpec{Type: 1, ChaincodeId: &pb.ChaincodeID{Name: "sample_syscc", Path: url, Version: sysCCVers}, Input: &pb.ChaincodeInput{Args: args}}
107107
var nextBlockNumber uint64
108-
_, _, _, err := invokeWithVersion(ctxt, chainID, sysCCVers, spec, nextBlockNumber)
108+
_, _, _, err := invokeWithVersion(ctxt, chainID, sysCCVers, spec, nextBlockNumber, nil)
109109
nextBlockNumber++
110110

111111
cccid := ccprovider.NewCCContext(chainID, "sample_syscc", sysCCVers, "", true, nil, nil)
@@ -119,7 +119,7 @@ func deploySampleSysCC(t *testing.T, ctxt context.Context, chainID string) error
119119
f = "getval"
120120
args = util.ToChaincodeArgs(f, "greeting")
121121
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: &pb.ChaincodeID{Name: "sample_syscc", Path: url, Version: sysCCVers}, Input: &pb.ChaincodeInput{Args: args}}
122-
_, _, _, err = invokeWithVersion(ctxt, chainID, sysCCVers, spec, nextBlockNumber)
122+
_, _, _, err = invokeWithVersion(ctxt, chainID, sysCCVers, spec, nextBlockNumber, nil)
123123
if err != nil {
124124
theChaincodeSupport.Stop(ctxt, cccid, cdsforStop)
125125
t.Logf("Error invoking sample_syscc: %s", err)

core/chaincode/upgrade_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ func TestUpgradeCC(t *testing.T) {
163163
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: chaincodeID, Input: &pb.ChaincodeInput{Args: qArgs}}
164164

165165
//Do not increment block number here because, the block will not be committted because of error
166-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber)
166+
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
167167
if err == nil {
168168
t.Fail()
169169
t.Logf("querying chaincode exampl01 should fail transaction: %s", err)
@@ -200,7 +200,7 @@ func TestUpgradeCC(t *testing.T) {
200200
//go back and do the same query now
201201
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: chaincodeID, Input: &pb.ChaincodeInput{Args: qArgs}}
202202
nextBlockNumber++
203-
_, _, _, err = invokeWithVersion(ctxt, chainID, cccid2.Version, spec, nextBlockNumber)
203+
_, _, _, err = invokeWithVersion(ctxt, chainID, cccid2.Version, spec, nextBlockNumber, nil)
204204

205205
if err != nil {
206206
t.Fail()

core/endorser/endorser.go

+11-25
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ import (
3333
"github.com/hyperledger/fabric/core/common/validation"
3434
"github.com/hyperledger/fabric/core/ledger"
3535
"github.com/hyperledger/fabric/core/peer"
36+
"github.com/hyperledger/fabric/core/policy"
3637
syscc "github.com/hyperledger/fabric/core/scc"
3738
"github.com/hyperledger/fabric/msp"
39+
"github.com/hyperledger/fabric/msp/mgmt"
3840
"github.com/hyperledger/fabric/protos/common"
3941
pb "github.com/hyperledger/fabric/protos/peer"
4042
putils "github.com/hyperledger/fabric/protos/utils"
@@ -47,41 +49,25 @@ var endorserLogger = logging.MustGetLogger("endorser")
4749

4850
// Endorser provides the Endorser service ProcessProposal
4951
type Endorser struct {
52+
policyChecker policy.PolicyChecker
5053
}
5154

5255
// NewEndorserServer creates and returns a new Endorser server instance.
5356
func NewEndorserServer() pb.EndorserServer {
5457
e := new(Endorser)
58+
e.policyChecker = policy.NewPolicyChecker(
59+
peer.NewChannelPolicyManagerGetter(),
60+
mgmt.GetLocalMSP(),
61+
mgmt.NewLocalMSPPrincipalGetter(),
62+
)
63+
5564
return e
5665
}
5766

5867
// checkACL checks that the supplied proposal complies
5968
// with the writers policy of the chain
60-
func (*Endorser) checkACL(signedProp *pb.SignedProposal, chdr *common.ChannelHeader, shdr *common.SignatureHeader, hdrext *pb.ChaincodeHeaderExtension) error {
61-
// get policy manager to check ACLs
62-
pm := peer.GetPolicyManager(chdr.ChannelId)
63-
if pm == nil {
64-
return fmt.Errorf("No policy manager available for chain %s", chdr.ChannelId)
65-
}
66-
67-
// access the policy to use to validate this proposal
68-
policy, _ := pm.GetPolicy(policies.ChannelApplicationWriters)
69-
70-
// evaluate that this proposal complies with the writers
71-
err := policy.Evaluate(
72-
[]*common.SignedData{{
73-
Data: signedProp.ProposalBytes,
74-
Identity: shdr.Creator,
75-
Signature: signedProp.Signature,
76-
}})
77-
if err != nil {
78-
return fmt.Errorf("The proposal does not comply with the %s for channel %s, error %s",
79-
policies.ChannelApplicationWriters,
80-
chdr.ChannelId,
81-
err)
82-
}
83-
84-
return nil
69+
func (e *Endorser) checkACL(signedProp *pb.SignedProposal, chdr *common.ChannelHeader, shdr *common.SignatureHeader, hdrext *pb.ChaincodeHeaderExtension) error {
70+
return e.policyChecker.CheckPolicy(chdr.ChannelId, policies.ChannelApplicationWriters, signedProp)
8571
}
8672

8773
//TODO - check for escc and vscc

core/endorser/endorser_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ func TestWritersACLFail(t *testing.T) {
559559
Err: errors.New("The creator of this proposal does not fulfil the writers policy of this chain"),
560560
}
561561
pm := peer.GetPolicyManager(chainID)
562-
pm.(*mockpolicies.Manager).PolicyMap = map[string]*mockpolicies.Policy{policies.ChannelApplicationWriters: rejectpolicy}
562+
pm.(*mockpolicies.Manager).PolicyMap = map[string]policies.Policy{policies.ChannelApplicationWriters: rejectpolicy}
563563

564564
f = "invoke"
565565
invokeArgs := append([]string{f}, args...)
@@ -594,7 +594,7 @@ func TestAdminACLFail(t *testing.T) {
594594
Err: errors.New("The creator of this proposal does not fulfil the writers policy of this chain"),
595595
}
596596
pm := peer.GetPolicyManager(chainID)
597-
pm.(*mockpolicies.Manager).PolicyMap = map[string]*mockpolicies.Policy{policies.ChannelApplicationAdmins: rejectpolicy}
597+
pm.(*mockpolicies.Manager).PolicyMap = map[string]policies.Policy{policies.ChannelApplicationAdmins: rejectpolicy}
598598

599599
var ctxt = context.Background()
600600

core/peer/peer.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,6 @@ func MockCreateChain(cid string) error {
264264
return err
265265
}
266266

267-
chains.Lock()
268-
defer chains.Unlock()
269-
270267
// Here we need to mock also the policy manager
271268
// in order for the ACL to be checked
272269
initializer := mockconfigtx.Initializer{
@@ -282,11 +279,13 @@ func MockCreateChain(cid string) error {
282279
Transactional: mockconfigtx.Transactional{},
283280
},
284281
}
285-
286282
manager := &mockconfigtx.Manager{
287283
Initializer: initializer,
288284
}
289285

286+
chains.Lock()
287+
defer chains.Unlock()
288+
290289
chains.list[cid] = &chain{
291290
cs: &chainSupport{
292291
Manager: manager,

examples/chaincode/go/chaincode_example04/chaincode_example04.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string
6363
var eventVal int // State of event
6464
var err error
6565

66-
if len(args) != 3 {
67-
return shim.Error("Incorrect number of arguments. Expecting 3")
66+
if len(args) != 3 && len(args) != 4 {
67+
return shim.Error("Incorrect number of arguments. Expecting 3 or 4")
6868
}
6969

7070
chainCodeToCall := args[0]
@@ -73,6 +73,10 @@ func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string
7373
if err != nil {
7474
return shim.Error("Expected integer value for event state change")
7575
}
76+
channelID := ""
77+
if len(args) == 4 {
78+
channelID = args[3]
79+
}
7680

7781
if eventVal != 1 {
7882
fmt.Printf("Unexpected event. Doing nothing\n")
@@ -81,7 +85,7 @@ func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string
8185

8286
f := "invoke"
8387
invokeArgs := util.ToChaincodeArgs(f, "a", "b", "10")
84-
response := stub.InvokeChaincode(chainCodeToCall, invokeArgs, "")
88+
response := stub.InvokeChaincode(chainCodeToCall, invokeArgs, channelID)
8589
if response.Status != shim.OK {
8690
errStr := fmt.Sprintf("Failed to invoke chaincode. Got error: %s", string(response.Payload))
8791
fmt.Printf(errStr)

0 commit comments

Comments
 (0)