diff --git a/core/chaincode/exectransaction_test.go b/core/chaincode/exectransaction_test.go index f64f5f9bb25..3435595f44b 100644 --- a/core/chaincode/exectransaction_test.go +++ b/core/chaincode/exectransaction_test.go @@ -42,6 +42,7 @@ import ( "github.com/hyperledger/fabric/core/ledger" "github.com/hyperledger/fabric/core/ledger/util/couchdb" "github.com/hyperledger/fabric/core/peer" + "github.com/hyperledger/fabric/core/policy" "github.com/hyperledger/fabric/core/scc" pb "github.com/hyperledger/fabric/protos/peer" putils "github.com/hyperledger/fabric/protos/utils" @@ -93,6 +94,9 @@ func initPeer(chainIDs ...string) (net.Listener, error) { ccStartupTimeout := time.Duration(chaincodeStartupTimeoutDefault) * time.Millisecond pb.RegisterChaincodeSupportServer(grpcServer, NewChaincodeSupport(getPeerEndpoint, false, ccStartupTimeout)) + // Mock policy checker + policy.RegisterPolicyCheckerFactory(&mockPolicyCheckerFactory{}) + scc.RegisterSysCCs() for _, id := range chainIDs { @@ -313,15 +317,16 @@ func deploy2(ctx context.Context, cccid *ccprovider.CCContext, chaincodeDeployme ccprovider.PutChaincodeIntoFS(chaincodeDeploymentSpec) sysCCVers := util.GetSysCCVersion() - lsccid := ccprovider.NewCCContext(cccid.ChainID, cis.ChaincodeSpec.ChaincodeId.Name, sysCCVers, uuid, true, nil, nil) + sprop, prop := putils.MockSignedEndorserProposalOrPanic(cccid.ChainID, cis.ChaincodeSpec, []byte("Admin"), []byte("msg1")) + lsccid := ccprovider.NewCCContext(cccid.ChainID, cis.ChaincodeSpec.ChaincodeId.Name, sysCCVers, uuid, true, sprop, prop) //write to lscc if _, _, err = ExecuteWithErrorFilter(ctx, lsccid, cis); err != nil { - return nil, fmt.Errorf("Error deploying chaincode: %s", err) + return nil, fmt.Errorf("Error deploying chaincode (1): %s", err) } if b, _, err = ExecuteWithErrorFilter(ctx, cccid, chaincodeDeploymentSpec); err != nil { - return nil, fmt.Errorf("Error deploying chaincode: %s", err) + return nil, fmt.Errorf("Error deploying chaincode(2): %s", err) } return b, nil @@ -356,7 +361,10 @@ func invokeWithVersion(ctx context.Context, chainID string, version string, spec } }() - sprop, prop := putils.MockSignedEndorserProposalOrPanic(util.GetTestChainID(), spec, creator, nil) + if len(creator) == 0 { + creator = []byte("Admin") + } + sprop, prop := putils.MockSignedEndorserProposalOrPanic(chainID, spec, creator, []byte("msg1")) cccid := ccprovider.NewCCContext(chainID, cdInvocationSpec.ChaincodeSpec.ChaincodeId.Name, version, uuid, false, sprop, prop) retval, ccevt, err = ExecuteWithErrorFilter(ctx, cccid, cdInvocationSpec) if err != nil { @@ -1797,3 +1805,13 @@ func (c *CreatorPolicy) Evaluate(signatureSet []*common.SignedData) error { } return fmt.Errorf("Creator not recognized [%s]", string(signatureSet[0].Identity)) } + +type mockPolicyCheckerFactory struct{} + +func (f *mockPolicyCheckerFactory) NewPolicyChecker() policy.PolicyChecker { + return policy.NewPolicyChecker( + peer.NewChannelPolicyManagerGetter(), + &policy.MockIdentityDeserializer{[]byte("Admin"), []byte("msg1")}, + &policy.MockMSPPrincipalGetter{Principal: []byte("Admin")}, + ) +} diff --git a/core/committer/txvalidator/validator.go b/core/committer/txvalidator/validator.go index c31a42adb38..2318cfcf560 100644 --- a/core/committer/txvalidator/validator.go +++ b/core/committer/txvalidator/validator.go @@ -403,11 +403,13 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b // of VSCC and of the policy that should be used // obtain name of the VSCC and the policy from LSCC - vscc, policy, err = v.ccprovider.GetCCValidationInfoFromLSCC(ctxt, txid, nil, nil, chainID, hdrExt.ChaincodeId.Name) + cd, err := v.getCDataForCC(hdrExt.ChaincodeId.Name) if err != nil { - logger.Errorf("Unable to get chaincode data from LSCC for txid %s, due to %s", txid, err) + logger.Errorf("Unable to get chaincode data from ledger for txid %s, due to %s", txid, err) return err } + vscc = cd.Vscc + policy = cd.Policy } else { // when we are validating LSCC, we use the default // VSCC and a default policy that requires one signature @@ -442,3 +444,41 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b return nil } + +func (v *vsccValidatorImpl) getCDataForCC(ccid string) (*ccprovider.ChaincodeData, error) { + l := v.support.Ledger() + if l == nil { + return nil, fmt.Errorf("nil ledger instance") + } + + qe, err := l.NewQueryExecutor() + if err != nil { + return nil, fmt.Errorf("Could not retrieve QueryExecutor, error %s", err) + } + defer qe.Done() + + bytes, err := qe.GetState("lscc", ccid) + if err != nil { + return nil, fmt.Errorf("Could not retrieve state for chaincode %s, error %s", ccid, err) + } + + if bytes == nil { + return nil, fmt.Errorf("lscc's state for [%s] not found.", ccid) + } + + cd := &ccprovider.ChaincodeData{} + err = proto.Unmarshal(bytes, cd) + if err != nil { + return nil, fmt.Errorf("Unmarshalling ChaincodeQueryResponse failed, error %s", err) + } + + if cd.Vscc == "" { + return nil, fmt.Errorf("lscc's state for [%s] is invalid, vscc field must be set.", ccid) + } + + if len(cd.Policy) == 0 { + return nil, fmt.Errorf("lscc's state for [%s] is invalid, policy field must be set.", ccid) + } + + return cd, err +} diff --git a/core/policy/policy.go b/core/policy/policy.go index 8dba1d21519..690e5a168a8 100644 --- a/core/policy/policy.go +++ b/core/policy/policy.go @@ -184,3 +184,27 @@ func (p *policyChecker) CheckPolicyBySignedData(channelID, policyName string, sd return nil } + +var pcFactory PolicyCheckerFactory + +// PolicyCheckerFactory defines a factory interface so +// that the actual implementation can be injected +type PolicyCheckerFactory interface { + NewPolicyChecker() PolicyChecker +} + +// RegisterPolicyCheckerFactory is to be called once to set +// the factory that will be used to obtain instances of PolicyChecker +func RegisterPolicyCheckerFactory(f PolicyCheckerFactory) { + pcFactory = f +} + +// GetPolicyChecker returns instances of PolicyChecker; +// the actual implementation is controlled by the factory that +// is registered via RegisterPolicyCheckerFactory +func GetPolicyChecker() PolicyChecker { + if pcFactory == nil { + panic("The factory must be set first via RegisterPolicyCheckerFactory") + } + return pcFactory.NewPolicyChecker() +} diff --git a/core/policyprovider/provider.go b/core/policyprovider/provider.go new file mode 100644 index 00000000000..46af56b645f --- /dev/null +++ b/core/policyprovider/provider.go @@ -0,0 +1,43 @@ +/* +Copyright IBM Corp. 2017 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package policyprovider + +import ( + "github.com/hyperledger/fabric/core/peer" + "github.com/hyperledger/fabric/core/policy" + "github.com/hyperledger/fabric/msp/mgmt" +) + +// init is called when this package is loaded. This implementation registers the factory +func init() { + policy.RegisterPolicyCheckerFactory(&defaultFactory{}) +} + +type defaultFactory struct{} + +func (f *defaultFactory) NewPolicyChecker() policy.PolicyChecker { + return policy.NewPolicyChecker( + peer.NewChannelPolicyManagerGetter(), + mgmt.GetLocalMSP(), + mgmt.NewLocalMSPPrincipalGetter(), + ) +} + +// GetPolicyChecker returns instances of PolicyChecker; +func GetPolicyChecker() policy.PolicyChecker { + return policy.GetPolicyChecker() +} diff --git a/core/scc/lscc/lscc.go b/core/scc/lscc/lscc.go index 35a54b647f4..13767afc932 100644 --- a/core/scc/lscc/lscc.go +++ b/core/scc/lscc/lscc.go @@ -23,10 +23,14 @@ import ( "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/common/cauthdsl" "github.com/hyperledger/fabric/common/flogging" + "github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/core/common/ccprovider" "github.com/hyperledger/fabric/core/common/sysccprovider" "github.com/hyperledger/fabric/core/peer" + "github.com/hyperledger/fabric/core/policy" + "github.com/hyperledger/fabric/core/policyprovider" + "github.com/hyperledger/fabric/msp/mgmt" pb "github.com/hyperledger/fabric/protos/peer" "github.com/hyperledger/fabric/protos/utils" ) @@ -82,6 +86,10 @@ type LifeCycleSysCC struct { // methods of the system chaincode package without // import cycles sccprovider sysccprovider.SystemChaincodeProvider + + // policyChecker is the interface used to perform + // access control + policyChecker policy.PolicyChecker } //----------------errors--------------- @@ -564,6 +572,10 @@ func (lscc *LifeCycleSysCC) executeUpgrade(stub shim.ChaincodeStubInterface, cha //Init only initializes the system chaincode provider func (lscc *LifeCycleSysCC) Init(stub shim.ChaincodeStubInterface) pb.Response { lscc.sccprovider = sysccprovider.GetSystemChaincodeProvider() + + // Init policy checker for access control + lscc.policyChecker = policyprovider.GetPolicyChecker() + return shim.Success(nil) } @@ -580,12 +592,24 @@ func (lscc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response function := string(args[0]) + // Handle ACL: + // 1. get the signed proposal + sp, err := stub.GetSignedProposal() + if err != nil { + return shim.Error(fmt.Sprintf("Failed retrieving signed proposal on executing %s with error %s", function, err)) + } + switch function { case INSTALL: if len(args) < 2 { return shim.Error(InvalidArgsLenErr(len(args)).Error()) } + // 2. check local MSP Admins policy + if err = lscc.policyChecker.CheckPolicyNoChannel(mgmt.Admins, sp); err != nil { + return shim.Error(fmt.Sprintf("Authorization for INSTALL on %s has been denied with error %s", args[1], err)) + } + depSpec := args[1] err := lscc.executeInstall(stub, depSpec) @@ -598,6 +622,9 @@ func (lscc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response return shim.Error(InvalidArgsLenErr(len(args)).Error()) } + // TODO: add access control check + // once the instantiation process will be completed. + //chain the chaincode shoud be associated with. It //should be created with a register call chainname := string(args[1]) @@ -652,6 +679,9 @@ func (lscc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response return shim.Error(InvalidChainNameErr(chainname).Error()) } + // TODO: add access control check + // once the instantiation process will be completed. + depSpec := args[2] // 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 chain := string(args[1]) ccname := string(args[2]) + // 2. check local Channel Readers policy + // Notice that this information are already available on the ledger + // therefore we enforce here that the caller is reader of the channel. + if err = lscc.policyChecker.CheckPolicy(chain, policies.ChannelApplicationReaders, sp); err != nil { + return shim.Error(fmt.Sprintf("Authorization for %s on channel %s has been denied with error %s", function, args[1], err)) + } + cdbytes, err := lscc.getCCInstance(stub, ccname) if err != nil { 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 if len(args) != 1 { return shim.Error(InvalidArgsLenErr(len(args)).Error()) } + + // 2. check local MSP Admins policy + if err = lscc.policyChecker.CheckPolicyNoChannel(mgmt.Admins, sp); err != nil { + return shim.Error(fmt.Sprintf("Authorization for GETCHAINCODES on channel %s has been denied with error %s", args[0], err)) + } + return lscc.getChaincodes(stub) case GETINSTALLEDCHAINCODES: if len(args) != 1 { return shim.Error(InvalidArgsLenErr(len(args)).Error()) } + + // 2. check local MSP Admins policy + if err = lscc.policyChecker.CheckPolicyNoChannel(mgmt.Admins, sp); err != nil { + return shim.Error(fmt.Sprintf("Authorization for GETINSTALLEDCHAINCODES on channel %s has been denied with error %s", args[0], err)) + } + return lscc.getInstalledChaincodes() } diff --git a/core/scc/lscc/lscc_test.go b/core/scc/lscc/lscc_test.go index 87ed8ee4a95..24091756269 100644 --- a/core/scc/lscc/lscc_test.go +++ b/core/scc/lscc/lscc_test.go @@ -31,8 +31,11 @@ import ( "bytes" "compress/gzip" + "github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/core/container/util" + "github.com/hyperledger/fabric/core/policy" pb "github.com/hyperledger/fabric/protos/peer" + "github.com/hyperledger/fabric/protos/utils" ) var lscctestpath = "/tmp/lscctest" @@ -94,14 +97,15 @@ func constructDeploymentSpec(name string, path string, version string, initArgs func TestInstall(t *testing.T) { path := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" - testInstall(t, "example02", "0", path, "") - testInstall(t, "example02-2", "1.0", path, "") - testInstall(t, "example02.go", "0", path, InvalidChaincodeNameErr("example02.go").Error()) - testInstall(t, "", "0", path, EmptyChaincodeNameErr("").Error()) - testInstall(t, "example02", "1{}0", path, InvalidVersionErr("1{}0").Error()) + testInstall(t, "example02", "0", path, "", "Alice") + testInstall(t, "example02-2", "1.0", path, "", "Alice") + testInstall(t, "example02.go", "0", path, InvalidChaincodeNameErr("example02.go").Error(), "Alice") + testInstall(t, "", "0", path, EmptyChaincodeNameErr("").Error(), "Alice") + testInstall(t, "example02", "1{}0", path, InvalidVersionErr("1{}0").Error(), "Alice") + testInstall(t, "example02", "0", path, "Authorization for INSTALL on", "Bob") } -func testInstall(t *testing.T, ccname string, version string, path string, expectedErrorMsg string) { +func testInstall(t *testing.T, ccname string, version string, path string, expectedErrorMsg string, caller string) { scc := new(LifeCycleSysCC) stub := shim.NewMockStub("lscc", scc) @@ -110,6 +114,19 @@ func testInstall(t *testing.T, ccname string, version string, path string, expec t.FailNow() } + // Init the policy checker + identityDeserializer := &policy.MockIdentityDeserializer{[]byte("Alice"), []byte("msg1")} + policyManagerGetter := &policy.MockChannelPolicyManagerGetter{ + Managers: map[string]policies.Manager{ + "test": &policy.MockChannelPolicyManager{MockPolicy: &policy.MockPolicy{Deserializer: identityDeserializer}}, + }, + } + scc.policyChecker = policy.NewPolicyChecker( + policyManagerGetter, + identityDeserializer, + &policy.MockMSPPrincipalGetter{Principal: []byte("Alice")}, + ) + cds, err := constructDeploymentSpec(ccname, path, version, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, false) if err != nil { t.FailNow() @@ -122,20 +139,27 @@ func testInstall(t *testing.T, ccname string, version string, path string, expec //constructDeploymentSpec puts the depspec on the FS. This should succeed args := [][]byte{[]byte(INSTALL), b} + sProp, _ := utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte(caller), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + if expectedErrorMsg == "" { defer os.Remove(lscctestpath + "/" + ccname + "." + version) - if res := stub.MockInvoke("1", args); res.Status != shim.OK { + if res := stub.MockInvokeWithSignedProposal("1", args, sProp); res.Status != shim.OK { t.FailNow() } } else { - if res := stub.MockInvoke("1", args); string(res.Message) != expectedErrorMsg { - t.Logf("Received error: %s", res.Message) + if res := stub.MockInvokeWithSignedProposal("1", args, sProp); !strings.HasPrefix(string(res.Message), expectedErrorMsg) { + t.Logf("Received error: [%s]", res.Message) t.FailNow() } } args = [][]byte{[]byte(GETINSTALLEDCHAINCODES)} - res := stub.MockInvoke("1", args) + sProp, _ = utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Alice"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + res := stub.MockInvokeWithSignedProposal("1", args, sProp) if res.Status != shim.OK { t.FailNow() } @@ -242,6 +266,22 @@ func testDeploy(t *testing.T, ccname string, version string, path string, forceB t.FailNow() } + // Init the policy checker + identityDeserializer := &policy.MockIdentityDeserializer{[]byte("Alice"), []byte("msg1")} + policyManagerGetter := &policy.MockChannelPolicyManagerGetter{ + Managers: map[string]policies.Manager{ + "test": &policy.MockChannelPolicyManager{MockPolicy: &policy.MockPolicy{Deserializer: identityDeserializer}}, + }, + } + scc.policyChecker = policy.NewPolicyChecker( + policyManagerGetter, + identityDeserializer, + &policy.MockMSPPrincipalGetter{Principal: []byte("Alice")}, + ) + sProp, _ := utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Alice"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + cds, err := constructDeploymentSpec(ccname, path, version, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true) if err != nil { t.FailNow() @@ -273,7 +313,7 @@ func testDeploy(t *testing.T, ccname string, version string, path string, forceB } args = [][]byte{[]byte(GETCHAINCODES)} - res = stub.MockInvoke("1", args) + res = stub.MockInvokeWithSignedProposal("1", args, sProp) if res.Status != shim.OK { t.FailNow() } @@ -297,7 +337,7 @@ func testDeploy(t *testing.T, ccname string, version string, path string, forceB } args = [][]byte{[]byte(GETCCINFO), []byte("test"), []byte(cds.ChaincodeSpec.ChaincodeId.Name)} - if res := stub.MockInvoke("1", args); res.Status != shim.OK { + if res := stub.MockInvokeWithSignedProposal("1", args, sProp); res.Status != shim.OK { t.FailNow() } } else { @@ -352,6 +392,22 @@ func TestMultipleDeploy(t *testing.T) { t.FailNow() } + // Init the policy checker + identityDeserializer := &policy.MockIdentityDeserializer{[]byte("Alice"), []byte("msg1")} + policyManagerGetter := &policy.MockChannelPolicyManagerGetter{ + Managers: map[string]policies.Manager{ + "test": &policy.MockChannelPolicyManager{MockPolicy: &policy.MockPolicy{Deserializer: identityDeserializer}}, + }, + } + scc.policyChecker = policy.NewPolicyChecker( + policyManagerGetter, + identityDeserializer, + &policy.MockMSPPrincipalGetter{Principal: []byte("Alice")}, + ) + sProp, _ := utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Alice"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + //deploy 02 cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true) if err != nil { @@ -369,7 +425,7 @@ func TestMultipleDeploy(t *testing.T) { } args = [][]byte{[]byte(GETCCINFO), []byte("test"), []byte(cds.ChaincodeSpec.ChaincodeId.Name)} - if res := stub.MockInvoke("1", args); res.Status != shim.OK { + if res := stub.MockInvokeWithSignedProposal("1", args, sProp); res.Status != shim.OK { t.FailNow() } @@ -389,12 +445,12 @@ func TestMultipleDeploy(t *testing.T) { } args = [][]byte{[]byte(GETCCINFO), []byte("test"), []byte(cds.ChaincodeSpec.ChaincodeId.Name)} - if res := stub.MockInvoke("1", args); res.Status != shim.OK { + if res := stub.MockInvokeWithSignedProposal("1", args, sProp); res.Status != shim.OK { t.FailNow() } args = [][]byte{[]byte(GETCHAINCODES)} - res := stub.MockInvoke("1", args) + res := stub.MockInvokeWithSignedProposal("1", args, sProp) if res.Status != shim.OK { t.FailNow() } @@ -421,6 +477,21 @@ func TestRetryFailedDeploy(t *testing.T) { fmt.Println("Init failed", string(res.Message)) t.FailNow() } + // Init the policy checker + identityDeserializer := &policy.MockIdentityDeserializer{[]byte("Alice"), []byte("msg1")} + policyManagerGetter := &policy.MockChannelPolicyManagerGetter{ + Managers: map[string]policies.Manager{ + "test": &policy.MockChannelPolicyManager{MockPolicy: &policy.MockPolicy{Deserializer: identityDeserializer}}, + }, + } + scc.policyChecker = policy.NewPolicyChecker( + policyManagerGetter, + identityDeserializer, + &policy.MockMSPPrincipalGetter{Principal: []byte("Alice")}, + ) + sProp, _ := utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Alice"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes //deploy 02 cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true) @@ -454,7 +525,7 @@ func TestRetryFailedDeploy(t *testing.T) { //get the deploymentspec args = [][]byte{[]byte(GETDEPSPEC), []byte("test"), []byte(cds.ChaincodeSpec.ChaincodeId.Name)} - if res := stub.MockInvoke("1", args); res.Status != shim.OK || res.Payload == nil { + if res := stub.MockInvokeWithSignedProposal("1", args, sProp); res.Status != shim.OK || res.Payload == nil { t.FailNow() } } @@ -469,10 +540,26 @@ func TestTamperChaincode(t *testing.T) { t.FailNow() } + // Init the policy checker + identityDeserializer := &policy.MockIdentityDeserializer{[]byte("Alice"), []byte("msg1")} + policyManagerGetter := &policy.MockChannelPolicyManagerGetter{ + Managers: map[string]policies.Manager{ + "test": &policy.MockChannelPolicyManager{MockPolicy: &policy.MockPolicy{Deserializer: identityDeserializer}}, + }, + } + scc.policyChecker = policy.NewPolicyChecker( + policyManagerGetter, + identityDeserializer, + &policy.MockMSPPrincipalGetter{Principal: []byte("Alice")}, + ) + sProp, _ := utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Alice"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + //deploy 01 cds, err := constructDeploymentSpec("example01", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01", "0", [][]byte{[]byte("init"), []byte("a"), []byte("1"), []byte("b"), []byte("2")}, true) if err != nil { - t.Logf("Could not construct example01.0") + t.Logf("Could not construct example01.0 [%s]", err) t.FailNow() } @@ -527,7 +614,7 @@ func TestTamperChaincode(t *testing.T) { //get the deploymentspec args = [][]byte{[]byte(GETDEPSPEC), []byte("test"), []byte(cds.ChaincodeSpec.ChaincodeId.Name)} - if res = stub.MockInvoke("1", args); res.Status == shim.OK { + if res = stub.MockInvokeWithSignedProposal("1", args, sProp); res.Status == shim.OK { t.Logf("Expected error on tampering files but succeeded") t.FailNow() } @@ -630,6 +717,21 @@ func TestGetAPIsWithoutInstall(t *testing.T) { fmt.Println("Init failed", string(res.Message)) t.FailNow() } + // Init the policy checker + identityDeserializer := &policy.MockIdentityDeserializer{[]byte("Alice"), []byte("msg1")} + policyManagerGetter := &policy.MockChannelPolicyManagerGetter{ + Managers: map[string]policies.Manager{ + "test": &policy.MockChannelPolicyManager{MockPolicy: &policy.MockPolicy{Deserializer: identityDeserializer}}, + }, + } + scc.policyChecker = policy.NewPolicyChecker( + policyManagerGetter, + identityDeserializer, + &policy.MockMSPPrincipalGetter{Principal: []byte("Alice")}, + ) + sProp, _ := utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Alice"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true) @@ -648,25 +750,25 @@ func TestGetAPIsWithoutInstall(t *testing.T) { //GETCCINFO should still work args = [][]byte{[]byte(GETCCINFO), []byte("test"), []byte(cds.ChaincodeSpec.ChaincodeId.Name)} - if res := stub.MockInvoke("1", args); res.Status != shim.OK { + if res := stub.MockInvokeWithSignedProposal("1", args, sProp); res.Status != shim.OK { t.FailNow() } //GETCCDATA should still work args = [][]byte{[]byte(GETCCDATA), []byte("test"), []byte(cds.ChaincodeSpec.ChaincodeId.Name)} - if res := stub.MockInvoke("1", args); res.Status != shim.OK { + if res := stub.MockInvokeWithSignedProposal("1", args, sProp); res.Status != shim.OK { t.FailNow() } //GETDEPSPEC should not work args = [][]byte{[]byte(GETDEPSPEC), []byte("test"), []byte(cds.ChaincodeSpec.ChaincodeId.Name)} - if res := stub.MockInvoke("1", args); res.Status == shim.OK { + if res := stub.MockInvokeWithSignedProposal("1", args, sProp); res.Status == shim.OK { t.FailNow() } // get instantiated chaincodes args = [][]byte{[]byte(GETCHAINCODES)} - res := stub.MockInvoke("1", args) + res := stub.MockInvokeWithSignedProposal("1", args, sProp) if res.Status != shim.OK { t.FailNow() } @@ -685,7 +787,7 @@ func TestGetAPIsWithoutInstall(t *testing.T) { // get installed chaincodes args = [][]byte{[]byte(GETINSTALLEDCHAINCODES)} - res = stub.MockInvoke("1", args) + res = stub.MockInvokeWithSignedProposal("1", args, sProp) if res.Status != shim.OK { t.FailNow() } @@ -704,6 +806,200 @@ func TestGetAPIsWithoutInstall(t *testing.T) { } +// TestGetInstalledChaincodesAccessRights verifies that only authorized parties can call +// the GETINSTALLEDCHAINCODES function +func TestGetInstalledChaincodesAccessRights(t *testing.T) { + scc := new(LifeCycleSysCC) + stub := shim.NewMockStub("lscc", scc) + + if res := stub.MockInit("1", nil); res.Status != shim.OK { + fmt.Println("Init failed", string(res.Message)) + t.FailNow() + } + + // Init the policy checker + identityDeserializer := &policy.MockIdentityDeserializer{[]byte("Alice"), []byte("msg1")} + policyManagerGetter := &policy.MockChannelPolicyManagerGetter{ + Managers: map[string]policies.Manager{ + "test": &policy.MockChannelPolicyManager{MockPolicy: &policy.MockPolicy{Deserializer: identityDeserializer}}, + }, + } + scc.policyChecker = policy.NewPolicyChecker( + policyManagerGetter, + identityDeserializer, + &policy.MockMSPPrincipalGetter{Principal: []byte("Alice")}, + ) + + // Should pass + args := [][]byte{[]byte(GETINSTALLEDCHAINCODES)} + sProp, _ := utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Alice"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + res := stub.MockInvokeWithSignedProposal("1", args, sProp) + if res.Status != shim.OK { + t.FailNow() + } + + // Should fail + sProp, _ = utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Bob"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + res = stub.MockInvokeWithSignedProposal("1", args, sProp) + if res.Status == shim.OK { + t.FailNow() + } +} + +// TestGetChaincodesAccessRights verifies that only authorized parties can call +// the GETCHAINCODES function +func TestGetChaincodesAccessRights(t *testing.T) { + scc := new(LifeCycleSysCC) + stub := shim.NewMockStub("lscc", scc) + + if res := stub.MockInit("1", nil); res.Status != shim.OK { + fmt.Println("Init failed", string(res.Message)) + t.FailNow() + } + + // Init the policy checker + identityDeserializer := &policy.MockIdentityDeserializer{[]byte("Alice"), []byte("msg1")} + policyManagerGetter := &policy.MockChannelPolicyManagerGetter{ + Managers: map[string]policies.Manager{ + "test": &policy.MockChannelPolicyManager{MockPolicy: &policy.MockPolicy{Deserializer: identityDeserializer}}, + }, + } + scc.policyChecker = policy.NewPolicyChecker( + policyManagerGetter, + identityDeserializer, + &policy.MockMSPPrincipalGetter{Principal: []byte("Alice")}, + ) + + // Should pass + args := [][]byte{[]byte(GETCHAINCODES)} + sProp, _ := utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Alice"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + res := stub.MockInvokeWithSignedProposal("1", args, sProp) + if res.Status != shim.OK { + t.FailNow() + } + + // Should fail + sProp, _ = utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Bob"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + res = stub.MockInvokeWithSignedProposal("1", args, sProp) + if res.Status == shim.OK { + t.FailNow() + } +} + +// TestGetCCInfoAccessRights verifies that only authorized parties can call +// the GETCCINFO function +func TestGetCCAccessRights(t *testing.T) { + scc := new(LifeCycleSysCC) + stub := shim.NewMockStub("lscc", scc) + + if res := stub.MockInit("1", nil); res.Status != shim.OK { + fmt.Println("Init failed", string(res.Message)) + t.FailNow() + } + + // Init the policy checker + identityDeserializer := &policy.MockIdentityDeserializer{[]byte("Alice"), []byte("msg1")} + policyManagerGetter := &policy.MockChannelPolicyManagerGetter{ + Managers: map[string]policies.Manager{ + "test": &policy.MockChannelPolicyManager{MockPolicy: &policy.MockPolicy{Deserializer: identityDeserializer}}, + }, + } + scc.policyChecker = policy.NewPolicyChecker( + policyManagerGetter, + identityDeserializer, + &policy.MockMSPPrincipalGetter{Principal: []byte("Alice")}, + ) + + cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true) + + var b []byte + if b, err = proto.Marshal(cds); err != nil || b == nil { + t.FailNow() + } + + args := [][]byte{[]byte(DEPLOY), []byte("test"), b} + if res := stub.MockInvoke("1", args); res.Status != shim.OK { + t.FailNow() + } + + //Force remove CC + defer os.Remove(lscctestpath + "/example02.0") + + // GETCCINFO + // Should pass + args = [][]byte{[]byte(GETCCINFO), []byte("test"), []byte(cds.ChaincodeSpec.ChaincodeId.Name)} + sProp, _ := utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Alice"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + res := stub.MockInvokeWithSignedProposal("1", args, sProp) + if res.Status != shim.OK { + t.Logf("This should pass [%s]", res.Message) + t.FailNow() + } + + // Should fail + sProp, _ = utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Bob"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + res = stub.MockInvokeWithSignedProposal("1", args, sProp) + if res.Status == shim.OK { + t.Logf("This should fail [%s]", res.Message) + t.FailNow() + } + + // GETDEPSPEC + // Should pass + args = [][]byte{[]byte(GETDEPSPEC), []byte("test"), []byte(cds.ChaincodeSpec.ChaincodeId.Name)} + sProp, _ = utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Alice"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + res = stub.MockInvokeWithSignedProposal("1", args, sProp) + if res.Status != shim.OK { + t.Logf("This should pass [%s]", res.Message) + t.FailNow() + } + + // Should fail + sProp, _ = utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Bob"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + res = stub.MockInvokeWithSignedProposal("1", args, sProp) + if res.Status == shim.OK { + t.Logf("This should fail [%s]", res.Message) + t.FailNow() + } + + // GETCCDATA + // Should pass + args = [][]byte{[]byte(GETCCDATA), []byte("test"), []byte(cds.ChaincodeSpec.ChaincodeId.Name)} + sProp, _ = utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Alice"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + res = stub.MockInvokeWithSignedProposal("1", args, sProp) + if res.Status != shim.OK { + t.Logf("This should pass [%s]", res.Message) + t.FailNow() + } + + // Should fail + sProp, _ = utils.MockSignedEndorserProposalOrPanic("", &pb.ChaincodeSpec{}, []byte("Bob"), []byte("msg1")) + identityDeserializer.Msg = sProp.ProposalBytes + sProp.Signature = sProp.ProposalBytes + res = stub.MockInvokeWithSignedProposal("1", args, sProp) + if res.Status == shim.OK { + t.Logf("This should fail [%s]", res.Message) + t.FailNow() + } +} + func TestMain(m *testing.M) { ccprovider.SetChaincodesPath(lscctestpath) sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{})