Fine-Grained Access Control Marbles Sample

The marbles chaincode application lets you create assets (marbles) with unique attributes (name, size, color and owner) and trade these assets with fellow participants in a blockchain network.

This sample application includes a variety of functions to let you examine how to work with access control lists and groups to restrict functions to certain users.

Overview of the Sample

The test scenario included in the sample contains the following restrictions in order to manage assets:

  • Bulk transfer of red marbles is only allowed by identities having the "redMarblesTransferPermission" Fabric attribute.
  • Bulk transfer of blue marbles is only allowed by identities having the "blueMarblesTransferPermission" Fabric attribute.
  • Deletion of marbles is only allowed to identities with "deleteMarblePermission" Fabric attribute.

These restrictions are enforced by implementing the following library methods in the fgMarbles_chaincode.go chaincode:

  • Create a fine-grained ACL group named bulkMarblesTransferGroup. This group will define all the identities which can transfer marbles based on color (bulk transfers):
    createGroup(stub, []string{" bulkMarblesTransferGroup", 
    "List of Identities allowed to Transfer Marbles in Bulk", 
    "%ATTR%redMarblesTransferPermission=true, %ATTR%blueMarblesTransferPermission=true", ".ACLs"})
  • Create a fine-grained ACL named redMarblesAcl which provides bulk transfer of red marbles access to bulkMarblesTransferGroup:
    createACL(stub, []string{"redMarblesAcl", 
    "ACL to control who can transfer red marbles in bulk", 
    "redMarblesTransferPermission", "%GRP%bulkMarblesTransferGroup", "true", ".ACLs"})
  • Create a fine-grained ACL named blueMarblesAcl which provides bulk transfer of blue marbles access to bulkMarblesTransferGroup:
    createACL(stub, []string{"blueMarblesAcl", 
    "ACL to control who can transfer blue marbles in bulk", 
    "blueMarblesTransferPermission", "%GRP%bulkMarblesTransferGroup", "true", ".ACLs"})
  • Create a fine-grained ACL named deleteMarbleAcl to restrict marble deletion based on "canDeleteMarble=true" Fabric attribute:
    createACL(stub, []string{"deleteMarbleAcl", 
    "ACL to control who can Delete a Marble", 
    "deleteMarblePermission", "%ATTR%deleteMarblePermission=true", "true", ".ACLs"})
  • Create a fine-grained ACL resource named marble, operations on which are controlled using the various ACLs we created:
    createResource(stub, []string{"marble", 
    "System marble resource", 
    "deleteMarbleAcl,blueMarblesAcl,redMarblesAcl,.ACLs"})

Pre-requisites and Setup

In order to run the fine-grained access control version of the marbles sample, complete these steps:

  1. Download the fine-grained access control version of the marbles sample. On the Developer Tools tab, open the Samples pane, and then click the download link under Marbles with Fine-Grained ACLs. Extract this package - it contains ZIP files of the marbles sample (fgACL_MarbleSampleCC.zip), Node.js files to run the sample (fgACL-NodeJSCode.zip), and the fine-grained access control library (Fine-GrainedAccessControlLibrary.zip).
  2. Hyperledger Fabric v2.x only: Generate the chaincode package that will be deployed to Blockchain Platform:
    • Extract the contents of the fgACL_MarbleSampleCC.zip file to the fgACL_MarbleSampleCC directory. The contents of the fgACL_MarbleSampleCC directory will be the fgACL_Operations.go, fgGroups_Operations.go, fgMarbles_chaincode.go ,fgResource_Operations.go, and go.mod files and the oracle.com directory.
    • From the command line, go to the fgACL_MarbleSampleCC directory, and run GO111MODULE=on go mod vendor. This command downloads the required dependencies and adds them to the vendor directory.
    • Compress all the contents (the four Go files, the go.mod file, and the vendor and oracle.com directories) of the fgACL_MarbleSampleCC directory in ZIP format. Your chaincode is ready to be deployed to Blockchain Platform.
  3. Hyperledger Fabric v1.4.7 only: Generate the chaincode package that will be deployed to Blockchain Platform:
    • Install govendor:
      go get -u github.com/kardianos/govendor
    • Extract the contents of fgACL_MarbleSampleCC.zip to the fgACL_MarbleSampleCC directory. The contents of the fgACL_MarbleSampleCC directory would be: fgACL_Operations.go, fgGroups_Operations.go, fgMarbles_chaincode.go, fgResource_Operations.go and the vendor directory.
    • From a command line, go to the fgACL_MarbleSampleCC directory, and run govendor sync. This will download the required dependency (github.com/op/go-logging) and add it to the vendor directory.
    • Compress all the contents (the four Go files and the vendor directory) of the fgACL_MarbleSampleCC directory in ZIP format. Your chaincode is ready to be deployed to Blockchain Platform.
  4. Install and deploy the updated sample chaincode package (fgACL_MarbleSampleCC.zip) as described in Use Quick Deployment.
  5. On the Developer Tools tab, open the Application Development pane, and then follow the instructions to download the Node.js SDK.
  6. On the Developer Tools tab, open the Application Development pane, and then click Download the development package.
    1. Extract the development package into the same folder with the Node.js files downloaded with the sample.
    2. In the network.yaml file, look for the certificateAuthorities entry and its registrar entry. The administrator's password is masked (converted to ***) in the network.yaml when downloaded. It should be replaced with the administrator's clear text password when running this sample.
  7. Register a new identity with your Blockchain Platform instance:
    1. Create a new user in IDCS (referred to as <NewIdentity> in the following steps) in the IDCS mapped to your tenancy.
    2. Give this user the CA_User application role for your instance.

Implement the Fine-Grained Access Control Marble Sample

The following steps will enroll your new user and implement the ACL restrictions using the provided Node.js scripts.

  1. Enroll the new user:
    node registerEnrollUser.js <NewIdentity> <Password>
  2. Initialization: Initialize the access control lists.
    node invokeQueryCC.js <NewIdentity> <Password> <ChannelName> <ChaincodeName> ACLInitialization
  3. Create the access control lists, groups, and resources: This creates the ACL resources described in the overview.
    node invokeQueryCC.js <NewIdentity> <Password> <ChannelName> <ChaincodeName> createFineGrainedAclSampleResources
  4. Create your test marble resources: This creates several test marble assets - blue1 and blue2 owned by tom, red1 and red2 owned by jerry, and green1 and green2 owned by spike.
    node invokeQueryCC.js <NewIdentity> <Password> <ChannelName> <ChaincodeName> createTestMarbles

Testing the Access Control

In order to test that our access control lists are only allowing the correct users to perform each function, we'll run through some sample scenarios.

  1. Transfer a marble: We're transferring marble blue1 from tom to jerry. Since there are no restrictions on who can transfer a single marble, this should complete successfully.
    node invokeQueryCC.js <NewIdentity> <Password> <ChannelName> <ChaincodeName> transferMarble blue1 jerry
  2. Transfer a marble as the administrative user: We're transferring marble blue1 from jerry to spike. Since there are no restrictions on who can transfer a single marble, this should also complete successfully.
    node invokeQueryCC.js <AdminIdentity> <Password> <ChannelName> <ChaincodeName> transferMarble blue1 spike
  3. Get history: Now we'll query the history of the marble named blue1. It should return that it was transferred first to jerry then to spike.
    node invokeQueryCC.js <AdminIdentity> <Password> <ChannelName> <ChaincodeName> getHistoryForMarble blue1
  4. Transfer all red marbles: The redMarblesAcl ACL should allow this transfer because the newly registered identity has the required "redMarblesTransferPermission=true" Fabric attribute, so the two red marbles should be transferred to tom.
    node invokeQueryCC.js <NewIdentity> <Password> <ChannelName> <ChaincodeName> transferMarblesBasedOnColor red tom
  5. Transfer all red marbles as the administrative user: The administrative identity doesn't have the "redMarblesTransferPermission=true" Fabric attribute, so the redMarblesAcl ACL should block this transfer.
    node invokeQueryCC.js <AdminIdentity> <Password> <ChannelName> <ChaincodeName> transferMarblesBasedOnColor red jerry
  6. Transfer all green marbles: By default, only explicitly defined access is allowed. Because there isn't an ACL which allows for bulk transfer of green marbles, this should fail.
    node invokeQueryCC.js <NewIdentity> <Password> <ChannelName> <ChaincodeName> transferMarblesBasedOnColor green tom
  7. Delete a marble: The deleteMarbleAcl ACL allows this deletion because the newly registered identity has the required "deleteMarblePermission=true" Fabric attribute.
    node invokeQueryCC.js <NewIdentity> <Password> <ChannelName> <ChaincodeName> delete green1
  8. Delete a marble as the administrative user: The deleteMarbleAcl ACL should prevent this deletion because the administrative identity doesn't have the required "deleteMarblePermission=true" Fabric attribute.
    node invokeQueryCC.js < AdminIdentity > <Password> <ChannelName> <ChaincodeName> delete green2

Sample Files Reference

These tables list the methods available in the chaincode and application files included with the sample.

fgMarbles_chaincode.go

Function Description
initMarble Create a new marble
transferMarble Transfer a marble from one owner to another based on name
createTestMarbles Calls initMarble to create new sample marbles for testing purposes
createFineGrainedAclSampleResources Creates the fine-grained access control list (ACL), groups, and resources required by our test scenario
transferMarblesBasedOnColor Transfers multiple marbles of a certain color to another owner
delete Delete a marble
readMarble Returns all attributes of a marble based on name
getHistoryForMarble Returns a history of values for a marble

fgACL_Operations.go

Methods Parameters Description
getACL
  • name
Get a named ACL or read all ACLs. The user invoking the method must have READ access to the named ACL.
createACL
  • name
  • description
  • accesses
  • patterns
  • allowed
  • BindACLs
  • Identity_Certificate
To create a new ACL, the user invoking the method needs to have CREATE access to the bootstrap resource named ". ACLs". Duplicate named ACLs are not allowed
deleteACL
  • name
The user invoking the method must have DELETE access to the named ACL.
updateACL
  • name
  • description
  • accesses
  • patterns
  • allowed
  • BindACLs
The user invoking the method must have UPDATE access to the named resource, and the named ACL must exist.
addAfterACL
  • aclName
  • existingBindAclName
  • newBindAclName
The user invoking the method must have UPDATE access to the named resource, and the named ACL must exist.
addBeforeACL
  • aclName
  • existingBindAclName
  • newBindAclName
The user invoking the method must have UPDATE access to the named resource, and the named ACL must exist.
addPatternToACL
  • aclName
  • BindPattern
The user invoking the method must have UPDATE access to the named resource, and the named ACL must exist.
removePatternFromACL
  • aclName
  • BindPattern
The user invoking the method must have UPDATE access to the named resource, and the named ACL must exist.
updateDescription
  • aclName
  • newDesc
The user invoking the method must have UPDATE access to the named resource, and the named ACL must exist.
removeBindACL
  • aclName
  • bindAclNameToRemove
The user invoking the method must have UPDATE access to the named resource, and the named ACL must exist.
addAccess
  • aclName
  • accessName
The user invoking the method must have UPDATE access to the named resource, and the named ACL must exist.
removeAccess
  • aclName
  • accessName
The user invoking the method must have UPDATE access to the named resource, and the named ACL must exist.
ACLInitialization
  • none
This function is used to initialize the fine-grained ACL support.

fgGroups_Operations.go

Methods Parameters Description
getGroup
  • name

If name="GetAll", it returns all the groups the identity has access to. Otherwise, it returns the individual group details (if accessible) based on name.

The user invoking the method must have READ access to this group.

createGroup
  • name
  • description
  • patterns
  • bindACLs

Returns success or error.

The user invoking the method must have CREATE access to bootstrap group ". Group"

deleteGroup
  • name
The user invoking the method must have DELETE access to this group.
addAfterGroup
  • groupName
  • existingBindAclName
  • newBindAclName
The user invoking the method must have UPDATE access to this group.
addBeforeGroup
  • groupName
  • existingBindAclName
  • newBindAclName
The user invoking the method must have UPDATE access to this group.
updateDescriptionForGroup
  • groupName
  • newDesc
The user invoking the method must have UPDATE access to this group.
removeBindAclFromGroup
  • groupName
  • bindAclNameToRemove
The user invoking the method must have UPDATE access to this group.
addMembersToGroup
  • groupName
  • pattern
The user invoking the method must have UPDATE access to this group.
removeMembersFromGroup
  • groupName
  • pattern
The user invoking the method must have UPDATE access to this group.

fgResource_Operations.go

Methods Parameters Description
createResource
  • name
  • description
  • bindACLs
The user invoking the method needs to have CREATE access to the bootstrap resource named ". Resources". Duplicate named resources are not allowed.
getResource
  • name
The user invoking the method must have READ access to the resource
deleteResource
  • name
The user invoking the method must have DELETE access to the named resource
addAfterACLInResource
  • ResourceName
  • existingBindAclName
  • newBindAclName
The user invoking the method must have UPDATE access to this resource
addBeforeACLInResource
  • ResourceName
  • existingBindAclName
  • newBindAclName
The user invoking the method must have UPDATE access to this resource
updateDescriptionInResource
  • ResourceName
  • newDesc
The user invoking the method must have UPDATE access to this resource
removeBindACLInResource
  • ResourceName
  • bindAclNameToRemove
The user invoking the method must have UPDATE access to this resource
checkResourceAccess
  • ResourceName
  • access
Checks whether the current user invoking the method has the specified access to the named resource.