573 lines
25 KiB
Go
573 lines
25 KiB
Go
/*
|
|
Copyright IBM Corp All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package e2e
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
docker "github.com/fsouza/go-dockerclient"
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/hyperledger/fabric-protos-go/common"
|
|
pb "github.com/hyperledger/fabric-protos-go/peer"
|
|
"github.com/hyperledger/fabric/core/aclmgmt/resources"
|
|
"github.com/hyperledger/fabric/integration/channelparticipation"
|
|
"github.com/hyperledger/fabric/integration/nwo"
|
|
"github.com/hyperledger/fabric/integration/nwo/commands"
|
|
"github.com/hyperledger/fabric/protoutil"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
"github.com/onsi/gomega/gbytes"
|
|
"github.com/onsi/gomega/gexec"
|
|
"github.com/tedsuo/ifrit"
|
|
ginkgomon "github.com/tedsuo/ifrit/ginkgomon_v2"
|
|
)
|
|
|
|
var _ = Describe("EndToEndACL", func() {
|
|
var (
|
|
testDir string
|
|
client *docker.Client
|
|
network *nwo.Network
|
|
chaincode nwo.Chaincode
|
|
ordererRunner *ginkgomon.Runner
|
|
ordererProcess, peerProcess ifrit.Process
|
|
|
|
orderer *nwo.Orderer
|
|
org1Peer0 *nwo.Peer
|
|
org2Peer0 *nwo.Peer
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
var err error
|
|
testDir, err = ioutil.TempDir("", "acl-e2e")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
client, err = docker.NewClientFromEnv()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Speed up test by reducing the number of peers we
|
|
// bring up and install chaincode to.
|
|
etcdRaftConfig := nwo.BasicEtcdRaft()
|
|
etcdRaftConfig.RemovePeer("Org1", "peer1")
|
|
etcdRaftConfig.RemovePeer("Org2", "peer1")
|
|
Expect(etcdRaftConfig.Peers).To(HaveLen(2))
|
|
|
|
network = nwo.New(etcdRaftConfig, testDir, client, StartPort(), components)
|
|
network.GenerateConfigTree()
|
|
network.Bootstrap()
|
|
// Start all the fabric processes
|
|
ordererRunner, ordererProcess, peerProcess = network.StartSingleOrdererNetwork("orderer")
|
|
|
|
orderer = network.Orderer("orderer")
|
|
org1Peer0 = network.Peer("Org1", "peer0")
|
|
org2Peer0 = network.Peer("Org2", "peer0")
|
|
|
|
chaincode = nwo.Chaincode{
|
|
Name: "mycc",
|
|
Version: "0.0",
|
|
Path: "github.com/hyperledger/fabric/integration/chaincode/simple/cmd",
|
|
Ctor: `{"Args":["init","a","100","b","200"]}`,
|
|
Policy: `OR ('Org1MSP.member','Org2MSP.member')`,
|
|
}
|
|
channelparticipation.JoinOrdererJoinPeersAppChannel(network, "testchannel", orderer, ordererRunner)
|
|
nwo.DeployChaincodeLegacy(network, "testchannel", orderer, chaincode)
|
|
})
|
|
|
|
AfterEach(func() {
|
|
if ordererProcess != nil {
|
|
ordererProcess.Signal(syscall.SIGTERM)
|
|
Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive())
|
|
}
|
|
if peerProcess != nil {
|
|
peerProcess.Signal(syscall.SIGTERM)
|
|
Eventually(peerProcess.Wait(), network.EventuallyTimeout).Should(Receive())
|
|
}
|
|
if network != nil {
|
|
network.Cleanup()
|
|
}
|
|
os.RemoveAll(testDir)
|
|
})
|
|
|
|
It("enforces access control list policies", func() {
|
|
invokeChaincode := commands.ChaincodeInvoke{
|
|
ChannelID: "testchannel",
|
|
Orderer: network.OrdererAddress(orderer, nwo.ListenPort),
|
|
Name: chaincode.Name,
|
|
Ctor: `{"Args":["invoke","a","b","10"]}`,
|
|
WaitForEvent: true,
|
|
}
|
|
|
|
outputBlock := filepath.Join(testDir, "newest_block.pb")
|
|
fetchNewest := commands.ChannelFetch{
|
|
ChannelID: "testchannel",
|
|
Block: "newest",
|
|
OutputFile: outputBlock,
|
|
}
|
|
|
|
//
|
|
// when the ACL policy for DeliverFiltered is satisfied
|
|
//
|
|
By("setting the filtered block event ACL policy to Org1/Admins")
|
|
policyName := resources.Event_FilteredBlock
|
|
policy := "/Channel/Application/Org1/Admins"
|
|
SetACLPolicy(network, "testchannel", policyName, policy, "orderer")
|
|
|
|
By("invoking chaincode as a permitted Org1 Admin identity")
|
|
sess, err := network.PeerAdminSession(org1Peer0, invokeChaincode)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess.Err, network.EventuallyTimeout).Should(gbytes.Say("Chaincode invoke successful. result: status:200"))
|
|
|
|
//
|
|
// when the ACL policy for DeliverFiltered is not satisfied
|
|
//
|
|
By("setting the filtered block event ACL policy to org2/Admins")
|
|
policyName = resources.Event_FilteredBlock
|
|
policy = "/Channel/Application/org2/Admins"
|
|
SetACLPolicy(network, "testchannel", policyName, policy, "orderer")
|
|
|
|
By("invoking chaincode as a forbidden Org1 Admin identity")
|
|
sess, err = network.PeerAdminSession(org1Peer0, invokeChaincode)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess.Err, network.EventuallyTimeout).Should(gbytes.Say(`\Qdeliver completed with status (FORBIDDEN)\E`))
|
|
|
|
//
|
|
// when the ACL policy for Deliver is satisfied
|
|
//
|
|
By("setting the block event ACL policy to Org1/Admins")
|
|
policyName = resources.Event_Block
|
|
policy = "/Channel/Application/Org1/Admins"
|
|
SetACLPolicy(network, "testchannel", policyName, policy, "orderer")
|
|
|
|
By("fetching the latest block from the peer as a permitted Org1 Admin identity")
|
|
sess, err = network.PeerAdminSession(org1Peer0, fetchNewest)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
|
|
Expect(sess.Err).To(gbytes.Say("Received block: "))
|
|
|
|
//
|
|
// when the ACL policy for Deliver is not satisfied
|
|
//
|
|
By("fetching the latest block from the peer as a forbidden org2 Admin identity")
|
|
sess, err = network.PeerAdminSession(org2Peer0, fetchNewest)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say("can't read the block: &{FORBIDDEN}"))
|
|
|
|
//
|
|
// when the ACL policy for lscc/GetInstantiatedChaincodes is satisfied
|
|
//
|
|
By("setting the lscc/GetInstantiatedChaincodes ACL policy to Org1/Admins")
|
|
policyName = resources.Lscc_GetInstantiatedChaincodes
|
|
policy = "/Channel/Application/Org1/Admins"
|
|
SetACLPolicy(network, "testchannel", policyName, policy, "orderer")
|
|
|
|
By("listing the instantiated chaincodes as a permitted Org1 Admin identity")
|
|
sess, err = network.PeerAdminSession(org1Peer0, commands.ChaincodeListInstantiatedLegacy{
|
|
ChannelID: "testchannel",
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
|
|
Expect(sess).To(gbytes.Say("Name: mycc, Version: 0.0, Path: .*, Escc: escc, Vscc: vscc"))
|
|
|
|
//
|
|
// when the ACL policy for lscc/GetInstantiatedChaincodes is not satisfied
|
|
//
|
|
By("listing the instantiated chaincodes as a forbidden org2 Admin identity")
|
|
sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeListInstantiatedLegacy{
|
|
ChannelID: "testchannel",
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess).NotTo(gbytes.Say("Name: mycc, Version: 0.0, Path: .*, Escc: escc, Vscc: vscc"))
|
|
Expect(sess.Err).To(gbytes.Say(`access denied for \[getchaincodes\]\[testchannel\](.*)signature set did not satisfy policy`))
|
|
|
|
//
|
|
// when a system chaincode ACL policy is set and a query is performed
|
|
//
|
|
|
|
// getting a transaction id from a block in the ledger
|
|
sess, err = network.PeerAdminSession(org1Peer0, fetchNewest)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
|
|
Expect(sess.Err).To(gbytes.Say("Received block: "))
|
|
txID := GetTxIDFromBlockFile(outputBlock)
|
|
|
|
ItEnforcesPolicy := func(scc, operation string, args ...string) {
|
|
policyName := fmt.Sprintf("%s/%s", scc, operation)
|
|
policy := "/Channel/Application/Org1/Admins"
|
|
By("setting " + policyName + " to Org1 Admins")
|
|
SetACLPolicy(network, "testchannel", policyName, policy, "orderer")
|
|
|
|
args = append([]string{operation}, args...)
|
|
chaincodeQuery := commands.ChaincodeQuery{
|
|
ChannelID: "testchannel",
|
|
Name: scc,
|
|
Ctor: ToCLIChaincodeArgs(args...),
|
|
}
|
|
|
|
By("evaluating " + policyName + " for a permitted subject")
|
|
sess, err := network.PeerAdminSession(org1Peer0, chaincodeQuery)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))
|
|
|
|
By("evaluating " + policyName + " for a forbidden subject")
|
|
sess, err = network.PeerAdminSession(org2Peer0, chaincodeQuery)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say(fmt.Sprintf(`access denied for \[%s\]\[%s\](.*)signature set did not satisfy policy`, operation, "testchannel")))
|
|
}
|
|
|
|
//
|
|
// qscc
|
|
//
|
|
ItEnforcesPolicy("qscc", "GetChainInfo", "testchannel")
|
|
ItEnforcesPolicy("qscc", "GetBlockByNumber", "testchannel", "0")
|
|
ItEnforcesPolicy("qscc", "GetBlockByTxID", "testchannel", txID)
|
|
ItEnforcesPolicy("qscc", "GetTransactionByID", "testchannel", txID)
|
|
|
|
//
|
|
// lscc
|
|
//
|
|
ItEnforcesPolicy("lscc", "GetChaincodeData", "testchannel", "mycc")
|
|
ItEnforcesPolicy("lscc", "ChaincodeExists", "testchannel", "mycc")
|
|
|
|
//
|
|
// cscc
|
|
//
|
|
ItEnforcesPolicy("cscc", "GetConfigBlock", "testchannel")
|
|
ItEnforcesPolicy("cscc", "GetChannelConfig", "testchannel")
|
|
|
|
//
|
|
// _lifecycle ACL policies
|
|
//
|
|
|
|
chaincode = nwo.Chaincode{
|
|
Name: "mycc",
|
|
Version: "0.0",
|
|
Path: components.Build("github.com/hyperledger/fabric/integration/chaincode/simple/cmd"),
|
|
Lang: "binary",
|
|
PackageFile: filepath.Join(testDir, "simplecc.tar.gz"),
|
|
Ctor: `{"Args":["init","a","100","b","200"]}`,
|
|
ChannelConfigPolicy: "/Channel/Application/Endorsement",
|
|
Sequence: "1",
|
|
InitRequired: true,
|
|
Label: "my_prebuilt_chaincode",
|
|
}
|
|
|
|
nwo.PackageChaincodeBinary(chaincode)
|
|
|
|
//
|
|
// when the ACL policy for _lifecycle/InstallChaincode is not satisfied
|
|
//
|
|
By("installing the chaincode to an org1 peer as an org2 admin")
|
|
sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeInstall{
|
|
PackageFile: chaincode.PackageFile,
|
|
PeerAddresses: []string{network.PeerAddress(org1Peer0, nwo.ListenPort)},
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say(`access denied: channel \[\] creator org unknown, creator is malformed`))
|
|
|
|
By("installing the chaincode to an org1 peer as a non-admin org1 identity")
|
|
sess, err = network.PeerUserSession(org1Peer0, "User1", commands.ChaincodeInstall{
|
|
PackageFile: chaincode.PackageFile,
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say(`Error: chaincode install failed with status: 500 - Failed to authorize invocation due to failed ACL check: Failed verifying that proposal's creator satisfies local MSP principal during channelless check policy with policy \Q[Admins]\E: \Q[The identity is not an admin under this MSP [Org1MSP]: The identity does not contain OU [ADMIN], MSP: [Org1MSP]]\E`))
|
|
|
|
//
|
|
// when the ACL policy for _lifecycle/InstallChaincode is satisfied
|
|
//
|
|
nwo.InstallChaincode(network, chaincode, org1Peer0, org2Peer0)
|
|
|
|
//
|
|
// when the V2_0 application capabilities flag has not yet been enabled
|
|
//
|
|
By("approving a chaincode definition on a channel without V2_0 capabilities enabled")
|
|
sess, err = network.PeerAdminSession(org1Peer0, commands.ChaincodeApproveForMyOrg{
|
|
ChannelID: "testchannel",
|
|
Orderer: network.OrdererAddress(orderer, nwo.ListenPort),
|
|
Name: chaincode.Name,
|
|
Version: chaincode.Version,
|
|
Sequence: chaincode.Sequence,
|
|
EndorsementPlugin: chaincode.EndorsementPlugin,
|
|
ValidationPlugin: chaincode.ValidationPlugin,
|
|
SignaturePolicy: chaincode.SignaturePolicy,
|
|
ChannelConfigPolicy: chaincode.ChannelConfigPolicy,
|
|
InitRequired: chaincode.InitRequired,
|
|
CollectionsConfig: chaincode.CollectionsConfig,
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say("Error: proposal failed with status: 500 - cannot use new lifecycle for channel 'testchannel' as it does not have the required capabilities enabled"))
|
|
|
|
By("committing a chaincode definition on a channel without V2_0 capabilities enabled")
|
|
sess, err = network.PeerAdminSession(org1Peer0, commands.ChaincodeCommit{
|
|
ChannelID: "testchannel",
|
|
Orderer: network.OrdererAddress(orderer, nwo.ListenPort),
|
|
Name: chaincode.Name,
|
|
Version: chaincode.Version,
|
|
Sequence: chaincode.Sequence,
|
|
EndorsementPlugin: chaincode.EndorsementPlugin,
|
|
ValidationPlugin: chaincode.ValidationPlugin,
|
|
SignaturePolicy: chaincode.SignaturePolicy,
|
|
ChannelConfigPolicy: chaincode.ChannelConfigPolicy,
|
|
InitRequired: chaincode.InitRequired,
|
|
CollectionsConfig: chaincode.CollectionsConfig,
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say("Error: proposal failed with status: 500 - cannot use new lifecycle for channel 'testchannel' as it does not have the required capabilities enabled"))
|
|
|
|
// enable V2_0 application capabilities on the channel
|
|
By("enabling V2_0 application capabilities on the channel")
|
|
nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, org1Peer0, org2Peer0)
|
|
|
|
//
|
|
// when the ACL policy for _lifecycle/ApproveChaincodeDefinitionForOrg is not satisfied
|
|
//
|
|
By("approving a chaincode definition for org1 as an org2 admin")
|
|
sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeApproveForMyOrg{
|
|
ChannelID: "testchannel",
|
|
Orderer: network.OrdererAddress(orderer, nwo.ListenPort),
|
|
Name: chaincode.Name,
|
|
Version: chaincode.Version,
|
|
Sequence: chaincode.Sequence,
|
|
EndorsementPlugin: chaincode.EndorsementPlugin,
|
|
ValidationPlugin: chaincode.ValidationPlugin,
|
|
SignaturePolicy: chaincode.SignaturePolicy,
|
|
ChannelConfigPolicy: chaincode.ChannelConfigPolicy,
|
|
InitRequired: chaincode.InitRequired,
|
|
CollectionsConfig: chaincode.CollectionsConfig,
|
|
PeerAddresses: []string{network.PeerAddress(org1Peer0, nwo.ListenPort)},
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say(`Error: proposal failed with status: 500 - Failed to authorize invocation due to failed ACL check: Failed deserializing proposal creator during channelless check policy with policy \[Admins\]: \[expected MSP ID Org1MSP, received Org2MSP\]`))
|
|
|
|
//
|
|
// when the ACL policy for _lifecycle/ApproveChaincodeDefinitionForOrg is satisfied
|
|
//
|
|
By("approving a chaincode definition for org1 and org2")
|
|
nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, org1Peer0, org2Peer0)
|
|
|
|
//
|
|
// when the ACL policy for _lifecycle/QueryApprovedChaincodeDefinition is not satisfied
|
|
//
|
|
By("querying the approved chaincode definition for org1 as an org2 admin")
|
|
sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeQueryApproved{
|
|
ChannelID: "testchannel",
|
|
Name: chaincode.Name,
|
|
Sequence: chaincode.Sequence,
|
|
PeerAddresses: []string{network.PeerAddress(org1Peer0, nwo.ListenPort)},
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say(`\QError: query failed with status: 500 - Failed to authorize invocation due to failed ACL check: Failed deserializing proposal creator during channelless check policy with policy [Admins]: [expected MSP ID Org1MSP, received Org2MSP]\E`))
|
|
|
|
//
|
|
// when the ACL policy for _lifecycle/QueryApprovedChaincodeDefinition is satisfied
|
|
//
|
|
By("querying the approved chaincode definition for org1 as an org1 admin")
|
|
nwo.EnsureChaincodeApproved(network, org1Peer0, "testchannel", chaincode.Name, chaincode.Sequence)
|
|
|
|
//
|
|
// when the ACL policy for CheckCommitReadiness is not satisfied
|
|
//
|
|
By("setting the simulate commit chaincode definition ACL policy to Org1/Admins")
|
|
policyName = resources.Lifecycle_CheckCommitReadiness
|
|
policy = "/Channel/Application/Org1/Admins"
|
|
SetACLPolicy(network, "testchannel", policyName, policy, "orderer")
|
|
|
|
By("simulating the commit of a chaincode dwefinition as a forbidden Org2 Admin identity")
|
|
sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeCheckCommitReadiness{
|
|
ChannelID: "testchannel",
|
|
Name: chaincode.Name,
|
|
Version: chaincode.Version,
|
|
Sequence: chaincode.Sequence,
|
|
EndorsementPlugin: chaincode.EndorsementPlugin,
|
|
ValidationPlugin: chaincode.ValidationPlugin,
|
|
SignaturePolicy: chaincode.SignaturePolicy,
|
|
ChannelConfigPolicy: chaincode.ChannelConfigPolicy,
|
|
InitRequired: chaincode.InitRequired,
|
|
CollectionsConfig: chaincode.CollectionsConfig,
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say(`\QError: query failed with status: 500 - Failed to authorize invocation due to failed ACL check: failed evaluating policy on signed data during check policy [/Channel/Application/Org1/Admins]: [signature set did not satisfy policy]\E`))
|
|
|
|
//
|
|
// when the ACL policy for CheckCommitReadiness is satisfied
|
|
//
|
|
nwo.CheckCommitReadinessUntilReady(network, "testchannel", chaincode, network.PeerOrgs(), org1Peer0)
|
|
|
|
//
|
|
// when the ACL policy for CommitChaincodeDefinition is not satisfied
|
|
//
|
|
By("setting the commit chaincode definition ACL policy to Org1/Admins")
|
|
policyName = resources.Lifecycle_CommitChaincodeDefinition
|
|
policy = "/Channel/Application/Org1/Admins"
|
|
SetACLPolicy(network, "testchannel", policyName, policy, "orderer")
|
|
|
|
By("committing the chaincode definition as a forbidden Org2 Admin identity")
|
|
peerAddresses := []string{
|
|
network.PeerAddress(org1Peer0, nwo.ListenPort),
|
|
network.PeerAddress(org2Peer0, nwo.ListenPort),
|
|
}
|
|
sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeCommit{
|
|
ChannelID: "testchannel",
|
|
Orderer: network.OrdererAddress(orderer, nwo.ListenPort),
|
|
Name: chaincode.Name,
|
|
Version: chaincode.Version,
|
|
Sequence: chaincode.Sequence,
|
|
EndorsementPlugin: chaincode.EndorsementPlugin,
|
|
ValidationPlugin: chaincode.ValidationPlugin,
|
|
SignaturePolicy: chaincode.SignaturePolicy,
|
|
ChannelConfigPolicy: chaincode.ChannelConfigPolicy,
|
|
InitRequired: chaincode.InitRequired,
|
|
CollectionsConfig: chaincode.CollectionsConfig,
|
|
PeerAddresses: peerAddresses,
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say(`\QError: proposal failed with status: 500 - Failed to authorize invocation due to failed ACL check: failed evaluating policy on signed data during check policy [/Channel/Application/Org1/Admins]: [signature set did not satisfy policy]\E`))
|
|
|
|
//
|
|
// when the ACL policy for CommitChaincodeDefinition is satisfied
|
|
//
|
|
nwo.CommitChaincode(network, "testchannel", orderer, chaincode, org1Peer0, org1Peer0, org2Peer0)
|
|
|
|
//
|
|
// when the ACL policy for QueryChaincodeDefinition is satisfied
|
|
//
|
|
By("setting the query chaincode definition ACL policy to Org1/Admins")
|
|
policyName = resources.Lifecycle_QueryChaincodeDefinition
|
|
policy = "/Channel/Application/Org1/Admins"
|
|
SetACLPolicy(network, "testchannel", policyName, policy, "orderer")
|
|
|
|
By("querying the chaincode definition as a permitted Org1 Admin identity")
|
|
nwo.EnsureChaincodeCommitted(network, "testchannel", "mycc", "0.0", "1", []*nwo.Organization{network.Organization("Org1"), network.Organization("Org2")}, org1Peer0)
|
|
|
|
By("querying the chaincode definition as a forbidden Org2 Admin identity")
|
|
sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeListCommitted{
|
|
ChannelID: "testchannel",
|
|
Name: "mycc",
|
|
})
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say(`\QError: query failed with status: 500 - Failed to authorize invocation due to failed ACL check: failed evaluating policy on signed data during check policy [/Channel/Application/Org1/Admins]: [signature set did not satisfy policy]\E`))
|
|
|
|
//
|
|
// when the ACL policy for snapshot related commands is not satisfied (e.g., non-admin user or admin in another org)
|
|
//
|
|
By("calling snapshot submitrequest as a non-permitted identity")
|
|
expectedMsgNonAdmin := `\Qfailed verifying that the signed data identity satisfies local MSP principal during channelless check policy with policy [Admins]: [The identity is not an admin under this MSP [Org1MSP]: The identity does not contain OU [ADMIN], MSP: [Org1MSP]]\E`
|
|
expectedMsgAdminWrongOrg := `\Qfailed deserializing signed data identity during channelless check policy with policy [Admins]: [expected MSP ID Org1MSP, received Org2MSP]\E`
|
|
submitrequestCmd := &commands.SnapshotSubmitRequest{
|
|
ChannelID: "testchannel",
|
|
BlockNumber: "100",
|
|
ClientAuth: network.ClientAuthRequired,
|
|
PeerAddress: network.PeerAddress(org1Peer0, nwo.ListenPort),
|
|
}
|
|
verifyCommandErr(network, org1Peer0, "User1", submitrequestCmd, expectedMsgNonAdmin)
|
|
verifyCommandErr(network, org2Peer0, "Admin", submitrequestCmd, expectedMsgAdminWrongOrg)
|
|
|
|
By("calling snapshot cancelrequest as a non-permitted identity")
|
|
cancelrequestCmd := &commands.SnapshotCancelRequest{
|
|
ChannelID: "testchannel",
|
|
BlockNumber: "100",
|
|
ClientAuth: network.ClientAuthRequired,
|
|
PeerAddress: network.PeerAddress(org1Peer0, nwo.ListenPort),
|
|
}
|
|
verifyCommandErr(network, org1Peer0, "User1", cancelrequestCmd, expectedMsgNonAdmin)
|
|
verifyCommandErr(network, org2Peer0, "Admin", cancelrequestCmd, expectedMsgAdminWrongOrg)
|
|
|
|
By("calling snapshot listpending as a non-permitted identity")
|
|
listpendingCmd := &commands.SnapshotListPending{
|
|
ChannelID: "testchannel",
|
|
ClientAuth: network.ClientAuthRequired,
|
|
PeerAddress: network.PeerAddress(org1Peer0, nwo.ListenPort),
|
|
}
|
|
verifyCommandErr(network, org1Peer0, "User1", listpendingCmd, expectedMsgNonAdmin)
|
|
verifyCommandErr(network, org2Peer0, "Admin", listpendingCmd, expectedMsgAdminWrongOrg)
|
|
|
|
By("calling joinbysnapshot as a non-permitted identity")
|
|
expectedMsgNonAdmin = `\QFailed verifying that proposal's creator satisfies local MSP principal during channelless check policy with policy [Admins]: [The identity is not an admin under this MSP [Org1MSP]: The identity does not contain OU [ADMIN], MSP: [Org1MSP]]\E`
|
|
joinbysnapshotCmd := commands.ChannelJoinBySnapshot{
|
|
SnapshotPath: "/tmp/dummy_dir",
|
|
ClientAuth: network.ClientAuthRequired,
|
|
}
|
|
verifyCommandErr(network, org1Peer0, "User1", joinbysnapshotCmd, expectedMsgNonAdmin)
|
|
|
|
By("calling joinbysnapshotstatus as a non-permitted identity")
|
|
joinbysnapshotstatusCmd := commands.ChannelJoinBySnapshotStatus{
|
|
ClientAuth: network.ClientAuthRequired,
|
|
}
|
|
verifyCommandErr(network, org1Peer0, "User1", joinbysnapshotstatusCmd, expectedMsgNonAdmin)
|
|
})
|
|
})
|
|
|
|
// SetACLPolicy sets the ACL policy for a running network. It resets all
|
|
// previously defined ACL policies, generates the config update, signs the
|
|
// configuration with Org2's signer, and then submits the config update using
|
|
// Org1.
|
|
func SetACLPolicy(network *nwo.Network, channel, policyName, policy string, ordererName string) {
|
|
orderer := network.Orderer(ordererName)
|
|
submitter := network.Peer("Org1", "peer0")
|
|
signer := network.Peer("Org2", "peer0")
|
|
|
|
config := nwo.GetConfig(network, submitter, orderer, channel)
|
|
updatedConfig := proto.Clone(config).(*common.Config)
|
|
|
|
// set the policy
|
|
updatedConfig.ChannelGroup.Groups["Application"].Values["ACLs"] = &common.ConfigValue{
|
|
ModPolicy: "Admins",
|
|
Value: protoutil.MarshalOrPanic(&pb.ACLs{
|
|
Acls: map[string]*pb.APIResource{
|
|
policyName: {PolicyRef: policy},
|
|
},
|
|
}),
|
|
}
|
|
|
|
nwo.UpdateConfig(network, orderer, channel, config, updatedConfig, true, submitter, signer)
|
|
}
|
|
|
|
// GetTxIDFromBlock gets a transaction id from a block that has been
|
|
// marshaled and stored on the filesystem
|
|
func GetTxIDFromBlockFile(blockFile string) string {
|
|
block := nwo.UnmarshalBlockFromFile(blockFile)
|
|
|
|
txID, err := protoutil.GetOrComputeTxIDFromEnvelope(block.Data.Data[0])
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
return txID
|
|
}
|
|
|
|
// ToCLIChaincodeArgs converts string args to args for use with chaincode calls
|
|
// from the CLI.
|
|
func ToCLIChaincodeArgs(args ...string) string {
|
|
type cliArgs struct {
|
|
Args []string
|
|
}
|
|
cArgs := &cliArgs{Args: args}
|
|
cArgsJSON, err := json.Marshal(cArgs)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
return string(cArgsJSON)
|
|
}
|
|
|
|
func verifyCommandErr(network *nwo.Network, peer *nwo.Peer, user string, cmd nwo.Command, expectedMsg string) {
|
|
sess, err := network.PeerUserSession(peer, user, cmd)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit())
|
|
Expect(sess.Err).To(gbytes.Say(expectedMsg))
|
|
}
|