83634

Restrictive ACL for Trading network in Hyperledger Composer

Question:

I couldn't solve my problem, so i try to explain it again: There are 2 Participants (Provider). Both of them holds own Wallet and Account and they want to exchange Cash to Tokens or visa versa. They should have just READ-access to their own assets, because of fraud, security etc. But for transactions they need UPDATE-access. Here is my code:

org.acme.biznet.cto:

namespace org.acme.biznet abstract participant Member identified by memberId { o String memberId o String name o String email } // Sensorbesitzer, z.B private Personen, Haushalte etc. participant Provider identified by providerId extends Member { o String providerId --> SDTWallet sdtWallet --> Account account } // SDT Token Wallet von den Netzwerkteilnehmern. asset SDTWallet identified by sdtWalletId { o String sdtWalletId o Double balance default = 0.0 --> Member owner } // Geldkonto von den Netzwerkteilnehmern. asset Account identified by accountId { o String accountId o Double balance default = 0.0 --> Member owner } // Cash gegen Tokens getauscht. transaction TradeCashToTokens { o Double cashRate default = 2.0 o Double cashValue default = 1.0 range = [1.0,] --> SDTWallet fromSDT --> SDTWallet toSDT --> Account fromCash --> Account toCash } // Tokens gegen Cash getauscht. transaction TradeTokensToCash { o Double tokenRate default = 0.5 o Double tokenValue default = 2.0 range = [2.0,] --> SDTWallet fromSDT --> SDTWallet toSDT --> Account fromCash --> Account toCash }

and logic.js:

/** * Cash to tokens transaction * @param {org.acme.biznet.TradeCashToTokens} UpdateValues * @transaction */ function TradeCashToTokens(UpdateValues) { //determine change in tokens value from the rate var tokensChange = (UpdateValues.cashRate * UpdateValues.cashValue); if(UpdateValues.fromCash.balance < UpdateValues.cashValue) { throw new Error('Insufficient cash funds!'); } else if (tokensChange > UpdateValues.fromSDT.balance) { throw new Error('Not enough tokens for this transaction!'); } //alert("Fehler!"); //update values of exchanger1 cash account console.log('#### exchanger1 cash balance before: ' + UpdateValues.fromCash.balance); UpdateValues.fromCash.balance -= UpdateValues.cashValue; console.log('#### exchanger1 cash balance after: ' + UpdateValues.fromCash.balance); //update values of exchanger2 cash account console.log('#### exchanger2 cash balance before: ' + UpdateValues.toCash.balance); UpdateValues.toCash.balance += UpdateValues.cashValue; console.log('#### exchanger2 cash balance after: ' + UpdateValues.toCash.balance); //update values of exchanger1 token wallet console.log('#### exchanger1 token balance before: ' + UpdateValues.toSDT.balance); UpdateValues.toSDT.balance += tokensChange; console.log('#### exchanger1 token balance after: ' + UpdateValues.toSDT.balance); //update values of exchanger2 token wallet console.log('#### exchanger2 token balance before: ' + UpdateValues.fromSDT.balance); UpdateValues.fromSDT.balance -= tokensChange; console.log('#### exchanger2 token balance after: ' + UpdateValues.fromSDT.balance); console.log(UpdateValues.cashValue + ' EUR exchanged to ' + tokensChange + ' SDT Tokens with actual rate of ' + UpdateValues.cashRate); return getAssetRegistry('org.acme.biznet.SDTWallet') .then(function (assetRegistry) { return assetRegistry.updateAll([UpdateValues.toSDT,UpdateValues.fromSDT]); }) .then(function () { return getAssetRegistry('org.acme.biznet.Account') .then(function (assetRegistry) { return assetRegistry.updateAll([UpdateValues.toCash,UpdateValues.fromCash]); }); }); }

and permissions.acl:

//****************PROVIDER_PARTICIPANTS********************** //Provider has access only to their own profile rule ProviderAccessOwnProfile { description: "Allow providers to access only their profile" participant(p): "org.acme.biznet.Provider" operation: READ, UPDATE resource(r): "org.acme.biznet.Provider" condition: (r.getIdentifier() === p.getIdentifier()) action: ALLOW } //Provider has read only access to other Providers rule ProviderReadAccessProviders { description: "Allow provider read access to other providers" participant: "org.acme.biznet.Provider" operation: READ resource: "org.acme.biznet.Provider" action: ALLOW } //****************PROVIDER_ASSETS********************** rule ProvidersReadAccesstoAccount { description: "Traders see their own BankAccount only" participant: "org.acme.biznet.Provider" operation: READ resource: "org.acme.biznet.Account" action: ALLOW } rule ProvidersReadAccesstoSDTWallet { description: "Providers see their own SDT Wallet only" participant: "org.acme.biznet.Provider" operation: READ resource: "org.acme.biznet.SDTWallet" action: ALLOW } //Provider can submit CashToToken transaction rule ProvidercanUpdateAccountthroughTransactionOnly { description: "Allow trader to submit trade transactions" participant(p): "org.acme.biznet.Provider" operation: READ, UPDATE resource(r): "org.acme.biznet.Account" transaction(tx): "org.acme.biznet.TradeCashToTokens" condition: (p.getIdentifier() === r.owner.getIdentifier() && r.getIdentifier() === tx.toCash.getIdentifier()) action: ALLOW } //Provider can submit CashToToken transaction rule ProvidercanUpdateSDTWalletthroughTransactionOnly { description: "Allow trader to submit trade transactions" participant(p): "org.acme.biznet.Provider" operation: READ, UPDATE resource(r): "org.acme.biznet.SDTWallet" transaction(tx): "org.acme.biznet.TradeCashToTokens" condition: (p.getIdentifier() === r.owner.getIdentifier() && r.getIdentifier() === tx.fromSDT.getIdentifier()) action: ALLOW } //****************PROVIDER_TRANSACTIONS********************** //Provider can submit CashToTokens transaction rule ProviderSubmitCashToTokenTransactions { description: "Allow provider to submit cash to tokens transactions" participant: "org.acme.biznet.Provider" operation: CREATE, READ resource: "org.acme.biznet.TradeCashToTokens" action: ALLOW } //Provider can submit TokenToCash transaction rule ProviderSubmitTokensToCashTransactions { description: "Allow provider to submit tokens to cash transactions" participant: "org.acme.biznet.Provider" operation: CREATE, READ resource: "org.acme.biznet.TradeTokensToCash" action: ALLOW } //****************PROVIDER_HISTORY********************** //Provider can see the history of own transactions only rule ProviderSeeOwnHistoryOnly { description: "Proviers should be able to see the history of their own transactions only" participant(p): "org.acme.biznet.Provider" operation: READ resource(r): "org.hyperledger.composer.system.HistorianRecord" condition: (r.participantInvoking.getIdentifier() != p.getIdentifier()) action: DENY } //*********************NETWORK*************************** rule SystemACL { description: "System ACL to permit all access" participant: "org.hyperledger.composer.system.Participant" operation: ALL resource: "org.hyperledger.composer.system.**" action: ALLOW } rule NetworkAdminUser { description: "Grant business network administrators full access to user resources" participant: "org.hyperledger.composer.system.NetworkAdmin" operation: ALL resource: "**" action: ALLOW } rule NetworkAdminSystem { description: "Grant business network administrators full access to system resources" participant: "org.hyperledger.composer.system.NetworkAdmin" operation: ALL resource: "org.hyperledger.composer.system.**" action: ALLOW }

And when i want to try make transactions as Provider, e.g. TradeCachToTokens, it says t: Participant 'org.acme.biznet.Provider#P1' does not have 'UPDATE' access to resource 'org.acme.biznet.SDTWallet#SDT1'

please see the screenshot: <a href="https://i.stack.imgur.com/rz47Z.png" rel="nofollow">cash_to_tokens</a>

Provider(P1) should get UPDATE-access for Wallet and Account, if he make transaction, but not only his own, for his opposite (P2) too.

Whats the problem here?

Answer1:

UPDATED ANSWER: the answer is (May 10):

<ol><li>

You are updating the registries org.acme.biznet.SDTWallet and org.acme.bixnet.Account - and I see you have rules to allow updates to occur from the transaction TradeCashToTokens or indeed TradeTokensToCash. I think the problem is the condition should be || and not && - one resource at a time is evaluated, and the resource owner can be TRUE in the conditional match. As the trxn is invoked by the participant, should always evaluate TRUE (unless he's not the resource owner of course), part A of the condition ; for the target resource (toCash or toSDT), you compare it with the owner of the resource (being updated in your transaction function code - names as above). Note the rules are based allowing the invoking participant update the 2 target resources (based on participant, not Account - ps I think the reason your 'SDT' rule failed is because the rule says 'fromSDT' (evaluates to one target resource only).

Suggest a set of rules like:

rule UpdateAccountsviaTradeCashToTokens { description: "Allow source/target providers defined in trxn (ie 2)- to access/update their Accounts from, trxn TradeCashToTokens only" participant(p): "org.acme.biznet.Provider" operation: READ, UPDATE resource(r): "org.acme.biznet.Account" transaction(tx): "org.acme.biznet.TradeCashToTokens" condition: ( p.getIdentifier() === r.owner.getIdentifier() || tx.toCash.owner.getIdentifier() === r.owner.getIdentifier() ) action: ALLOW } rule UpdateSDTWalletsviaTradeCashToTokens { description: "Allow source/target providers defined in trxn (ie 2)- to access/update their SDT Wallets from, trxn TradeCashToTokens only" participant(p): "org.acme.biznet.Provider" operation: READ, UPDATE resource(r): "org.acme.biznet.SDTWallet" transaction(tx): "org.acme.biznet.TradeCashToTokens" condition: ( p.getIdentifier() === r.owner.getIdentifier() || tx.toSDT.owner.getIdentifier() === r.owner.getIdentifier() ) action: ALLOW } </li> <li>

Similarly - for the other transaction TradeTokenstoCash you can have

rule UpdateAccountsviaTradeTokensToCash { description: "Allow source/target providers defined in trxn (ie 2)- to access/update their Accounts from, trxn TradeTokensToCash only" participant(p): "org.acme.biznet.Provider" operation: READ, UPDATE resource(r): "org.acme.biznet.Account" transaction(tx): "org.acme.biznet.TradeTokensToCash" condition: ( p.getIdentifier() === r.owner.getIdentifier() || tx.toCash.owner.getIdentifier() === r.owner.getIdentifier() ) action: ALLOW } rule UpdateSDTWalletsviaTradeTokenstoCash { description: "Allow source/target providers defined in trxn (ie 2)- to access/update their SDT Wallets from, trxn TradeTokenstoCash only" participant(p): "org.acme.biznet.Provider" operation: READ, UPDATE resource(r): "org.acme.biznet.SDTWallet" transaction(tx): "org.acme.biznet.TradeTokenstoCash" condition: ( p.getIdentifier() === r.owner.getIdentifier() || tx.toSDT.owner.getIdentifier() === r.owner.getIdentifier() ) action: ALLOW } </li> <li>

You will still need your PROVIDER_TRANSACTIONS rules.

</li> <li>

You are correct to say you will need the PROVIDER_ASSETS rules - before the transaction update based rules (ie mentioned above).

</li> <li>

I have created an ACL tutorial - that I will incorporate into the Composer docs in due course (for benefit of others too) - similar to what you've done.

</li> </ol>

<a href="https://github.com/mahoney1/test/blob/master/acl_dynamic.md" rel="nofollow">https://github.com/mahoney1/test/blob/master/acl_dynamic.md</a>

Hope this helps, have tried your complete ruleset with changes and it works; if you wish me to post the complete set of rules, let me know.

Recommend