Search code examples
hyperledger-fabricblockchainhyperledgersmartcontractshyperledger-chaincode

Hyperledger Fabric: is there a way to prevent a member of an organization to access a specific smart contract within a chaincode on a channel?


Suppose I have two organizations on the same channel, A and B, and a chaincode including these methods:

  • queryA;
  • queryB (that returns a different set of data as output than queryA);
  • create;
  • update;
  • submitNewData.

How can I restrict access of the single methods so that, for example, a member of A can only access create, update and queryA; a member of B can only access submitNewData and queryB. So, a member of A can create the asset and modify a subset of fields (with "update"), a member of B can only modify another subset of fields (according to "submitNewData) and cannot create the asset.

If a peer of B executes a "peer chaincode invoke" to create or queryA, the access is denied.

Should I use ACLs? But how can I refer to the specific smart contract inside the chaincode?


Solution

  • You begin talking about a "member", but later you talk about a "peer".

    You cannot restrict operations per peer. Every peer joined to the channel with the chaincode installed must proceed in the same way, so that the chaincode works in a deterministic way.

    But you can, of course, restrict operations for the requestor, by evaluating its user ID, MSP ID, certificate attributes or whatever you want. For instance, in Go chaincodes, it is usually evaluated in BeforeTransaction function:

    
    type SmartContract struct {
        contractapi.Contract
    }
    
    func checkACL(ctx contractapi.TransactionContextInterface) error {
        // Read incoming data from stub
        stub := ctx.GetStub()
    
        // Extract operation name
        operation, parameters := stub.GetFunctionAndParameters()
        operationSplitted := strings.Split(operation, ":")
        operationName := operationSplitted[len(operationSplitted)-1]
    
        // Get requestor info from stub
        mspID, err := cid.GetMSPID(stub)
        userID, err := cid.GetID(stub)
        value, found, err := cid.GetAttributeValue(stub, "role")
    
        // Evaluate your ACLs by contrasting the operation and the requestor your own way
        // ...
    
        // Return error when disallowed
    
        // Operation allowed
        return nil
    }
    
    func BeforeTransaction(ctx contractapi.TransactionContextInterface) error {
        return checkACL(ctx)
    }
    
    func NewSmartContract() *SmartContract {
        sc := new(SmartContract)
        sc.BeforeTransaction = BeforeTransaction
        // ...
        return sc
    }