github.com/ewagmig/fabric@v2.1.1+incompatible/integration/e2e/acl_test.go (about) 1 /* 2 Copyright IBM Corp All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package e2e 8 9 import ( 10 "encoding/json" 11 "fmt" 12 "io/ioutil" 13 "os" 14 "path/filepath" 15 "syscall" 16 17 docker "github.com/fsouza/go-dockerclient" 18 "github.com/golang/protobuf/proto" 19 "github.com/hyperledger/fabric-protos-go/common" 20 pb "github.com/hyperledger/fabric-protos-go/peer" 21 "github.com/hyperledger/fabric/core/aclmgmt/resources" 22 "github.com/hyperledger/fabric/integration/nwo" 23 "github.com/hyperledger/fabric/integration/nwo/commands" 24 "github.com/hyperledger/fabric/protoutil" 25 . "github.com/onsi/ginkgo" 26 . "github.com/onsi/gomega" 27 "github.com/onsi/gomega/gbytes" 28 "github.com/onsi/gomega/gexec" 29 "github.com/tedsuo/ifrit" 30 ) 31 32 var _ = Describe("EndToEndACL", func() { 33 var ( 34 testDir string 35 client *docker.Client 36 network *nwo.Network 37 chaincode nwo.Chaincode 38 process ifrit.Process 39 40 orderer *nwo.Orderer 41 org1Peer0 *nwo.Peer 42 org2Peer0 *nwo.Peer 43 ) 44 45 BeforeEach(func() { 46 var err error 47 testDir, err = ioutil.TempDir("", "acl-e2e") 48 Expect(err).NotTo(HaveOccurred()) 49 50 client, err = docker.NewClientFromEnv() 51 Expect(err).NotTo(HaveOccurred()) 52 53 // Speed up test by reducing the number of peers we 54 // bring up and install chaincode to. 55 soloConfig := nwo.BasicSolo() 56 soloConfig.RemovePeer("Org1", "peer1") 57 soloConfig.RemovePeer("Org2", "peer1") 58 Expect(soloConfig.Peers).To(HaveLen(2)) 59 60 network = nwo.New(soloConfig, testDir, client, StartPort(), components) 61 network.GenerateConfigTree() 62 network.Bootstrap() 63 64 networkRunner := network.NetworkGroupRunner() 65 process = ifrit.Invoke(networkRunner) 66 Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed()) 67 68 orderer = network.Orderer("orderer") 69 org1Peer0 = network.Peer("Org1", "peer0") 70 org2Peer0 = network.Peer("Org2", "peer0") 71 72 chaincode = nwo.Chaincode{ 73 Name: "mycc", 74 Version: "0.0", 75 Path: "github.com/hyperledger/fabric/integration/chaincode/simple/cmd", 76 Ctor: `{"Args":["init","a","100","b","200"]}`, 77 Policy: `OR ('Org1MSP.member','Org2MSP.member')`, 78 } 79 network.CreateAndJoinChannel(orderer, "testchannel") 80 nwo.DeployChaincodeLegacy(network, "testchannel", orderer, chaincode) 81 }) 82 83 AfterEach(func() { 84 process.Signal(syscall.SIGTERM) 85 Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive()) 86 network.Cleanup() 87 os.RemoveAll(testDir) 88 }) 89 90 It("enforces access control list policies", func() { 91 invokeChaincode := commands.ChaincodeInvoke{ 92 ChannelID: "testchannel", 93 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 94 Name: chaincode.Name, 95 Ctor: `{"Args":["invoke","a","b","10"]}`, 96 WaitForEvent: true, 97 } 98 99 outputBlock := filepath.Join(testDir, "newest_block.pb") 100 fetchNewest := commands.ChannelFetch{ 101 ChannelID: "testchannel", 102 Block: "newest", 103 OutputFile: outputBlock, 104 } 105 106 // 107 // when the ACL policy for DeliverFiltered is satisified 108 // 109 By("setting the filtered block event ACL policy to Org1/Admins") 110 policyName := resources.Event_FilteredBlock 111 policy := "/Channel/Application/Org1/Admins" 112 SetACLPolicy(network, "testchannel", policyName, policy, "orderer") 113 114 By("invoking chaincode as a permitted Org1 Admin identity") 115 sess, err := network.PeerAdminSession(org1Peer0, invokeChaincode) 116 Expect(err).NotTo(HaveOccurred()) 117 Eventually(sess.Err, network.EventuallyTimeout).Should(gbytes.Say("Chaincode invoke successful. result: status:200")) 118 119 // 120 // when the ACL policy for DeliverFiltered is not satisfied 121 // 122 By("setting the filtered block event ACL policy to org2/Admins") 123 policyName = resources.Event_FilteredBlock 124 policy = "/Channel/Application/org2/Admins" 125 SetACLPolicy(network, "testchannel", policyName, policy, "orderer") 126 127 By("invoking chaincode as a forbidden Org1 Admin identity") 128 sess, err = network.PeerAdminSession(org1Peer0, invokeChaincode) 129 Expect(err).NotTo(HaveOccurred()) 130 Eventually(sess.Err, network.EventuallyTimeout).Should(gbytes.Say(`\Qdeliver completed with status (FORBIDDEN)\E`)) 131 132 // 133 // when the ACL policy for Deliver is satisfied 134 // 135 By("setting the block event ACL policy to Org1/Admins") 136 policyName = resources.Event_Block 137 policy = "/Channel/Application/Org1/Admins" 138 SetACLPolicy(network, "testchannel", policyName, policy, "orderer") 139 140 By("fetching the latest block from the peer as a permitted Org1 Admin identity") 141 sess, err = network.PeerAdminSession(org1Peer0, fetchNewest) 142 Expect(err).NotTo(HaveOccurred()) 143 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 144 Expect(sess.Err).To(gbytes.Say("Received block: ")) 145 146 // 147 // when the ACL policy for Deliver is not satisfied 148 // 149 By("fetching the latest block from the peer as a forbidden org2 Admin identity") 150 sess, err = network.PeerAdminSession(org2Peer0, fetchNewest) 151 Expect(err).NotTo(HaveOccurred()) 152 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 153 Expect(sess.Err).To(gbytes.Say("can't read the block: &{FORBIDDEN}")) 154 155 // 156 // when the ACL policy for lscc/GetInstantiatedChaincodes is satisfied 157 // 158 By("setting the lscc/GetInstantiatedChaincodes ACL policy to Org1/Admins") 159 policyName = resources.Lscc_GetInstantiatedChaincodes 160 policy = "/Channel/Application/Org1/Admins" 161 SetACLPolicy(network, "testchannel", policyName, policy, "orderer") 162 163 By("listing the instantiated chaincodes as a permitted Org1 Admin identity") 164 sess, err = network.PeerAdminSession(org1Peer0, commands.ChaincodeListInstantiatedLegacy{ 165 ChannelID: "testchannel", 166 }) 167 Expect(err).NotTo(HaveOccurred()) 168 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 169 Expect(sess).To(gbytes.Say("Name: mycc, Version: 0.0, Path: .*, Escc: escc, Vscc: vscc")) 170 171 // 172 // when the ACL policy for lscc/GetInstantiatedChaincodes is not satisfied 173 // 174 By("listing the instantiated chaincodes as a forbidden org2 Admin identity") 175 sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeListInstantiatedLegacy{ 176 ChannelID: "testchannel", 177 }) 178 Expect(err).NotTo(HaveOccurred()) 179 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 180 Expect(sess).NotTo(gbytes.Say("Name: mycc, Version: 0.0, Path: .*, Escc: escc, Vscc: vscc")) 181 Expect(sess.Err).To(gbytes.Say(`access denied for \[getchaincodes\]\[testchannel\](.*)signature set did not satisfy policy`)) 182 183 // 184 // when a system chaincode ACL policy is set and a query is performed 185 // 186 187 // getting a transaction id from a block in the ledger 188 sess, err = network.PeerAdminSession(org1Peer0, fetchNewest) 189 Expect(err).NotTo(HaveOccurred()) 190 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 191 Expect(sess.Err).To(gbytes.Say("Received block: ")) 192 txID := GetTxIDFromBlockFile(outputBlock) 193 194 ItEnforcesPolicy := func(scc, operation string, args ...string) { 195 policyName := fmt.Sprintf("%s/%s", scc, operation) 196 policy := "/Channel/Application/Org1/Admins" 197 By("setting " + policyName + " to Org1 Admins") 198 SetACLPolicy(network, "testchannel", policyName, policy, "orderer") 199 200 args = append([]string{operation}, args...) 201 chaincodeQuery := commands.ChaincodeQuery{ 202 ChannelID: "testchannel", 203 Name: scc, 204 Ctor: ToCLIChaincodeArgs(args...), 205 } 206 207 By("evaluating " + policyName + " for a permitted subject") 208 sess, err := network.PeerAdminSession(org1Peer0, chaincodeQuery) 209 Expect(err).NotTo(HaveOccurred()) 210 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 211 212 By("evaluating " + policyName + " for a forbidden subject") 213 sess, err = network.PeerAdminSession(org2Peer0, chaincodeQuery) 214 Expect(err).NotTo(HaveOccurred()) 215 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 216 Expect(sess.Err).To(gbytes.Say(fmt.Sprintf(`access denied for \[%s\]\[%s\](.*)signature set did not satisfy policy`, operation, "testchannel"))) 217 } 218 219 // 220 // qscc 221 // 222 ItEnforcesPolicy("qscc", "GetChainInfo", "testchannel") 223 ItEnforcesPolicy("qscc", "GetBlockByNumber", "testchannel", "0") 224 ItEnforcesPolicy("qscc", "GetBlockByTxID", "testchannel", txID) 225 ItEnforcesPolicy("qscc", "GetTransactionByID", "testchannel", txID) 226 227 // 228 // lscc 229 // 230 ItEnforcesPolicy("lscc", "GetChaincodeData", "testchannel", "mycc") 231 ItEnforcesPolicy("lscc", "ChaincodeExists", "testchannel", "mycc") 232 233 // 234 // cscc 235 // 236 ItEnforcesPolicy("cscc", "GetConfigBlock", "testchannel") 237 238 // 239 // _lifecycle ACL policies 240 // 241 242 chaincode = nwo.Chaincode{ 243 Name: "mycc", 244 Version: "0.0", 245 Path: components.Build("github.com/hyperledger/fabric/integration/chaincode/module"), 246 Lang: "binary", 247 PackageFile: filepath.Join(testDir, "modulecc.tar.gz"), 248 Ctor: `{"Args":["init","a","100","b","200"]}`, 249 ChannelConfigPolicy: "/Channel/Application/Endorsement", 250 Sequence: "1", 251 InitRequired: true, 252 Label: "my_prebuilt_chaincode", 253 } 254 255 nwo.PackageChaincodeBinary(chaincode) 256 257 // 258 // when the ACL policy for _lifecycle/InstallChaincode is not satisfied 259 // 260 By("installing the chaincode to an org1 peer as an org2 admin") 261 sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeInstall{ 262 PackageFile: chaincode.PackageFile, 263 PeerAddresses: []string{network.PeerAddress(org1Peer0, nwo.ListenPort)}, 264 }) 265 Expect(err).NotTo(HaveOccurred()) 266 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 267 Expect(sess.Err).To(gbytes.Say(`access denied: channel \[\] creator org \[Org2MSP\]`)) 268 269 By("installing the chaincode to an org1 peer as a non-admin org1 identity") 270 sess, err = network.PeerUserSession(org1Peer0, "User1", commands.ChaincodeInstall{ 271 PackageFile: chaincode.PackageFile, 272 }) 273 Expect(err).NotTo(HaveOccurred()) 274 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 275 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`)) 276 277 // 278 // when the ACL policy for _lifecycle/InstallChaincode is satisfied 279 // 280 nwo.InstallChaincode(network, chaincode, org1Peer0, org2Peer0) 281 282 // 283 // when the V2_0 application capabilities flag has not yet been enabled 284 // 285 By("approving a chaincode definition on a channel without V2_0 capabilities enabled") 286 sess, err = network.PeerAdminSession(org1Peer0, commands.ChaincodeApproveForMyOrg{ 287 ChannelID: "testchannel", 288 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 289 Name: chaincode.Name, 290 Version: chaincode.Version, 291 Sequence: chaincode.Sequence, 292 EndorsementPlugin: chaincode.EndorsementPlugin, 293 ValidationPlugin: chaincode.ValidationPlugin, 294 SignaturePolicy: chaincode.SignaturePolicy, 295 ChannelConfigPolicy: chaincode.ChannelConfigPolicy, 296 InitRequired: chaincode.InitRequired, 297 CollectionsConfig: chaincode.CollectionsConfig, 298 }) 299 Expect(err).NotTo(HaveOccurred()) 300 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 301 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")) 302 303 By("committing a chaincode definition on a channel without V2_0 capabilities enabled") 304 sess, err = network.PeerAdminSession(org1Peer0, commands.ChaincodeCommit{ 305 ChannelID: "testchannel", 306 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 307 Name: chaincode.Name, 308 Version: chaincode.Version, 309 Sequence: chaincode.Sequence, 310 EndorsementPlugin: chaincode.EndorsementPlugin, 311 ValidationPlugin: chaincode.ValidationPlugin, 312 SignaturePolicy: chaincode.SignaturePolicy, 313 ChannelConfigPolicy: chaincode.ChannelConfigPolicy, 314 InitRequired: chaincode.InitRequired, 315 CollectionsConfig: chaincode.CollectionsConfig, 316 }) 317 Expect(err).NotTo(HaveOccurred()) 318 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 319 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")) 320 321 // enable V2_0 application capabilities on the channel 322 By("enabling V2_0 application capabilities on the channel") 323 nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, org1Peer0, org2Peer0) 324 325 // 326 // when the ACL policy for _lifecycle/ApproveChaincodeDefinitionForOrg is not satisfied 327 // 328 By("approving a chaincode definition for org1 as an org2 admin") 329 sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeApproveForMyOrg{ 330 ChannelID: "testchannel", 331 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 332 Name: chaincode.Name, 333 Version: chaincode.Version, 334 Sequence: chaincode.Sequence, 335 EndorsementPlugin: chaincode.EndorsementPlugin, 336 ValidationPlugin: chaincode.ValidationPlugin, 337 SignaturePolicy: chaincode.SignaturePolicy, 338 ChannelConfigPolicy: chaincode.ChannelConfigPolicy, 339 InitRequired: chaincode.InitRequired, 340 CollectionsConfig: chaincode.CollectionsConfig, 341 PeerAddresses: []string{network.PeerAddress(org1Peer0, nwo.ListenPort)}, 342 }) 343 Expect(err).NotTo(HaveOccurred()) 344 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 345 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\]`)) 346 347 // 348 // when the ACL policy for _lifecycle/ApproveChaincodeDefinitionForOrg is satisfied 349 // 350 By("approving a chaincode definition for org1 and org2") 351 nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, org1Peer0, org2Peer0) 352 353 // 354 // when the ACL policy for CheckCommitReadiness is not satisified 355 // 356 By("setting the simulate commit chaincode definition ACL policy to Org1/Admins") 357 policyName = resources.Lifecycle_CheckCommitReadiness 358 policy = "/Channel/Application/Org1/Admins" 359 SetACLPolicy(network, "testchannel", policyName, policy, "orderer") 360 361 By("simulating the commit of a chaincode dwefinition as a forbidden Org2 Admin identity") 362 sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeCheckCommitReadiness{ 363 ChannelID: "testchannel", 364 Name: chaincode.Name, 365 Version: chaincode.Version, 366 Sequence: chaincode.Sequence, 367 EndorsementPlugin: chaincode.EndorsementPlugin, 368 ValidationPlugin: chaincode.ValidationPlugin, 369 SignaturePolicy: chaincode.SignaturePolicy, 370 ChannelConfigPolicy: chaincode.ChannelConfigPolicy, 371 InitRequired: chaincode.InitRequired, 372 CollectionsConfig: chaincode.CollectionsConfig, 373 }) 374 Expect(err).NotTo(HaveOccurred()) 375 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 376 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`)) 377 378 // 379 // when the ACL policy for CheckCommitReadiness is satisified 380 // 381 nwo.CheckCommitReadinessUntilReady(network, "testchannel", chaincode, network.PeerOrgs(), org1Peer0) 382 383 // 384 // when the ACL policy for CommitChaincodeDefinition is not satisified 385 // 386 By("setting the commit chaincode definition ACL policy to Org1/Admins") 387 policyName = resources.Lifecycle_CommitChaincodeDefinition 388 policy = "/Channel/Application/Org1/Admins" 389 SetACLPolicy(network, "testchannel", policyName, policy, "orderer") 390 391 By("committing the chaincode definition as a forbidden Org2 Admin identity") 392 peerAddresses := []string{ 393 network.PeerAddress(org1Peer0, nwo.ListenPort), 394 network.PeerAddress(org2Peer0, nwo.ListenPort), 395 } 396 sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeCommit{ 397 ChannelID: "testchannel", 398 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 399 Name: chaincode.Name, 400 Version: chaincode.Version, 401 Sequence: chaincode.Sequence, 402 EndorsementPlugin: chaincode.EndorsementPlugin, 403 ValidationPlugin: chaincode.ValidationPlugin, 404 SignaturePolicy: chaincode.SignaturePolicy, 405 ChannelConfigPolicy: chaincode.ChannelConfigPolicy, 406 InitRequired: chaincode.InitRequired, 407 CollectionsConfig: chaincode.CollectionsConfig, 408 PeerAddresses: peerAddresses, 409 }) 410 Expect(err).NotTo(HaveOccurred()) 411 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 412 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`)) 413 414 // 415 // when the ACL policy for CommitChaincodeDefinition is satisified 416 // 417 nwo.CommitChaincode(network, "testchannel", orderer, chaincode, org1Peer0, org1Peer0, org2Peer0) 418 419 // 420 // when the ACL policy for QueryChaincodeDefinition is satisified 421 // 422 By("setting the query chaincode definition ACL policy to Org1/Admins") 423 policyName = resources.Lifecycle_QueryChaincodeDefinition 424 policy = "/Channel/Application/Org1/Admins" 425 SetACLPolicy(network, "testchannel", policyName, policy, "orderer") 426 427 By("querying the chaincode definition as a permitted Org1 Admin identity") 428 nwo.EnsureChaincodeCommitted(network, "testchannel", "mycc", "0.0", "1", []*nwo.Organization{network.Organization("Org1"), network.Organization("Org2")}, org1Peer0) 429 430 By("querying the chaincode definition as a forbidden Org2 Admin identity") 431 sess, err = network.PeerAdminSession(org2Peer0, commands.ChaincodeListCommitted{ 432 ChannelID: "testchannel", 433 Name: "mycc", 434 }) 435 Expect(err).NotTo(HaveOccurred()) 436 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit()) 437 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`)) 438 }) 439 }) 440 441 // SetACLPolicy sets the ACL policy for a running network. It resets all 442 // previously defined ACL policies, generates the config update, signs the 443 // configuration with Org2's signer, and then submits the config update using 444 // Org1. 445 func SetACLPolicy(network *nwo.Network, channel, policyName, policy string, ordererName string) { 446 orderer := network.Orderer(ordererName) 447 submitter := network.Peer("Org1", "peer0") 448 signer := network.Peer("Org2", "peer0") 449 450 config := nwo.GetConfig(network, submitter, orderer, channel) 451 updatedConfig := proto.Clone(config).(*common.Config) 452 453 // set the policy 454 updatedConfig.ChannelGroup.Groups["Application"].Values["ACLs"] = &common.ConfigValue{ 455 ModPolicy: "Admins", 456 Value: protoutil.MarshalOrPanic(&pb.ACLs{ 457 Acls: map[string]*pb.APIResource{ 458 policyName: {PolicyRef: policy}, 459 }, 460 }), 461 } 462 463 nwo.UpdateConfig(network, orderer, channel, config, updatedConfig, true, submitter, signer) 464 } 465 466 // GetTxIDFromBlock gets a transaction id from a block that has been 467 // marshaled and stored on the filesystem 468 func GetTxIDFromBlockFile(blockFile string) string { 469 block := nwo.UnmarshalBlockFromFile(blockFile) 470 471 txID, err := protoutil.GetOrComputeTxIDFromEnvelope(block.Data.Data[0]) 472 Expect(err).NotTo(HaveOccurred()) 473 474 return txID 475 } 476 477 // ToCLIChaincodeArgs converts string args to args for use with chaincode calls 478 // from the CLI. 479 func ToCLIChaincodeArgs(args ...string) string { 480 type cliArgs struct { 481 Args []string 482 } 483 cArgs := &cliArgs{Args: args} 484 cArgsJSON, err := json.Marshal(cArgs) 485 Expect(err).NotTo(HaveOccurred()) 486 return string(cArgsJSON) 487 }