Skip to content

Commit c3c1216

Browse files
committed
[FAB-2969] Access control at LSCC
This change-set does the following: 1. Add access control to lscc by verifying that the caller has appropriate rights. Tests have been modified to cover this access control It is left to complete access control for instantiation. This will be put in place once the instantation process gets completed. This change-set comes in the context of 1. https://jira.hyperledger.org/browse/FAB-2969 Change-Id: Ife15a69f963e33ce32704598e4febe24742bcb9c Signed-off-by: Angelo De Caro <[email protected]>
1 parent 88ac3ba commit c3c1216

File tree

6 files changed

+499
-29
lines changed

6 files changed

+499
-29
lines changed

core/chaincode/exectransaction_test.go

+22-4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import (
4242
"github.com/hyperledger/fabric/core/ledger"
4343
"github.com/hyperledger/fabric/core/ledger/util/couchdb"
4444
"github.com/hyperledger/fabric/core/peer"
45+
"github.com/hyperledger/fabric/core/policy"
4546
"github.com/hyperledger/fabric/core/scc"
4647
pb "github.com/hyperledger/fabric/protos/peer"
4748
putils "github.com/hyperledger/fabric/protos/utils"
@@ -93,6 +94,9 @@ func initPeer(chainIDs ...string) (net.Listener, error) {
9394
ccStartupTimeout := time.Duration(chaincodeStartupTimeoutDefault) * time.Millisecond
9495
pb.RegisterChaincodeSupportServer(grpcServer, NewChaincodeSupport(getPeerEndpoint, false, ccStartupTimeout))
9596

97+
// Mock policy checker
98+
policy.RegisterPolicyCheckerFactory(&mockPolicyCheckerFactory{})
99+
96100
scc.RegisterSysCCs()
97101

98102
for _, id := range chainIDs {
@@ -313,15 +317,16 @@ func deploy2(ctx context.Context, cccid *ccprovider.CCContext, chaincodeDeployme
313317
ccprovider.PutChaincodeIntoFS(chaincodeDeploymentSpec)
314318

315319
sysCCVers := util.GetSysCCVersion()
316-
lsccid := ccprovider.NewCCContext(cccid.ChainID, cis.ChaincodeSpec.ChaincodeId.Name, sysCCVers, uuid, true, nil, nil)
320+
sprop, prop := putils.MockSignedEndorserProposalOrPanic(cccid.ChainID, cis.ChaincodeSpec, []byte("Admin"), []byte("msg1"))
321+
lsccid := ccprovider.NewCCContext(cccid.ChainID, cis.ChaincodeSpec.ChaincodeId.Name, sysCCVers, uuid, true, sprop, prop)
317322

318323
//write to lscc
319324
if _, _, err = ExecuteWithErrorFilter(ctx, lsccid, cis); err != nil {
320-
return nil, fmt.Errorf("Error deploying chaincode: %s", err)
325+
return nil, fmt.Errorf("Error deploying chaincode (1): %s", err)
321326
}
322327

323328
if b, _, err = ExecuteWithErrorFilter(ctx, cccid, chaincodeDeploymentSpec); err != nil {
324-
return nil, fmt.Errorf("Error deploying chaincode: %s", err)
329+
return nil, fmt.Errorf("Error deploying chaincode(2): %s", err)
325330
}
326331

327332
return b, nil
@@ -356,7 +361,10 @@ func invokeWithVersion(ctx context.Context, chainID string, version string, spec
356361
}
357362
}()
358363

359-
sprop, prop := putils.MockSignedEndorserProposalOrPanic(util.GetTestChainID(), spec, creator, nil)
364+
if len(creator) == 0 {
365+
creator = []byte("Admin")
366+
}
367+
sprop, prop := putils.MockSignedEndorserProposalOrPanic(chainID, spec, creator, []byte("msg1"))
360368
cccid := ccprovider.NewCCContext(chainID, cdInvocationSpec.ChaincodeSpec.ChaincodeId.Name, version, uuid, false, sprop, prop)
361369
retval, ccevt, err = ExecuteWithErrorFilter(ctx, cccid, cdInvocationSpec)
362370
if err != nil {
@@ -1797,3 +1805,13 @@ func (c *CreatorPolicy) Evaluate(signatureSet []*common.SignedData) error {
17971805
}
17981806
return fmt.Errorf("Creator not recognized [%s]", string(signatureSet[0].Identity))
17991807
}
1808+
1809+
type mockPolicyCheckerFactory struct{}
1810+
1811+
func (f *mockPolicyCheckerFactory) NewPolicyChecker() policy.PolicyChecker {
1812+
return policy.NewPolicyChecker(
1813+
peer.NewChannelPolicyManagerGetter(),
1814+
&policy.MockIdentityDeserializer{[]byte("Admin"), []byte("msg1")},
1815+
&policy.MockMSPPrincipalGetter{Principal: []byte("Admin")},
1816+
)
1817+
}

core/committer/txvalidator/validator.go

+42-2
Original file line numberDiff line numberDiff line change
@@ -403,11 +403,13 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b
403403
// of VSCC and of the policy that should be used
404404

405405
// obtain name of the VSCC and the policy from LSCC
406-
vscc, policy, err = v.ccprovider.GetCCValidationInfoFromLSCC(ctxt, txid, nil, nil, chainID, hdrExt.ChaincodeId.Name)
406+
cd, err := v.getCDataForCC(hdrExt.ChaincodeId.Name)
407407
if err != nil {
408-
logger.Errorf("Unable to get chaincode data from LSCC for txid %s, due to %s", txid, err)
408+
logger.Errorf("Unable to get chaincode data from ledger for txid %s, due to %s", txid, err)
409409
return err
410410
}
411+
vscc = cd.Vscc
412+
policy = cd.Policy
411413
} else {
412414
// when we are validating LSCC, we use the default
413415
// VSCC and a default policy that requires one signature
@@ -442,3 +444,41 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b
442444

443445
return nil
444446
}
447+
448+
func (v *vsccValidatorImpl) getCDataForCC(ccid string) (*ccprovider.ChaincodeData, error) {
449+
l := v.support.Ledger()
450+
if l == nil {
451+
return nil, fmt.Errorf("nil ledger instance")
452+
}
453+
454+
qe, err := l.NewQueryExecutor()
455+
if err != nil {
456+
return nil, fmt.Errorf("Could not retrieve QueryExecutor, error %s", err)
457+
}
458+
defer qe.Done()
459+
460+
bytes, err := qe.GetState("lscc", ccid)
461+
if err != nil {
462+
return nil, fmt.Errorf("Could not retrieve state for chaincode %s, error %s", ccid, err)
463+
}
464+
465+
if bytes == nil {
466+
return nil, fmt.Errorf("lscc's state for [%s] not found.", ccid)
467+
}
468+
469+
cd := &ccprovider.ChaincodeData{}
470+
err = proto.Unmarshal(bytes, cd)
471+
if err != nil {
472+
return nil, fmt.Errorf("Unmarshalling ChaincodeQueryResponse failed, error %s", err)
473+
}
474+
475+
if cd.Vscc == "" {
476+
return nil, fmt.Errorf("lscc's state for [%s] is invalid, vscc field must be set.", ccid)
477+
}
478+
479+
if len(cd.Policy) == 0 {
480+
return nil, fmt.Errorf("lscc's state for [%s] is invalid, policy field must be set.", ccid)
481+
}
482+
483+
return cd, err
484+
}

core/policy/policy.go

+24
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,27 @@ func (p *policyChecker) CheckPolicyBySignedData(channelID, policyName string, sd
184184

185185
return nil
186186
}
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+
}

core/policyprovider/provider.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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 policyprovider
18+
19+
import (
20+
"github.com/hyperledger/fabric/core/peer"
21+
"github.com/hyperledger/fabric/core/policy"
22+
"github.com/hyperledger/fabric/msp/mgmt"
23+
)
24+
25+
// init is called when this package is loaded. This implementation registers the factory
26+
func init() {
27+
policy.RegisterPolicyCheckerFactory(&defaultFactory{})
28+
}
29+
30+
type defaultFactory struct{}
31+
32+
func (f *defaultFactory) NewPolicyChecker() policy.PolicyChecker {
33+
return policy.NewPolicyChecker(
34+
peer.NewChannelPolicyManagerGetter(),
35+
mgmt.GetLocalMSP(),
36+
mgmt.NewLocalMSPPrincipalGetter(),
37+
)
38+
}
39+
40+
// GetPolicyChecker returns instances of PolicyChecker;
41+
func GetPolicyChecker() policy.PolicyChecker {
42+
return policy.GetPolicyChecker()
43+
}

core/scc/lscc/lscc.go

+49
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,14 @@ import (
2323
"github.com/golang/protobuf/proto"
2424
"github.com/hyperledger/fabric/common/cauthdsl"
2525
"github.com/hyperledger/fabric/common/flogging"
26+
"github.com/hyperledger/fabric/common/policies"
2627
"github.com/hyperledger/fabric/core/chaincode/shim"
2728
"github.com/hyperledger/fabric/core/common/ccprovider"
2829
"github.com/hyperledger/fabric/core/common/sysccprovider"
2930
"github.com/hyperledger/fabric/core/peer"
31+
"github.com/hyperledger/fabric/core/policy"
32+
"github.com/hyperledger/fabric/core/policyprovider"
33+
"github.com/hyperledger/fabric/msp/mgmt"
3034
pb "github.com/hyperledger/fabric/protos/peer"
3135
"github.com/hyperledger/fabric/protos/utils"
3236
)
@@ -82,6 +86,10 @@ type LifeCycleSysCC struct {
8286
// methods of the system chaincode package without
8387
// import cycles
8488
sccprovider sysccprovider.SystemChaincodeProvider
89+
90+
// policyChecker is the interface used to perform
91+
// access control
92+
policyChecker policy.PolicyChecker
8593
}
8694

8795
//----------------errors---------------
@@ -564,6 +572,10 @@ func (lscc *LifeCycleSysCC) executeUpgrade(stub shim.ChaincodeStubInterface, cha
564572
//Init only initializes the system chaincode provider
565573
func (lscc *LifeCycleSysCC) Init(stub shim.ChaincodeStubInterface) pb.Response {
566574
lscc.sccprovider = sysccprovider.GetSystemChaincodeProvider()
575+
576+
// Init policy checker for access control
577+
lscc.policyChecker = policyprovider.GetPolicyChecker()
578+
567579
return shim.Success(nil)
568580
}
569581

@@ -580,12 +592,24 @@ func (lscc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response
580592

581593
function := string(args[0])
582594

595+
// Handle ACL:
596+
// 1. get the signed proposal
597+
sp, err := stub.GetSignedProposal()
598+
if err != nil {
599+
return shim.Error(fmt.Sprintf("Failed retrieving signed proposal on executing %s with error %s", function, err))
600+
}
601+
583602
switch function {
584603
case INSTALL:
585604
if len(args) < 2 {
586605
return shim.Error(InvalidArgsLenErr(len(args)).Error())
587606
}
588607

608+
// 2. check local MSP Admins policy
609+
if err = lscc.policyChecker.CheckPolicyNoChannel(mgmt.Admins, sp); err != nil {
610+
return shim.Error(fmt.Sprintf("Authorization for INSTALL on %s has been denied with error %s", args[1], err))
611+
}
612+
589613
depSpec := args[1]
590614

591615
err := lscc.executeInstall(stub, depSpec)
@@ -598,6 +622,9 @@ func (lscc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response
598622
return shim.Error(InvalidArgsLenErr(len(args)).Error())
599623
}
600624

625+
// TODO: add access control check
626+
// once the instantiation process will be completed.
627+
601628
//chain the chaincode shoud be associated with. It
602629
//should be created with a register call
603630
chainname := string(args[1])
@@ -652,6 +679,9 @@ func (lscc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response
652679
return shim.Error(InvalidChainNameErr(chainname).Error())
653680
}
654681

682+
// TODO: add access control check
683+
// once the instantiation process will be completed.
684+
655685
depSpec := args[2]
656686

657687
// optional arguments here (they can each be nil and may or may not be present)
@@ -696,6 +726,13 @@ func (lscc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response
696726
chain := string(args[1])
697727
ccname := string(args[2])
698728

729+
// 2. check local Channel Readers policy
730+
// Notice that this information are already available on the ledger
731+
// therefore we enforce here that the caller is reader of the channel.
732+
if err = lscc.policyChecker.CheckPolicy(chain, policies.ChannelApplicationReaders, sp); err != nil {
733+
return shim.Error(fmt.Sprintf("Authorization for %s on channel %s has been denied with error %s", function, args[1], err))
734+
}
735+
699736
cdbytes, err := lscc.getCCInstance(stub, ccname)
700737
if err != nil {
701738
logger.Errorf("error getting chaincode %s on channel: %s(err:%s)", ccname, chain, err)
@@ -722,11 +759,23 @@ func (lscc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response
722759
if len(args) != 1 {
723760
return shim.Error(InvalidArgsLenErr(len(args)).Error())
724761
}
762+
763+
// 2. check local MSP Admins policy
764+
if err = lscc.policyChecker.CheckPolicyNoChannel(mgmt.Admins, sp); err != nil {
765+
return shim.Error(fmt.Sprintf("Authorization for GETCHAINCODES on channel %s has been denied with error %s", args[0], err))
766+
}
767+
725768
return lscc.getChaincodes(stub)
726769
case GETINSTALLEDCHAINCODES:
727770
if len(args) != 1 {
728771
return shim.Error(InvalidArgsLenErr(len(args)).Error())
729772
}
773+
774+
// 2. check local MSP Admins policy
775+
if err = lscc.policyChecker.CheckPolicyNoChannel(mgmt.Admins, sp); err != nil {
776+
return shim.Error(fmt.Sprintf("Authorization for GETINSTALLEDCHAINCODES on channel %s has been denied with error %s", args[0], err))
777+
}
778+
730779
return lscc.getInstalledChaincodes()
731780
}
732781

0 commit comments

Comments
 (0)